# 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
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
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS ON)
-# Set a default valgrind suppression file.
-# This unfortunately needs to duplicate information from CTest to work as
-# expected...
-set(MEMORYCHECK_SUPPRESSIONS_FILE
- "${CMAKE_SOURCE_DIR}/cmake/legacy_and_external.supp"
- CACHE FILEPATH
- "File that contains suppressions for the memory checker")
-include(CTest)
+include(gmxCTestUtilities)
+gmx_ctest_init()
include(gmxCPackUtilities)
gmx_cpack_init()
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)
# 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
# Find external packages #
########################################################################
-# TNG wants zlib if it is available. And static libxml2 might have a dependency
-find_package(ZLIB QUIET)
-include(gmxTestZLib)
-gmx_test_zlib(HAVE_ZLIB)
-
# Unconditionally find the package, as it is also required for unit
# tests. This exports LIBXML2_FOUND, which we should not use because
# it does not tell us that linking will succeed. Instead, we test that
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.")
add_definitions(-DTMPI_ATOMICS_DISABLED)
endif()
-# Note this relies on zlib detection having already run
include(gmxManageTNG)
include(gmxManageLmfit)
if(GMX_GPU)
# now that we have detected the dependencies, do the second configure pass
gmx_gpu_setup()
-else()
- mark_as_advanced(CUDA_HOST_COMPILER)
endif()
if(CYGWIN)
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)
################################################################
# Shared library load path settings
################################################################
-# CMake supports RPATH on OS X only from 2.8.12 upwards.
-# CMAKE_SYSTEM_VERSION > 8.0 matches OS X 10.5 and above, where RPATH support
-# was added.
-
if(NOT GMX_BUILD_SHARED_EXE)
# No rpath
set(CMAKE_SKIP_RPATH TRUE)
set(CMAKE_EXE_LINK_DYNAMIC_C_FLAGS) # remove -Wl,-Bdynamic
set(CMAKE_EXE_LINK_DYNAMIC_CXX_FLAGS)
-elseif((NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") OR
- ((CMAKE_SYSTEM_VERSION VERSION_GREATER 8.0) AND (NOT CMAKE_VERSION VERSION_LESS 2.8.12)))
+else()
# The build folder always has bin/ and lib/; if we are also going to
# install to lib/, then the installation RPATH works also in the build
# tree. This makes installation slightly faster (no need to rewrite the
endif()
# Set the RPATH as relative to the executable location to make the
# binaries relocatable.
- if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ if(NOT CMAKE_SYSTEM_NAME STREQUAL "Darwin") #Assume OS X >=10.5
set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${GMX_LIB_INSTALL_DIR}")
else()
set(CMAKE_INSTALL_RPATH "@executable_path/../${GMX_LIB_INSTALL_DIR}")
endif()
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
set(CMAKE_MACOSX_RPATH 1)
-else()
- # We are on Darwin/OSX, and CMake cannot handle RPATHs automatically.
- if(CMAKE_SYSTEM_VERSION VERSION_GREATER 8.0)
- # Set the RPATH options manually.
- set(CMAKE_INSTALL_NAME_DIR "@rpath")
- set(GMX_EXE_LINKER_FLAGS ${GMX_EXE_LINKER_FLAGS} "-Wl,-rpath,@executable_path/../${GMX_LIB_INSTALL_DIR}")
- else()
- # Use the old INSTALL_NAME_DIR mechanism if RPATH is not supported.
- set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}")
- endif()
endif()
#COPYING file: Only necessary for binary distributions.
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)
--- /dev/null
+The GROMACS developers generally suggest you install GROMACS for
+production scientific use only from a tarball from an official
+source-code release.
+
+However, if you have a special need and wish to build and/or install a
+version from a git repository, please see
+docs/install-guide/index.rst in this repository, or (if applicable)
+the latest master branch documentation found via
+http://manual.gromacs.org/documentation/.
+
+Note for GROMACS developers
+---------------------------
+This file is excluded from the GROMACS source packages made with CPack,
+and not included into binary packages made with CPack. Source packages
+do include an INSTALL file containing the installation instructions, which
+has been compiled into plain text by Sphinx from docs/install-guide.
import os.path
-build_options = ['gcc-4.6']
+build_options = ['gcc-6.1', 'gcov-6.1']
extra_projects = [Project.REGRESSIONTESTS]
def do_build(context):
# TODO: Make the XMLs go directly to the desired folder.
# xml_dir = context.workspace.get_log_dir(category='cppcheck')
cmake_opts = {
- 'CPPCHECK_EXECUTABLE': context.env.get_cppcheck_command(version='1.72'),
+ 'CPPCHECK_EXECUTABLE': context.env.get_cppcheck_command(version='1.76.1'),
'CPPCHECK_XML_OUTPUT': 'ON',
'GMX_SIMD': 'Reference'
}
if context.opts.x11:
cmake_opts['GMX_X11'] = 'ON'
+ # At least hwloc on Jenkins produces a massive amount of reports about
+ # memory leaks, which cannot be reasonably suppressed because ASAN cannot
+ # produce a reasonable stack trace for them.
+ if context.opts.asan:
+ cmake_opts['GMX_HWLOC'] = 'OFF'
+
regressiontests_path = context.workspace.get_project_dir(Project.REGRESSIONTESTS)
if context.job_type == JobType.RELEASE:
else:
context.build_target(target='tests', keep_going=True)
- context.run_ctest(args=['--output-on-failure'])
+ context.run_ctest(args=['--output-on-failure'], memcheck=context.opts.asan)
context.build_target(target='install')
# TODO: Consider what could be tested about the installed binaries.
use_tmpi = not context.opts.mpi and context.opts.thread_mpi is not False
cmd = 'perl gmxtest.pl -mpirun mpirun -xml -nosuffix all'
- if context.opts.asan:
- cmd+=' -parse asan_symbolize.py'
# setting this stuff below is just a temporary solution,
# it should all be passed as a proper the runconf from outside
cmd += ' -nt 2'
if context.opts.double:
cmd += ' -double'
+ if context.opts.asan:
+ context.env.set_env_var('ASAN_OPTIONS', 'detect_leaks=0')
context.run_cmd(cmd, shell=True, failure_message='Regression tests failed to execute')
-gcc-4.6 gpu cuda-5.0 mpi openmp x11 cmake-2.8.8
-gcc-4.8 gpu cuda-7.5 openmp release
+gcc-4.8 gpu cuda-6.5 mpi openmp x11
+gcc-4.8 gpu cuda-8.0 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
+clang-3.8 no-openmp 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
-gcc-4.8 openmp opencl cuda-7.5 mpi release
-gcc-5.2 openmp opencl amdappsdk-3.0
+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-8.0 mpi release
+gcc-5.2 openmp opencl simd=avx_128_fma amdappsdk-3.0
import os.path
-# TODO when merging this to master, update gcc to 4.8
-build_options = ['gcc-4.7', 'cmake-3.4.3']
+build_options = ['gcc-4.8', 'cmake-3.4.3']
extra_projects = [Project.REGRESSIONTESTS]
def run_build(context, cmake_opts):
# 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
+++ /dev/null
-#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;
-}
-
+++ /dev/null
-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
-}
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2014, by the GROMACS development team, led by
+# 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.
set(CMAKE_${_language}_FLAGS_ASAN ${_flags} CACHE STRING "${_human_readable_language} flags for address sanitizer")
mark_as_advanced(CMAKE_${_language}_FLAGS_ASAN)
endforeach()
-
-string(TOUPPER "${CMAKE_BUILD_TYPE}" _cmake_build_type)
-if (APPLE AND _cmake_build_type STREQUAL ASAN) #https://code.google.com/p/address-sanitizer/issues/detail?id=210
- set(BUILD_SHARED_LIBS OFF CACHE BOOL "Disabled for ASAN builds" FORCE)
-endif()
-
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()
# Problematic with CUDA
# GMX_TEST_CXXFLAG(CXXFLAGS_WARN_EFFCXX "-Wnon-virtual-dtor" GMXC_CXXFLAGS)
GMX_TEST_CXXFLAG(CXXFLAGS_WARN_EXTRA "-Wextra -Wno-missing-field-initializers -Wpointer-arith" GMXC_CXXFLAGS)
- GMX_TEST_CXXFLAG(CXXFLAGS_WARN_UNDEF "-Wundef" GMXC_CXXFLAGS)
+ # CUDA versions prior to 7.5 come with a header (math_functions.h) which uses the _MSC_VER macro
+ # unconditionally, so we don't use -Wundef for earlier CUDA versions.
+ if(NOT(GMX_GPU AND CUDA_VERSION VERSION_LESS "7.5"))
+ GMX_TEST_CXXFLAG(CXXFLAGS_WARN_UNDEF "-Wundef" GMXC_CXXFLAGS)
+ endif()
GMX_TEST_CFLAG(CXXFLAGS_WARN_REL "-Wno-array-bounds" GMXC_CXXFLAGS_RELEASE_ONLY)
endif()
# new in gcc 4.5
if (CMAKE_C_COMPILER_ID MATCHES "Intel")
if (NOT WIN32)
if(NOT GMX_OPENMP)
- if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 13.99.99)
# 3180: unrecognized OpenMP #pragma
- GMX_TEST_CFLAG(CFLAGS_PRAGMA "-wd3180" GMXC_CFLAGS)
- else()
-# 161: unrecognized #pragma
- GMX_TEST_CFLAG(CFLAGS_PRAGMA "-wd161" GMXC_CFLAGS)
- endif()
+ GMX_TEST_CFLAG(CFLAGS_PRAGMA "-wd3180" GMXC_CFLAGS)
endif()
if (GMX_COMPILER_WARNINGS)
- if(CMAKE_C_COMPILER_VERSION VERSION_LESS 15.00.00)
-# 193: zero used for undefined preprocessing identifier ".."
- GMX_TEST_CFLAG(CFLAGS_WARN_OLD -wd193 GMXC_CFLAGS)
- endif()
# 177: function/variable ".." was declared but never referenced
-# 271: trailing comma is nonstandard
-# 304: access control not specified ("public" by default)
-# 383: value copied to temporary, reference to temporary used
-# 424: extra ";" ignored
-# 444: destructor for base class ".." is not virtual
-# 522: function ".." redeclared "inline" after being called
+# 411: class defines no constructor to initialize the following (incorrect for struct, initializer list works)
# 593: variable ".." was set but never used
-# 869: parameter ".." was never referenced
# 981: operands are evaluated in unspecified order
#1418: external function definition with no prior declaration
#1419: external declaration in primary source file
#2547: ".." was specified as both a system and non-system include directory
#2557: comparison between signed and unsigned operands
#3280: declaration hides member ".."
-#3346: dynamic exception specifications are deprecated
#11074: Inlining inhibited by limit max-size(/max-total-size)
#11076: To get full report use -opt-report=3 -opt-report-phase ipo (shown for previous remark)
- GMX_TEST_CFLAG(CFLAGS_WARN "-w3 -wd177 -wd271 -wd304 -wd383 -wd424 -wd444 -wd522 -wd593 -wd869 -wd981 -wd1418 -wd1419 -wd1572 -wd1599 -wd2259 -wd2415 -wd2547 -wd2557 -wd3280 -wd3346 -wd11074 -wd11076" GMXC_CFLAGS)
+ GMX_TEST_CFLAG(CFLAGS_WARN "-w3 -wd177 -wd411 -wd593 -wd981 -wd1418 -wd1419 -wd1572 -wd1599 -wd2259 -wd2415 -wd2547 -wd2557 -wd3280 -wd11074 -wd11076" GMXC_CFLAGS)
endif()
GMX_TEST_CFLAG(CFLAGS_STDGNU "-std=gnu99" GMXC_CFLAGS)
- GMX_TEST_CFLAG(CFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias" GMXC_CFLAGS_RELEASE)
+ GMX_TEST_CFLAG(CFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias -no-prec-div -fimf-domain-exclusion=14 -static-intel" GMXC_CFLAGS_RELEASE)
GMX_TEST_CFLAG(CFLAGS_DEBUG "-O0" GMXC_CFLAGS_DEBUG) #icc defaults to -O2 even with -g
GMX_TEST_CFLAG(CFLAGS_FP_RELASSERT "-fp-model except -fp-model precise" GMXC_CFLAGS_RELWITHASSERT)
else()
if(NOT GMX_OPENMP)
- if(CMAKE_C_COMPILER_VERSION VERSION_GREATER 13.99.99)
- GMX_TEST_CFLAG(CFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
- else()
- GMX_TEST_CFLAG(CFLAGS_PRAGMA "/wd161" GMXC_CFLAGS)
- endif()
+ GMX_TEST_CFLAG(CFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
endif()
if (GMX_COMPILER_WARNINGS)
- if(CMAKE_C_COMPILER_VERSION VERSION_LESS 15.00.00)
- GMX_TEST_CFLAG(CFLAGS_WARN_OLD /wd193 GMXC_CFLAGS)
- endif()
- GMX_TEST_CFLAG(CFLAGS_WARN "/W3 /wd177 /wd271 /wd304 /wd383 /wd424 /wd444 /wd522 /wd593 /wd869 /wd981 /wd1418 /wd1419 /wd1572 /wd1599 /wd2259 /wd2415 /wd2547 /wd2557 /wd3280 /wd3346" GMXC_CFLAGS)
+GMX_TEST_CFLAG(CFLAGS_WARN "/W3 /wd177 /wd411 /wd593 /wd981 /wd1418 /wd1419 /wd1572 /wd1599 /wd2259 /wd2415 /wd2547 /wd2557 /wd3280" GMXC_CFLAGS)
endif()
GMX_TEST_CFLAG(CFLAGS_OPT "/Qip" GMXC_CFLAGS_RELEASE)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Intel")
if (NOT WIN32)
if(NOT GMX_OPENMP)
- if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 13.99.99)
- GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "-wd3180" GMXC_CXXFLAGS)
- else()
- GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "-wd161" GMXC_CXXFLAGS)
- endif()
+ GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "-wd3180" GMXC_CXXFLAGS)
endif()
if (GMX_COMPILER_WARNINGS)
- if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.00.00)
- GMX_TEST_CXXFLAG(CXXFLAGS_WARN_OLD -wd193 GMXC_CXXFLAGS)
+ if (GMX_GPU)
+# Suppress warnings from CUDA headers
+# 7: unrecognized token
+# 82: storage class is not first
+# The below are also required for math_functions.h / math_functions.hpp at least until CUDA 8.0-RC
+# 193: zero used for undefined preprocessing identifer
+# 3346:dynamic exception specifiers are deprecated
+ GMX_TEST_CXXFLAG(CXXFLAGS_WARN_OLD_GPU "-wd7 -wd82 -wd193 -wd3346" GMXC_CXXFLAGS)
endif()
#All but the following warnings are identical for the C-compiler (see above)
-#1782: #pragma once is obsolete
+# 383: value copied to temporary, reference to temporary used
+# 444: destructor for base class ".." is not virtual
#2282: unrecognized GCC pragma
- GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-w3 -wd177 -wd271 -wd304 -wd383 -wd424 -wd444 -wd522 -wd593 -wd869 -wd981 -wd1418 -wd1419 -wd1572 -wd1599 -wd2259 -wd2415 -wd2547 -wd2557 -wd3280 -wd3346 -wd11074 -wd11076 -wd1782 -wd2282" GMXC_CXXFLAGS)
+ GMX_TEST_CXXFLAG(CXXFLAGS_WARN "-w3 -wd177 -wd383 -wd411 -wd444 -wd981 -wd1418 -wd1572 -wd1599 -wd2259 -wd3280 -wd11074 -wd11076 -wd2282" GMXC_CXXFLAGS)
endif()
- GMX_TEST_CXXFLAG(CXXFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias" GMXC_CXXFLAGS_RELEASE)
+ GMX_TEST_CXXFLAG(CXXFLAGS_OPT "-ip -funroll-all-loops -alias-const -ansi-alias -no-prec-div -fimf-domain-exclusion=14 -static-intel" GMXC_CXXFLAGS_RELEASE)
GMX_TEST_CXXFLAG(CXXFLAGS_DEBUG "-O0" GMXC_CXXFLAGS_DEBUG)
GMX_TEST_CXXFLAG(CXXFLAGS_FP_RELASSERT "-fp-model except -fp-model precise" GMXC_CXXFLAGS_RELWITHASSERT)
else()
+#809: exception specification for virtual function X is incompatible with that of overridden function
if(NOT GMX_OPENMP)
- if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 13.99.99)
- GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
- else()
- GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "/wd161" GMXC_CXXFLAGS)
- endif()
+ GMX_TEST_CXXFLAG(CXXFLAGS_PRAGMA "/wd3180" GMXC_CFLAGS)
endif()
if (GMX_COMPILER_WARNINGS)
- 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 /wd411 /wd444 /wd809 /wd981 /wd1418 /wd1572 /wd1599 /wd2259 /wd3280 /wd11074 /wd11076 /wd2282" GMXC_CXXFLAGS)
endif()
GMX_TEST_CXXFLAG(CXXFLAGS_OPT "/Qip" GMXC_CXXFLAGS_RELEASE)
endif()
#
# 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.
set(CPACK_SOURCE_GENERATOR TGZ)
set(CPACK_SOURCE_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}")
set(CPACK_SOURCE_IGNORE_FILES
- "\\\\.isreposource$;\\\\.git/;\\\\.gitignore$;\\\\.gitattributes;")
+ "\\\\.isreposource$;\\\\.git/;\\\\.gitignore$;\\\\.gitattributes;INSTALL-dev;")
# Get the list of directories added with gmx_cpack_add_generated_source_directory()
get_property(CPACK_SOURCE_INSTALLED_DIRECTORIES
GLOBAL PROPERTY GMX_CPACK_SOURCE_INSTALLED_DIRECTORIES)
--- /dev/null
+#
+# 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.
+
+# Helper macros to encapsulate some usage of CTest
+#
+# This file is intended to contain CTest workarounds and such.
+include(CMakeParseArguments)
+
+macro (gmx_ctest_init)
+ # Set a default valgrind suppression file.
+ # This unfortunately needs to duplicate information from CTest to work as
+ # expected...
+ #set(MEMORYCHECK_SUPPRESSIONS_FILE
+ # "${CMAKE_SOURCE_DIR}/cmake/legacy_and_external.supp"
+ # CACHE FILEPATH
+ # "File that contains suppressions for the memory checker")
+ string(TOUPPER "${CMAKE_BUILD_TYPE}" _cmake_build_type)
+ if (_cmake_build_type STREQUAL "ASAN")
+ set(MEMORYCHECK_TYPE "AddressSanitizer")
+ endif()
+ include(CTest)
+ # At least with CMake 3.4.1 on OS X, AddressSanitizer support in CTest
+ # does not work without this...
+ set(_ctest_config_file "${PROJECT_BINARY_DIR}/DartConfiguration.tcl")
+ file(STRINGS ${_ctest_config_file} _existing REGEX "^CMakeCommand: ")
+ if (NOT _existing)
+ file(APPEND ${_ctest_config_file} "\nCMakeCommand: ${CMAKE_COMMAND}\n")
+ endif()
+endmacro()
+
+function (gmx_get_test_prefix_cmd VAR)
+ set(_options IGNORE_LEAKS)
+ cmake_parse_arguments(ARG "${_options}" "" "" ${ARGN})
+ set(_opts "")
+ if (ARG_IGNORE_LEAKS OR APPLE)
+ list(APPEND _opts "detect_leaks=0")
+ endif()
+ set(_cmd "")
+ if (MEMORYCHECK_TYPE STREQUAL "AddressSanitizer")
+ string(REPLACE ";" " " _opts "${_opts}")
+ set(_cmd ${PROJECT_SOURCE_DIR}/cmake/with_asan_opts.sh ${_opts} --)
+ endif()
+ set(${VAR} "${_cmd}" PARENT_SCOPE)
+endfunction()
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.
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:
# 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
#
# 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.
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)
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})
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 "
# 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
# 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)
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()
#
# 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
# 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
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)
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)
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.
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")
# 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(GMX_TNG_MINIMUM_REQUIRED_VERSION "1.7.6")
-set(BUNDLED_TNG_LOCATION "${CMAKE_SOURCE_DIR}/src/external/tng_io")
-if(GMX_USE_TNG)
- option(GMX_EXTERNAL_TNG "Use external TNG instead of compiling the version shipped with GROMACS." OFF)
+set(GMX_TNG_MINIMUM_REQUIRED_VERSION "1.7.10")
+
+gmx_dependent_option(
+ GMX_EXTERNAL_TNG
+ "Use external TNG instead of compiling the version shipped with GROMACS."
+ OFF
+ GMX_USE_TNG)
+gmx_dependent_option(
+ GMX_EXTERNAL_ZLIB
+ "Use external ZLIB instead of compiling the version shipped with GROMACS as part of TNG."
+ OFF
+ "NOT GMX_EXTERNAL_TNG")
+if(GMX_USE_TNG)
# Detect TNG if GMX_EXTERNAL_TNG is explicitly ON
if(GMX_EXTERNAL_TNG)
find_package(TNG_IO ${GMX_TNG_MINIMUM_REQUIRED_VERSION})
if(NOT TNG_IO_FOUND)
message(FATAL_ERROR "TNG >= ${GMX_TNG_MINIMUM_REQUIRED_VERSION} not found. You can set GMX_EXTERNAL_TNG=OFF to compile the TNG bundled with GROMACS.")
endif()
- include_directories(SYSTEM ${TNG_IO_INCLUDE_DIRS})
else()
- include(${BUNDLED_TNG_LOCATION}/BuildTNG.cmake)
- tng_get_source_list(TNG_SOURCES TNG_IO_DEFINITIONS)
-
- if (HAVE_ZLIB)
- list(APPEND GMX_EXTRA_LIBRARIES ${ZLIB_LIBRARIES})
- include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
+ # Detect zlib if the user requires us to use an external
+ # version. If found, it can be used by TNG.
+ if(GMX_EXTERNAL_ZLIB)
+ find_package(ZLIB)
+ if(NOT ZLIB_FOUND)
+ message(FATAL_ERROR "External zlib compression library was required but could not be found. Set GMX_EXTERNAL_ZLIB=OFF to compile zlib as part of GROMACS.")
+ endif()
+ include(gmxTestZLib)
+ gmx_test_zlib(HAVE_ZLIB)
+ if(NOT HAVE_ZLIB)
+ message(FATAL_ERROR "External zlib compression library was required but could not compile and link. Set GMX_EXTERNAL_ZLIB=OFF to compile zlib as part of GROMACS.")
+ endif()
endif()
endif()
-else()
- # We still need to get tng/tng_io_fwd.h from somewhere!
- include_directories(BEFORE ${BUNDLED_TNG_LOCATION}/include)
endif()
+function(gmx_setup_tng_for_libgromacs)
+ set(BUNDLED_TNG_LOCATION "${CMAKE_SOURCE_DIR}/src/external/tng_io")
+ if (GMX_USE_TNG)
+ if (GMX_EXTERNAL_TNG)
+ target_link_libraries(libgromacs PRIVATE tng_io::tng_io)
+ else()
+ set(_zlib_arg)
+ if (NOT GMX_EXTERNAL_ZLIB)
+ set(_zlib_arg OWN_ZLIB)
+ endif()
+ include(${BUNDLED_TNG_LOCATION}/BuildTNG.cmake)
+ add_tng_io_library(tng_io OBJECT ${_zlib_arg})
+ add_library(tng_io::tng_io ALIAS tng_io)
+ target_link_libraries(libgromacs PRIVATE $<BUILD_INTERFACE:tng_io::tng_io>)
+ endif()
+ endif()
+endfunction()
+++ /dev/null
-#
-# 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()
# 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)
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()
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;
}
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)
# 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 2)
+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
# 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_MINOR 1)
+set(LIBRARY_SOVERSION_MAJOR 3)
+set(LIBRARY_SOVERSION_MINOR 0)
set(LIBRARY_VERSION ${LIBRARY_SOVERSION_MAJOR}.${LIBRARY_SOVERSION_MINOR}.0)
#####################################################################
--- /dev/null
+#!/bin/bash
+#
+# 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.
+
+while [[ "$1" != "--" ]] ; do
+ extra_opts="$extra_opts $1"
+ shift
+done
+for opt in $ASAN_OPTIONS ; do
+ if [[ "$opt" == log_path=* ]] ; then
+ # CTest gives errors if the file does not exist, but AddressSanitizer
+ # only produces it if it finds issues...
+ log_path="${opt#log_path=}"
+ log_path="${log_path%\"}"
+ log_path="${log_path#\"}"
+ touch ${log_path}.99999
+ fi
+done
+# Suppressions are not currently necessary, but can be introduced like this.
+#path=`dirname $0`
+#export LSAN_OPTIONS="suppressions=$path/../admin/lsan-suppressions.txt"
+export ASAN_OPTIONS="$ASAN_OPTIONS $extra_opts"
+exec "$@"
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
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@'),
.. _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
=====================
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
* 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
'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']
--- /dev/null
+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.
test. The test can naturally also use its own test assertions for additional
checks, but any mismatch will automatically also fail the test.
+It is also possible to read values of the reference data items using
+gmx::test::TestReferenceChecker, so that they can be used programmatically.
+For this to work, those items should first be written in the same test.
+This supports tests that want to both check data against a reference, and use
+that reference as a persistence layer for storing information. This is useful
+at least for serialization tests.
+This is currently not supported for all use cases, but with some caveats, it is
+possible to use this for testing.
+
When using floating-point values in reference data, the tolerance for the
comparison can be influenced with
gmx::test::TestReferenceChecker::setDefaultTolerance().
src/gromacs/simd/tests/scalar.cpp: warning: includes "simd.h" unnecessarily
src/gromacs/simd/tests/scalar_math.cpp: warning: includes "simd.h" unnecessarily
src/gromacs/simd/tests/scalar_util.cpp: warning: includes "simd.h" unnecessarily
+src/gromacs/tables/cubicsplinetable.h: warning: includes "simd.h" unnecessarily
+src/gromacs/tables/quadraticsplinetable.h: warning: includes "simd.h" unnecessarily
# These are specific to Folding@Home, and easiest to suppress here
*: warning: includes non-local file as "corewrap.h"
\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.
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
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
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``
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
--------------------------------------
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
-----
|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,
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
\item {\em Restraints}: position restraints, angle restraints,
distance restraints, orientation restraints and dihedral restraints, all
based on fixed lists.
+%\ifthenelse{\equal{\gmxlite}{1}}{}{
+\item {\em Applied Forces}:
+externally applied forces, see \chref{special}.
+%}
\end{enumerate}
\section{Non-bonded interactions}
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
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",
pages = {1986--1994}
}
+@article{Caleman2008a,
+ author = {Caleman, C and van der Spoel, D},
+ title = {{Picosecond Melting of Ice by an Infrared Laser Pulse - A simulation
+ study}},
+ journal = {Angew. Chem., Int. Ed. Engl.},
+ year = {2008},
+ volume = {47},
+ pages = {1417--1420}
+}
+
@article{Wolf2010,
author = {Wolf, M.G. and Hoefling, M. and Aponte-Santamar\'{i}a, C. and Grubm\"{u}ller, H. and Groenhof, G.},
title = {{g\_membed}: Efficient insertion of a membrane protein into an equilibrated lipid bilayer with minimal perturbation},
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}}
+
--- /dev/null
+%!PS-Adobe-3.0 EPSF-3.0
+%%BoundingBox: 5 8 769 591
+%%LanguageLevel: 2
+%%Creator: Grace-5.1.25
+%%CreationDate: Tue Jul 5 08:32:47 2016
+%%DocumentData: Clean8Bit
+%%Orientation: Portrait
+%%Title: field.xvg
+%%For: spoel
+%%DocumentNeededResources: (atend)
+%%EndComments
+%%BeginProlog
+/m {moveto} def
+/l {lineto} def
+/s {stroke} def
+/n {newpath} def
+/c {closepath} def
+/RL {rlineto} def
+/SLW {setlinewidth} def
+/GS {gsave} def
+/GR {grestore} def
+/SC {setcolor} def
+/SGRY {setgray} def
+/SRGB {setrgbcolor} def
+/SD {setdash} def
+/SLC {setlinecap} def
+/SLJ {setlinejoin} def
+/SCS {setcolorspace} def
+/FFSF {findfont setfont} def
+/CC {concat} def
+/PXL {n m 0 0 RL s} def
+/Color0 {1.0000 1.0000 1.0000} def
+/Color1 {0.0000 0.0000 0.0000} def
+/Color2 {1.0000 0.0000 0.0000} def
+/Color3 {0.0000 1.0000 0.0000} def
+/Color4 {0.0000 0.0000 1.0000} def
+/Color5 {1.0000 1.0000 0.0000} def
+/Color6 {0.7373 0.5608 0.5608} def
+/Color7 {0.8627 0.8627 0.8627} def
+/Color8 {0.5804 0.0000 0.8275} def
+/Color9 {0.0000 1.0000 1.0000} def
+/Color10 {1.0000 0.0000 1.0000} def
+/Color11 {1.0000 0.6471 0.0000} def
+/Color12 {0.4471 0.1294 0.7373} def
+/Color13 {0.4039 0.0275 0.2824} def
+/Color14 {0.2510 0.8784 0.8157} def
+/Color15 {0.0000 0.5451 0.0000} def
+/Color16 {0.7529 0.7529 0.7529} def
+/Color17 {0.5059 0.5059 0.5059} def
+/Color18 {0.2588 0.2588 0.2588} def
+/PTRN {
+ /pat_bits exch def
+ <<
+ /PaintType 2
+ /PatternType 1 /TilingType 1
+ /BBox[0 0 16 16]
+ /XStep 16 /YStep 16
+ /PaintProc {
+ pop
+ 16 16 true [-1 0 0 -1 16 16] pat_bits imagemask
+ }
+ >>
+ [0.0016 0 0 0.0016 0 0]
+ makepattern
+} def
+/Pattern0 {<0000000000000000000000000000000000000000000000000000000000000000> PTRN} bind def
+/Pattern1 {<ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff> PTRN} bind def
+/Pattern2 {<eeeeffffbbbbffffeeeeffffbbbbffffeeeeffffbbbbffffeeeeffffbbbbffff> PTRN} bind def
+/Pattern3 {<eeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbbeeeebbbb> PTRN} bind def
+/Pattern4 {<5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa5555aaaa> PTRN} bind def
+/Pattern5 {<1111444411114444111144441111444411114444111144441111444411114444> PTRN} bind def
+/Pattern6 {<1111000044440000111100004444000011110000444400001111000044440000> PTRN} bind def
+/Pattern7 {<1010000000000000010100000000000010100000000000000101000000000000> PTRN} bind def
+/Pattern8 {<0000000000000000000000000000000000000000000000000000000000000000> PTRN} bind def
+/Pattern9 {<1e1e0f0f8787c3c3e1e1f0f078783c3c1e1e0f0f8787c3c3e1e1f0f078783c3c> PTRN} bind def
+/Pattern10 {<7878f0f0e1e1c3c387870f0f1e1e3c3c7878f0f0e1e1c3c387870f0f1e1e3c3c> PTRN} bind def
+/Pattern11 {<3333333333333333333333333333333333333333333333333333333333333333> PTRN} bind def
+/Pattern12 {<ffffffff00000000ffffffff00000000ffffffff00000000ffffffff00000000> PTRN} bind def
+/Pattern13 {<8181424224241818181824244242818181814242242418181818242442428181> PTRN} bind def
+/Pattern14 {<8080404020201010080804040202010180804040202010100808040402020101> PTRN} bind def
+/Pattern15 {<0101020204040808101020204040808001010202040408081010202040408080> PTRN} bind def
+/Pattern16 {<2222222222222222222222222222222222222222222222222222222222222222> PTRN} bind def
+/Pattern17 {<0000ffff000000000000ffff000000000000ffff000000000000ffff00000000> PTRN} bind def
+/Pattern18 {<2222ffff222222222222ffff222222222222ffff222222222222ffff22222222> PTRN} bind def
+/Pattern19 {<ffffffff33333333ffffffff33333333ffffffff33333333ffffffff33333333> PTRN} bind def
+/Pattern20 {<0f0f0f0f0f0f0f0ff0f0f0f0f0f0f0f00f0f0f0f0f0f0f0ff0f0f0f0f0f0f0f0> PTRN} bind def
+/Pattern21 {<ff00ff00ff00ff00ff00ff00ff00ff0000ff00ff00ff00ff00ff00ff00ff00ff> PTRN} bind def
+/Pattern22 {<8001800180018001800180018001ffffffff8001800180018001800180018001> PTRN} bind def
+/Pattern23 {<c003c003c003c003c003c003ffffffffffffffffc003c003c003c003c003c003> PTRN} bind def
+/Pattern24 {<040404040404ffff404040404040ffff040404040404ffff404040404040ffff> PTRN} bind def
+/Pattern25 {<180018001800180018001800ffffffff001800180018001800180018ffffffff> PTRN} bind def
+/Pattern26 {<1111b8b87c7c3a3a1111a3a3c7c78b8b1111b8b87c7c3a3a1111a3a3c7c78b8b> PTRN} bind def
+/Pattern27 {<101010102828c7c70101010182827c7c101010102828c7c70101010182827c7c> PTRN} bind def
+/Pattern28 {<1c1c121211112121c1c12121111112121c1c121211112121c1c1212111111212> PTRN} bind def
+/Pattern29 {<3e3e414180808080e3e31414080808083e3e414180808080e3e3141408080808> PTRN} bind def
+/Pattern30 {<4848888884848383848488884848383848488888848483838484888848483838> PTRN} bind def
+/Pattern31 {<03030404080808080c0c12122121c0c003030404080808080c0c12122121c0c0> PTRN} bind def
+/ellipsedict 8 dict def
+ellipsedict /mtrx matrix put
+/EARC {
+ ellipsedict begin
+ /endangle exch def
+ /startangle exch def
+ /yrad exch def
+ /xrad exch def
+ /y exch def
+ /x exch def
+ /savematrix mtrx currentmatrix def
+ x y translate
+ xrad yrad scale
+ 0 0 1 startangle endangle arc
+ savematrix setmatrix
+ end
+} def
+/TL {
+ /kcomp exch def
+ /linewidth exch def
+ /offset exch def
+ GS
+ 0 offset rmoveto
+ linewidth SLW
+ dup stringwidth exch kcomp add exch RL s
+ GR
+} def
+/KINIT
+{
+ /kvector exch def
+ /kid 0 def
+} def
+/KPROC
+{
+ pop pop
+ kvector kid get
+ 0 rmoveto
+ /kid 1 kid add def
+} def
+/DefEncoding [
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /space
+ /exclam
+ /quotedbl
+ /numbersign
+ /dollar
+ /percent
+ /ampersand
+ /quoteright
+ /parenleft
+ /parenright
+ /asterisk
+ /plus
+ /comma
+ /hyphen
+ /period
+ /slash
+ /zero
+ /one
+ /two
+ /three
+ /four
+ /five
+ /six
+ /seven
+ /eight
+ /nine
+ /colon
+ /semicolon
+ /less
+ /equal
+ /greater
+ /question
+ /at
+ /A
+ /B
+ /C
+ /D
+ /E
+ /F
+ /G
+ /H
+ /I
+ /J
+ /K
+ /L
+ /M
+ /N
+ /O
+ /P
+ /Q
+ /R
+ /S
+ /T
+ /U
+ /V
+ /W
+ /X
+ /Y
+ /Z
+ /bracketleft
+ /backslash
+ /bracketright
+ /asciicircum
+ /underscore
+ /grave
+ /a
+ /b
+ /c
+ /d
+ /e
+ /f
+ /g
+ /h
+ /i
+ /j
+ /k
+ /l
+ /m
+ /n
+ /o
+ /p
+ /q
+ /r
+ /s
+ /t
+ /u
+ /v
+ /w
+ /x
+ /y
+ /z
+ /braceleft
+ /bar
+ /braceright
+ /asciitilde
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /.notdef
+ /space
+ /exclamdown
+ /cent
+ /sterling
+ /currency
+ /yen
+ /brokenbar
+ /section
+ /dieresis
+ /copyright
+ /ordfeminine
+ /guillemotleft
+ /logicalnot
+ /hyphen
+ /registered
+ /macron
+ /degree
+ /plusminus
+ /twosuperior
+ /threesuperior
+ /acute
+ /mu
+ /paragraph
+ /periodcentered
+ /cedilla
+ /onesuperior
+ /ordmasculine
+ /guillemotright
+ /onequarter
+ /onehalf
+ /threequarters
+ /questiondown
+ /Agrave
+ /Aacute
+ /Acircumflex
+ /Atilde
+ /Adieresis
+ /Aring
+ /AE
+ /Ccedilla
+ /Egrave
+ /Eacute
+ /Ecircumflex
+ /Edieresis
+ /Igrave
+ /Iacute
+ /Icircumflex
+ /Idieresis
+ /Eth
+ /Ntilde
+ /Ograve
+ /Oacute
+ /Ocircumflex
+ /Otilde
+ /Odieresis
+ /multiply
+ /Oslash
+ /Ugrave
+ /Uacute
+ /Ucircumflex
+ /Udieresis
+ /Yacute
+ /Thorn
+ /germandbls
+ /agrave
+ /aacute
+ /acircumflex
+ /atilde
+ /adieresis
+ /aring
+ /ae
+ /ccedilla
+ /egrave
+ /eacute
+ /ecircumflex
+ /edieresis
+ /igrave
+ /iacute
+ /icircumflex
+ /idieresis
+ /eth
+ /ntilde
+ /ograve
+ /oacute
+ /ocircumflex
+ /otilde
+ /odieresis
+ /divide
+ /oslash
+ /ugrave
+ /uacute
+ /ucircumflex
+ /udieresis
+ /yacute
+ /thorn
+ /ydieresis
+] def
+%%EndProlog
+%%BeginSetup
+%%EndSetup
+612.00 612.00 scale
+n
+0.0000 0.0000 m
+0.0000 1.0000 l
+1.2941 1.0000 l
+1.2941 0.0000 l
+c
+[/DeviceRGB] SCS
+Color0 SC
+fill
+[/DeviceRGB] SCS
+Color1 SC
+[] 0 SD
+0.0015 SLW
+0 SLC
+0 SLJ
+n
+0.1000 0.5250 m
+0.1003 0.5250 l
+0.1006 0.5250 l
+0.1009 0.5250 l
+0.1011 0.5250 l
+0.1014 0.5250 l
+0.1017 0.5250 l
+0.1020 0.5250 l
+0.1023 0.5250 l
+0.1026 0.5250 l
+0.1029 0.5250 l
+0.1031 0.5250 l
+0.1034 0.5250 l
+0.1037 0.5250 l
+0.1040 0.5250 l
+0.1043 0.5250 l
+0.1046 0.5250 l
+0.1049 0.5250 l
+0.1052 0.5250 l
+0.1054 0.5250 l
+0.1057 0.5250 l
+0.1060 0.5250 l
+0.1063 0.5250 l
+0.1066 0.5250 l
+0.1069 0.5250 l
+0.1072 0.5250 l
+0.1074 0.5250 l
+0.1077 0.5250 l
+0.1080 0.5250 l
+0.1083 0.5250 l
+0.1086 0.5250 l
+0.1089 0.5250 l
+0.1092 0.5250 l
+0.1094 0.5250 l
+0.1097 0.5250 l
+0.1100 0.5250 l
+0.1103 0.5250 l
+0.1106 0.5250 l
+0.1109 0.5250 l
+0.1112 0.5250 l
+0.1114 0.5250 l
+0.1117 0.5250 l
+0.1120 0.5250 l
+0.1123 0.5250 l
+0.1126 0.5250 l
+0.1129 0.5250 l
+0.1132 0.5250 l
+0.1135 0.5250 l
+0.1137 0.5250 l
+0.1140 0.5250 l
+0.1143 0.5250 l
+0.1146 0.5250 l
+0.1149 0.5250 l
+0.1152 0.5250 l
+0.1155 0.5250 l
+0.1157 0.5250 l
+0.1160 0.5250 l
+0.1163 0.5250 l
+0.1166 0.5250 l
+0.1169 0.5250 l
+0.1172 0.5250 l
+0.1175 0.5250 l
+0.1177 0.5250 l
+0.1180 0.5250 l
+0.1183 0.5250 l
+0.1186 0.5250 l
+0.1189 0.5250 l
+0.1192 0.5250 l
+0.1195 0.5250 l
+0.1197 0.5250 l
+0.1200 0.5250 l
+0.1203 0.5250 l
+0.1206 0.5250 l
+0.1209 0.5250 l
+0.1212 0.5250 l
+0.1215 0.5250 l
+0.1218 0.5250 l
+0.1220 0.5250 l
+0.1223 0.5250 l
+0.1226 0.5250 l
+0.1229 0.5250 l
+0.1232 0.5250 l
+0.1235 0.5250 l
+0.1238 0.5250 l
+0.1240 0.5250 l
+0.1243 0.5250 l
+0.1246 0.5250 l
+0.1249 0.5250 l
+0.1252 0.5250 l
+0.1255 0.5250 l
+0.1258 0.5250 l
+0.1260 0.5250 l
+0.1263 0.5250 l
+0.1266 0.5250 l
+0.1269 0.5250 l
+0.1272 0.5250 l
+0.1275 0.5250 l
+0.1278 0.5250 l
+0.1281 0.5250 l
+0.1283 0.5250 l
+0.1286 0.5250 l
+0.1289 0.5250 l
+0.1292 0.5250 l
+0.1295 0.5250 l
+0.1298 0.5250 l
+0.1301 0.5250 l
+0.1303 0.5250 l
+0.1306 0.5250 l
+0.1309 0.5250 l
+0.1312 0.5250 l
+0.1315 0.5250 l
+0.1318 0.5250 l
+0.1321 0.5250 l
+0.1323 0.5250 l
+0.1326 0.5250 l
+0.1329 0.5250 l
+0.1332 0.5250 l
+0.1335 0.5250 l
+0.1338 0.5250 l
+0.1341 0.5250 l
+0.1343 0.5250 l
+0.1346 0.5250 l
+0.1349 0.5250 l
+0.1352 0.5250 l
+0.1355 0.5250 l
+0.1358 0.5250 l
+0.1361 0.5250 l
+0.1364 0.5250 l
+0.1366 0.5250 l
+0.1369 0.5250 l
+0.1372 0.5250 l
+0.1375 0.5250 l
+0.1378 0.5250 l
+0.1381 0.5250 l
+0.1384 0.5250 l
+0.1386 0.5250 l
+0.1389 0.5250 l
+0.1392 0.5250 l
+0.1395 0.5250 l
+0.1398 0.5250 l
+0.1401 0.5250 l
+0.1404 0.5250 l
+0.1406 0.5250 l
+0.1409 0.5250 l
+0.1412 0.5250 l
+0.1415 0.5250 l
+0.1418 0.5250 l
+0.1421 0.5250 l
+0.1424 0.5250 l
+0.1426 0.5250 l
+0.1429 0.5250 l
+0.1432 0.5250 l
+0.1435 0.5250 l
+0.1438 0.5250 l
+0.1441 0.5250 l
+0.1444 0.5250 l
+0.1447 0.5250 l
+0.1449 0.5250 l
+0.1452 0.5250 l
+0.1455 0.5250 l
+0.1458 0.5250 l
+0.1461 0.5250 l
+0.1464 0.5250 l
+0.1467 0.5250 l
+0.1469 0.5250 l
+0.1472 0.5250 l
+0.1475 0.5250 l
+0.1478 0.5250 l
+0.1481 0.5250 l
+0.1484 0.5250 l
+0.1487 0.5250 l
+0.1489 0.5250 l
+0.1492 0.5250 l
+0.1495 0.5250 l
+0.1498 0.5250 l
+0.1501 0.5250 l
+0.1504 0.5250 l
+0.1507 0.5250 l
+0.1509 0.5250 l
+0.1512 0.5250 l
+0.1515 0.5250 l
+0.1518 0.5250 l
+0.1521 0.5250 l
+0.1524 0.5250 l
+0.1527 0.5250 l
+0.1530 0.5250 l
+0.1532 0.5250 l
+0.1535 0.5250 l
+0.1538 0.5250 l
+0.1541 0.5250 l
+0.1544 0.5250 l
+0.1547 0.5250 l
+0.1550 0.5250 l
+0.1552 0.5250 l
+0.1555 0.5250 l
+0.1558 0.5250 l
+0.1561 0.5250 l
+0.1564 0.5250 l
+0.1567 0.5250 l
+0.1570 0.5250 l
+0.1572 0.5250 l
+0.1575 0.5250 l
+0.1578 0.5250 l
+0.1581 0.5250 l
+0.1584 0.5250 l
+0.1587 0.5250 l
+0.1590 0.5250 l
+0.1592 0.5250 l
+0.1595 0.5250 l
+0.1598 0.5250 l
+0.1601 0.5250 l
+0.1604 0.5250 l
+0.1607 0.5250 l
+0.1610 0.5250 l
+0.1613 0.5250 l
+0.1615 0.5250 l
+0.1618 0.5250 l
+0.1621 0.5250 l
+0.1624 0.5250 l
+0.1627 0.5250 l
+0.1630 0.5250 l
+0.1633 0.5250 l
+0.1635 0.5250 l
+0.1638 0.5250 l
+0.1641 0.5250 l
+0.1644 0.5250 l
+0.1647 0.5250 l
+0.1650 0.5250 l
+0.1653 0.5250 l
+0.1655 0.5250 l
+0.1658 0.5250 l
+0.1661 0.5250 l
+0.1664 0.5250 l
+0.1667 0.5250 l
+0.1670 0.5250 l
+0.1673 0.5250 l
+0.1675 0.5250 l
+0.1678 0.5250 l
+0.1681 0.5250 l
+0.1684 0.5250 l
+0.1687 0.5250 l
+0.1690 0.5250 l
+0.1693 0.5250 l
+0.1696 0.5250 l
+0.1698 0.5250 l
+0.1701 0.5250 l
+0.1704 0.5250 l
+0.1707 0.5250 l
+0.1710 0.5250 l
+0.1713 0.5250 l
+0.1716 0.5250 l
+0.1718 0.5250 l
+0.1721 0.5250 l
+0.1724 0.5250 l
+0.1727 0.5250 l
+0.1730 0.5250 l
+0.1733 0.5250 l
+0.1736 0.5250 l
+0.1738 0.5250 l
+0.1741 0.5250 l
+0.1744 0.5250 l
+0.1747 0.5250 l
+0.1750 0.5250 l
+0.1753 0.5250 l
+0.1756 0.5250 l
+0.1758 0.5250 l
+0.1761 0.5250 l
+0.1764 0.5250 l
+0.1767 0.5250 l
+0.1770 0.5250 l
+0.1773 0.5250 l
+0.1776 0.5250 l
+0.1779 0.5250 l
+0.1781 0.5250 l
+0.1784 0.5250 l
+0.1787 0.5250 l
+0.1790 0.5250 l
+0.1793 0.5250 l
+0.1796 0.5250 l
+0.1799 0.5250 l
+0.1801 0.5250 l
+0.1804 0.5250 l
+0.1807 0.5250 l
+0.1810 0.5250 l
+0.1813 0.5250 l
+0.1816 0.5250 l
+0.1819 0.5250 l
+0.1821 0.5250 l
+0.1824 0.5250 l
+0.1827 0.5250 l
+0.1830 0.5250 l
+0.1833 0.5250 l
+0.1836 0.5250 l
+0.1839 0.5250 l
+0.1842 0.5250 l
+0.1844 0.5250 l
+0.1847 0.5250 l
+0.1850 0.5250 l
+0.1853 0.5250 l
+0.1856 0.5250 l
+0.1859 0.5250 l
+0.1862 0.5250 l
+0.1864 0.5250 l
+0.1867 0.5250 l
+0.1870 0.5250 l
+0.1873 0.5250 l
+0.1876 0.5250 l
+0.1879 0.5250 l
+0.1882 0.5250 l
+0.1884 0.5250 l
+0.1887 0.5250 l
+0.1890 0.5250 l
+0.1893 0.5250 l
+0.1896 0.5250 l
+0.1899 0.5250 l
+0.1902 0.5250 l
+0.1904 0.5250 l
+0.1907 0.5251 l
+0.1910 0.5251 l
+0.1913 0.5251 l
+0.1916 0.5251 l
+0.1919 0.5251 l
+0.1922 0.5251 l
+0.1925 0.5251 l
+0.1927 0.5251 l
+0.1930 0.5251 l
+0.1933 0.5251 l
+0.1936 0.5251 l
+0.1939 0.5251 l
+0.1942 0.5251 l
+0.1945 0.5251 l
+0.1947 0.5251 l
+0.1950 0.5251 l
+0.1953 0.5251 l
+0.1956 0.5251 l
+0.1959 0.5251 l
+0.1962 0.5250 l
+0.1965 0.5250 l
+0.1967 0.5250 l
+0.1970 0.5250 l
+0.1973 0.5250 l
+0.1976 0.5250 l
+0.1979 0.5250 l
+0.1982 0.5250 l
+0.1985 0.5250 l
+0.1987 0.5250 l
+0.1990 0.5250 l
+0.1993 0.5250 l
+0.1996 0.5250 l
+0.1999 0.5250 l
+0.2002 0.5250 l
+0.2005 0.5250 l
+0.2008 0.5250 l
+0.2010 0.5250 l
+0.2013 0.5249 l
+0.2016 0.5249 l
+0.2019 0.5249 l
+0.2022 0.5249 l
+0.2025 0.5249 l
+0.2028 0.5249 l
+0.2030 0.5249 l
+0.2033 0.5249 l
+0.2036 0.5249 l
+0.2039 0.5249 l
+0.2042 0.5249 l
+0.2045 0.5249 l
+0.2048 0.5249 l
+0.2050 0.5249 l
+0.2053 0.5249 l
+0.2056 0.5249 l
+0.2059 0.5249 l
+0.2062 0.5249 l
+0.2065 0.5249 l
+0.2068 0.5249 l
+0.2070 0.5249 l
+0.2073 0.5249 l
+0.2076 0.5249 l
+0.2079 0.5249 l
+0.2082 0.5249 l
+0.2085 0.5249 l
+0.2088 0.5249 l
+0.2091 0.5249 l
+0.2093 0.5250 l
+0.2096 0.5250 l
+0.2099 0.5250 l
+0.2102 0.5250 l
+0.2105 0.5250 l
+0.2108 0.5250 l
+0.2111 0.5250 l
+0.2113 0.5250 l
+0.2116 0.5250 l
+0.2119 0.5250 l
+0.2122 0.5250 l
+0.2125 0.5251 l
+0.2128 0.5251 l
+0.2131 0.5251 l
+0.2133 0.5251 l
+0.2136 0.5251 l
+0.2139 0.5251 l
+0.2142 0.5251 l
+0.2145 0.5251 l
+0.2148 0.5251 l
+0.2151 0.5251 l
+0.2153 0.5251 l
+0.2156 0.5251 l
+0.2159 0.5251 l
+0.2162 0.5251 l
+0.2165 0.5252 l
+0.2168 0.5252 l
+0.2171 0.5252 l
+0.2174 0.5252 l
+0.2176 0.5252 l
+0.2179 0.5252 l
+0.2182 0.5252 l
+0.2185 0.5251 l
+0.2188 0.5251 l
+0.2191 0.5251 l
+0.2194 0.5251 l
+0.2196 0.5251 l
+0.2199 0.5251 l
+0.2202 0.5251 l
+0.2205 0.5251 l
+0.2208 0.5251 l
+0.2211 0.5251 l
+0.2214 0.5251 l
+0.2216 0.5251 l
+0.2219 0.5250 l
+0.2222 0.5250 l
+0.2225 0.5250 l
+0.2228 0.5250 l
+0.2231 0.5250 l
+0.2234 0.5250 l
+0.2236 0.5250 l
+0.2239 0.5249 l
+0.2242 0.5249 l
+0.2245 0.5249 l
+0.2248 0.5249 l
+0.2251 0.5249 l
+0.2254 0.5249 l
+0.2257 0.5249 l
+0.2259 0.5248 l
+0.2262 0.5248 l
+0.2265 0.5248 l
+0.2268 0.5248 l
+0.2271 0.5248 l
+0.2274 0.5248 l
+0.2277 0.5248 l
+0.2279 0.5248 l
+0.2282 0.5248 l
+0.2285 0.5248 l
+0.2288 0.5248 l
+0.2291 0.5248 l
+0.2294 0.5248 l
+0.2297 0.5248 l
+0.2299 0.5248 l
+0.2302 0.5248 l
+0.2305 0.5248 l
+0.2308 0.5248 l
+0.2311 0.5248 l
+0.2314 0.5248 l
+0.2317 0.5248 l
+0.2320 0.5248 l
+0.2322 0.5248 l
+0.2325 0.5248 l
+0.2328 0.5249 l
+0.2331 0.5249 l
+0.2334 0.5249 l
+0.2337 0.5249 l
+0.2340 0.5249 l
+0.2342 0.5250 l
+0.2345 0.5250 l
+0.2348 0.5250 l
+0.2351 0.5250 l
+0.2354 0.5250 l
+0.2357 0.5251 l
+0.2360 0.5251 l
+0.2362 0.5251 l
+0.2365 0.5251 l
+0.2368 0.5252 l
+0.2371 0.5252 l
+0.2374 0.5252 l
+0.2377 0.5252 l
+0.2380 0.5252 l
+0.2382 0.5252 l
+0.2385 0.5253 l
+0.2388 0.5253 l
+0.2391 0.5253 l
+0.2394 0.5253 l
+0.2397 0.5253 l
+0.2400 0.5253 l
+0.2403 0.5253 l
+0.2405 0.5253 l
+0.2408 0.5253 l
+0.2411 0.5254 l
+0.2414 0.5254 l
+0.2417 0.5253 l
+0.2420 0.5253 l
+0.2423 0.5253 l
+0.2425 0.5253 l
+0.2428 0.5253 l
+0.2431 0.5253 l
+0.2434 0.5253 l
+0.2437 0.5253 l
+0.2440 0.5253 l
+0.2443 0.5252 l
+0.2445 0.5252 l
+0.2448 0.5252 l
+0.2451 0.5252 l
+0.2454 0.5251 l
+0.2457 0.5251 l
+0.2460 0.5251 l
+0.2463 0.5251 l
+0.2465 0.5250 l
+0.2468 0.5250 l
+0.2471 0.5250 l
+0.2474 0.5249 l
+0.2477 0.5249 l
+0.2480 0.5249 l
+0.2483 0.5248 l
+0.2486 0.5248 l
+0.2488 0.5248 l
+0.2491 0.5247 l
+0.2494 0.5247 l
+0.2497 0.5247 l
+0.2500 0.5247 l
+0.2503 0.5246 l
+0.2506 0.5246 l
+0.2508 0.5246 l
+0.2511 0.5246 l
+0.2514 0.5245 l
+0.2517 0.5245 l
+0.2520 0.5245 l
+0.2523 0.5245 l
+0.2526 0.5245 l
+0.2528 0.5245 l
+0.2531 0.5245 l
+0.2534 0.5245 l
+0.2537 0.5245 l
+0.2540 0.5245 l
+0.2543 0.5245 l
+0.2546 0.5245 l
+0.2548 0.5245 l
+0.2551 0.5245 l
+0.2554 0.5246 l
+0.2557 0.5246 l
+0.2560 0.5246 l
+0.2563 0.5246 l
+0.2566 0.5247 l
+0.2569 0.5247 l
+0.2571 0.5247 l
+0.2574 0.5248 l
+0.2577 0.5248 l
+0.2580 0.5249 l
+0.2583 0.5249 l
+0.2586 0.5250 l
+0.2589 0.5250 l
+0.2591 0.5251 l
+0.2594 0.5251 l
+0.2597 0.5251 l
+0.2600 0.5252 l
+0.2603 0.5252 l
+0.2606 0.5253 l
+0.2609 0.5253 l
+0.2611 0.5254 l
+0.2614 0.5254 l
+0.2617 0.5255 l
+0.2620 0.5255 l
+0.2623 0.5255 l
+0.2626 0.5256 l
+0.2629 0.5256 l
+0.2631 0.5256 l
+0.2634 0.5257 l
+0.2637 0.5257 l
+0.2640 0.5257 l
+0.2643 0.5257 l
+0.2646 0.5257 l
+0.2649 0.5258 l
+0.2652 0.5258 l
+0.2654 0.5258 l
+0.2657 0.5258 l
+0.2660 0.5257 l
+0.2663 0.5257 l
+0.2666 0.5257 l
+0.2669 0.5257 l
+0.2672 0.5257 l
+0.2674 0.5256 l
+0.2677 0.5256 l
+0.2680 0.5256 l
+0.2683 0.5255 l
+0.2686 0.5255 l
+0.2689 0.5254 l
+0.2692 0.5254 l
+0.2694 0.5253 l
+0.2697 0.5252 l
+0.2700 0.5252 l
+0.2703 0.5251 l
+0.2706 0.5251 l
+0.2709 0.5250 l
+0.2712 0.5249 l
+0.2714 0.5248 l
+0.2717 0.5248 l
+0.2720 0.5247 l
+0.2723 0.5246 l
+0.2726 0.5246 l
+0.2729 0.5245 l
+0.2732 0.5244 l
+0.2735 0.5244 l
+0.2737 0.5243 l
+0.2740 0.5243 l
+0.2743 0.5242 l
+0.2746 0.5242 l
+0.2749 0.5241 l
+0.2752 0.5241 l
+0.2755 0.5240 l
+0.2757 0.5240 l
+0.2760 0.5240 l
+0.2763 0.5239 l
+0.2766 0.5239 l
+0.2769 0.5239 l
+0.2772 0.5239 l
+0.2775 0.5239 l
+0.2777 0.5239 l
+0.2780 0.5239 l
+0.2783 0.5240 l
+0.2786 0.5240 l
+0.2789 0.5240 l
+0.2792 0.5241 l
+0.2795 0.5241 l
+0.2797 0.5242 l
+0.2800 0.5242 l
+0.2803 0.5243 l
+0.2806 0.5243 l
+0.2809 0.5244 l
+0.2812 0.5245 l
+0.2815 0.5246 l
+0.2818 0.5247 l
+0.2820 0.5248 l
+0.2823 0.5248 l
+0.2826 0.5249 l
+0.2829 0.5250 l
+0.2832 0.5251 l
+0.2835 0.5252 l
+0.2838 0.5253 l
+0.2840 0.5254 l
+0.2843 0.5255 l
+0.2846 0.5256 l
+0.2849 0.5257 l
+0.2852 0.5258 l
+0.2855 0.5259 l
+0.2858 0.5260 l
+0.2860 0.5261 l
+0.2863 0.5262 l
+0.2866 0.5262 l
+0.2869 0.5263 l
+0.2872 0.5263 l
+0.2875 0.5264 l
+0.2878 0.5264 l
+0.2881 0.5265 l
+0.2883 0.5265 l
+0.2886 0.5265 l
+0.2889 0.5266 l
+0.2892 0.5266 l
+0.2895 0.5266 l
+0.2898 0.5265 l
+0.2901 0.5265 l
+0.2903 0.5265 l
+0.2906 0.5264 l
+0.2909 0.5264 l
+0.2912 0.5263 l
+0.2915 0.5263 l
+0.2918 0.5262 l
+0.2921 0.5261 l
+0.2923 0.5260 l
+0.2926 0.5259 l
+0.2929 0.5258 l
+0.2932 0.5257 l
+0.2935 0.5256 l
+0.2938 0.5255 l
+0.2941 0.5253 l
+0.2943 0.5252 l
+0.2946 0.5251 l
+0.2949 0.5249 l
+0.2952 0.5248 l
+0.2955 0.5247 l
+0.2958 0.5245 l
+0.2961 0.5244 l
+0.2964 0.5242 l
+0.2966 0.5241 l
+0.2969 0.5240 l
+0.2972 0.5238 l
+0.2975 0.5237 l
+0.2978 0.5236 l
+0.2981 0.5235 l
+0.2984 0.5234 l
+0.2986 0.5233 l
+0.2989 0.5232 l
+0.2992 0.5231 l
+0.2995 0.5230 l
+0.2998 0.5229 l
+0.3001 0.5229 l
+0.3004 0.5229 l
+0.3006 0.5228 l
+0.3009 0.5228 l
+0.3012 0.5228 l
+0.3015 0.5228 l
+0.3018 0.5228 l
+0.3021 0.5229 l
+0.3024 0.5229 l
+0.3026 0.5230 l
+0.3029 0.5230 l
+0.3032 0.5231 l
+0.3035 0.5232 l
+0.3038 0.5233 l
+0.3041 0.5234 l
+0.3044 0.5236 l
+0.3047 0.5237 l
+0.3049 0.5239 l
+0.3052 0.5240 l
+0.3055 0.5242 l
+0.3058 0.5244 l
+0.3061 0.5245 l
+0.3064 0.5247 l
+0.3067 0.5249 l
+0.3069 0.5251 l
+0.3072 0.5253 l
+0.3075 0.5255 l
+0.3078 0.5257 l
+0.3081 0.5259 l
+0.3084 0.5261 l
+0.3087 0.5263 l
+0.3089 0.5265 l
+0.3092 0.5267 l
+0.3095 0.5268 l
+0.3098 0.5270 l
+0.3101 0.5272 l
+0.3104 0.5273 l
+0.3107 0.5275 l
+0.3109 0.5276 l
+0.3112 0.5277 l
+0.3115 0.5278 l
+0.3118 0.5279 l
+0.3121 0.5280 l
+0.3124 0.5280 l
+0.3127 0.5280 l
+0.3130 0.5281 l
+0.3132 0.5281 l
+0.3135 0.5281 l
+0.3138 0.5280 l
+0.3141 0.5280 l
+0.3144 0.5279 l
+0.3147 0.5278 l
+0.3150 0.5277 l
+0.3152 0.5276 l
+0.3155 0.5275 l
+0.3158 0.5273 l
+0.3161 0.5272 l
+0.3164 0.5270 l
+0.3167 0.5268 l
+0.3170 0.5266 l
+0.3172 0.5263 l
+0.3175 0.5261 l
+0.3178 0.5259 l
+0.3181 0.5256 l
+0.3184 0.5253 l
+0.3187 0.5251 l
+0.3190 0.5248 l
+0.3192 0.5245 l
+0.3195 0.5243 l
+0.3198 0.5240 l
+0.3201 0.5237 l
+0.3204 0.5234 l
+0.3207 0.5232 l
+0.3210 0.5229 l
+0.3213 0.5227 l
+0.3215 0.5224 l
+0.3218 0.5222 l
+0.3221 0.5220 l
+0.3224 0.5218 l
+0.3227 0.5216 l
+0.3230 0.5214 l
+0.3233 0.5213 l
+0.3235 0.5211 l
+0.3238 0.5210 l
+0.3241 0.5209 l
+0.3244 0.5208 l
+0.3247 0.5208 l
+0.3250 0.5208 l
+0.3253 0.5208 l
+0.3255 0.5208 l
+0.3258 0.5208 l
+0.3261 0.5209 l
+0.3264 0.5210 l
+0.3267 0.5211 l
+0.3270 0.5213 l
+0.3273 0.5214 l
+0.3275 0.5216 l
+0.3278 0.5218 l
+0.3281 0.5221 l
+0.3284 0.5223 l
+0.3287 0.5226 l
+0.3290 0.5229 l
+0.3293 0.5232 l
+0.3296 0.5235 l
+0.3298 0.5239 l
+0.3301 0.5242 l
+0.3304 0.5246 l
+0.3307 0.5249 l
+0.3310 0.5253 l
+0.3313 0.5257 l
+0.3316 0.5261 l
+0.3318 0.5264 l
+0.3321 0.5268 l
+0.3324 0.5272 l
+0.3327 0.5275 l
+0.3330 0.5279 l
+0.3333 0.5282 l
+0.3336 0.5286 l
+0.3338 0.5289 l
+0.3341 0.5292 l
+0.3344 0.5295 l
+0.3347 0.5297 l
+0.3350 0.5299 l
+0.3353 0.5302 l
+0.3356 0.5303 l
+0.3359 0.5305 l
+0.3361 0.5306 l
+0.3364 0.5307 l
+0.3367 0.5308 l
+0.3370 0.5308 l
+0.3373 0.5308 l
+0.3376 0.5308 l
+0.3379 0.5307 l
+0.3381 0.5306 l
+0.3384 0.5305 l
+0.3387 0.5303 l
+0.3390 0.5301 l
+0.3393 0.5298 l
+0.3396 0.5296 l
+0.3399 0.5293 l
+0.3401 0.5290 l
+0.3404 0.5286 l
+0.3407 0.5282 l
+0.3410 0.5278 l
+0.3413 0.5274 l
+0.3416 0.5270 l
+0.3419 0.5265 l
+0.3421 0.5260 l
+0.3424 0.5255 l
+0.3427 0.5250 l
+0.3430 0.5245 l
+0.3433 0.5240 l
+0.3436 0.5235 l
+0.3439 0.5230 l
+0.3442 0.5225 l
+0.3444 0.5220 l
+0.3447 0.5215 l
+0.3450 0.5210 l
+0.3453 0.5206 l
+0.3456 0.5201 l
+0.3459 0.5197 l
+0.3462 0.5193 l
+0.3464 0.5189 l
+0.3467 0.5186 l
+0.3470 0.5183 l
+0.3473 0.5180 l
+0.3476 0.5178 l
+0.3479 0.5176 l
+0.3482 0.5174 l
+0.3484 0.5173 l
+0.3487 0.5172 l
+0.3490 0.5172 l
+0.3493 0.5172 l
+0.3496 0.5172 l
+0.3499 0.5173 l
+0.3502 0.5175 l
+0.3504 0.5177 l
+0.3507 0.5179 l
+0.3510 0.5182 l
+0.3513 0.5185 l
+0.3516 0.5189 l
+0.3519 0.5193 l
+0.3522 0.5197 l
+0.3525 0.5202 l
+0.3527 0.5207 l
+0.3530 0.5212 l
+0.3533 0.5218 l
+0.3536 0.5224 l
+0.3539 0.5230 l
+0.3542 0.5237 l
+0.3545 0.5243 l
+0.3547 0.5250 l
+0.3550 0.5257 l
+0.3553 0.5264 l
+0.3556 0.5271 l
+0.3559 0.5278 l
+0.3562 0.5284 l
+0.3565 0.5291 l
+0.3567 0.5298 l
+0.3570 0.5304 l
+0.3573 0.5310 l
+0.3576 0.5316 l
+0.3579 0.5322 l
+0.3582 0.5327 l
+0.3585 0.5332 l
+0.3587 0.5336 l
+0.3590 0.5341 l
+0.3593 0.5344 l
+0.3596 0.5347 l
+0.3599 0.5350 l
+0.3602 0.5352 l
+0.3605 0.5353 l
+0.3608 0.5354 l
+0.3610 0.5355 l
+0.3613 0.5355 l
+0.3616 0.5354 l
+0.3619 0.5352 l
+0.3622 0.5350 l
+0.3625 0.5348 l
+0.3628 0.5344 l
+0.3630 0.5341 l
+0.3633 0.5336 l
+0.3636 0.5331 l
+0.3639 0.5326 l
+0.3642 0.5320 l
+0.3645 0.5313 l
+0.3648 0.5306 l
+0.3650 0.5299 l
+0.3653 0.5291 l
+0.3656 0.5283 l
+0.3659 0.5275 l
+0.3662 0.5266 l
+0.3665 0.5258 l
+0.3668 0.5249 l
+0.3670 0.5240 l
+0.3673 0.5230 l
+0.3676 0.5221 l
+0.3679 0.5212 l
+0.3682 0.5203 l
+0.3685 0.5194 l
+0.3688 0.5186 l
+0.3691 0.5177 l
+0.3693 0.5169 l
+0.3696 0.5161 l
+0.3699 0.5154 l
+0.3702 0.5147 l
+0.3705 0.5141 l
+0.3708 0.5135 l
+0.3711 0.5129 l
+0.3713 0.5125 l
+0.3716 0.5121 l
+0.3719 0.5117 l
+0.3722 0.5115 l
+0.3725 0.5113 l
+0.3728 0.5112 l
+0.3731 0.5111 l
+0.3733 0.5112 l
+0.3736 0.5113 l
+0.3739 0.5115 l
+0.3742 0.5118 l
+0.3745 0.5121 l
+0.3748 0.5126 l
+0.3751 0.5131 l
+0.3753 0.5137 l
+0.3756 0.5144 l
+0.3759 0.5151 l
+0.3762 0.5159 l
+0.3765 0.5167 l
+0.3768 0.5177 l
+0.3771 0.5186 l
+0.3774 0.5197 l
+0.3776 0.5207 l
+0.3779 0.5218 l
+0.3782 0.5230 l
+0.3785 0.5241 l
+0.3788 0.5253 l
+0.3791 0.5265 l
+0.3794 0.5277 l
+0.3796 0.5289 l
+0.3799 0.5301 l
+0.3802 0.5313 l
+0.3805 0.5324 l
+0.3808 0.5336 l
+0.3811 0.5347 l
+0.3814 0.5357 l
+0.3816 0.5367 l
+0.3819 0.5377 l
+0.3822 0.5386 l
+0.3825 0.5394 l
+0.3828 0.5402 l
+0.3831 0.5409 l
+0.3834 0.5415 l
+0.3836 0.5420 l
+0.3839 0.5424 l
+0.3842 0.5427 l
+0.3845 0.5430 l
+0.3848 0.5431 l
+0.3851 0.5431 l
+0.3854 0.5431 l
+0.3857 0.5429 l
+0.3859 0.5426 l
+0.3862 0.5422 l
+0.3865 0.5417 l
+0.3868 0.5411 l
+0.3871 0.5404 l
+0.3874 0.5397 l
+0.3877 0.5388 l
+0.3879 0.5378 l
+0.3882 0.5368 l
+0.3885 0.5356 l
+0.3888 0.5344 l
+0.3891 0.5331 l
+0.3894 0.5318 l
+0.3897 0.5304 l
+0.3899 0.5290 l
+0.3902 0.5275 l
+0.3905 0.5260 l
+0.3908 0.5244 l
+0.3911 0.5229 l
+0.3914 0.5213 l
+0.3917 0.5198 l
+0.3920 0.5182 l
+0.3922 0.5167 l
+0.3925 0.5152 l
+0.3928 0.5137 l
+0.3931 0.5123 l
+0.3934 0.5109 l
+0.3937 0.5096 l
+0.3940 0.5084 l
+0.3942 0.5072 l
+0.3945 0.5062 l
+0.3948 0.5052 l
+0.3951 0.5044 l
+0.3954 0.5036 l
+0.3957 0.5029 l
+0.3960 0.5024 l
+0.3962 0.5020 l
+0.3965 0.5017 l
+0.3968 0.5016 l
+0.3971 0.5016 l
+0.3974 0.5017 l
+0.3977 0.5019 l
+0.3980 0.5023 l
+0.3982 0.5028 l
+0.3985 0.5035 l
+0.3988 0.5043 l
+0.3991 0.5052 l
+0.3994 0.5062 l
+0.3997 0.5073 l
+0.4000 0.5086 l
+0.4003 0.5100 l
+0.4005 0.5115 l
+0.4008 0.5130 l
+0.4011 0.5147 l
+0.4014 0.5164 l
+0.4017 0.5182 l
+0.4020 0.5201 l
+0.4023 0.5220 l
+0.4025 0.5240 l
+0.4028 0.5260 l
+0.4031 0.5280 l
+0.4034 0.5300 l
+0.4037 0.5320 l
+0.4040 0.5340 l
+0.4043 0.5359 l
+0.4045 0.5378 l
+0.4048 0.5397 l
+0.4051 0.5415 l
+0.4054 0.5433 l
+0.4057 0.5449 l
+0.4060 0.5465 l
+0.4063 0.5479 l
+0.4065 0.5493 l
+0.4068 0.5505 l
+0.4071 0.5516 l
+0.4074 0.5525 l
+0.4077 0.5533 l
+0.4080 0.5540 l
+0.4083 0.5545 l
+0.4086 0.5548 l
+0.4088 0.5550 l
+0.4091 0.5550 l
+0.4094 0.5548 l
+0.4097 0.5545 l
+0.4100 0.5539 l
+0.4103 0.5533 l
+0.4106 0.5524 l
+0.4108 0.5514 l
+0.4111 0.5502 l
+0.4114 0.5489 l
+0.4117 0.5474 l
+0.4120 0.5457 l
+0.4123 0.5440 l
+0.4126 0.5421 l
+0.4128 0.5400 l
+0.4131 0.5379 l
+0.4134 0.5357 l
+0.4137 0.5334 l
+0.4140 0.5310 l
+0.4143 0.5285 l
+0.4146 0.5260 l
+0.4148 0.5235 l
+0.4151 0.5210 l
+0.4154 0.5184 l
+0.4157 0.5159 l
+0.4160 0.5133 l
+0.4163 0.5108 l
+0.4166 0.5084 l
+0.4169 0.5060 l
+0.4171 0.5038 l
+0.4174 0.5016 l
+0.4177 0.4995 l
+0.4180 0.4975 l
+0.4183 0.4957 l
+0.4186 0.4940 l
+0.4189 0.4925 l
+0.4191 0.4912 l
+0.4194 0.4900 l
+0.4197 0.4890 l
+0.4200 0.4882 l
+0.4203 0.4876 l
+0.4206 0.4872 l
+0.4209 0.4870 l
+0.4211 0.4871 l
+0.4214 0.4873 l
+0.4217 0.4878 l
+0.4220 0.4885 l
+0.4223 0.4894 l
+0.4226 0.4905 l
+0.4229 0.4918 l
+0.4231 0.4934 l
+0.4234 0.4951 l
+0.4237 0.4970 l
+0.4240 0.4991 l
+0.4243 0.5013 l
+0.4246 0.5038 l
+0.4249 0.5063 l
+0.4252 0.5090 l
+0.4254 0.5119 l
+0.4257 0.5148 l
+0.4260 0.5178 l
+0.4263 0.5209 l
+0.4266 0.5241 l
+0.4269 0.5272 l
+0.4272 0.5305 l
+0.4274 0.5337 l
+0.4277 0.5369 l
+0.4280 0.5400 l
+0.4283 0.5431 l
+0.4286 0.5462 l
+0.4289 0.5491 l
+0.4292 0.5520 l
+0.4294 0.5547 l
+0.4297 0.5573 l
+0.4300 0.5597 l
+0.4303 0.5620 l
+0.4306 0.5641 l
+0.4309 0.5659 l
+0.4312 0.5676 l
+0.4314 0.5690 l
+0.4317 0.5702 l
+0.4320 0.5712 l
+0.4323 0.5719 l
+0.4326 0.5723 l
+0.4329 0.5725 l
+0.4332 0.5724 l
+0.4335 0.5721 l
+0.4337 0.5714 l
+0.4340 0.5705 l
+0.4343 0.5694 l
+0.4346 0.5679 l
+0.4349 0.5662 l
+0.4352 0.5643 l
+0.4355 0.5621 l
+0.4357 0.5597 l
+0.4360 0.5570 l
+0.4363 0.5542 l
+0.4366 0.5511 l
+0.4369 0.5479 l
+0.4372 0.5445 l
+0.4375 0.5410 l
+0.4377 0.5373 l
+0.4380 0.5335 l
+0.4383 0.5297 l
+0.4386 0.5257 l
+0.4389 0.5218 l
+0.4392 0.5178 l
+0.4395 0.5138 l
+0.4397 0.5098 l
+0.4400 0.5059 l
+0.4403 0.5020 l
+0.4406 0.4982 l
+0.4409 0.4946 l
+0.4412 0.4911 l
+0.4415 0.4877 l
+0.4418 0.4845 l
+0.4420 0.4816 l
+0.4423 0.4788 l
+0.4426 0.4762 l
+0.4429 0.4740 l
+0.4432 0.4720 l
+0.4435 0.4702 l
+0.4438 0.4688 l
+0.4440 0.4676 l
+0.4443 0.4668 l
+0.4446 0.4663 l
+0.4449 0.4662 l
+0.4452 0.4663 l
+0.4455 0.4668 l
+0.4458 0.4677 l
+0.4460 0.4688 l
+0.4463 0.4703 l
+0.4466 0.4721 l
+0.4469 0.4743 l
+0.4472 0.4767 l
+0.4475 0.4795 l
+0.4478 0.4825 l
+0.4481 0.4858 l
+0.4483 0.4894 l
+0.4486 0.4932 l
+0.4489 0.4972 l
+0.4492 0.5014 l
+0.4495 0.5058 l
+0.4498 0.5104 l
+0.4501 0.5150 l
+0.4503 0.5198 l
+0.4506 0.5246 l
+0.4509 0.5295 l
+0.4512 0.5345 l
+0.4515 0.5394 l
+0.4518 0.5442 l
+0.4521 0.5491 l
+0.4523 0.5538 l
+0.4526 0.5584 l
+0.4529 0.5629 l
+0.4532 0.5672 l
+0.4535 0.5712 l
+0.4538 0.5751 l
+0.4541 0.5787 l
+0.4543 0.5821 l
+0.4546 0.5852 l
+0.4549 0.5879 l
+0.4552 0.5903 l
+0.4555 0.5924 l
+0.4558 0.5941 l
+0.4561 0.5954 l
+0.4564 0.5964 l
+0.4566 0.5969 l
+0.4569 0.5971 l
+0.4572 0.5968 l
+0.4575 0.5961 l
+0.4578 0.5950 l
+0.4581 0.5935 l
+0.4584 0.5916 l
+0.4586 0.5894 l
+0.4589 0.5867 l
+0.4592 0.5836 l
+0.4595 0.5802 l
+0.4598 0.5764 l
+0.4601 0.5724 l
+0.4604 0.5680 l
+0.4606 0.5633 l
+0.4609 0.5583 l
+0.4612 0.5532 l
+0.4615 0.5478 l
+0.4618 0.5422 l
+0.4621 0.5365 l
+0.4624 0.5307 l
+0.4626 0.5248 l
+0.4629 0.5188 l
+0.4632 0.5128 l
+0.4635 0.5068 l
+0.4638 0.5009 l
+0.4641 0.4951 l
+0.4644 0.4893 l
+0.4647 0.4838 l
+0.4649 0.4784 l
+0.4652 0.4732 l
+0.4655 0.4683 l
+0.4658 0.4636 l
+0.4661 0.4593 l
+0.4664 0.4552 l
+0.4667 0.4516 l
+0.4669 0.4483 l
+0.4672 0.4455 l
+0.4675 0.4430 l
+0.4678 0.4410 l
+0.4681 0.4395 l
+0.4684 0.4384 l
+0.4687 0.4378 l
+0.4689 0.4377 l
+0.4692 0.4381 l
+0.4695 0.4390 l
+0.4698 0.4404 l
+0.4701 0.4423 l
+0.4704 0.4447 l
+0.4707 0.4475 l
+0.4709 0.4508 l
+0.4712 0.4546 l
+0.4715 0.4588 l
+0.4718 0.4634 l
+0.4721 0.4684 l
+0.4724 0.4737 l
+0.4727 0.4794 l
+0.4730 0.4854 l
+0.4732 0.4917 l
+0.4735 0.4983 l
+0.4738 0.5050 l
+0.4741 0.5119 l
+0.4744 0.5189 l
+0.4747 0.5261 l
+0.4750 0.5333 l
+0.4752 0.5405 l
+0.4755 0.5477 l
+0.4758 0.5548 l
+0.4761 0.5618 l
+0.4764 0.5687 l
+0.4767 0.5753 l
+0.4770 0.5818 l
+0.4772 0.5879 l
+0.4775 0.5938 l
+0.4778 0.5994 l
+0.4781 0.6045 l
+0.4784 0.6093 l
+0.4787 0.6136 l
+0.4790 0.6174 l
+0.4792 0.6208 l
+0.4795 0.6236 l
+0.4798 0.6259 l
+0.4801 0.6277 l
+0.4804 0.6289 l
+0.4807 0.6295 l
+0.4810 0.6295 l
+0.4813 0.6289 l
+0.4815 0.6278 l
+0.4818 0.6260 l
+0.4821 0.6237 l
+0.4824 0.6208 l
+0.4827 0.6173 l
+0.4830 0.6132 l
+0.4833 0.6086 l
+0.4835 0.6036 l
+0.4838 0.5980 l
+0.4841 0.5919 l
+0.4844 0.5855 l
+0.4847 0.5786 l
+0.4850 0.5714 l
+0.4853 0.5638 l
+0.4855 0.5560 l
+0.4858 0.5480 l
+0.4861 0.5397 l
+0.4864 0.5313 l
+0.4867 0.5228 l
+0.4870 0.5142 l
+0.4873 0.5056 l
+0.4875 0.4971 l
+0.4878 0.4886 l
+0.4881 0.4803 l
+0.4884 0.4722 l
+0.4887 0.4643 l
+0.4890 0.4566 l
+0.4893 0.4494 l
+0.4896 0.4424 l
+0.4898 0.4359 l
+0.4901 0.4299 l
+0.4904 0.4243 l
+0.4907 0.4193 l
+0.4910 0.4148 l
+0.4913 0.4109 l
+0.4916 0.4076 l
+0.4918 0.4050 l
+0.4921 0.4030 l
+0.4924 0.4017 l
+0.4927 0.4011 l
+0.4930 0.4012 l
+0.4933 0.4020 l
+0.4936 0.4035 l
+0.4938 0.4057 l
+0.4941 0.4086 l
+0.4944 0.4121 l
+0.4947 0.4164 l
+0.4950 0.4212 l
+0.4953 0.4267 l
+0.4956 0.4329 l
+0.4959 0.4395 l
+0.4961 0.4467 l
+0.4964 0.4545 l
+0.4967 0.4626 l
+0.4970 0.4712 l
+0.4973 0.4802 l
+0.4976 0.4895 l
+0.4979 0.4990 l
+0.4981 0.5088 l
+0.4984 0.5187 l
+0.4987 0.5288 l
+0.4990 0.5389 l
+0.4993 0.5490 l
+0.4996 0.5590 l
+0.4999 0.5690 l
+0.5001 0.5787 l
+0.5004 0.5882 l
+0.5007 0.5975 l
+0.5010 0.6064 l
+0.5013 0.6149 l
+0.5016 0.6229 l
+0.5019 0.6305 l
+0.5021 0.6375 l
+0.5024 0.6440 l
+0.5027 0.6498 l
+0.5030 0.6549 l
+0.5033 0.6594 l
+0.5036 0.6631 l
+0.5039 0.6661 l
+0.5042 0.6683 l
+0.5044 0.6697 l
+0.5047 0.6702 l
+0.5050 0.6700 l
+0.5053 0.6690 l
+0.5056 0.6671 l
+0.5059 0.6644 l
+0.5062 0.6609 l
+0.5064 0.6566 l
+0.5067 0.6515 l
+0.5070 0.6457 l
+0.5073 0.6391 l
+0.5076 0.6319 l
+0.5079 0.6240 l
+0.5082 0.6155 l
+0.5084 0.6064 l
+0.5087 0.5967 l
+0.5090 0.5866 l
+0.5093 0.5761 l
+0.5096 0.5652 l
+0.5099 0.5541 l
+0.5102 0.5426 l
+0.5104 0.5310 l
+0.5107 0.5193 l
+0.5110 0.5075 l
+0.5113 0.4957 l
+0.5116 0.4841 l
+0.5119 0.4725 l
+0.5122 0.4612 l
+0.5125 0.4502 l
+0.5127 0.4395 l
+0.5130 0.4292 l
+0.5133 0.4194 l
+0.5136 0.4101 l
+0.5139 0.4014 l
+0.5142 0.3934 l
+0.5145 0.3860 l
+0.5147 0.3794 l
+0.5150 0.3735 l
+0.5153 0.3685 l
+0.5156 0.3643 l
+0.5159 0.3610 l
+0.5162 0.3586 l
+0.5165 0.3571 l
+0.5167 0.3566 l
+0.5170 0.3570 l
+0.5173 0.3584 l
+0.5176 0.3607 l
+0.5179 0.3640 l
+0.5182 0.3682 l
+0.5185 0.3733 l
+0.5187 0.3793 l
+0.5190 0.3862 l
+0.5193 0.3939 l
+0.5196 0.4024 l
+0.5199 0.4116 l
+0.5202 0.4216 l
+0.5205 0.4322 l
+0.5208 0.4434 l
+0.5210 0.4551 l
+0.5213 0.4674 l
+0.5216 0.4800 l
+0.5219 0.4929 l
+0.5222 0.5062 l
+0.5225 0.5196 l
+0.5228 0.5331 l
+0.5230 0.5467 l
+0.5233 0.5602 l
+0.5236 0.5737 l
+0.5239 0.5869 l
+0.5242 0.5999 l
+0.5245 0.6126 l
+0.5248 0.6248 l
+0.5250 0.6365 l
+0.5253 0.6477 l
+0.5256 0.6583 l
+0.5259 0.6682 l
+0.5262 0.6773 l
+0.5265 0.6856 l
+0.5268 0.6931 l
+0.5270 0.6997 l
+0.5273 0.7053 l
+0.5276 0.7100 l
+0.5279 0.7136 l
+0.5282 0.7162 l
+0.5285 0.7177 l
+0.5288 0.7181 l
+0.5291 0.7175 l
+0.5293 0.7157 l
+0.5296 0.7129 l
+0.5299 0.7090 l
+0.5302 0.7040 l
+0.5305 0.6980 l
+0.5308 0.6909 l
+0.5311 0.6829 l
+0.5313 0.6740 l
+0.5316 0.6641 l
+0.5319 0.6534 l
+0.5322 0.6419 l
+0.5325 0.6297 l
+0.5328 0.6168 l
+0.5331 0.6033 l
+0.5333 0.5892 l
+0.5336 0.5748 l
+0.5339 0.5599 l
+0.5342 0.5448 l
+0.5345 0.5295 l
+0.5348 0.5140 l
+0.5351 0.4985 l
+0.5353 0.4831 l
+0.5356 0.4678 l
+0.5359 0.4528 l
+0.5362 0.4380 l
+0.5365 0.4237 l
+0.5368 0.4099 l
+0.5371 0.3966 l
+0.5374 0.3840 l
+0.5376 0.3721 l
+0.5379 0.3610 l
+0.5382 0.3507 l
+0.5385 0.3414 l
+0.5388 0.3331 l
+0.5391 0.3258 l
+0.5394 0.3196 l
+0.5396 0.3145 l
+0.5399 0.3105 l
+0.5402 0.3078 l
+0.5405 0.3063 l
+0.5408 0.3060 l
+0.5411 0.3069 l
+0.5414 0.3091 l
+0.5416 0.3125 l
+0.5419 0.3171 l
+0.5422 0.3229 l
+0.5425 0.3300 l
+0.5428 0.3381 l
+0.5431 0.3473 l
+0.5434 0.3577 l
+0.5436 0.3690 l
+0.5439 0.3812 l
+0.5442 0.3944 l
+0.5445 0.4083 l
+0.5448 0.4230 l
+0.5451 0.4383 l
+0.5454 0.4543 l
+0.5457 0.4707 l
+0.5459 0.4875 l
+0.5462 0.5046 l
+0.5465 0.5219 l
+0.5468 0.5394 l
+0.5471 0.5568 l
+0.5474 0.5742 l
+0.5477 0.5914 l
+0.5479 0.6083 l
+0.5482 0.6248 l
+0.5485 0.6408 l
+0.5488 0.6563 l
+0.5491 0.6711 l
+0.5494 0.6852 l
+0.5497 0.6985 l
+0.5499 0.7108 l
+0.5502 0.7222 l
+0.5505 0.7325 l
+0.5508 0.7417 l
+0.5511 0.7497 l
+0.5514 0.7565 l
+0.5517 0.7620 l
+0.5520 0.7662 l
+0.5522 0.7690 l
+0.5525 0.7705 l
+0.5528 0.7706 l
+0.5531 0.7694 l
+0.5534 0.7667 l
+0.5537 0.7627 l
+0.5540 0.7573 l
+0.5542 0.7505 l
+0.5545 0.7425 l
+0.5548 0.7332 l
+0.5551 0.7226 l
+0.5554 0.7109 l
+0.5557 0.6981 l
+0.5560 0.6842 l
+0.5562 0.6694 l
+0.5565 0.6537 l
+0.5568 0.6371 l
+0.5571 0.6199 l
+0.5574 0.6020 l
+0.5577 0.5836 l
+0.5580 0.5648 l
+0.5582 0.5456 l
+0.5585 0.5263 l
+0.5588 0.5068 l
+0.5591 0.4873 l
+0.5594 0.4680 l
+0.5597 0.4489 l
+0.5600 0.4301 l
+0.5603 0.4118 l
+0.5605 0.3940 l
+0.5608 0.3769 l
+0.5611 0.3605 l
+0.5614 0.3450 l
+0.5617 0.3304 l
+0.5620 0.3168 l
+0.5623 0.3044 l
+0.5625 0.2931 l
+0.5628 0.2831 l
+0.5631 0.2744 l
+0.5634 0.2671 l
+0.5637 0.2612 l
+0.5640 0.2568 l
+0.5643 0.2538 l
+0.5645 0.2524 l
+0.5648 0.2525 l
+0.5651 0.2542 l
+0.5654 0.2574 l
+0.5657 0.2621 l
+0.5660 0.2683 l
+0.5663 0.2760 l
+0.5665 0.2852 l
+0.5668 0.2957 l
+0.5671 0.3076 l
+0.5674 0.3207 l
+0.5677 0.3351 l
+0.5680 0.3506 l
+0.5683 0.3672 l
+0.5686 0.3847 l
+0.5688 0.4032 l
+0.5691 0.4223 l
+0.5694 0.4422 l
+0.5697 0.4626 l
+0.5700 0.4834 l
+0.5703 0.5046 l
+0.5706 0.5260 l
+0.5708 0.5475 l
+0.5711 0.5689 l
+0.5714 0.5902 l
+0.5717 0.6112 l
+0.5720 0.6319 l
+0.5723 0.6520 l
+0.5726 0.6715 l
+0.5728 0.6902 l
+0.5731 0.7081 l
+0.5734 0.7250 l
+0.5737 0.7409 l
+0.5740 0.7556 l
+0.5743 0.7691 l
+0.5746 0.7813 l
+0.5748 0.7921 l
+0.5751 0.8014 l
+0.5754 0.8092 l
+0.5757 0.8154 l
+0.5760 0.8200 l
+0.5763 0.8230 l
+0.5766 0.8243 l
+0.5769 0.8239 l
+0.5771 0.8218 l
+0.5774 0.8180 l
+0.5777 0.8126 l
+0.5780 0.8055 l
+0.5783 0.7968 l
+0.5786 0.7866 l
+0.5789 0.7748 l
+0.5791 0.7616 l
+0.5794 0.7469 l
+0.5797 0.7310 l
+0.5800 0.7138 l
+0.5803 0.6955 l
+0.5806 0.6762 l
+0.5809 0.6559 l
+0.5811 0.6348 l
+0.5814 0.6130 l
+0.5817 0.5906 l
+0.5820 0.5678 l
+0.5823 0.5446 l
+0.5826 0.5213 l
+0.5829 0.4978 l
+0.5831 0.4744 l
+0.5834 0.4513 l
+0.5837 0.4284 l
+0.5840 0.4060 l
+0.5843 0.3842 l
+0.5846 0.3631 l
+0.5849 0.3428 l
+0.5852 0.3235 l
+0.5854 0.3052 l
+0.5857 0.2881 l
+0.5860 0.2723 l
+0.5863 0.2578 l
+0.5866 0.2448 l
+0.5869 0.2334 l
+0.5872 0.2235 l
+0.5874 0.2153 l
+0.5877 0.2088 l
+0.5880 0.2041 l
+0.5883 0.2012 l
+0.5886 0.2000 l
+0.5889 0.2008 l
+0.5892 0.2033 l
+0.5894 0.2077 l
+0.5897 0.2139 l
+0.5900 0.2218 l
+0.5903 0.2315 l
+0.5906 0.2429 l
+0.5909 0.2559 l
+0.5912 0.2705 l
+0.5914 0.2866 l
+0.5917 0.3040 l
+0.5920 0.3228 l
+0.5923 0.3428 l
+0.5926 0.3639 l
+0.5929 0.3860 l
+0.5932 0.4089 l
+0.5935 0.4325 l
+0.5937 0.4568 l
+0.5940 0.4815 l
+0.5943 0.5066 l
+0.5946 0.5319 l
+0.5949 0.5572 l
+0.5952 0.5824 l
+0.5955 0.6073 l
+0.5957 0.6319 l
+0.5960 0.6560 l
+0.5963 0.6794 l
+0.5966 0.7020 l
+0.5969 0.7237 l
+0.5972 0.7444 l
+0.5975 0.7638 l
+0.5977 0.7820 l
+0.5980 0.7988 l
+0.5983 0.8141 l
+0.5986 0.8279 l
+0.5989 0.8399 l
+0.5992 0.8502 l
+0.5995 0.8588 l
+0.5998 0.8654 l
+0.6000 0.8702 l
+0.6003 0.8731 l
+0.6006 0.8739 l
+0.6009 0.8729 l
+0.6012 0.8698 l
+0.6015 0.8648 l
+0.6018 0.8579 l
+0.6020 0.8491 l
+0.6023 0.8384 l
+0.6026 0.8259 l
+0.6029 0.8117 l
+0.6032 0.7958 l
+0.6035 0.7783 l
+0.6038 0.7594 l
+0.6040 0.7391 l
+0.6043 0.7175 l
+0.6046 0.6948 l
+0.6049 0.6710 l
+0.6052 0.6464 l
+0.6055 0.6210 l
+0.6058 0.5949 l
+0.6060 0.5684 l
+0.6063 0.5416 l
+0.6066 0.5146 l
+0.6069 0.4876 l
+0.6072 0.4608 l
+0.6075 0.4342 l
+0.6078 0.4080 l
+0.6081 0.3825 l
+0.6083 0.3576 l
+0.6086 0.3337 l
+0.6089 0.3107 l
+0.6092 0.2889 l
+0.6095 0.2684 l
+0.6098 0.2492 l
+0.6101 0.2316 l
+0.6103 0.2156 l
+0.6106 0.2012 l
+0.6109 0.1887 l
+0.6112 0.1780 l
+0.6115 0.1693 l
+0.6118 0.1625 l
+0.6121 0.1577 l
+0.6123 0.1550 l
+0.6126 0.1544 l
+0.6129 0.1559 l
+0.6132 0.1595 l
+0.6135 0.1651 l
+0.6138 0.1728 l
+0.6141 0.1825 l
+0.6143 0.1941 l
+0.6146 0.2076 l
+0.6149 0.2230 l
+0.6152 0.2401 l
+0.6155 0.2588 l
+0.6158 0.2791 l
+0.6161 0.3008 l
+0.6164 0.3239 l
+0.6166 0.3481 l
+0.6169 0.3734 l
+0.6172 0.3996 l
+0.6175 0.4266 l
+0.6178 0.4542 l
+0.6181 0.4823 l
+0.6184 0.5106 l
+0.6186 0.5391 l
+0.6189 0.5676 l
+0.6192 0.5960 l
+0.6195 0.6240 l
+0.6198 0.6515 l
+0.6201 0.6783 l
+0.6204 0.7044 l
+0.6206 0.7295 l
+0.6209 0.7535 l
+0.6212 0.7763 l
+0.6215 0.7977 l
+0.6218 0.8176 l
+0.6221 0.8359 l
+0.6224 0.8525 l
+0.6226 0.8673 l
+0.6229 0.8802 l
+0.6232 0.8911 l
+0.6235 0.9000 l
+0.6238 0.9068 l
+0.6241 0.9114 l
+0.6244 0.9139 l
+0.6247 0.9142 l
+0.6249 0.9123 l
+0.6252 0.9082 l
+0.6255 0.9020 l
+0.6258 0.8936 l
+0.6261 0.8831 l
+0.6264 0.8706 l
+0.6267 0.8561 l
+0.6269 0.8397 l
+0.6272 0.8215 l
+0.6275 0.8016 l
+0.6278 0.7801 l
+0.6281 0.7571 l
+0.6284 0.7328 l
+0.6287 0.7072 l
+0.6289 0.6806 l
+0.6292 0.6530 l
+0.6295 0.6247 l
+0.6298 0.5958 l
+0.6301 0.5664 l
+0.6304 0.5367 l
+0.6307 0.5069 l
+0.6309 0.4771 l
+0.6312 0.4476 l
+0.6315 0.4184 l
+0.6318 0.3898 l
+0.6321 0.3619 l
+0.6324 0.3349 l
+0.6327 0.3089 l
+0.6330 0.2841 l
+0.6332 0.2606 l
+0.6335 0.2385 l
+0.6338 0.2180 l
+0.6341 0.1992 l
+0.6344 0.1822 l
+0.6347 0.1671 l
+0.6350 0.1540 l
+0.6352 0.1430 l
+0.6355 0.1341 l
+0.6358 0.1274 l
+0.6361 0.1229 l
+0.6364 0.1207 l
+0.6367 0.1208 l
+0.6370 0.1231 l
+0.6372 0.1277 l
+0.6375 0.1345 l
+0.6378 0.1436 l
+0.6381 0.1548 l
+0.6384 0.1681 l
+0.6387 0.1835 l
+0.6390 0.2008 l
+0.6392 0.2199 l
+0.6395 0.2408 l
+0.6398 0.2633 l
+0.6401 0.2874 l
+0.6404 0.3128 l
+0.6407 0.3394 l
+0.6410 0.3671 l
+0.6413 0.3958 l
+0.6415 0.4252 l
+0.6418 0.4552 l
+0.6421 0.4857 l
+0.6424 0.5164 l
+0.6427 0.5472 l
+0.6430 0.5779 l
+0.6433 0.6083 l
+0.6435 0.6384 l
+0.6438 0.6678 l
+0.6441 0.6964 l
+0.6444 0.7242 l
+0.6447 0.7508 l
+0.6450 0.7762 l
+0.6453 0.8002 l
+0.6455 0.8227 l
+0.6458 0.8436 l
+0.6461 0.8626 l
+0.6464 0.8798 l
+0.6467 0.8950 l
+0.6470 0.9082 l
+0.6473 0.9192 l
+0.6475 0.9280 l
+0.6478 0.9345 l
+0.6481 0.9388 l
+0.6484 0.9407 l
+0.6487 0.9402 l
+0.6490 0.9375 l
+0.6493 0.9324 l
+0.6496 0.9250 l
+0.6498 0.9153 l
+0.6501 0.9035 l
+0.6504 0.8895 l
+0.6507 0.8734 l
+0.6510 0.8554 l
+0.6513 0.8354 l
+0.6516 0.8137 l
+0.6518 0.7904 l
+0.6521 0.7656 l
+0.6524 0.7393 l
+0.6527 0.7119 l
+0.6530 0.6833 l
+0.6533 0.6539 l
+0.6536 0.6237 l
+0.6538 0.5929 l
+0.6541 0.5617 l
+0.6544 0.5303 l
+0.6547 0.4988 l
+0.6550 0.4675 l
+0.6553 0.4364 l
+0.6556 0.4058 l
+0.6559 0.3759 l
+0.6561 0.3468 l
+0.6564 0.3187 l
+0.6567 0.2917 l
+0.6570 0.2660 l
+0.6573 0.2417 l
+0.6576 0.2191 l
+0.6579 0.1981 l
+0.6581 0.1790 l
+0.6584 0.1618 l
+0.6587 0.1466 l
+0.6590 0.1336 l
+0.6593 0.1227 l
+0.6596 0.1141 l
+0.6599 0.1079 l
+0.6601 0.1039 l
+0.6604 0.1024 l
+0.6607 0.1032 l
+0.6610 0.1064 l
+0.6613 0.1119 l
+0.6616 0.1198 l
+0.6619 0.1299 l
+0.6621 0.1423 l
+0.6624 0.1569 l
+0.6627 0.1735 l
+0.6630 0.1921 l
+0.6633 0.2126 l
+0.6636 0.2349 l
+0.6639 0.2588 l
+0.6642 0.2842 l
+0.6644 0.3110 l
+0.6647 0.3390 l
+0.6650 0.3680 l
+0.6653 0.3979 l
+0.6656 0.4286 l
+0.6659 0.4598 l
+0.6662 0.4914 l
+0.6664 0.5232 l
+0.6667 0.5550 l
+0.6670 0.5867 l
+0.6673 0.6180 l
+0.6676 0.6488 l
+0.6679 0.6789 l
+0.6682 0.7081 l
+0.6684 0.7363 l
+0.6687 0.7634 l
+0.6690 0.7891 l
+0.6693 0.8133 l
+0.6696 0.8359 l
+0.6699 0.8567 l
+0.6702 0.8757 l
+0.6704 0.8927 l
+0.6707 0.9076 l
+0.6710 0.9204 l
+0.6713 0.9310 l
+0.6716 0.9393 l
+0.6719 0.9452 l
+0.6722 0.9488 l
+0.6725 0.9500 l
+0.6727 0.9488 l
+0.6730 0.9452 l
+0.6733 0.9393 l
+0.6736 0.9310 l
+0.6739 0.9204 l
+0.6742 0.9076 l
+0.6745 0.8927 l
+0.6747 0.8757 l
+0.6750 0.8567 l
+0.6753 0.8359 l
+0.6756 0.8133 l
+0.6759 0.7891 l
+0.6762 0.7634 l
+0.6765 0.7363 l
+0.6767 0.7081 l
+0.6770 0.6789 l
+0.6773 0.6488 l
+0.6776 0.6180 l
+0.6779 0.5867 l
+0.6782 0.5550 l
+0.6785 0.5232 l
+0.6787 0.4914 l
+0.6790 0.4598 l
+0.6793 0.4286 l
+0.6796 0.3979 l
+0.6799 0.3680 l
+0.6802 0.3390 l
+0.6805 0.3110 l
+0.6808 0.2842 l
+0.6810 0.2588 l
+0.6813 0.2349 l
+0.6816 0.2126 l
+0.6819 0.1921 l
+0.6822 0.1735 l
+0.6825 0.1569 l
+0.6828 0.1423 l
+0.6830 0.1299 l
+0.6833 0.1198 l
+0.6836 0.1119 l
+0.6839 0.1064 l
+0.6842 0.1032 l
+0.6845 0.1024 l
+0.6848 0.1039 l
+0.6850 0.1079 l
+0.6853 0.1141 l
+0.6856 0.1227 l
+0.6859 0.1336 l
+0.6862 0.1466 l
+0.6865 0.1618 l
+0.6868 0.1790 l
+0.6870 0.1981 l
+0.6873 0.2191 l
+0.6876 0.2417 l
+0.6879 0.2660 l
+0.6882 0.2917 l
+0.6885 0.3187 l
+0.6888 0.3468 l
+0.6891 0.3759 l
+0.6893 0.4058 l
+0.6896 0.4364 l
+0.6899 0.4675 l
+0.6902 0.4988 l
+0.6905 0.5303 l
+0.6908 0.5617 l
+0.6911 0.5929 l
+0.6913 0.6237 l
+0.6916 0.6539 l
+0.6919 0.6833 l
+0.6922 0.7119 l
+0.6925 0.7393 l
+0.6928 0.7656 l
+0.6931 0.7904 l
+0.6933 0.8137 l
+0.6936 0.8354 l
+0.6939 0.8554 l
+0.6942 0.8734 l
+0.6945 0.8895 l
+0.6948 0.9035 l
+0.6951 0.9153 l
+0.6953 0.9250 l
+0.6956 0.9324 l
+0.6959 0.9375 l
+0.6962 0.9402 l
+0.6965 0.9407 l
+0.6968 0.9388 l
+0.6971 0.9345 l
+0.6974 0.9280 l
+0.6976 0.9192 l
+0.6979 0.9082 l
+0.6982 0.8950 l
+0.6985 0.8798 l
+0.6988 0.8626 l
+0.6991 0.8436 l
+0.6994 0.8227 l
+0.6996 0.8002 l
+0.6999 0.7762 l
+0.7002 0.7508 l
+0.7005 0.7242 l
+0.7008 0.6964 l
+0.7011 0.6678 l
+0.7014 0.6384 l
+0.7016 0.6083 l
+0.7019 0.5779 l
+0.7022 0.5472 l
+0.7025 0.5164 l
+0.7028 0.4857 l
+0.7031 0.4552 l
+0.7034 0.4252 l
+0.7037 0.3958 l
+0.7039 0.3671 l
+0.7042 0.3394 l
+0.7045 0.3128 l
+0.7048 0.2874 l
+0.7051 0.2633 l
+0.7054 0.2408 l
+0.7057 0.2199 l
+0.7059 0.2008 l
+0.7062 0.1835 l
+0.7065 0.1681 l
+0.7068 0.1548 l
+0.7071 0.1436 l
+0.7074 0.1345 l
+0.7077 0.1277 l
+0.7079 0.1231 l
+0.7082 0.1208 l
+0.7085 0.1207 l
+0.7088 0.1229 l
+0.7091 0.1274 l
+0.7094 0.1341 l
+0.7097 0.1430 l
+0.7099 0.1540 l
+0.7102 0.1671 l
+0.7105 0.1822 l
+0.7108 0.1992 l
+0.7111 0.2180 l
+0.7114 0.2385 l
+0.7117 0.2606 l
+0.7120 0.2841 l
+0.7122 0.3089 l
+0.7125 0.3349 l
+0.7128 0.3619 l
+0.7131 0.3898 l
+0.7134 0.4184 l
+0.7137 0.4476 l
+0.7140 0.4771 l
+0.7142 0.5069 l
+0.7145 0.5367 l
+0.7148 0.5664 l
+0.7151 0.5958 l
+0.7154 0.6247 l
+0.7157 0.6530 l
+0.7160 0.6806 l
+0.7162 0.7072 l
+0.7165 0.7328 l
+0.7168 0.7571 l
+0.7171 0.7801 l
+0.7174 0.8016 l
+0.7177 0.8215 l
+0.7180 0.8397 l
+0.7182 0.8561 l
+0.7185 0.8706 l
+0.7188 0.8831 l
+0.7191 0.8936 l
+0.7194 0.9020 l
+0.7197 0.9082 l
+0.7200 0.9123 l
+0.7203 0.9142 l
+0.7205 0.9139 l
+0.7208 0.9114 l
+0.7211 0.9068 l
+0.7214 0.9000 l
+0.7217 0.8911 l
+0.7220 0.8802 l
+0.7223 0.8673 l
+0.7225 0.8525 l
+0.7228 0.8359 l
+0.7231 0.8176 l
+0.7234 0.7977 l
+0.7237 0.7763 l
+0.7240 0.7535 l
+0.7243 0.7295 l
+0.7245 0.7044 l
+0.7248 0.6783 l
+0.7251 0.6515 l
+0.7254 0.6240 l
+0.7257 0.5960 l
+0.7260 0.5676 l
+0.7263 0.5391 l
+0.7265 0.5106 l
+0.7268 0.4823 l
+0.7271 0.4542 l
+0.7274 0.4266 l
+0.7277 0.3996 l
+0.7280 0.3734 l
+0.7283 0.3481 l
+0.7286 0.3239 l
+0.7288 0.3008 l
+0.7291 0.2791 l
+0.7294 0.2588 l
+0.7297 0.2401 l
+0.7300 0.2230 l
+0.7303 0.2076 l
+0.7306 0.1941 l
+0.7308 0.1825 l
+0.7311 0.1728 l
+0.7314 0.1651 l
+0.7317 0.1595 l
+0.7320 0.1559 l
+0.7323 0.1544 l
+0.7326 0.1550 l
+0.7328 0.1577 l
+0.7331 0.1625 l
+0.7334 0.1693 l
+0.7337 0.1780 l
+0.7340 0.1887 l
+0.7343 0.2012 l
+0.7346 0.2156 l
+0.7348 0.2316 l
+0.7351 0.2492 l
+0.7354 0.2684 l
+0.7357 0.2889 l
+0.7360 0.3107 l
+0.7363 0.3337 l
+0.7366 0.3576 l
+0.7369 0.3825 l
+0.7371 0.4080 l
+0.7374 0.4342 l
+0.7377 0.4608 l
+0.7380 0.4876 l
+0.7383 0.5146 l
+0.7386 0.5416 l
+0.7389 0.5684 l
+0.7391 0.5949 l
+0.7394 0.6210 l
+0.7397 0.6464 l
+0.7400 0.6710 l
+0.7403 0.6948 l
+0.7406 0.7175 l
+0.7409 0.7391 l
+0.7411 0.7594 l
+0.7414 0.7783 l
+0.7417 0.7958 l
+0.7420 0.8117 l
+0.7423 0.8259 l
+0.7426 0.8384 l
+0.7429 0.8491 l
+0.7431 0.8579 l
+0.7434 0.8648 l
+0.7437 0.8698 l
+0.7440 0.8729 l
+0.7443 0.8739 l
+0.7446 0.8731 l
+0.7449 0.8702 l
+0.7452 0.8654 l
+0.7454 0.8588 l
+0.7457 0.8502 l
+0.7460 0.8399 l
+0.7463 0.8279 l
+0.7466 0.8141 l
+0.7469 0.7988 l
+0.7472 0.7820 l
+0.7474 0.7638 l
+0.7477 0.7444 l
+0.7480 0.7237 l
+0.7483 0.7020 l
+0.7486 0.6794 l
+0.7489 0.6560 l
+0.7492 0.6319 l
+0.7494 0.6073 l
+0.7497 0.5824 l
+0.7500 0.5572 l
+0.7503 0.5319 l
+0.7506 0.5066 l
+0.7509 0.4815 l
+0.7512 0.4568 l
+0.7514 0.4325 l
+0.7517 0.4089 l
+0.7520 0.3859 l
+0.7523 0.3639 l
+0.7526 0.3428 l
+0.7529 0.3228 l
+0.7532 0.3040 l
+0.7535 0.2866 l
+0.7537 0.2705 l
+0.7540 0.2559 l
+0.7543 0.2429 l
+0.7546 0.2315 l
+0.7549 0.2218 l
+0.7552 0.2139 l
+0.7555 0.2077 l
+0.7557 0.2033 l
+0.7560 0.2008 l
+0.7563 0.2000 l
+0.7566 0.2012 l
+0.7569 0.2041 l
+0.7572 0.2088 l
+0.7575 0.2153 l
+0.7577 0.2235 l
+0.7580 0.2334 l
+0.7583 0.2448 l
+0.7586 0.2578 l
+0.7589 0.2723 l
+0.7592 0.2881 l
+0.7595 0.3052 l
+0.7598 0.3235 l
+0.7600 0.3428 l
+0.7603 0.3631 l
+0.7606 0.3842 l
+0.7609 0.4060 l
+0.7612 0.4284 l
+0.7615 0.4513 l
+0.7618 0.4744 l
+0.7620 0.4978 l
+0.7623 0.5213 l
+0.7626 0.5446 l
+0.7629 0.5678 l
+0.7632 0.5906 l
+0.7635 0.6130 l
+0.7638 0.6348 l
+0.7640 0.6559 l
+0.7643 0.6762 l
+0.7646 0.6955 l
+0.7649 0.7138 l
+0.7652 0.7310 l
+0.7655 0.7469 l
+0.7658 0.7616 l
+0.7660 0.7748 l
+0.7663 0.7866 l
+0.7666 0.7968 l
+0.7669 0.8055 l
+0.7672 0.8126 l
+0.7675 0.8180 l
+0.7678 0.8218 l
+0.7681 0.8239 l
+0.7683 0.8243 l
+0.7686 0.8230 l
+0.7689 0.8200 l
+0.7692 0.8154 l
+0.7695 0.8092 l
+0.7698 0.8014 l
+0.7701 0.7921 l
+0.7703 0.7813 l
+0.7706 0.7691 l
+0.7709 0.7556 l
+0.7712 0.7409 l
+0.7715 0.7250 l
+0.7718 0.7081 l
+0.7721 0.6902 l
+0.7723 0.6715 l
+0.7726 0.6520 l
+0.7729 0.6319 l
+0.7732 0.6112 l
+0.7735 0.5902 l
+0.7738 0.5689 l
+0.7741 0.5475 l
+0.7743 0.5260 l
+0.7746 0.5046 l
+0.7749 0.4834 l
+0.7752 0.4626 l
+0.7755 0.4422 l
+0.7758 0.4223 l
+0.7761 0.4032 l
+0.7764 0.3847 l
+0.7766 0.3672 l
+0.7769 0.3506 l
+0.7772 0.3351 l
+0.7775 0.3207 l
+0.7778 0.3076 l
+0.7781 0.2957 l
+0.7784 0.2852 l
+0.7786 0.2760 l
+0.7789 0.2683 l
+0.7792 0.2621 l
+0.7795 0.2574 l
+0.7798 0.2542 l
+0.7801 0.2525 l
+0.7804 0.2524 l
+0.7806 0.2538 l
+0.7809 0.2568 l
+0.7812 0.2612 l
+0.7815 0.2671 l
+0.7818 0.2744 l
+0.7821 0.2831 l
+0.7824 0.2931 l
+0.7826 0.3044 l
+0.7829 0.3168 l
+0.7832 0.3304 l
+0.7835 0.3450 l
+0.7838 0.3605 l
+0.7841 0.3769 l
+0.7844 0.3940 l
+0.7847 0.4118 l
+0.7849 0.4301 l
+0.7852 0.4489 l
+0.7855 0.4680 l
+0.7858 0.4873 l
+0.7861 0.5068 l
+0.7864 0.5263 l
+0.7867 0.5456 l
+0.7869 0.5648 l
+0.7872 0.5836 l
+0.7875 0.6020 l
+0.7878 0.6199 l
+0.7881 0.6371 l
+0.7884 0.6537 l
+0.7887 0.6694 l
+0.7889 0.6842 l
+0.7892 0.6981 l
+0.7895 0.7109 l
+0.7898 0.7226 l
+0.7901 0.7332 l
+0.7904 0.7425 l
+0.7907 0.7505 l
+0.7909 0.7573 l
+0.7912 0.7627 l
+0.7915 0.7667 l
+0.7918 0.7694 l
+0.7921 0.7706 l
+0.7924 0.7705 l
+0.7927 0.7690 l
+0.7930 0.7662 l
+0.7932 0.7620 l
+0.7935 0.7565 l
+0.7938 0.7497 l
+0.7941 0.7417 l
+0.7944 0.7325 l
+0.7947 0.7222 l
+0.7950 0.7108 l
+0.7952 0.6985 l
+0.7955 0.6852 l
+0.7958 0.6711 l
+0.7961 0.6563 l
+0.7964 0.6408 l
+0.7967 0.6248 l
+0.7970 0.6083 l
+0.7972 0.5914 l
+0.7975 0.5742 l
+0.7978 0.5568 l
+0.7981 0.5394 l
+0.7984 0.5219 l
+0.7987 0.5046 l
+0.7990 0.4875 l
+0.7992 0.4707 l
+0.7995 0.4543 l
+0.7998 0.4383 l
+0.8001 0.4230 l
+0.8004 0.4083 l
+0.8007 0.3944 l
+0.8010 0.3812 l
+0.8013 0.3690 l
+0.8015 0.3577 l
+0.8018 0.3473 l
+0.8021 0.3381 l
+0.8024 0.3300 l
+0.8027 0.3229 l
+0.8030 0.3171 l
+0.8033 0.3125 l
+0.8035 0.3091 l
+0.8038 0.3069 l
+0.8041 0.3060 l
+0.8044 0.3063 l
+0.8047 0.3078 l
+0.8050 0.3105 l
+0.8053 0.3145 l
+0.8055 0.3196 l
+0.8058 0.3258 l
+0.8061 0.3331 l
+0.8064 0.3414 l
+0.8067 0.3507 l
+0.8070 0.3610 l
+0.8073 0.3721 l
+0.8076 0.3840 l
+0.8078 0.3966 l
+0.8081 0.4099 l
+0.8084 0.4237 l
+0.8087 0.4380 l
+0.8090 0.4528 l
+0.8093 0.4678 l
+0.8096 0.4831 l
+0.8098 0.4985 l
+0.8101 0.5140 l
+0.8104 0.5295 l
+0.8107 0.5448 l
+0.8110 0.5599 l
+0.8113 0.5748 l
+0.8116 0.5892 l
+0.8118 0.6033 l
+0.8121 0.6168 l
+0.8124 0.6297 l
+0.8127 0.6419 l
+0.8130 0.6534 l
+0.8133 0.6641 l
+0.8136 0.6740 l
+0.8138 0.6829 l
+0.8141 0.6909 l
+0.8144 0.6980 l
+0.8147 0.7040 l
+0.8150 0.7090 l
+0.8153 0.7129 l
+0.8156 0.7157 l
+0.8159 0.7175 l
+0.8161 0.7181 l
+0.8164 0.7177 l
+0.8167 0.7162 l
+0.8170 0.7136 l
+0.8173 0.7100 l
+0.8176 0.7053 l
+0.8179 0.6997 l
+0.8181 0.6931 l
+0.8184 0.6856 l
+0.8187 0.6773 l
+0.8190 0.6682 l
+0.8193 0.6583 l
+0.8196 0.6477 l
+0.8199 0.6365 l
+0.8201 0.6248 l
+0.8204 0.6126 l
+0.8207 0.5999 l
+0.8210 0.5869 l
+0.8213 0.5737 l
+0.8216 0.5602 l
+0.8219 0.5467 l
+0.8221 0.5331 l
+0.8224 0.5196 l
+0.8227 0.5062 l
+0.8230 0.4929 l
+0.8233 0.4800 l
+0.8236 0.4674 l
+0.8239 0.4551 l
+0.8242 0.4434 l
+0.8244 0.4322 l
+0.8247 0.4216 l
+0.8250 0.4116 l
+0.8253 0.4024 l
+0.8256 0.3939 l
+0.8259 0.3862 l
+0.8262 0.3793 l
+0.8264 0.3733 l
+0.8267 0.3682 l
+0.8270 0.3640 l
+0.8273 0.3607 l
+0.8276 0.3584 l
+0.8279 0.3570 l
+0.8282 0.3566 l
+0.8284 0.3571 l
+0.8287 0.3586 l
+0.8290 0.3610 l
+0.8293 0.3643 l
+0.8296 0.3685 l
+0.8299 0.3735 l
+0.8302 0.3794 l
+0.8304 0.3860 l
+0.8307 0.3934 l
+0.8310 0.4014 l
+0.8313 0.4101 l
+0.8316 0.4194 l
+0.8319 0.4292 l
+0.8322 0.4395 l
+0.8325 0.4502 l
+0.8327 0.4612 l
+0.8330 0.4725 l
+0.8333 0.4841 l
+0.8336 0.4957 l
+0.8339 0.5075 l
+0.8342 0.5193 l
+0.8345 0.5310 l
+0.8347 0.5426 l
+0.8350 0.5541 l
+0.8353 0.5652 l
+0.8356 0.5761 l
+0.8359 0.5866 l
+0.8362 0.5967 l
+0.8365 0.6064 l
+0.8367 0.6155 l
+0.8370 0.6240 l
+0.8373 0.6319 l
+0.8376 0.6391 l
+0.8379 0.6457 l
+0.8382 0.6515 l
+0.8385 0.6566 l
+0.8387 0.6609 l
+0.8390 0.6644 l
+0.8393 0.6671 l
+0.8396 0.6690 l
+0.8399 0.6700 l
+0.8402 0.6702 l
+0.8405 0.6697 l
+0.8408 0.6683 l
+0.8410 0.6661 l
+0.8413 0.6631 l
+0.8416 0.6594 l
+0.8419 0.6549 l
+0.8422 0.6498 l
+0.8425 0.6440 l
+0.8428 0.6375 l
+0.8430 0.6305 l
+0.8433 0.6229 l
+0.8436 0.6149 l
+0.8439 0.6064 l
+0.8442 0.5975 l
+0.8445 0.5882 l
+0.8448 0.5787 l
+0.8450 0.5690 l
+0.8453 0.5590 l
+0.8456 0.5490 l
+0.8459 0.5389 l
+0.8462 0.5288 l
+0.8465 0.5187 l
+0.8468 0.5088 l
+0.8470 0.4990 l
+0.8473 0.4895 l
+0.8476 0.4802 l
+0.8479 0.4712 l
+0.8482 0.4626 l
+0.8485 0.4545 l
+0.8488 0.4467 l
+0.8491 0.4395 l
+0.8493 0.4329 l
+0.8496 0.4267 l
+0.8499 0.4212 l
+0.8502 0.4164 l
+0.8505 0.4121 l
+0.8508 0.4086 l
+0.8511 0.4057 l
+0.8513 0.4035 l
+0.8516 0.4020 l
+0.8519 0.4012 l
+0.8522 0.4011 l
+0.8525 0.4017 l
+0.8528 0.4030 l
+0.8531 0.4050 l
+0.8533 0.4076 l
+0.8536 0.4109 l
+0.8539 0.4148 l
+0.8542 0.4193 l
+0.8545 0.4243 l
+0.8548 0.4299 l
+0.8551 0.4359 l
+0.8553 0.4424 l
+0.8556 0.4494 l
+0.8559 0.4566 l
+0.8562 0.4643 l
+0.8565 0.4722 l
+0.8568 0.4803 l
+0.8571 0.4886 l
+0.8574 0.4971 l
+0.8576 0.5056 l
+0.8579 0.5142 l
+0.8582 0.5228 l
+0.8585 0.5313 l
+0.8588 0.5397 l
+0.8591 0.5480 l
+0.8594 0.5560 l
+0.8596 0.5638 l
+0.8599 0.5714 l
+0.8602 0.5786 l
+0.8605 0.5855 l
+0.8608 0.5919 l
+0.8611 0.5980 l
+0.8614 0.6036 l
+0.8616 0.6086 l
+0.8619 0.6132 l
+0.8622 0.6173 l
+0.8625 0.6208 l
+0.8628 0.6237 l
+0.8631 0.6260 l
+0.8634 0.6278 l
+0.8637 0.6289 l
+0.8639 0.6295 l
+0.8642 0.6295 l
+0.8645 0.6289 l
+0.8648 0.6277 l
+0.8651 0.6259 l
+0.8654 0.6236 l
+0.8657 0.6208 l
+0.8659 0.6174 l
+0.8662 0.6136 l
+0.8665 0.6093 l
+0.8668 0.6045 l
+0.8671 0.5994 l
+0.8674 0.5938 l
+0.8677 0.5880 l
+0.8679 0.5818 l
+0.8682 0.5753 l
+0.8685 0.5687 l
+0.8688 0.5618 l
+0.8691 0.5548 l
+0.8694 0.5477 l
+0.8697 0.5405 l
+0.8699 0.5333 l
+0.8702 0.5261 l
+0.8705 0.5189 l
+0.8708 0.5119 l
+0.8711 0.5050 l
+0.8714 0.4983 l
+0.8717 0.4917 l
+0.8720 0.4854 l
+0.8722 0.4794 l
+0.8725 0.4737 l
+0.8728 0.4684 l
+0.8731 0.4634 l
+0.8734 0.4588 l
+0.8737 0.4546 l
+0.8740 0.4508 l
+0.8742 0.4475 l
+0.8745 0.4447 l
+0.8748 0.4423 l
+0.8751 0.4404 l
+0.8754 0.4390 l
+0.8757 0.4381 l
+0.8760 0.4377 l
+0.8762 0.4378 l
+0.8765 0.4384 l
+0.8768 0.4395 l
+0.8771 0.4410 l
+0.8774 0.4430 l
+0.8777 0.4455 l
+0.8780 0.4483 l
+0.8782 0.4516 l
+0.8785 0.4552 l
+0.8788 0.4593 l
+0.8791 0.4636 l
+0.8794 0.4683 l
+0.8797 0.4732 l
+0.8800 0.4784 l
+0.8803 0.4838 l
+0.8805 0.4893 l
+0.8808 0.4951 l
+0.8811 0.5009 l
+0.8814 0.5068 l
+0.8817 0.5128 l
+0.8820 0.5188 l
+0.8823 0.5248 l
+0.8825 0.5307 l
+0.8828 0.5365 l
+0.8831 0.5422 l
+0.8834 0.5478 l
+0.8837 0.5532 l
+0.8840 0.5583 l
+0.8843 0.5633 l
+0.8845 0.5680 l
+0.8848 0.5724 l
+0.8851 0.5764 l
+0.8854 0.5802 l
+0.8857 0.5836 l
+0.8860 0.5867 l
+0.8863 0.5894 l
+0.8865 0.5916 l
+0.8868 0.5935 l
+0.8871 0.5950 l
+0.8874 0.5961 l
+0.8877 0.5968 l
+0.8880 0.5971 l
+0.8883 0.5969 l
+0.8886 0.5964 l
+0.8888 0.5954 l
+0.8891 0.5941 l
+0.8894 0.5924 l
+0.8897 0.5903 l
+0.8900 0.5879 l
+0.8903 0.5852 l
+0.8906 0.5821 l
+0.8908 0.5787 l
+0.8911 0.5751 l
+0.8914 0.5712 l
+0.8917 0.5672 l
+0.8920 0.5629 l
+0.8923 0.5584 l
+0.8926 0.5538 l
+0.8928 0.5491 l
+0.8931 0.5442 l
+0.8934 0.5394 l
+0.8937 0.5345 l
+0.8940 0.5295 l
+0.8943 0.5246 l
+0.8946 0.5198 l
+0.8948 0.5150 l
+0.8951 0.5104 l
+0.8954 0.5058 l
+0.8957 0.5014 l
+0.8960 0.4972 l
+0.8963 0.4932 l
+0.8966 0.4894 l
+0.8969 0.4858 l
+0.8971 0.4825 l
+0.8974 0.4795 l
+0.8977 0.4767 l
+0.8980 0.4743 l
+0.8983 0.4721 l
+0.8986 0.4703 l
+0.8989 0.4688 l
+0.8991 0.4677 l
+0.8994 0.4668 l
+0.8997 0.4663 l
+0.9000 0.4662 l
+0.9003 0.4663 l
+0.9006 0.4668 l
+0.9009 0.4676 l
+0.9011 0.4688 l
+0.9014 0.4702 l
+0.9017 0.4720 l
+0.9020 0.4740 l
+0.9023 0.4762 l
+0.9026 0.4788 l
+0.9029 0.4816 l
+0.9031 0.4845 l
+0.9034 0.4877 l
+0.9037 0.4911 l
+0.9040 0.4946 l
+0.9043 0.4982 l
+0.9046 0.5020 l
+0.9049 0.5059 l
+0.9052 0.5098 l
+0.9054 0.5138 l
+0.9057 0.5178 l
+0.9060 0.5218 l
+0.9063 0.5257 l
+0.9066 0.5297 l
+0.9069 0.5335 l
+0.9072 0.5373 l
+0.9074 0.5410 l
+0.9077 0.5445 l
+0.9080 0.5479 l
+0.9083 0.5511 l
+0.9086 0.5542 l
+0.9089 0.5570 l
+0.9092 0.5597 l
+0.9094 0.5621 l
+0.9097 0.5643 l
+0.9100 0.5662 l
+0.9103 0.5679 l
+0.9106 0.5694 l
+0.9109 0.5705 l
+0.9112 0.5714 l
+0.9115 0.5721 l
+0.9117 0.5724 l
+0.9120 0.5725 l
+0.9123 0.5723 l
+0.9126 0.5719 l
+0.9129 0.5712 l
+0.9132 0.5702 l
+0.9135 0.5690 l
+0.9137 0.5676 l
+0.9140 0.5659 l
+0.9143 0.5641 l
+0.9146 0.5620 l
+0.9149 0.5597 l
+0.9152 0.5573 l
+0.9155 0.5547 l
+0.9157 0.5520 l
+0.9160 0.5491 l
+0.9163 0.5462 l
+0.9166 0.5431 l
+0.9169 0.5400 l
+0.9172 0.5369 l
+0.9175 0.5337 l
+0.9177 0.5305 l
+0.9180 0.5272 l
+0.9183 0.5241 l
+0.9186 0.5209 l
+0.9189 0.5178 l
+0.9192 0.5148 l
+0.9195 0.5119 l
+0.9198 0.5090 l
+0.9200 0.5063 l
+0.9203 0.5038 l
+0.9206 0.5013 l
+0.9209 0.4991 l
+0.9212 0.4970 l
+0.9215 0.4951 l
+0.9218 0.4934 l
+0.9220 0.4918 l
+0.9223 0.4905 l
+0.9226 0.4894 l
+0.9229 0.4885 l
+0.9232 0.4878 l
+0.9235 0.4873 l
+0.9238 0.4871 l
+0.9240 0.4870 l
+0.9243 0.4872 l
+0.9246 0.4876 l
+0.9249 0.4882 l
+0.9252 0.4890 l
+0.9255 0.4900 l
+0.9258 0.4912 l
+0.9260 0.4925 l
+0.9263 0.4940 l
+0.9266 0.4957 l
+0.9269 0.4975 l
+0.9272 0.4995 l
+0.9275 0.5016 l
+0.9278 0.5038 l
+0.9281 0.5060 l
+0.9283 0.5084 l
+0.9286 0.5108 l
+0.9289 0.5133 l
+0.9292 0.5159 l
+0.9295 0.5184 l
+0.9298 0.5210 l
+0.9301 0.5235 l
+0.9303 0.5260 l
+0.9306 0.5285 l
+0.9309 0.5310 l
+0.9312 0.5334 l
+0.9315 0.5357 l
+0.9318 0.5379 l
+0.9321 0.5400 l
+0.9323 0.5421 l
+0.9326 0.5440 l
+0.9329 0.5457 l
+0.9332 0.5474 l
+0.9335 0.5489 l
+0.9338 0.5502 l
+0.9341 0.5514 l
+0.9343 0.5524 l
+0.9346 0.5533 l
+0.9349 0.5539 l
+0.9352 0.5545 l
+0.9355 0.5548 l
+0.9358 0.5550 l
+0.9361 0.5550 l
+0.9364 0.5548 l
+0.9366 0.5545 l
+0.9369 0.5540 l
+0.9372 0.5533 l
+0.9375 0.5525 l
+0.9378 0.5516 l
+0.9381 0.5505 l
+0.9384 0.5493 l
+0.9386 0.5479 l
+0.9389 0.5465 l
+0.9392 0.5449 l
+0.9395 0.5433 l
+0.9398 0.5415 l
+0.9401 0.5397 l
+0.9404 0.5378 l
+0.9406 0.5359 l
+0.9409 0.5340 l
+0.9412 0.5320 l
+0.9415 0.5300 l
+0.9418 0.5280 l
+0.9421 0.5260 l
+0.9424 0.5240 l
+0.9426 0.5220 l
+0.9429 0.5201 l
+0.9432 0.5182 l
+0.9435 0.5164 l
+0.9438 0.5147 l
+0.9441 0.5130 l
+0.9444 0.5115 l
+0.9447 0.5100 l
+0.9449 0.5086 l
+0.9452 0.5073 l
+0.9455 0.5062 l
+0.9458 0.5052 l
+0.9461 0.5043 l
+0.9464 0.5035 l
+0.9467 0.5028 l
+0.9469 0.5023 l
+0.9472 0.5019 l
+0.9475 0.5017 l
+0.9478 0.5016 l
+0.9481 0.5016 l
+0.9484 0.5017 l
+0.9487 0.5020 l
+0.9489 0.5024 l
+0.9492 0.5029 l
+0.9495 0.5036 l
+0.9498 0.5044 l
+0.9501 0.5052 l
+0.9504 0.5062 l
+0.9507 0.5072 l
+0.9509 0.5084 l
+0.9512 0.5096 l
+0.9515 0.5109 l
+0.9518 0.5123 l
+0.9521 0.5137 l
+0.9524 0.5152 l
+0.9527 0.5167 l
+0.9530 0.5182 l
+0.9532 0.5198 l
+0.9535 0.5213 l
+0.9538 0.5229 l
+0.9541 0.5244 l
+0.9544 0.5260 l
+0.9547 0.5275 l
+0.9550 0.5290 l
+0.9552 0.5304 l
+0.9555 0.5318 l
+0.9558 0.5331 l
+0.9561 0.5344 l
+0.9564 0.5356 l
+0.9567 0.5368 l
+0.9570 0.5378 l
+0.9572 0.5388 l
+0.9575 0.5397 l
+0.9578 0.5404 l
+0.9581 0.5411 l
+0.9584 0.5417 l
+0.9587 0.5422 l
+0.9590 0.5426 l
+0.9592 0.5429 l
+0.9595 0.5431 l
+0.9598 0.5431 l
+0.9601 0.5431 l
+0.9604 0.5430 l
+0.9607 0.5427 l
+0.9610 0.5424 l
+0.9613 0.5420 l
+0.9615 0.5415 l
+0.9618 0.5409 l
+0.9621 0.5402 l
+0.9624 0.5394 l
+0.9627 0.5386 l
+0.9630 0.5377 l
+0.9633 0.5367 l
+0.9635 0.5357 l
+0.9638 0.5347 l
+0.9641 0.5336 l
+0.9644 0.5324 l
+0.9647 0.5313 l
+0.9650 0.5301 l
+0.9653 0.5289 l
+0.9655 0.5277 l
+0.9658 0.5265 l
+0.9661 0.5253 l
+0.9664 0.5241 l
+0.9667 0.5230 l
+0.9670 0.5218 l
+0.9673 0.5207 l
+0.9676 0.5197 l
+0.9678 0.5186 l
+0.9681 0.5177 l
+0.9684 0.5167 l
+0.9687 0.5159 l
+0.9690 0.5151 l
+0.9693 0.5144 l
+0.9696 0.5137 l
+0.9698 0.5131 l
+0.9701 0.5126 l
+0.9704 0.5121 l
+0.9707 0.5118 l
+0.9710 0.5115 l
+0.9713 0.5113 l
+0.9716 0.5112 l
+0.9718 0.5111 l
+0.9721 0.5112 l
+0.9724 0.5113 l
+0.9727 0.5115 l
+0.9730 0.5117 l
+0.9733 0.5121 l
+0.9736 0.5125 l
+0.9738 0.5129 l
+0.9741 0.5135 l
+0.9744 0.5141 l
+0.9747 0.5147 l
+0.9750 0.5154 l
+0.9753 0.5161 l
+0.9756 0.5169 l
+0.9759 0.5177 l
+0.9761 0.5186 l
+0.9764 0.5194 l
+0.9767 0.5203 l
+0.9770 0.5212 l
+0.9773 0.5221 l
+0.9776 0.5230 l
+0.9779 0.5240 l
+0.9781 0.5249 l
+0.9784 0.5258 l
+0.9787 0.5266 l
+0.9790 0.5275 l
+0.9793 0.5283 l
+0.9796 0.5291 l
+0.9799 0.5299 l
+0.9801 0.5306 l
+0.9804 0.5313 l
+0.9807 0.5320 l
+0.9810 0.5326 l
+0.9813 0.5331 l
+0.9816 0.5336 l
+0.9819 0.5341 l
+0.9821 0.5344 l
+0.9824 0.5348 l
+0.9827 0.5350 l
+0.9830 0.5352 l
+0.9833 0.5354 l
+0.9836 0.5355 l
+0.9839 0.5355 l
+0.9842 0.5354 l
+0.9844 0.5353 l
+0.9847 0.5352 l
+0.9850 0.5350 l
+0.9853 0.5347 l
+0.9856 0.5344 l
+0.9859 0.5341 l
+0.9862 0.5336 l
+0.9864 0.5332 l
+0.9867 0.5327 l
+0.9870 0.5322 l
+0.9873 0.5316 l
+0.9876 0.5310 l
+0.9879 0.5304 l
+0.9882 0.5298 l
+0.9884 0.5291 l
+0.9887 0.5284 l
+0.9890 0.5278 l
+0.9893 0.5271 l
+0.9896 0.5264 l
+0.9899 0.5257 l
+0.9902 0.5250 l
+0.9904 0.5243 l
+0.9907 0.5237 l
+0.9910 0.5230 l
+0.9913 0.5224 l
+0.9916 0.5218 l
+0.9919 0.5212 l
+0.9922 0.5207 l
+0.9925 0.5202 l
+0.9927 0.5197 l
+0.9930 0.5193 l
+0.9933 0.5189 l
+0.9936 0.5185 l
+0.9939 0.5182 l
+0.9942 0.5179 l
+0.9945 0.5177 l
+0.9947 0.5175 l
+0.9950 0.5173 l
+0.9953 0.5172 l
+0.9956 0.5172 l
+0.9959 0.5172 l
+0.9962 0.5172 l
+0.9965 0.5173 l
+0.9967 0.5174 l
+0.9970 0.5176 l
+0.9973 0.5178 l
+0.9976 0.5180 l
+0.9979 0.5183 l
+0.9982 0.5186 l
+0.9985 0.5189 l
+0.9987 0.5193 l
+0.9990 0.5197 l
+0.9993 0.5201 l
+0.9996 0.5206 l
+0.9999 0.5210 l
+1.0002 0.5215 l
+1.0005 0.5220 l
+1.0008 0.5225 l
+1.0010 0.5230 l
+1.0013 0.5235 l
+1.0016 0.5240 l
+1.0019 0.5245 l
+1.0022 0.5250 l
+1.0025 0.5255 l
+1.0028 0.5260 l
+1.0030 0.5265 l
+1.0033 0.5270 l
+1.0036 0.5274 l
+1.0039 0.5278 l
+1.0042 0.5282 l
+1.0045 0.5286 l
+1.0048 0.5290 l
+1.0050 0.5293 l
+1.0053 0.5296 l
+1.0056 0.5298 l
+1.0059 0.5301 l
+1.0062 0.5303 l
+1.0065 0.5305 l
+1.0068 0.5306 l
+1.0070 0.5307 l
+1.0073 0.5308 l
+1.0076 0.5308 l
+1.0079 0.5308 l
+1.0082 0.5308 l
+1.0085 0.5307 l
+1.0088 0.5306 l
+1.0091 0.5305 l
+1.0093 0.5303 l
+1.0096 0.5302 l
+1.0099 0.5299 l
+1.0102 0.5297 l
+1.0105 0.5295 l
+1.0108 0.5292 l
+1.0111 0.5289 l
+1.0113 0.5286 l
+1.0116 0.5282 l
+1.0119 0.5279 l
+1.0122 0.5275 l
+1.0125 0.5272 l
+1.0128 0.5268 l
+1.0131 0.5264 l
+1.0133 0.5261 l
+1.0136 0.5257 l
+1.0139 0.5253 l
+1.0142 0.5249 l
+1.0145 0.5246 l
+1.0148 0.5242 l
+1.0151 0.5239 l
+1.0153 0.5235 l
+1.0156 0.5232 l
+1.0159 0.5229 l
+1.0162 0.5226 l
+1.0165 0.5223 l
+1.0168 0.5221 l
+1.0171 0.5218 l
+1.0174 0.5216 l
+1.0176 0.5214 l
+1.0179 0.5213 l
+1.0182 0.5211 l
+1.0185 0.5210 l
+1.0188 0.5209 l
+1.0191 0.5208 l
+1.0194 0.5208 l
+1.0196 0.5208 l
+1.0199 0.5208 l
+1.0202 0.5208 l
+1.0205 0.5208 l
+1.0208 0.5209 l
+1.0211 0.5210 l
+1.0214 0.5211 l
+1.0216 0.5213 l
+1.0219 0.5214 l
+1.0222 0.5216 l
+1.0225 0.5218 l
+1.0228 0.5220 l
+1.0231 0.5222 l
+1.0234 0.5224 l
+1.0237 0.5227 l
+1.0239 0.5229 l
+1.0242 0.5232 l
+1.0245 0.5234 l
+1.0248 0.5237 l
+1.0251 0.5240 l
+1.0254 0.5243 l
+1.0257 0.5245 l
+1.0259 0.5248 l
+1.0262 0.5251 l
+1.0265 0.5253 l
+1.0268 0.5256 l
+1.0271 0.5259 l
+1.0274 0.5261 l
+1.0277 0.5263 l
+1.0279 0.5266 l
+1.0282 0.5268 l
+1.0285 0.5270 l
+1.0288 0.5272 l
+1.0291 0.5273 l
+1.0294 0.5275 l
+1.0297 0.5276 l
+1.0299 0.5277 l
+1.0302 0.5278 l
+1.0305 0.5279 l
+1.0308 0.5280 l
+1.0311 0.5280 l
+1.0314 0.5281 l
+1.0317 0.5281 l
+1.0320 0.5281 l
+1.0322 0.5280 l
+1.0325 0.5280 l
+1.0328 0.5280 l
+1.0331 0.5279 l
+1.0334 0.5278 l
+1.0337 0.5277 l
+1.0340 0.5276 l
+1.0342 0.5275 l
+1.0345 0.5273 l
+1.0348 0.5272 l
+1.0351 0.5270 l
+1.0354 0.5268 l
+1.0357 0.5267 l
+1.0360 0.5265 l
+1.0362 0.5263 l
+1.0365 0.5261 l
+1.0368 0.5259 l
+1.0371 0.5257 l
+1.0374 0.5255 l
+1.0377 0.5253 l
+1.0380 0.5251 l
+1.0382 0.5249 l
+1.0385 0.5247 l
+1.0388 0.5245 l
+1.0391 0.5244 l
+1.0394 0.5242 l
+1.0397 0.5240 l
+1.0400 0.5239 l
+1.0403 0.5237 l
+1.0405 0.5236 l
+1.0408 0.5234 l
+1.0411 0.5233 l
+1.0414 0.5232 l
+1.0417 0.5231 l
+1.0420 0.5230 l
+1.0423 0.5230 l
+1.0425 0.5229 l
+1.0428 0.5229 l
+1.0431 0.5228 l
+1.0434 0.5228 l
+1.0437 0.5228 l
+1.0440 0.5228 l
+1.0443 0.5228 l
+1.0445 0.5229 l
+1.0448 0.5229 l
+1.0451 0.5229 l
+1.0454 0.5230 l
+1.0457 0.5231 l
+1.0460 0.5232 l
+1.0463 0.5233 l
+1.0465 0.5234 l
+1.0468 0.5235 l
+1.0471 0.5236 l
+1.0474 0.5237 l
+1.0477 0.5238 l
+1.0480 0.5240 l
+1.0483 0.5241 l
+1.0486 0.5242 l
+1.0488 0.5244 l
+1.0491 0.5245 l
+1.0494 0.5247 l
+1.0497 0.5248 l
+1.0500 0.5249 l
+1.0503 0.5251 l
+1.0506 0.5252 l
+1.0508 0.5253 l
+1.0511 0.5255 l
+1.0514 0.5256 l
+1.0517 0.5257 l
+1.0520 0.5258 l
+1.0523 0.5259 l
+1.0526 0.5260 l
+1.0528 0.5261 l
+1.0531 0.5262 l
+1.0534 0.5263 l
+1.0537 0.5263 l
+1.0540 0.5264 l
+1.0543 0.5264 l
+1.0546 0.5265 l
+1.0548 0.5265 l
+1.0551 0.5265 l
+1.0554 0.5266 l
+1.0557 0.5266 l
+1.0560 0.5266 l
+1.0563 0.5265 l
+1.0566 0.5265 l
+1.0569 0.5265 l
+1.0571 0.5264 l
+1.0574 0.5264 l
+1.0577 0.5263 l
+1.0580 0.5263 l
+1.0583 0.5262 l
+1.0586 0.5262 l
+1.0589 0.5261 l
+1.0591 0.5260 l
+1.0594 0.5259 l
+1.0597 0.5258 l
+1.0600 0.5257 l
+1.0603 0.5256 l
+1.0606 0.5255 l
+1.0609 0.5254 l
+1.0611 0.5253 l
+1.0614 0.5252 l
+1.0617 0.5251 l
+1.0620 0.5250 l
+1.0623 0.5249 l
+1.0626 0.5248 l
+1.0629 0.5248 l
+1.0631 0.5247 l
+1.0634 0.5246 l
+1.0637 0.5245 l
+1.0640 0.5244 l
+1.0643 0.5243 l
+1.0646 0.5243 l
+1.0649 0.5242 l
+1.0652 0.5242 l
+1.0654 0.5241 l
+1.0657 0.5241 l
+1.0660 0.5240 l
+1.0663 0.5240 l
+1.0666 0.5240 l
+1.0669 0.5239 l
+1.0672 0.5239 l
+1.0674 0.5239 l
+1.0677 0.5239 l
+1.0680 0.5239 l
+1.0683 0.5239 l
+1.0686 0.5239 l
+1.0689 0.5240 l
+1.0692 0.5240 l
+1.0694 0.5240 l
+1.0697 0.5241 l
+1.0700 0.5241 l
+1.0703 0.5242 l
+1.0706 0.5242 l
+1.0709 0.5243 l
+1.0712 0.5243 l
+1.0715 0.5244 l
+1.0717 0.5244 l
+1.0720 0.5245 l
+1.0723 0.5246 l
+1.0726 0.5246 l
+1.0729 0.5247 l
+1.0732 0.5248 l
+1.0735 0.5248 l
+1.0737 0.5249 l
+1.0740 0.5250 l
+1.0743 0.5251 l
+1.0746 0.5251 l
+1.0749 0.5252 l
+1.0752 0.5252 l
+1.0755 0.5253 l
+1.0757 0.5254 l
+1.0760 0.5254 l
+1.0763 0.5255 l
+1.0766 0.5255 l
+1.0769 0.5256 l
+1.0772 0.5256 l
+1.0775 0.5256 l
+1.0777 0.5257 l
+1.0780 0.5257 l
+1.0783 0.5257 l
+1.0786 0.5257 l
+1.0789 0.5257 l
+1.0792 0.5258 l
+1.0795 0.5258 l
+1.0798 0.5258 l
+1.0800 0.5258 l
+1.0803 0.5257 l
+1.0806 0.5257 l
+1.0809 0.5257 l
+1.0812 0.5257 l
+1.0815 0.5257 l
+1.0818 0.5256 l
+1.0820 0.5256 l
+1.0823 0.5256 l
+1.0826 0.5255 l
+1.0829 0.5255 l
+1.0832 0.5255 l
+1.0835 0.5254 l
+1.0838 0.5254 l
+1.0840 0.5253 l
+1.0843 0.5253 l
+1.0846 0.5252 l
+1.0849 0.5252 l
+1.0852 0.5251 l
+1.0855 0.5251 l
+1.0858 0.5251 l
+1.0860 0.5250 l
+1.0863 0.5250 l
+1.0866 0.5249 l
+1.0869 0.5249 l
+1.0872 0.5248 l
+1.0875 0.5248 l
+1.0878 0.5247 l
+1.0881 0.5247 l
+1.0883 0.5247 l
+1.0886 0.5246 l
+1.0889 0.5246 l
+1.0892 0.5246 l
+1.0895 0.5246 l
+1.0898 0.5245 l
+1.0901 0.5245 l
+1.0903 0.5245 l
+1.0906 0.5245 l
+1.0909 0.5245 l
+1.0912 0.5245 l
+1.0915 0.5245 l
+1.0918 0.5245 l
+1.0921 0.5245 l
+1.0923 0.5245 l
+1.0926 0.5245 l
+1.0929 0.5245 l
+1.0932 0.5245 l
+1.0935 0.5245 l
+1.0938 0.5246 l
+1.0941 0.5246 l
+1.0943 0.5246 l
+1.0946 0.5246 l
+1.0949 0.5247 l
+1.0952 0.5247 l
+1.0955 0.5247 l
+1.0958 0.5247 l
+1.0961 0.5248 l
+1.0964 0.5248 l
+1.0966 0.5248 l
+1.0969 0.5249 l
+1.0972 0.5249 l
+1.0975 0.5249 l
+1.0978 0.5250 l
+1.0981 0.5250 l
+1.0984 0.5250 l
+1.0986 0.5251 l
+1.0989 0.5251 l
+1.0992 0.5251 l
+1.0995 0.5251 l
+1.0998 0.5252 l
+1.1001 0.5252 l
+1.1004 0.5252 l
+1.1006 0.5252 l
+1.1009 0.5253 l
+1.1012 0.5253 l
+1.1015 0.5253 l
+1.1018 0.5253 l
+1.1021 0.5253 l
+1.1024 0.5253 l
+1.1026 0.5253 l
+1.1029 0.5253 l
+1.1032 0.5253 l
+1.1035 0.5254 l
+1.1038 0.5254 l
+1.1041 0.5253 l
+1.1044 0.5253 l
+1.1047 0.5253 l
+1.1049 0.5253 l
+1.1052 0.5253 l
+1.1055 0.5253 l
+1.1058 0.5253 l
+1.1061 0.5253 l
+1.1064 0.5253 l
+1.1067 0.5252 l
+1.1069 0.5252 l
+1.1072 0.5252 l
+1.1075 0.5252 l
+1.1078 0.5252 l
+1.1081 0.5252 l
+1.1084 0.5251 l
+1.1087 0.5251 l
+1.1089 0.5251 l
+1.1092 0.5251 l
+1.1095 0.5250 l
+1.1098 0.5250 l
+1.1101 0.5250 l
+1.1104 0.5250 l
+1.1107 0.5250 l
+1.1109 0.5249 l
+1.1112 0.5249 l
+1.1115 0.5249 l
+1.1118 0.5249 l
+1.1121 0.5249 l
+1.1124 0.5248 l
+1.1127 0.5248 l
+1.1130 0.5248 l
+1.1132 0.5248 l
+1.1135 0.5248 l
+1.1138 0.5248 l
+1.1141 0.5248 l
+1.1144 0.5248 l
+1.1147 0.5248 l
+1.1150 0.5248 l
+1.1152 0.5248 l
+1.1155 0.5248 l
+1.1158 0.5248 l
+1.1161 0.5248 l
+1.1164 0.5248 l
+1.1167 0.5248 l
+1.1170 0.5248 l
+1.1172 0.5248 l
+1.1175 0.5248 l
+1.1178 0.5248 l
+1.1181 0.5248 l
+1.1184 0.5248 l
+1.1187 0.5248 l
+1.1190 0.5248 l
+1.1192 0.5249 l
+1.1195 0.5249 l
+1.1198 0.5249 l
+1.1201 0.5249 l
+1.1204 0.5249 l
+1.1207 0.5249 l
+1.1210 0.5249 l
+1.1213 0.5250 l
+1.1215 0.5250 l
+1.1218 0.5250 l
+1.1221 0.5250 l
+1.1224 0.5250 l
+1.1227 0.5250 l
+1.1230 0.5250 l
+1.1233 0.5251 l
+1.1235 0.5251 l
+1.1238 0.5251 l
+1.1241 0.5251 l
+1.1244 0.5251 l
+1.1247 0.5251 l
+1.1250 0.5251 l
+1.1253 0.5251 l
+1.1255 0.5251 l
+1.1258 0.5251 l
+1.1261 0.5251 l
+1.1264 0.5251 l
+1.1267 0.5252 l
+1.1270 0.5252 l
+1.1273 0.5252 l
+1.1276 0.5252 l
+1.1278 0.5252 l
+1.1281 0.5252 l
+1.1284 0.5252 l
+1.1287 0.5251 l
+1.1290 0.5251 l
+1.1293 0.5251 l
+1.1296 0.5251 l
+1.1298 0.5251 l
+1.1301 0.5251 l
+1.1304 0.5251 l
+1.1307 0.5251 l
+1.1310 0.5251 l
+1.1313 0.5251 l
+1.1316 0.5251 l
+1.1318 0.5251 l
+1.1321 0.5251 l
+1.1324 0.5251 l
+1.1327 0.5250 l
+1.1330 0.5250 l
+1.1333 0.5250 l
+1.1336 0.5250 l
+1.1338 0.5250 l
+1.1341 0.5250 l
+1.1344 0.5250 l
+1.1347 0.5250 l
+1.1350 0.5250 l
+1.1353 0.5250 l
+1.1356 0.5250 l
+1.1359 0.5249 l
+1.1361 0.5249 l
+1.1364 0.5249 l
+1.1367 0.5249 l
+1.1370 0.5249 l
+1.1373 0.5249 l
+1.1376 0.5249 l
+1.1379 0.5249 l
+1.1381 0.5249 l
+1.1384 0.5249 l
+1.1387 0.5249 l
+1.1390 0.5249 l
+1.1393 0.5249 l
+1.1396 0.5249 l
+1.1399 0.5249 l
+1.1401 0.5249 l
+1.1404 0.5249 l
+1.1407 0.5249 l
+1.1410 0.5249 l
+1.1413 0.5249 l
+1.1416 0.5249 l
+1.1419 0.5249 l
+1.1421 0.5249 l
+1.1424 0.5249 l
+1.1427 0.5249 l
+1.1430 0.5249 l
+1.1433 0.5249 l
+1.1436 0.5249 l
+1.1439 0.5250 l
+1.1442 0.5250 l
+1.1444 0.5250 l
+1.1447 0.5250 l
+1.1450 0.5250 l
+1.1453 0.5250 l
+1.1456 0.5250 l
+1.1459 0.5250 l
+1.1462 0.5250 l
+1.1464 0.5250 l
+1.1467 0.5250 l
+1.1470 0.5250 l
+1.1473 0.5250 l
+1.1476 0.5250 l
+1.1479 0.5250 l
+1.1482 0.5250 l
+1.1484 0.5250 l
+1.1487 0.5250 l
+1.1490 0.5251 l
+1.1493 0.5251 l
+1.1496 0.5251 l
+1.1499 0.5251 l
+1.1502 0.5251 l
+1.1504 0.5251 l
+1.1507 0.5251 l
+1.1510 0.5251 l
+1.1513 0.5251 l
+1.1516 0.5251 l
+1.1519 0.5251 l
+1.1522 0.5251 l
+1.1525 0.5251 l
+1.1527 0.5251 l
+1.1530 0.5251 l
+1.1533 0.5251 l
+1.1536 0.5251 l
+1.1539 0.5251 l
+1.1542 0.5251 l
+1.1545 0.5250 l
+1.1547 0.5250 l
+1.1550 0.5250 l
+1.1553 0.5250 l
+1.1556 0.5250 l
+1.1559 0.5250 l
+1.1562 0.5250 l
+1.1565 0.5250 l
+1.1567 0.5250 l
+1.1570 0.5250 l
+1.1573 0.5250 l
+1.1576 0.5250 l
+1.1579 0.5250 l
+1.1582 0.5250 l
+1.1585 0.5250 l
+1.1587 0.5250 l
+1.1590 0.5250 l
+1.1593 0.5250 l
+1.1596 0.5250 l
+1.1599 0.5250 l
+1.1602 0.5250 l
+1.1605 0.5250 l
+1.1608 0.5250 l
+1.1610 0.5250 l
+1.1613 0.5250 l
+1.1616 0.5250 l
+1.1619 0.5250 l
+1.1622 0.5250 l
+1.1625 0.5250 l
+1.1628 0.5250 l
+1.1630 0.5250 l
+1.1633 0.5250 l
+1.1636 0.5250 l
+1.1639 0.5250 l
+1.1642 0.5250 l
+1.1645 0.5250 l
+1.1648 0.5250 l
+1.1650 0.5250 l
+1.1653 0.5250 l
+1.1656 0.5250 l
+1.1659 0.5250 l
+1.1662 0.5250 l
+1.1665 0.5250 l
+1.1668 0.5250 l
+1.1670 0.5250 l
+1.1673 0.5250 l
+1.1676 0.5250 l
+1.1679 0.5250 l
+1.1682 0.5250 l
+1.1685 0.5250 l
+1.1688 0.5250 l
+1.1691 0.5250 l
+1.1693 0.5250 l
+1.1696 0.5250 l
+1.1699 0.5250 l
+1.1702 0.5250 l
+1.1705 0.5250 l
+1.1708 0.5250 l
+1.1711 0.5250 l
+1.1713 0.5250 l
+1.1716 0.5250 l
+1.1719 0.5250 l
+1.1722 0.5250 l
+1.1725 0.5250 l
+1.1728 0.5250 l
+1.1731 0.5250 l
+1.1733 0.5250 l
+1.1736 0.5250 l
+1.1739 0.5250 l
+1.1742 0.5250 l
+1.1745 0.5250 l
+1.1748 0.5250 l
+1.1751 0.5250 l
+1.1754 0.5250 l
+1.1756 0.5250 l
+1.1759 0.5250 l
+1.1762 0.5250 l
+1.1765 0.5250 l
+1.1768 0.5250 l
+1.1771 0.5250 l
+1.1774 0.5250 l
+1.1776 0.5250 l
+1.1779 0.5250 l
+1.1782 0.5250 l
+1.1785 0.5250 l
+1.1788 0.5250 l
+1.1791 0.5250 l
+1.1794 0.5250 l
+1.1796 0.5250 l
+1.1799 0.5250 l
+1.1802 0.5250 l
+1.1805 0.5250 l
+1.1808 0.5250 l
+1.1811 0.5250 l
+1.1814 0.5250 l
+1.1816 0.5250 l
+1.1819 0.5250 l
+1.1822 0.5250 l
+1.1825 0.5250 l
+1.1828 0.5250 l
+1.1831 0.5250 l
+1.1834 0.5250 l
+1.1837 0.5250 l
+1.1839 0.5250 l
+1.1842 0.5250 l
+1.1845 0.5250 l
+1.1848 0.5250 l
+1.1851 0.5250 l
+1.1854 0.5250 l
+1.1857 0.5250 l
+1.1859 0.5250 l
+1.1862 0.5250 l
+1.1865 0.5250 l
+1.1868 0.5250 l
+1.1871 0.5250 l
+1.1874 0.5250 l
+1.1877 0.5250 l
+1.1879 0.5250 l
+1.1882 0.5250 l
+1.1885 0.5250 l
+1.1888 0.5250 l
+1.1891 0.5250 l
+1.1894 0.5250 l
+1.1897 0.5250 l
+1.1899 0.5250 l
+1.1902 0.5250 l
+1.1905 0.5250 l
+1.1908 0.5250 l
+1.1911 0.5250 l
+1.1914 0.5250 l
+1.1917 0.5250 l
+1.1920 0.5250 l
+1.1922 0.5250 l
+1.1925 0.5250 l
+1.1928 0.5250 l
+1.1931 0.5250 l
+1.1934 0.5250 l
+1.1937 0.5250 l
+1.1940 0.5250 l
+1.1942 0.5250 l
+1.1945 0.5250 l
+1.1948 0.5250 l
+1.1951 0.5250 l
+1.1954 0.5250 l
+1.1957 0.5250 l
+1.1960 0.5250 l
+1.1962 0.5250 l
+1.1965 0.5250 l
+1.1968 0.5250 l
+1.1971 0.5250 l
+1.1974 0.5250 l
+1.1977 0.5250 l
+1.1980 0.5250 l
+1.1982 0.5250 l
+1.1985 0.5250 l
+1.1988 0.5250 l
+1.1991 0.5250 l
+1.1994 0.5250 l
+1.1997 0.5250 l
+1.2000 0.5250 l
+1.2003 0.5250 l
+1.2005 0.5250 l
+1.2008 0.5250 l
+1.2011 0.5250 l
+1.2014 0.5250 l
+1.2017 0.5250 l
+1.2020 0.5250 l
+1.2023 0.5250 l
+1.2025 0.5250 l
+1.2028 0.5250 l
+1.2031 0.5250 l
+1.2034 0.5250 l
+1.2037 0.5250 l
+1.2040 0.5250 l
+1.2043 0.5250 l
+1.2045 0.5250 l
+1.2048 0.5250 l
+1.2051 0.5250 l
+1.2054 0.5250 l
+1.2057 0.5250 l
+1.2060 0.5250 l
+1.2063 0.5250 l
+1.2065 0.5250 l
+1.2068 0.5250 l
+1.2071 0.5250 l
+1.2074 0.5250 l
+1.2077 0.5250 l
+1.2080 0.5250 l
+1.2083 0.5250 l
+1.2086 0.5250 l
+1.2088 0.5250 l
+1.2091 0.5250 l
+1.2094 0.5250 l
+1.2097 0.5250 l
+1.2100 0.5250 l
+1.2103 0.5250 l
+1.2106 0.5250 l
+1.2108 0.5250 l
+1.2111 0.5250 l
+1.2114 0.5250 l
+1.2117 0.5250 l
+1.2120 0.5250 l
+1.2123 0.5250 l
+1.2126 0.5250 l
+1.2128 0.5250 l
+1.2131 0.5250 l
+1.2134 0.5250 l
+1.2137 0.5250 l
+1.2140 0.5250 l
+1.2143 0.5250 l
+1.2146 0.5250 l
+1.2148 0.5250 l
+1.2151 0.5250 l
+1.2154 0.5250 l
+1.2157 0.5250 l
+1.2160 0.5250 l
+1.2163 0.5250 l
+1.2166 0.5250 l
+1.2169 0.5250 l
+1.2171 0.5250 l
+1.2174 0.5250 l
+1.2177 0.5250 l
+1.2180 0.5250 l
+1.2183 0.5250 l
+1.2186 0.5250 l
+1.2189 0.5250 l
+1.2191 0.5250 l
+1.2194 0.5250 l
+1.2197 0.5250 l
+1.2200 0.5250 l
+1.2203 0.5250 l
+1.2206 0.5250 l
+1.2209 0.5250 l
+1.2211 0.5250 l
+1.2214 0.5250 l
+1.2217 0.5250 l
+1.2220 0.5250 l
+1.2223 0.5250 l
+1.2226 0.5250 l
+1.2229 0.5250 l
+1.2231 0.5250 l
+1.2234 0.5250 l
+1.2237 0.5250 l
+1.2240 0.5250 l
+1.2243 0.5250 l
+1.2246 0.5250 l
+1.2249 0.5250 l
+1.2252 0.5250 l
+1.2254 0.5250 l
+1.2257 0.5250 l
+1.2260 0.5250 l
+1.2263 0.5250 l
+1.2266 0.5250 l
+1.2269 0.5250 l
+1.2272 0.5250 l
+1.2274 0.5250 l
+1.2277 0.5250 l
+1.2280 0.5250 l
+1.2283 0.5250 l
+1.2286 0.5250 l
+1.2289 0.5250 l
+1.2292 0.5250 l
+1.2294 0.5250 l
+1.2297 0.5250 l
+1.2300 0.5250 l
+1.2303 0.5250 l
+1.2306 0.5250 l
+1.2309 0.5250 l
+1.2312 0.5250 l
+1.2315 0.5250 l
+1.2317 0.5250 l
+1.2320 0.5250 l
+1.2323 0.5250 l
+1.2326 0.5250 l
+1.2329 0.5250 l
+1.2332 0.5250 l
+1.2335 0.5250 l
+1.2337 0.5250 l
+1.2340 0.5250 l
+1.2343 0.5250 l
+1.2346 0.5250 l
+1.2349 0.5250 l
+1.2352 0.5250 l
+1.2355 0.5250 l
+1.2357 0.5250 l
+1.2360 0.5250 l
+1.2363 0.5250 l
+1.2366 0.5250 l
+1.2369 0.5250 l
+1.2372 0.5250 l
+1.2375 0.5250 l
+1.2377 0.5250 l
+1.2380 0.5250 l
+1.2383 0.5250 l
+1.2386 0.5250 l
+1.2389 0.5250 l
+1.2392 0.5250 l
+1.2395 0.5250 l
+1.2398 0.5250 l
+1.2400 0.5250 l
+1.2403 0.5250 l
+1.2406 0.5250 l
+1.2409 0.5250 l
+1.2412 0.5250 l
+1.2415 0.5250 l
+1.2418 0.5250 l
+1.2420 0.5250 l
+1.2423 0.5250 l
+1.2426 0.5250 l
+1.2429 0.5250 l
+1.2432 0.5250 l
+1.2435 0.5250 l
+1.2438 0.5250 l
+1.2440 0.5250 l
+1.2443 0.5250 l
+1.2446 0.5250 l
+1.2449 0.5250 l
+s
+n
+0.1000 0.1000 m
+1.2449 0.1000 l
+s
+n
+0.1000 0.9500 m
+1.2449 0.9500 l
+s
+n
+0.2431 0.1000 m
+0.2431 0.1100 l
+s
+n
+0.2431 0.9500 m
+0.2431 0.9400 l
+s
+n
+0.5293 0.1000 m
+0.5293 0.1100 l
+s
+n
+0.5293 0.9500 m
+0.5293 0.9400 l
+s
+n
+0.8156 0.1000 m
+0.8156 0.1100 l
+s
+n
+0.8156 0.9500 m
+0.8156 0.9400 l
+s
+n
+1.1018 0.1000 m
+1.1018 0.1100 l
+s
+n
+1.1018 0.9500 m
+1.1018 0.9400 l
+s
+n
+0.1000 0.1000 m
+0.1000 0.1200 l
+s
+n
+0.1000 0.9500 m
+0.1000 0.9300 l
+s
+n
+0.3862 0.1000 m
+0.3862 0.1200 l
+s
+n
+0.3862 0.9500 m
+0.3862 0.9300 l
+s
+n
+0.6725 0.1000 m
+0.6725 0.1200 l
+s
+n
+0.6725 0.9500 m
+0.6725 0.9300 l
+s
+n
+0.9587 0.1000 m
+0.9587 0.1200 l
+s
+n
+0.9587 0.9500 m
+0.9587 0.9300 l
+s
+n
+1.2449 0.1000 m
+1.2449 0.1200 l
+s
+n
+1.2449 0.9500 m
+1.2449 0.9300 l
+s
+/Helvetica findfont
+dup length dict begin
+ {1 index /FID ne {def} {pop pop} ifelse} forall
+ /Encoding DefEncoding def
+ currentdict
+end
+/Font4 exch definefont pop
+/Font4 FFSF
+0.0912 0.0653 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(0) show
+GR
+/Font4 FFSF
+0.3627 0.0653 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(0.5) show
+GR
+/Font4 FFSF
+0.6664 0.0653 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(1) show
+GR
+/Font4 FFSF
+0.9351 0.0653 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(1.5) show
+GR
+/Font4 FFSF
+1.2359 0.0653 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(2) show
+GR
+/Font4 FFSF
+0.5854 0.0239 m
+GS
+[0.0420 0.0000 0.0000 0.0420 0 0] CC
+(Time \(ps\)) show
+GR
+n
+0.1000 0.1000 m
+0.1000 0.9500 l
+s
+n
+1.2449 0.1000 m
+1.2449 0.9500 l
+s
+n
+0.1000 0.2063 m
+0.1100 0.2063 l
+s
+n
+1.2449 0.2063 m
+1.2349 0.2063 l
+s
+n
+0.1000 0.4188 m
+0.1100 0.4188 l
+s
+n
+1.2449 0.4188 m
+1.2349 0.4188 l
+s
+n
+0.1000 0.6312 m
+0.1100 0.6312 l
+s
+n
+1.2449 0.6312 m
+1.2349 0.6312 l
+s
+n
+0.1000 0.8438 m
+0.1100 0.8438 l
+s
+n
+1.2449 0.8438 m
+1.2349 0.8438 l
+s
+n
+0.1000 0.1000 m
+0.1200 0.1000 l
+s
+n
+1.2449 0.1000 m
+1.2249 0.1000 l
+s
+n
+0.1000 0.3125 m
+0.1200 0.3125 l
+s
+n
+1.2449 0.3125 m
+1.2249 0.3125 l
+s
+n
+0.1000 0.5250 m
+0.1200 0.5250 l
+s
+n
+1.2449 0.5250 m
+1.2249 0.5250 l
+s
+n
+0.1000 0.7375 m
+0.1200 0.7375 l
+s
+n
+1.2449 0.7375 m
+1.2249 0.7375 l
+s
+n
+0.1000 0.9500 m
+0.1200 0.9500 l
+s
+n
+1.2449 0.9500 m
+1.2249 0.9500 l
+s
+/Font4 FFSF
+0.0602 0.0878 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(-2) show
+GR
+/Font4 FFSF
+0.0661 0.3001 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(-1) show
+GR
+/Font4 FFSF
+0.0724 0.5130 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(0) show
+GR
+/Font4 FFSF
+0.0778 0.7251 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(1) show
+GR
+/Font4 FFSF
+0.0720 0.9378 m
+GS
+[0.0350 0.0000 0.0000 0.0350 0 0] CC
+(2) show
+GR
+/Font4 FFSF
+0.0412 0.3446 m
+GS
+[0.0000 0.0420 -0.0420 0.0000 0 0] CC
+(Electric field \(V/nm\)) show
+GR
+n
+0.1000 0.1000 m
+0.1000 0.9500 l
+1.2449 0.9500 l
+1.2449 0.1000 l
+0.1000 0.1000 l
+c
+s
+%%Trailer
+%%DocumentNeededResources: font Helvetica
+%%EOF
--- /dev/null
+# Grace project file
+#
+@version 50125
+@page size 792, 612
+@page scroll 5%
+@page inout 5%
+@link page off
+@map font 0 to "Times-Roman", "Times-Roman"
+@map font 1 to "Times-Italic", "Times-Italic"
+@map font 2 to "Times-Bold", "Times-Bold"
+@map font 3 to "Times-BoldItalic", "Times-BoldItalic"
+@map font 4 to "Helvetica", "Helvetica"
+@map font 5 to "Helvetica-Oblique", "Helvetica-Oblique"
+@map font 6 to "Helvetica-Bold", "Helvetica-Bold"
+@map font 7 to "Helvetica-BoldOblique", "Helvetica-BoldOblique"
+@map font 8 to "Courier", "Courier"
+@map font 9 to "Courier-Oblique", "Courier-Oblique"
+@map font 10 to "Courier-Bold", "Courier-Bold"
+@map font 11 to "Courier-BoldOblique", "Courier-BoldOblique"
+@map font 12 to "Symbol", "Symbol"
+@map font 13 to "ZapfDingbats", "ZapfDingbats"
+@map color 0 to (255, 255, 255), "white"
+@map color 1 to (0, 0, 0), "black"
+@map color 2 to (255, 0, 0), "red"
+@map color 3 to (0, 255, 0), "green"
+@map color 4 to (0, 0, 255), "blue"
+@map color 5 to (255, 255, 0), "yellow"
+@map color 6 to (188, 143, 143), "brown"
+@map color 7 to (220, 220, 220), "grey"
+@map color 8 to (148, 0, 211), "violet"
+@map color 9 to (0, 255, 255), "cyan"
+@map color 10 to (255, 0, 255), "magenta"
+@map color 11 to (255, 165, 0), "orange"
+@map color 12 to (114, 33, 188), "indigo"
+@map color 13 to (103, 7, 72), "maroon"
+@map color 14 to (64, 224, 208), "turquoise"
+@map color 15 to (0, 139, 0), "green4"
+@reference date 0
+@date wrap off
+@date wrap year 1950
+@default linewidth 1.0
+@default linestyle 1
+@default color 1
+@default pattern 1
+@default font 0
+@default char size 1.000000
+@default symbol size 1.000000
+@default sformat "%.8g"
+@background color 0
+@page background fill on
+@timestamp off
+@timestamp 0.03, 0.03
+@timestamp color 1
+@timestamp rot 0
+@timestamp font 0
+@timestamp char size 1.000000
+@timestamp def "Tue Jul 5 08:29:55 2016"
+@r0 off
+@link r0 to g0
+@r0 type above
+@r0 linestyle 1
+@r0 linewidth 1.0
+@r0 color 1
+@r0 line 0, 0, 0, 0
+@r1 off
+@link r1 to g0
+@r1 type above
+@r1 linestyle 1
+@r1 linewidth 1.0
+@r1 color 1
+@r1 line 0, 0, 0, 0
+@r2 off
+@link r2 to g0
+@r2 type above
+@r2 linestyle 1
+@r2 linewidth 1.0
+@r2 color 1
+@r2 line 0, 0, 0, 0
+@r3 off
+@link r3 to g0
+@r3 type above
+@r3 linestyle 1
+@r3 linewidth 1.0
+@r3 color 1
+@r3 line 0, 0, 0, 0
+@r4 off
+@link r4 to g0
+@r4 type above
+@r4 linestyle 1
+@r4 linewidth 1.0
+@r4 color 1
+@r4 line 0, 0, 0, 0
+@g0 on
+@g0 hidden false
+@g0 type XY
+@g0 stacked false
+@g0 bar hgap 0.000000
+@g0 fixedpoint off
+@g0 fixedpoint type 0
+@g0 fixedpoint xy 0.000000, 0.000000
+@g0 fixedpoint format general general
+@g0 fixedpoint prec 6, 6
+@with g0
+@ world 0, -2, 2, 2
+@ stack world 0, 0, 0, 0
+@ znorm 1
+@ view 0.100000, 0.100000, 1.244903, 0.950000
+@ title ""
+@ title font 0
+@ title size 1.500000
+@ title color 1
+@ subtitle ""
+@ subtitle font 0
+@ subtitle size 1.000000
+@ subtitle color 1
+@ xaxes scale Normal
+@ yaxes scale Normal
+@ xaxes invert off
+@ yaxes invert off
+@ xaxis on
+@ xaxis type zero false
+@ xaxis offset 0.000000 , 0.000000
+@ xaxis bar on
+@ xaxis bar color 1
+@ xaxis bar linestyle 1
+@ xaxis bar linewidth 1.0
+@ xaxis label "Time (ps)"
+@ xaxis label layout para
+@ xaxis label place auto
+@ xaxis label char size 1.500000
+@ xaxis label font 4
+@ xaxis label color 1
+@ xaxis label place normal
+@ xaxis tick on
+@ xaxis tick major 0.5
+@ xaxis tick minor ticks 1
+@ xaxis tick default 6
+@ xaxis tick place rounded true
+@ xaxis tick in
+@ xaxis tick major size 1.000000
+@ xaxis tick major color 1
+@ xaxis tick major linewidth 1.0
+@ xaxis tick major linestyle 1
+@ xaxis tick major grid off
+@ xaxis tick minor color 1
+@ xaxis tick minor linewidth 1.0
+@ xaxis tick minor linestyle 1
+@ xaxis tick minor grid off
+@ xaxis tick minor size 0.500000
+@ xaxis ticklabel on
+@ xaxis ticklabel format general
+@ xaxis ticklabel prec 5
+@ xaxis ticklabel formula ""
+@ xaxis ticklabel append ""
+@ xaxis ticklabel prepend ""
+@ xaxis ticklabel angle 0
+@ xaxis ticklabel skip 0
+@ xaxis ticklabel stagger 0
+@ xaxis ticklabel place normal
+@ xaxis ticklabel offset auto
+@ xaxis ticklabel offset 0.000000 , 0.010000
+@ xaxis ticklabel start type auto
+@ xaxis ticklabel start 0.000000
+@ xaxis ticklabel stop type auto
+@ xaxis ticklabel stop 0.000000
+@ xaxis ticklabel char size 1.250000
+@ xaxis ticklabel font 4
+@ xaxis ticklabel color 1
+@ xaxis tick place both
+@ xaxis tick spec type none
+@ yaxis on
+@ yaxis type zero false
+@ yaxis offset 0.000000 , 0.000000
+@ yaxis bar on
+@ yaxis bar color 1
+@ yaxis bar linestyle 1
+@ yaxis bar linewidth 1.0
+@ yaxis label "Electric field (V/nm)"
+@ yaxis label layout para
+@ yaxis label place auto
+@ yaxis label char size 1.500000
+@ yaxis label font 4
+@ yaxis label color 1
+@ yaxis label place normal
+@ yaxis tick on
+@ yaxis tick major 1
+@ yaxis tick minor ticks 1
+@ yaxis tick default 6
+@ yaxis tick place rounded true
+@ yaxis tick in
+@ yaxis tick major size 1.000000
+@ yaxis tick major color 1
+@ yaxis tick major linewidth 1.0
+@ yaxis tick major linestyle 1
+@ yaxis tick major grid off
+@ yaxis tick minor color 1
+@ yaxis tick minor linewidth 1.0
+@ yaxis tick minor linestyle 1
+@ yaxis tick minor grid off
+@ yaxis tick minor size 0.500000
+@ yaxis ticklabel on
+@ yaxis ticklabel format general
+@ yaxis ticklabel prec 5
+@ yaxis ticklabel formula ""
+@ yaxis ticklabel append ""
+@ yaxis ticklabel prepend ""
+@ yaxis ticklabel angle 0
+@ yaxis ticklabel skip 0
+@ yaxis ticklabel stagger 0
+@ yaxis ticklabel place normal
+@ yaxis ticklabel offset auto
+@ yaxis ticklabel offset 0.000000 , 0.010000
+@ yaxis ticklabel start type auto
+@ yaxis ticklabel start 0.000000
+@ yaxis ticklabel stop type auto
+@ yaxis ticklabel stop 0.000000
+@ yaxis ticklabel char size 1.250000
+@ yaxis ticklabel font 4
+@ yaxis ticklabel color 1
+@ yaxis tick place both
+@ yaxis tick spec type none
+@ altxaxis off
+@ altyaxis off
+@ legend on
+@ legend loctype view
+@ legend 0.85, 0.8
+@ legend box color 1
+@ legend box pattern 1
+@ legend box linewidth 1.0
+@ legend box linestyle 1
+@ legend box fill color 0
+@ legend box fill pattern 1
+@ legend font 0
+@ legend char size 1.000000
+@ legend color 1
+@ legend length 4
+@ legend vgap 1
+@ legend hgap 1
+@ legend invert false
+@ frame type 0
+@ frame linestyle 1
+@ frame linewidth 1.0
+@ frame color 1
+@ frame pattern 1
+@ frame background color 0
+@ frame background pattern 0
+@ s0 hidden false
+@ s0 type xy
+@ s0 symbol 0
+@ s0 symbol size 1.000000
+@ s0 symbol color 1
+@ s0 symbol pattern 1
+@ s0 symbol fill color 1
+@ s0 symbol fill pattern 0
+@ s0 symbol linewidth 1.0
+@ s0 symbol linestyle 1
+@ s0 symbol char 65
+@ s0 symbol char font 0
+@ s0 symbol skip 0
+@ s0 line type 1
+@ s0 line linestyle 1
+@ s0 line linewidth 1.0
+@ s0 line color 1
+@ s0 line pattern 1
+@ s0 baseline type 0
+@ s0 baseline off
+@ s0 dropline off
+@ s0 fill type 0
+@ s0 fill rule 0
+@ s0 fill color 1
+@ s0 fill pattern 1
+@ s0 avalue off
+@ s0 avalue type 2
+@ s0 avalue char size 1.000000
+@ s0 avalue font 0
+@ s0 avalue color 1
+@ s0 avalue rot 0
+@ s0 avalue format general
+@ s0 avalue prec 3
+@ s0 avalue prepend ""
+@ s0 avalue append ""
+@ s0 avalue offset 0.000000 , 0.000000
+@ s0 errorbar on
+@ s0 errorbar place both
+@ s0 errorbar color 1
+@ s0 errorbar pattern 1
+@ s0 errorbar size 1.000000
+@ s0 errorbar linewidth 1.0
+@ s0 errorbar linestyle 1
+@ s0 errorbar riser linewidth 1.0
+@ s0 errorbar riser linestyle 1
+@ s0 errorbar riser clip off
+@ s0 errorbar riser clip length 0.100000
+@ s0 comment "field.xvg"
+@ s0 legend ""
+@target G0.S0
+@type xy
+0 5.21174e-06
+0.0005 4.8582e-06
+0.001 4.46725e-06
+0.0015 4.04017e-06
+0.002 3.57871e-06
+0.0025 3.08465e-06
+0.003 2.56005e-06
+0.0035 2.0072e-06
+0.004 1.42855e-06
+0.0045 8.27051e-07
+0.005 2.0556e-07
+0.0055 -4.3279e-07
+0.006 -1.08468e-06
+0.0065 -1.74674e-06
+0.007 -2.4151e-06
+0.0075 -3.08612e-06
+0.008 -3.75593e-06
+0.0085 -4.42057e-06
+0.009 -5.07613e-06
+0.0095 -5.7183e-06
+0.01 -6.34309e-06
+0.0105 -6.94642e-06
+0.011 -7.52419e-06
+0.0115 -8.07249e-06
+0.012 -8.58716e-06
+0.0125 -9.06443e-06
+0.013 -9.5006e-06
+0.0135 -9.89205e-06
+0.014 -1.02354e-05
+0.0145 -1.05275e-05
+0.015 -1.07651e-05
+0.0155 -1.09458e-05
+0.016 -1.10668e-05
+0.0165 -1.11262e-05
+0.017 -1.11219e-05
+0.0175 -1.10524e-05
+0.018 -1.09166e-05
+0.0185 -1.07135e-05
+0.019 -1.04426e-05
+0.0195 -1.01039e-05
+0.02 -9.69779e-06
+0.0205 -9.22485e-06
+0.021 -8.68609e-06
+0.0215 -8.0833e-06
+0.022 -7.41831e-06
+0.0225 -6.69347e-06
+0.023 -5.91155e-06
+0.0235 -5.07554e-06
+0.024 -4.18956e-06
+0.0245 -3.25681e-06
+0.025 -2.28218e-06
+0.0255 -1.27017e-06
+0.026 -2.25546e-07
+0.0265 8.45705e-07
+0.027 1.93884e-06
+0.0275 3.04734e-06
+0.028 4.1653e-06
+0.0285 5.28662e-06
+0.029 6.40417e-06
+0.0295 7.51217e-06
+0.03 8.60324e-06
+0.0305 9.67081e-06
+0.031 1.07082e-05
+0.0315 1.17081e-05
+0.032 1.26644e-05
+0.0325 1.357e-05
+0.033 1.44184e-05
+0.0335 1.52034e-05
+0.034 1.59185e-05
+0.0345 1.65582e-05
+0.035 1.71168e-05
+0.0355 1.75889e-05
+0.036 1.79698e-05
+0.0365 1.82549e-05
+0.037 1.84404e-05
+0.0375 1.85226e-05
+0.038 1.84986e-05
+0.0385 1.83658e-05
+0.039 1.81227e-05
+0.0395 1.77676e-05
+0.04 1.73001e-05
+0.0405 1.67203e-05
+0.041 1.60287e-05
+0.0415 1.52266e-05
+0.042 1.4316e-05
+0.0425 1.32999e-05
+0.043 1.21814e-05
+0.0435 1.09648e-05
+0.044 9.65433e-06
+0.0445 8.2561e-06
+0.045 6.77585e-06
+0.0455 5.22026e-06
+0.046 3.59662e-06
+0.0465 1.91244e-06
+0.047 1.76813e-07
+0.0475 -1.60169e-06
+0.048 -3.4137e-06
+0.0485 -5.24943e-06
+0.049 -7.09906e-06
+0.0495 -8.95136e-06
+0.05 -1.0796e-05
+0.0505 -1.26218e-05
+0.051 -1.44179e-05
+0.0515 -1.61733e-05
+0.052 -1.7876e-05
+0.0525 -1.95152e-05
+0.053 -2.10797e-05
+0.0535 -2.25588e-05
+0.054 -2.39418e-05
+0.0545 -2.52179e-05
+0.055 -2.63773e-05
+0.0555 -2.74107e-05
+0.056 -2.83084e-05
+0.0565 -2.90627e-05
+0.057 -2.96652e-05
+0.0575 -3.0109e-05
+0.058 -3.03877e-05
+0.0585 -3.04957e-05
+0.059 -3.04283e-05
+0.0595 -3.01817e-05
+0.06 -2.97532e-05
+0.0605 -2.9141e-05
+0.061 -2.83441e-05
+0.0615 -2.73627e-05
+0.062 -2.61986e-05
+0.0625 -2.48541e-05
+0.063 -2.33327e-05
+0.0635 -2.16391e-05
+0.064 -1.97788e-05
+0.0645 -1.77594e-05
+0.065 -1.55887e-05
+0.0655 -1.32758e-05
+0.066 -1.08307e-05
+0.0665 -8.26413e-06
+0.067 -5.58933e-06
+0.0675 -2.8188e-06
+0.068 3.3503e-08
+0.0685 2.95285e-06
+0.069 5.92437e-06
+0.0695 8.93009e-06
+0.07 1.19557e-05
+0.0705 1.49822e-05
+0.071 1.79924e-05
+0.0715 2.09691e-05
+0.072 2.38928e-05
+0.0725 2.67458e-05
+0.073 2.95098e-05
+0.0735 3.21666e-05
+0.074 3.46986e-05
+0.0745 3.70872e-05
+0.075 3.93155e-05
+0.0755 4.13667e-05
+0.076 4.32248e-05
+0.0765 4.48746e-05
+0.077 4.63011e-05
+0.0775 4.74911e-05
+0.078 4.8432e-05
+0.0785 4.91127e-05
+0.079 4.95229e-05
+0.0795 4.96542e-05
+0.08 4.94991e-05
+0.0805 4.90519e-05
+0.081 4.83086e-05
+0.0815 4.72662e-05
+0.082 4.59245e-05
+0.0825 4.4284e-05
+0.083 4.23475e-05
+0.0835 4.01187e-05
+0.084 3.76052e-05
+0.0845 3.48143e-05
+0.085 3.1756e-05
+0.0855 2.8442e-05
+0.086 2.48848e-05
+0.0865 2.11021e-05
+0.087 1.71074e-05
+0.0875 1.29217e-05
+0.088 8.5642e-06
+0.0885 4.05536e-06
+0.089 -5.79145e-07
+0.0895 -5.31895e-06
+0.09 -1.01359e-05
+0.0905 -1.50047e-05
+0.091 -1.98991e-05
+0.0915 -2.47881e-05
+0.092 -2.96471e-05
+0.0925 -3.44439e-05
+0.093 -3.91504e-05
+0.0935 -4.37376e-05
+0.094 -4.81737e-05
+0.0945 -5.24325e-05
+0.095 -5.64828e-05
+0.0955 -6.02969e-05
+0.096 -6.38478e-05
+0.0965 -6.7107e-05
+0.097 -7.00511e-05
+0.0975 -7.26541e-05
+0.098 -7.48937e-05
+0.0985 -7.67485e-05
+0.099 -7.81986e-05
+0.0995 -7.92268e-05
+0.1 -7.98172e-05
+0.1005 -7.99564e-05
+0.101 -7.96334e-05
+0.1015 -7.884e-05
+0.102 -7.75691e-05
+0.1025 -7.58184e-05
+0.103 -7.35867e-05
+0.1035 -7.08762e-05
+0.104 -6.76919e-05
+0.1045 -6.40408e-05
+0.105 -5.99352e-05
+0.1055 -5.53879e-05
+0.106 -5.04157e-05
+0.1065 -4.50365e-05
+0.107 -3.92749e-05
+0.1075 -3.31549e-05
+0.108 -2.67039e-05
+0.1085 -1.9952e-05
+0.109 -1.2932e-05
+0.1095 -5.67709e-06
+0.11 1.77265e-06
+0.1105 9.37968e-06
+0.111 1.71032e-05
+0.1115 2.49024e-05
+0.112 3.27304e-05
+0.1125 4.05437e-05
+0.113 4.82966e-05
+0.1135 5.59424e-05
+0.114 6.34357e-05
+0.1145 7.07264e-05
+0.115 7.77691e-05
+0.1155 8.45172e-05
+0.116 9.09248e-05
+0.1165 9.69478e-05
+0.117 0.000102541
+0.1175 0.000107662
+0.118 0.000112273
+0.1185 0.000116332
+0.119 0.000119806
+0.1195 0.000122661
+0.12 0.000124867
+0.1205 0.000126395
+0.121 0.000127223
+0.1215 0.00012733
+0.122 0.000126699
+0.1225 0.000125318
+0.123 0.000123178
+0.1235 0.000120274
+0.124 0.000116606
+0.1245 0.00011218
+0.125 0.000107004
+0.1255 0.000101092
+0.126 9.44624e-05
+0.1265 8.71353e-05
+0.127 7.91416e-05
+0.1275 7.05119e-05
+0.128 6.12822e-05
+0.1285 5.14929e-05
+0.129 4.11867e-05
+0.1295 3.04165e-05
+0.13 1.92326e-05
+0.1305 7.69112e-06
+0.131 -4.14868e-06
+0.1315 -1.62269e-05
+0.132 -2.8471e-05
+0.1325 -4.08232e-05
+0.133 -5.32067e-05
+0.1335 -6.55524e-05
+0.134 -7.77902e-05
+0.1345 -8.98416e-05
+0.135 -0.000101635
+0.1355 -0.000113095
+0.136 -0.000124152
+0.1365 -0.000134726
+0.137 -0.000144748
+0.1375 -0.00015415
+0.138 -0.000162861
+0.1385 -0.000170816
+0.139 -0.000177954
+0.1395 -0.000184212
+0.14 -0.000189537
+0.1405 -0.000193877
+0.141 -0.000197186
+0.1415 -0.000199421
+0.142 -0.000200548
+0.1425 -0.000200535
+0.143 -0.000199357
+0.1435 -0.000196997
+0.144 -0.000193441
+0.1445 -0.000188686
+0.145 -0.000182733
+0.1455 -0.000175591
+0.146 -0.000167273
+0.1465 -0.000157807
+0.147 -0.000147221
+0.1475 -0.000135553
+0.148 -0.000122847
+0.1485 -0.000109154
+0.149 -9.45312e-05
+0.1495 -7.90457e-05
+0.15 -6.27703e-05
+0.1505 -4.57812e-05
+0.151 -2.816e-05
+0.1515 -9.9992e-06
+0.152 8.61086e-06
+0.1525 2.75697e-05
+0.153 4.67707e-05
+0.1535 6.61152e-05
+0.154 8.54878e-05
+0.1545 0.000104781
+0.155 0.000123874
+0.1555 0.00014266
+0.156 0.000161019
+0.1565 0.000178834
+0.157 0.000195993
+0.1575 0.00021238
+0.158 0.000227882
+0.1585 0.000242394
+0.159 0.000255808
+0.1595 0.000268024
+0.16 0.000278943
+0.1605 0.000288479
+0.161 0.000296543
+0.1615 0.000303058
+0.162 0.000307954
+0.1625 0.000311168
+0.163 0.000312645
+0.1635 0.00031234
+0.164 0.000310218
+0.1645 0.000306253
+0.165 0.000300429
+0.1655 0.00029274
+0.166 0.000283191
+0.1665 0.0002718
+0.167 0.000258592
+0.1675 0.000243609
+0.168 0.000226898
+0.1685 0.000208519
+0.169 0.000188545
+0.1695 0.000167064
+0.17 0.000144158
+0.1705 0.00011994
+0.171 9.45162e-05
+0.1715 6.8015e-05
+0.172 4.0565e-05
+0.1725 1.23028e-05
+0.173 -1.66184e-05
+0.1735 -4.60506e-05
+0.174 -7.58303e-05
+0.1745 -0.000105786
+0.175 -0.000135759
+0.1755 -0.00016557
+0.176 -0.00019504
+0.1765 -0.000223991
+0.177 -0.000252251
+0.1775 -0.000279638
+0.178 -0.00030597
+0.1785 -0.000331079
+0.179 -0.000354791
+0.1795 -0.000376935
+0.18 -0.000397359
+0.1805 -0.000415904
+0.181 -0.000432421
+0.1815 -0.000446777
+0.182 -0.00045884
+0.1825 -0.000468496
+0.183 -0.000475638
+0.1835 -0.000480172
+0.184 -0.000482019
+0.1845 -0.000481113
+0.185 -0.000477401
+0.1855 -0.000470848
+0.186 -0.000461434
+0.1865 -0.000449155
+0.187 -0.000434021
+0.1875 -0.000416065
+0.188 -0.000395332
+0.1885 -0.000371882
+0.189 -0.000345801
+0.1895 -0.000317184
+0.19 -0.000286141
+0.1905 -0.000252807
+0.191 -0.000217334
+0.1915 -0.000179872
+0.192 -0.000140603
+0.1925 -9.97231e-05
+0.193 -5.7428e-05
+0.1935 -1.39473e-05
+0.194 3.05086e-05
+0.1945 7.56883e-05
+0.195 0.000121353
+0.1955 0.000167245
+0.196 0.000213091
+0.1965 0.000258644
+0.197 0.000303625
+0.1975 0.000347756
+0.198 0.000390773
+0.1985 0.0004324
+0.199 0.000472359
+0.1995 0.000510397
+0.2 0.000546255
+0.2005 0.000579676
+0.201 0.000610412
+0.2015 0.000638241
+0.202 0.000662939
+0.2025 0.000684297
+0.203 0.000702128
+0.2035 0.000716255
+0.204 0.000726522
+0.2045 0.000732793
+0.205 0.000734951
+0.2055 0.0007329
+0.206 0.000726571
+0.2065 0.000715911
+0.207 0.000700895
+0.2075 0.000681526
+0.208 0.000657829
+0.2085 0.00062985
+0.209 0.000597673
+0.2095 0.000561393
+0.21 0.000521145
+0.2105 0.000477082
+0.211 0.000429382
+0.2115 0.000378243
+0.212 0.000323899
+0.2125 0.000266607
+0.213 0.000206634
+0.2135 0.000144268
+0.214 7.98362e-05
+0.2145 1.36575e-05
+0.215 -5.39127e-05
+0.2155 -0.000122496
+0.216 -0.000191745
+0.2165 -0.000261247
+0.217 -0.000330622
+0.2175 -0.000399443
+0.218 -0.000467329
+0.2185 -0.000533853
+0.219 -0.000598597
+0.2195 -0.000661164
+0.22 -0.000721143
+0.2205 -0.000778123
+0.221 -0.000831738
+0.2215 -0.000881594
+0.222 -0.000927342
+0.2225 -0.00096862
+0.223 -0.00100512
+0.2235 -0.00103652
+0.224 -0.00106255
+0.2245 -0.00108295
+0.225 -0.00109749
+0.2255 -0.00110598
+0.226 -0.00110824
+0.2265 -0.00110414
+0.227 -0.00109358
+0.2275 -0.0010765
+0.228 -0.00105286
+0.2285 -0.00102268
+0.229 -0.000986009
+0.2295 -0.000942923
+0.23 -0.000893556
+0.2305 -0.000838068
+0.231 -0.000776655
+0.2315 -0.000709563
+0.232 -0.000637087
+0.2325 -0.00055951
+0.233 -0.000477207
+0.2335 -0.000390545
+0.234 -0.000299961
+0.2345 -0.000205893
+0.235 -0.000108808
+0.2355 -9.23019e-06
+0.236 9.23325e-05
+0.2365 0.000195321
+0.237 0.000299144
+0.2375 0.000403262
+0.238 0.000507054
+0.2385 0.000609903
+0.239 0.000711199
+0.2395 0.000810355
+0.24 0.000906734
+0.2405 0.000999717
+0.241 0.00108872
+0.2415 0.00117314
+0.242 0.00125239
+0.2425 0.00132595
+0.243 0.00139325
+0.2435 0.00145379
+0.244 0.0015071
+0.2445 0.00155272
+0.245 0.00159025
+0.2455 0.00161932
+0.246 0.0016396
+0.2465 0.00165079
+0.247 0.00165268
+0.2475 0.00164506
+0.248 0.0016278
+0.2485 0.00160082
+0.249 0.0015641
+0.2495 0.00151765
+0.25 0.00146156
+0.2505 0.00139598
+0.251 0.0013211
+0.2515 0.00123719
+0.252 0.00114455
+0.2525 0.00104356
+0.253 0.000934631
+0.2535 0.000818285
+0.254 0.000695002
+0.2545 0.000565389
+0.255 0.000430088
+0.2555 0.000289763
+0.256 0.000145101
+0.2565 -3.06876e-06
+0.257 -0.000154016
+0.2575 -0.000306921
+0.258 -0.000460919
+0.2585 -0.000615112
+0.259 -0.000768673
+0.2595 -0.000920672
+0.26 -0.00107018
+0.2605 -0.00121633
+0.261 -0.00135819
+0.2615 -0.00149484
+0.262 -0.00162542
+0.2625 -0.00174908
+0.263 -0.00186495
+0.2635 -0.0019722
+0.264 -0.00207009
+0.2645 -0.00215786
+0.265 -0.00223481
+0.2655 -0.00230031
+0.266 -0.00235376
+0.2665 -0.00239462
+0.267 -0.00242243
+0.2675 -0.0024368
+0.268 -0.00243738
+0.2685 -0.00242393
+0.269 -0.00239625
+0.2695 -0.00235424
+0.27 -0.0022979
+0.2705 -0.00222727
+0.271 -0.0021425
+0.2715 -0.00204382
+0.272 -0.00193154
+0.2725 -0.00180607
+0.273 -0.00166791
+0.2735 -0.00151759
+0.274 -0.00135576
+0.2745 -0.00118314
+0.275 -0.00100057
+0.2755 -0.000808891
+0.276 -0.000609027
+0.2765 -0.000402025
+0.277 -0.000188906
+0.2775 2.91893e-05
+0.278 0.000251046
+0.2785 0.00047552
+0.279 0.000701385
+0.2795 0.000927272
+0.28 0.0011519
+0.2805 0.00137402
+0.281 0.00159225
+0.2815 0.00180524
+0.282 0.00201172
+0.2825 0.00221035
+0.283 0.0023998
+0.2835 0.00257887
+0.284 0.00274636
+0.2845 0.00290102
+0.285 0.00304176
+0.2855 0.00316753
+0.286 0.00327733
+0.2865 0.00337022
+0.287 0.00344538
+0.2875 0.00350205
+0.288 0.00353956
+0.2885 0.00355737
+0.289 0.00355501
+0.2895 0.00353213
+0.29 0.00348852
+0.2905 0.00342402
+0.291 0.00333865
+0.2915 0.00323254
+0.292 0.00310591
+0.2925 0.00295915
+0.293 0.00279274
+0.2935 0.00260726
+0.294 0.00240346
+0.2945 0.00218224
+0.295 0.0019445
+0.2955 0.00169129
+0.296 0.0014239
+0.2965 0.00114356
+0.297 0.000851664
+0.2975 0.000549661
+0.298 0.000239175
+0.2985 -7.82175e-05
+0.299 -0.000400775
+0.2995 -0.000726663
+0.3 -0.00105419
+0.3005 -0.00138144
+0.301 -0.00170647
+0.3015 -0.00202738
+0.302 -0.00234234
+0.3025 -0.00264937
+0.303 -0.00294652
+0.3035 -0.00323196
+0.304 -0.00350382
+0.3045 -0.00376024
+0.305 -0.00399958
+0.3055 -0.00422009
+0.306 -0.00442015
+0.3065 -0.00459828
+0.307 -0.00475312
+0.3075 -0.00488328
+0.308 -0.00498762
+0.3085 -0.0050651
+0.309 -0.00511479
+0.3095 -0.00513592
+0.31 -0.00512787
+0.3105 -0.00509018
+0.311 -0.00502256
+0.3115 -0.00492488
+0.312 -0.00479717
+0.3125 -0.00463965
+0.313 -0.00445273
+0.3135 -0.00423693
+0.314 -0.00399306
+0.3145 -0.003722
+0.315 -0.00342483
+0.3155 -0.00310282
+0.316 -0.00275748
+0.3165 -0.00239025
+0.317 -0.00200295
+0.3175 -0.0015975
+0.318 -0.00117589
+0.3185 -0.000740179
+0.319 -0.000292861
+0.3195 0.000163868
+0.32 0.000627539
+0.3205 0.00109555
+0.321 0.00156519
+0.3215 0.00203396
+0.322 0.00249906
+0.3225 0.0029577
+0.323 0.00340721
+0.3235 0.0038448
+0.324 0.00426768
+0.3245 0.00467327
+0.325 0.00505895
+0.3255 0.0054221
+0.326 0.00576021
+0.3265 0.00607101
+0.327 0.0063522
+0.3275 0.00660161
+0.328 0.00681734
+0.3285 0.00699752
+0.329 0.00714054
+0.3295 0.00724495
+0.33 0.00730949
+0.3305 0.00733311
+0.331 0.007315
+0.3315 0.00725454
+0.332 0.00715136
+0.3325 0.00700537
+0.333 0.00681668
+0.3335 0.00658563
+0.334 0.00631287
+0.3345 0.00599924
+0.335 0.00564587
+0.3355 0.00525422
+0.336 0.00482578
+0.3365 0.00436241
+0.337 0.00386622
+0.3375 0.00333958
+0.338 0.00278496
+0.3385 0.00220503
+0.339 0.00160282
+0.3395 0.000981312
+0.34 0.000343815
+0.3405 -0.00030613
+0.341 -0.000965188
+0.3415 -0.00162979
+0.342 -0.00229592
+0.3425 -0.00295985
+0.343 -0.00361791
+0.3435 -0.0042661
+0.344 -0.00490045
+0.3445 -0.0055172
+0.345 -0.00611246
+0.3455 -0.00668234
+0.346 -0.0072233
+0.3465 -0.00773181
+0.347 -0.00820419
+0.3475 -0.0086372
+0.348 -0.00902783
+0.3485 -0.00937304
+0.349 -0.00967006
+0.3495 -0.00991647
+0.35 -0.01011
+0.3505 -0.0102486
+0.351 -0.0103306
+0.3515 -0.0103547
+0.352 -0.0103198
+0.3525 -0.010225
+0.353 -0.01007
+0.3535 -0.00985468
+0.354 -0.00957927
+0.3545 -0.00924437
+0.355 -0.008851
+0.3555 -0.00840043
+0.356 -0.00789427
+0.3565 -0.00733459
+0.357 -0.00672387
+0.3575 -0.00606459
+0.358 -0.00535969
+0.3585 -0.00461278
+0.359 -0.00382731
+0.3595 -0.00300721
+0.36 -0.00215651
+0.3605 -0.00127982
+0.361 -0.000381554
+0.3615 0.000533364
+0.362 0.00145975
+0.3625 0.00239285
+0.363 0.00332721
+0.3635 0.00425738
+0.364 0.00517796
+0.3645 0.00608377
+0.365 0.00696918
+0.3655 0.00782868
+0.366 0.00865711
+0.3665 0.00944909
+0.367 0.0101994
+0.3675 0.0109033
+0.368 0.0115558
+0.3685 0.0121524
+0.369 0.0126887
+0.3695 0.013161
+0.37 0.0135651
+0.3705 0.0138979
+0.371 0.0141563
+0.3715 0.0143375
+0.372 0.0144394
+0.3725 0.0144601
+0.373 0.0143982
+0.3735 0.0142527
+0.374 0.0140233
+0.3745 0.0137097
+0.375 0.0133127
+0.3755 0.012833
+0.376 0.0122722
+0.3765 0.0116322
+0.377 0.0109155
+0.3775 0.0101249
+0.378 0.00926381
+0.3785 0.00833631
+0.379 0.00734629
+0.3795 0.00629867
+0.38 0.00519866
+0.3805 0.00405167
+0.381 0.00286331
+0.3815 0.00164037
+0.382 0.000388846
+0.3825 -0.000884521
+0.383 -0.00217263
+0.3835 -0.00346804
+0.384 -0.00476396
+0.3845 -0.00605269
+0.385 -0.00732657
+0.3855 -0.00857832
+0.386 -0.00980029
+0.3865 -0.0109847
+0.387 -0.0121247
+0.3875 -0.0132128
+0.388 -0.0142421
+0.3885 -0.0152053
+0.389 -0.0160965
+0.3895 -0.0169092
+0.39 -0.0176373
+0.3905 -0.0182757
+0.391 -0.018819
+0.3915 -0.0192629
+0.392 -0.0196032
+0.3925 -0.0198365
+0.393 -0.0199596
+0.3935 -0.0199703
+0.394 -0.0198667
+0.3945 -0.0196477
+0.395 -0.0193128
+0.3955 -0.0188622
+0.396 -0.0182966
+0.3965 -0.0176176
+0.397 -0.0168273
+0.3975 -0.0159286
+0.398 -0.0149253
+0.3985 -0.0138211
+0.399 -0.0126209
+0.3995 -0.0113302
+0.4 -0.0099553
+0.4005 -0.00850257
+0.401 -0.00697904
+0.4015 -0.00539271
+0.402 -0.00375142
+0.4025 -0.00206392
+0.403 -0.000339552
+0.4035 0.00141286
+0.404 0.00318388
+0.4045 0.00496288
+0.405 0.00673997
+0.4055 0.00850546
+0.406 0.0102487
+0.4065 0.0119591
+0.407 0.0136268
+0.4075 0.0152414
+0.408 0.0167925
+0.4085 0.0182707
+0.409 0.0196666
+0.4095 0.0209704
+0.41 0.0221735
+0.4105 0.0232677
+0.411 0.0242449
+0.4115 0.0250978
+0.412 0.0258196
+0.4125 0.0264044
+0.413 0.0268466
+0.4135 0.0271417
+0.414 0.0272858
+0.4145 0.0272758
+0.415 0.0271096
+0.4155 0.0267857
+0.416 0.0263037
+0.4165 0.0256642
+0.417 0.0248683
+0.4175 0.0239184
+0.418 0.0228178
+0.4185 0.0215703
+0.419 0.0201811
+0.4195 0.0186564
+0.42 0.0170024
+0.4205 0.0152267
+0.421 0.0133383
+0.4215 0.011346
+0.422 0.00925979
+0.4225 0.00709001
+0.423 0.00484833
+0.4235 0.00254611
+0.424 0.000195897
+0.4245 -0.00218904
+0.425 -0.0045965
+0.4255 -0.00701253
+0.426 -0.00942313
+0.4265 -0.0118144
+0.427 -0.0141732
+0.4275 -0.0164848
+0.428 -0.0187353
+0.4285 -0.0209112
+0.429 -0.0229988
+0.4295 -0.0249845
+0.43 -0.0268561
+0.4305 -0.028601
+0.431 -0.0302072
+0.4315 -0.0316634
+0.432 -0.0329599
+0.4325 -0.034086
+0.433 -0.0350334
+0.4335 -0.0357939
+0.434 -0.0363606
+0.4345 -0.0367274
+0.435 -0.0368894
+0.4355 -0.0368427
+0.436 -0.0365846
+0.4365 -0.0361138
+0.437 -0.0354296
+0.4375 -0.0345333
+0.438 -0.0334268
+0.4385 -0.0321134
+0.439 -0.0305979
+0.4395 -0.0288861
+0.44 -0.0269848
+0.4405 -0.0249024
+0.441 -0.0226488
+0.4415 -0.0202334
+0.442 -0.0176684
+0.4425 -0.0149667
+0.443 -0.0121414
+0.4435 -0.00920658
+0.444 -0.00617889
+0.4445 -0.00307319
+0.445 9.38279e-05
+0.4455 0.00330456
+0.446 0.00654057
+0.4465 0.00978498
+0.447 0.0130187
+0.4475 0.0162226
+0.448 0.0193787
+0.4485 0.0224679
+0.449 0.025471
+0.4495 0.0283705
+0.45 0.0311483
+0.4505 0.0337865
+0.451 0.0362676
+0.4515 0.0385763
+0.452 0.0406963
+0.4525 0.0426129
+0.453 0.0443125
+0.4535 0.0457821
+0.454 0.0470104
+0.4545 0.0479869
+0.455 0.0487028
+0.4555 0.0491501
+0.456 0.0493228
+0.4565 0.049216
+0.457 0.0488265
+0.4575 0.0481527
+0.458 0.0471947
+0.4585 0.0459539
+0.459 0.0444338
+0.4595 0.0426389
+0.46 0.040576
+0.4605 0.0382538
+0.461 0.0356813
+0.4615 0.0328698
+0.462 0.0298324
+0.4625 0.0265838
+0.463 0.0231394
+0.4635 0.0195159
+0.464 0.0157324
+0.4645 0.0118076
+0.465 0.00776245
+0.4655 0.00361934
+0.466 -0.000600586
+0.4665 -0.00487467
+0.467 -0.00917742
+0.4675 -0.0134851
+0.468 -0.0177743
+0.4685 -0.0220194
+0.469 -0.0261952
+0.4695 -0.0302776
+0.47 -0.0342415
+0.4705 -0.0380621
+0.471 -0.0417166
+0.4715 -0.0451823
+0.472 -0.0484354
+0.4725 -0.0514549
+0.473 -0.0542213
+0.4735 -0.0567147
+0.474 -0.0589172
+0.4745 -0.0608126
+0.475 -0.0623858
+0.4755 -0.0636236
+0.476 -0.0645146
+0.4765 -0.065049
+0.477 -0.065219
+0.4775 -0.0650191
+0.478 -0.0644453
+0.4785 -0.0634961
+0.479 -0.0621721
+0.4795 -0.0604757
+0.48 -0.058412
+0.4805 -0.055988
+0.481 -0.0532125
+0.4815 -0.0500969
+0.482 -0.0466555
+0.4825 -0.0429026
+0.483 -0.0388552
+0.4835 -0.0345342
+0.484 -0.0299599
+0.4845 -0.0251554
+0.485 -0.0201444
+0.4855 -0.014954
+0.486 -0.00961063
+0.4865 -0.00414326
+0.487 0.00141726
+0.4875 0.00704261
+0.488 0.0127003
+0.4885 0.0183578
+0.489 0.0239829
+0.4895 0.0295446
+0.49 0.0350091
+0.4905 0.0403434
+0.491 0.0455165
+0.4915 0.0504961
+0.492 0.0552504
+0.4925 0.0597511
+0.493 0.0639685
+0.4935 0.0678742
+0.494 0.0714423
+0.4945 0.0746493
+0.495 0.0774705
+0.4955 0.0798857
+0.496 0.081876
+0.4965 0.0834246
+0.497 0.0845167
+0.4975 0.0851407
+0.498 0.0852869
+0.4985 0.0849485
+0.499 0.0841214
+0.4995 0.082804
+0.5 0.0809979
+0.5005 0.0787068
+0.501 0.0759384
+0.5015 0.0727022
+0.502 0.0690109
+0.5025 0.0648793
+0.503 0.060326
+0.5035 0.0553728
+0.504 0.0500409
+0.5045 0.0443576
+0.505 0.03835
+0.5055 0.0320489
+0.506 0.0254881
+0.5065 0.018699
+0.507 0.011719
+0.5075 0.00458631
+0.508 -0.00266161
+0.5085 -0.00998256
+0.509 -0.0173386
+0.5095 -0.0246866
+0.51 -0.0319838
+0.5105 -0.0391894
+0.511 -0.0462588
+0.5115 -0.0531529
+0.512 -0.0598287
+0.5125 -0.0662447
+0.513 -0.0723624
+0.5135 -0.0781414
+0.514 -0.0835468
+0.5145 -0.088542
+0.515 -0.0930931
+0.5155 -0.0971695
+0.516 -0.100741
+0.5165 -0.103783
+0.517 -0.106269
+0.5175 -0.108181
+0.518 -0.109499
+0.5185 -0.110208
+0.519 -0.110299
+0.5195 -0.109762
+0.52 -0.108593
+0.5205 -0.106791
+0.521 -0.104358
+0.5215 -0.101302
+0.522 -0.0976316
+0.5225 -0.093361
+0.523 -0.0885072
+0.5235 -0.0830903
+0.524 -0.0771355
+0.5245 -0.0706694
+0.525 -0.0637239
+0.5255 -0.0563325
+0.526 -0.0485311
+0.5265 -0.040361
+0.527 -0.0318629
+0.5275 -0.0230839
+0.528 -0.0140672
+0.5285 -0.00486342
+0.529 0.00447629
+0.5295 0.0139021
+0.53 0.0233583
+0.5305 0.0327951
+0.531 0.0421565
+0.5315 0.0513873
+0.532 0.060435
+0.5325 0.0692449
+0.533 0.0777623
+0.5335 0.0859384
+0.534 0.0937202
+0.5345 0.10106
+0.535 0.10791
+0.5355 0.114225
+0.536 0.119964
+0.5365 0.125086
+0.537 0.129556
+0.5375 0.133339
+0.538 0.136408
+0.5385 0.138735
+0.539 0.140299
+0.5395 0.141083
+0.54 0.141072
+0.5405 0.140258
+0.541 0.138635
+0.5415 0.136205
+0.542 0.132971
+0.5425 0.128943
+0.543 0.124134
+0.5435 0.118563
+0.544 0.112252
+0.5445 0.105232
+0.545 0.0975308
+0.5455 0.0891869
+0.546 0.080239
+0.5465 0.0707321
+0.547 0.0607162
+0.5475 0.0502385
+0.548 0.0393566
+0.5485 0.028126
+0.549 0.0166077
+0.5495 0.00486666
+0.55 -0.00703746
+0.5505 -0.019035
+0.551 -0.031061
+0.5515 -0.0430459
+0.552 -0.0549185
+0.5525 -0.0666147
+0.553 -0.0780621
+0.5535 -0.0891951
+0.554 -0.0999452
+0.5545 -0.110245
+0.555 -0.120035
+0.5555 -0.12925
+0.556 -0.137834
+0.5565 -0.145729
+0.557 -0.152881
+0.5575 -0.159244
+0.558 -0.164772
+0.5585 -0.169423
+0.559 -0.173161
+0.5595 -0.175956
+0.56 -0.177781
+0.5605 -0.178614
+0.561 -0.17844
+0.5615 -0.177249
+0.562 -0.175036
+0.5625 -0.171803
+0.563 -0.167556
+0.5635 -0.162311
+0.564 -0.156084
+0.5645 -0.148901
+0.565 -0.140792
+0.5655 -0.131792
+0.566 -0.121947
+0.5665 -0.111299
+0.567 -0.0999022
+0.5675 -0.0878121
+0.568 -0.075091
+0.5685 -0.0618074
+0.569 -0.0480254
+0.5695 -0.0338208
+0.57 -0.0192717
+0.5705 -0.00445414
+0.571 0.0105456
+0.5715 0.0256502
+0.572 0.0407716
+0.5725 0.0558222
+0.573 0.0707186
+0.5735 0.0853704
+0.574 0.0996952
+0.5745 0.113607
+0.575 0.12702
+0.5755 0.139855
+0.576 0.152031
+0.5765 0.163472
+0.577 0.174107
+0.5775 0.183863
+0.578 0.192678
+0.5785 0.20049
+0.579 0.207245
+0.5795 0.212894
+0.58 0.217391
+0.5805 0.2207
+0.581 0.222789
+0.5815 0.223633
+0.582 0.223215
+0.5825 0.221523
+0.583 0.218554
+0.5835 0.214311
+0.584 0.208806
+0.5845 0.202055
+0.585 0.194086
+0.5855 0.18493
+0.586 0.174627
+0.5865 0.163225
+0.587 0.150776
+0.5875 0.137342
+0.588 0.122986
+0.5885 0.107783
+0.589 0.0918109
+0.5895 0.0751504
+0.59 0.0578935
+0.5905 0.0401271
+0.591 0.0219507
+0.5915 0.00346363
+0.592 -0.0152348
+0.5925 -0.0340354
+0.593 -0.052838
+0.5935 -0.0715316
+0.594 -0.0900087
+0.5945 -0.108164
+0.595 -0.12589
+0.5955 -0.143078
+0.596 -0.159631
+0.5965 -0.175443
+0.597 -0.190419
+0.5975 -0.204465
+0.598 -0.21749
+0.5985 -0.229412
+0.599 -0.24015
+0.5995 -0.249631
+0.6 -0.257791
+0.6005 -0.264566
+0.601 -0.269907
+0.6015 -0.273767
+0.602 -0.276112
+0.6025 -0.27691
+0.603 -0.276144
+0.6035 -0.2738
+0.604 -0.269879
+0.6045 -0.264384
+0.605 -0.257333
+0.6055 -0.248751
+0.606 -0.23867
+0.6065 -0.227132
+0.607 -0.214193
+0.6075 -0.199906
+0.608 -0.184346
+0.6085 -0.167583
+0.609 -0.149704
+0.6095 -0.1308
+0.61 -0.110965
+0.6105 -0.0903091
+0.611 -0.0689348
+0.6115 -0.0469612
+0.612 -0.0245075
+0.6125 -0.0016946
+0.613 0.0213488
+0.6135 0.0444974
+0.614 0.0676168
+0.6145 0.0905752
+0.615 0.113243
+0.6155 0.135485
+0.616 0.157174
+0.6165 0.178181
+0.617 0.198376
+0.6175 0.21764
+0.618 0.235853
+0.6185 0.252901
+0.619 0.268678
+0.6195 0.283078
+0.62 0.29601
+0.6205 0.307385
+0.621 0.317121
+0.6215 0.325151
+0.622 0.33141
+0.6225 0.335848
+0.623 0.338421
+0.6235 0.339096
+0.624 0.337853
+0.6245 0.33468
+0.625 0.329577
+0.6255 0.322554
+0.626 0.313636
+0.6265 0.302851
+0.627 0.290249
+0.6275 0.275878
+0.628 0.259807
+0.6285 0.242113
+0.629 0.222877
+0.6295 0.2022
+0.63 0.18018
+0.6305 0.156932
+0.631 0.132581
+0.6315 0.107248
+0.632 0.0810733
+0.6325 0.0541978
+0.633 0.0267653
+0.6335 -0.00107051
+0.634 -0.0291593
+0.6345 -0.0573394
+0.635 -0.0854513
+0.6355 -0.113337
+0.636 -0.140834
+0.6365 -0.167785
+0.637 -0.19403
+0.6375 -0.219411
+0.638 -0.243779
+0.6385 -0.266984
+0.639 -0.288886
+0.6395 -0.309349
+0.64 -0.328238
+0.6405 -0.345438
+0.641 -0.360832
+0.6415 -0.374318
+0.642 -0.385802
+0.6425 -0.395198
+0.643 -0.402438
+0.6435 -0.407459
+0.644 -0.410213
+0.6445 -0.410665
+0.645 -0.408791
+0.6455 -0.40458
+0.646 -0.398036
+0.6465 -0.389178
+0.647 -0.378031
+0.6475 -0.364643
+0.648 -0.349066
+0.6485 -0.33137
+0.649 -0.311641
+0.6495 -0.289968
+0.65 -0.266463
+0.6505 -0.241235
+0.651 -0.21442
+0.6515 -0.186154
+0.652 -0.156582
+0.6525 -0.125868
+0.653 -0.0941679
+0.6535 -0.0616588
+0.654 -0.0285188
+0.6545 0.00507432
+0.655 0.0389249
+0.6555 0.072853
+0.656 0.10666
+0.6565 0.140152
+0.657 0.17314
+0.6575 0.205431
+0.658 0.236831
+0.6585 0.267161
+0.659 0.296234
+0.6595 0.323877
+0.66 0.349921
+0.6605 0.374199
+0.661 0.396566
+0.6615 0.416873
+0.662 0.434989
+0.6625 0.450793
+0.663 0.464172
+0.6635 0.475035
+0.664 0.483295
+0.6645 0.488885
+0.665 0.49175
+0.6655 0.491851
+0.666 0.489164
+0.6665 0.483681
+0.667 0.47541
+0.6675 0.464374
+0.668 0.450615
+0.6685 0.434184
+0.669 0.415155
+0.6695 0.393617
+0.67 0.369666
+0.6705 0.343425
+0.671 0.315015
+0.6715 0.284587
+0.672 0.252296
+0.6725 0.218306
+0.673 0.182804
+0.6735 0.145969
+0.674 0.108006
+0.6745 0.0691231
+0.675 0.0295283
+0.6755 -0.0105549
+0.676 -0.0509088
+0.6765 -0.0913003
+0.677 -0.1315
+0.6775 -0.171283
+0.678 -0.210415
+0.6785 -0.248673
+0.679 -0.285832
+0.6795 -0.321666
+0.68 -0.355968
+0.6805 -0.388526
+0.681 -0.419146
+0.6815 -0.447636
+0.682 -0.473813
+0.6825 -0.497519
+0.683 -0.518593
+0.6835 -0.536893
+0.684 -0.552299
+0.6845 -0.564696
+0.685 -0.573993
+0.6855 -0.58011
+0.686 -0.582988
+0.6865 -0.582586
+0.687 -0.57888
+0.6875 -0.571864
+0.688 -0.561552
+0.6885 -0.547981
+0.689 -0.531196
+0.6895 -0.511273
+0.69 -0.488295
+0.6905 -0.462372
+0.691 -0.433632
+0.6915 -0.402208
+0.692 -0.368267
+0.6925 -0.331972
+0.693 -0.293516
+0.6935 -0.253107
+0.694 -0.210947
+0.6945 -0.167271
+0.695 -0.122314
+0.6955 -0.0763184
+0.696 -0.0295412
+0.6965 0.017765
+0.697 0.0653285
+0.6975 0.112881
+0.698 0.160158
+0.6985 0.206883
+0.699 0.252793
+0.6995 0.29762
+0.7 0.341094
+0.7005 0.382966
+0.701 0.422982
+0.7015 0.460905
+0.702 0.496502
+0.7025 0.529549
+0.703 0.559849
+0.7035 0.5872
+0.704 0.611431
+0.7045 0.63238
+0.705 0.649901
+0.7055 0.663873
+0.706 0.674188
+0.7065 0.680762
+0.707 0.683529
+0.7075 0.682445
+0.708 0.677489
+0.7085 0.66866
+0.709 0.655982
+0.7095 0.639494
+0.71 0.619269
+0.7105 0.595386
+0.711 0.567958
+0.7115 0.537121
+0.712 0.503014
+0.7125 0.465818
+0.713 0.42571
+0.7135 0.382906
+0.714 0.337628
+0.7145 0.290109
+0.715 0.240615
+0.7155 0.189396
+0.716 0.136743
+0.7165 0.0829431
+0.717 0.0282854
+0.7175 -0.0269121
+0.718 -0.082357
+0.7185 -0.137725
+0.719 -0.192702
+0.7195 -0.246978
+0.72 -0.300241
+0.7205 -0.35217
+0.721 -0.402478
+0.7215 -0.450854
+0.722 -0.49702
+0.7225 -0.540695
+0.723 -0.581609
+0.7235 -0.61952
+0.724 -0.654184
+0.7245 -0.685388
+0.725 -0.712929
+0.7255 -0.736621
+0.726 -0.756311
+0.7265 -0.771853
+0.727 -0.783135
+0.7275 -0.790062
+0.728 -0.792565
+0.7285 -0.790599
+0.729 -0.784146
+0.7295 -0.773211
+0.73 -0.757825
+0.7305 -0.73805
+0.731 -0.71396
+0.7315 -0.685668
+0.732 -0.653309
+0.7325 -0.617031
+0.733 -0.577025
+0.7335 -0.533478
+0.734 -0.486624
+0.7345 -0.436707
+0.735 -0.38398
+0.7355 -0.328739
+0.736 -0.271263
+0.7365 -0.211874
+0.737 -0.150897
+0.7375 -0.0886603
+0.738 -0.0255159
+0.7385 0.0381943
+0.739 0.102103
+0.7395 0.165849
+0.74 0.229077
+0.7405 0.291418
+0.741 0.352519
+0.7415 0.412025
+0.742 0.469581
+0.7425 0.524855
+0.743 0.577514
+0.7435 0.627249
+0.744 0.673757
+0.7445 0.716746
+0.745 0.755962
+0.7455 0.791153
+0.746 0.822087
+0.7465 0.848573
+0.747 0.870424
+0.7475 0.887493
+0.748 0.89965
+0.7485 0.906793
+0.749 0.908853
+0.7495 0.905786
+0.75 0.897576
+0.7505 0.884236
+0.751 0.865815
+0.7515 0.842379
+0.752 0.814037
+0.7525 0.780909
+0.753 0.743159
+0.7535 0.700979
+0.754 0.654566
+0.7545 0.604174
+0.755 0.550046
+0.7555 0.492474
+0.756 0.431774
+0.7565 0.368251
+0.757 0.302261
+0.7575 0.234163
+0.758 0.164323
+0.7585 0.0931338
+0.759 0.0209795
+0.7595 -0.0517257
+0.76 -0.124573
+0.7605 -0.197158
+0.761 -0.269061
+0.7615 -0.339877
+0.762 -0.409198
+0.7625 -0.476612
+0.763 -0.541736
+0.7635 -0.604181
+0.764 -0.663583
+0.7645 -0.719588
+0.765 -0.771847
+0.7655 -0.820057
+0.766 -0.86391
+0.7665 -0.903139
+0.767 -0.937492
+0.7675 -0.966741
+0.768 -0.9907
+0.7685 -1.00919
+0.769 -1.02209
+0.7695 -1.02929
+0.77 -1.0307
+0.7705 -1.0263
+0.771 -1.01607
+0.7715 -1.00004
+0.772 -0.978266
+0.7725 -0.950838
+0.773 -0.917875
+0.7735 -0.879534
+0.774 -0.836011
+0.7745 -0.787509
+0.775 -0.734289
+0.7755 -0.67661
+0.776 -0.614785
+0.7765 -0.549141
+0.777 -0.480018
+0.7775 -0.407807
+0.778 -0.332877
+0.7785 -0.255652
+0.779 -0.176557
+0.7795 -0.0960186
+0.78 -0.0145043
+0.7805 0.0675539
+0.781 0.149678
+0.7815 0.231402
+0.782 0.312271
+0.7825 0.391821
+0.783 0.469578
+0.7835 0.545116
+0.784 0.617976
+0.7845 0.687743
+0.785 0.754002
+0.7855 0.816349
+0.786 0.874426
+0.7865 0.927868
+0.787 0.976356
+0.7875 1.01959
+0.788 1.05728
+0.7885 1.08921
+0.789 1.11515
+0.7895 1.13492
+0.79 1.14839
+0.7905 1.15544
+0.791 1.15599
+0.7915 1.15002
+0.792 1.13752
+0.7925 1.11853
+0.793 1.09312
+0.7935 1.0614
+0.794 1.02352
+0.7945 0.979661
+0.795 0.930041
+0.7955 0.874917
+0.796 0.814559
+0.7965 0.749293
+0.797 0.679468
+0.7975 0.605441
+0.798 0.527627
+0.7985 0.44643
+0.799 0.362298
+0.7995 0.275707
+0.8 0.187114
+0.8005 0.0970296
+0.801 0.00593733
+0.8015 -0.0856452
+0.802 -0.177186
+0.8025 -0.268193
+0.803 -0.358125
+0.8035 -0.446487
+0.804 -0.532762
+0.8045 -0.616443
+0.805 -0.697062
+0.8055 -0.774127
+0.806 -0.847206
+0.8065 -0.915853
+0.807 -0.979653
+0.8075 -1.03824
+0.808 -1.09124
+0.8085 -1.13833
+0.809 -1.17921
+0.8095 -1.21364
+0.81 -1.24137
+0.8105 -1.26223
+0.811 -1.27605
+0.8115 -1.28273
+0.812 -1.28221
+0.8125 -1.27443
+0.813 -1.25943
+0.8135 -1.23724
+0.814 -1.20796
+0.8145 -1.17173
+0.815 -1.1287
+0.8155 -1.07911
+0.816 -1.02319
+0.8165 -0.961235
+0.817 -0.893574
+0.8175 -0.820547
+0.818 -0.742554
+0.8185 -0.660021
+0.819 -0.573377
+0.8195 -0.483101
+0.82 -0.389702
+0.8205 -0.293667
+0.821 -0.195555
+0.8215 -0.0958884
+0.822 0.00476546
+0.8225 0.105831
+0.823 0.206761
+0.8235 0.306957
+0.824 0.405877
+0.8245 0.50294
+0.825 0.59758
+0.8255 0.689271
+0.826 0.777462
+0.8265 0.86166
+0.827 0.941356
+0.8275 1.01608
+0.828 1.08539
+0.8285 1.14887
+0.829 1.20614
+0.8295 1.25685
+0.83 1.30068
+0.8305 1.33735
+0.831 1.36663
+0.8315 1.38831
+0.832 1.40226
+0.8325 1.40834
+0.833 1.4065
+0.8335 1.39672
+0.834 1.37901
+0.8345 1.35344
+0.835 1.32013
+0.8355 1.27922
+0.836 1.23093
+0.8365 1.1755
+0.837 1.11319
+0.8375 1.04436
+0.838 0.969344
+0.8385 0.888553
+0.839 0.802429
+0.8395 0.71142
+0.84 0.616039
+0.8405 0.51679
+0.841 0.414224
+0.8415 0.308925
+0.842 0.201454
+0.8425 0.0924322
+0.843 -0.0175529
+0.8435 -0.127874
+0.844 -0.23789
+0.8445 -0.347009
+0.845 -0.454593
+0.8455 -0.560018
+0.846 -0.662701
+0.8465 -0.762031
+0.847 -0.857454
+0.8475 -0.948402
+0.848 -1.03434
+0.8485 -1.11477
+0.849 -1.18921
+0.8495 -1.25723
+0.85 -1.31841
+0.8505 -1.37238
+0.851 -1.41881
+0.8515 -1.4574
+0.852 -1.48792
+0.8525 -1.51015
+0.853 -1.52394
+0.8535 -1.52919
+0.854 -1.52583
+0.8545 -1.51384
+0.855 -1.49327
+0.8555 -1.46421
+0.856 -1.42677
+0.8565 -1.38115
+0.857 -1.32758
+0.8575 -1.26632
+0.858 -1.1977
+0.8585 -1.12207
+0.859 -1.03985
+0.8595 -0.951477
+0.86 -0.857418
+0.8605 -0.758201
+0.861 -0.654351
+0.8615 -0.546444
+0.862 -0.435094
+0.8625 -0.320894
+0.863 -0.204502
+0.8635 -0.0865447
+0.864 0.0323067
+0.8645 0.151363
+0.865 0.269987
+0.8655 0.387474
+0.866 0.503183
+0.8665 0.616442
+0.867 0.726591
+0.8675 0.833022
+0.868 0.935092
+0.8685 1.03224
+0.869 1.12388
+0.8695 1.20948
+0.87 1.28854
+0.8705 1.36059
+0.871 1.42519
+0.8715 1.48197
+0.872 1.53057
+0.8725 1.5707
+0.873 1.60209
+0.8735 1.62455
+0.874 1.63792
+0.8745 1.64209
+0.875 1.63701
+0.8755 1.62268
+0.876 1.59916
+0.8765 1.56655
+0.877 1.525
+0.8775 1.47472
+0.878 1.41597
+0.8785 1.34906
+0.879 1.27433
+0.8795 1.1922
+0.88 1.10309
+0.8805 1.00748
+0.881 0.905927
+0.8815 0.798947
+0.882 0.687141
+0.8825 0.571147
+0.883 0.451574
+0.8835 0.329119
+0.884 0.204439
+0.8845 0.0782435
+0.885 -0.048745
+0.8855 -0.17584
+0.886 -0.302289
+0.8865 -0.427414
+0.887 -0.55048
+0.8875 -0.670779
+0.888 -0.787646
+0.8885 -0.900389
+0.889 -1.00838
+0.8895 -1.11099
+0.89 -1.2076
+0.8905 -1.29769
+0.891 -1.38069
+0.8915 -1.45615
+0.892 -1.5236
+0.8925 -1.58263
+0.893 -1.63291
+0.8935 -1.67411
+0.894 -1.70599
+0.8945 -1.72833
+0.895 -1.74098
+0.8955 -1.74386
+0.896 -1.73691
+0.8965 -1.72015
+0.897 -1.69365
+0.8975 -1.65754
+0.898 -1.61198
+0.8985 -1.55722
+0.899 -1.49355
+0.8995 -1.42129
+0.9 -1.34085
+0.9005 -1.25264
+0.901 -1.15714
+0.9015 -1.0549
+0.902 -0.946445
+0.9025 -0.832403
+0.903 -0.713377
+0.9035 -0.590041
+0.904 -0.463096
+0.9045 -0.333221
+0.905 -0.201171
+0.9055 -0.0676599
+0.906 0.06655
+0.9065 0.200685
+0.907 0.334018
+0.9075 0.465778
+0.908 0.595203
+0.9085 0.721587
+0.909 0.844177
+0.9095 0.962304
+0.91 1.07527
+0.9105 1.18243
+0.911 1.28316
+0.9115 1.37688
+0.912 1.46306
+0.9125 1.54118
+0.913 1.61078
+0.9135 1.67146
+0.914 1.72285
+0.9145 1.76464
+0.915 1.79657
+0.9155 1.81845
+0.916 1.83012
+0.9165 1.83151
+0.917 1.82257
+0.9175 1.80335
+0.918 1.77392
+0.9185 1.73444
+0.919 1.6851
+0.9195 1.62617
+0.92 1.55795
+0.9205 1.48082
+0.921 1.39519
+0.9215 1.30152
+0.922 1.20035
+0.9225 1.0922
+0.923 0.977703
+0.9235 0.857461
+0.924 0.732157
+0.9245 0.602506
+0.925 0.469198
+0.9255 0.333013
+0.926 0.19468
+0.9265 0.0549945
+0.927 -0.085242
+0.9275 -0.22527
+0.928 -0.364266
+0.9285 -0.501477
+0.929 -0.636108
+0.9295 -0.767377
+0.93 -0.89457
+0.9305 -1.01693
+0.931 -1.13379
+0.9315 -1.24446
+0.932 -1.3483
+0.9325 -1.44473
+0.933 -1.53318
+0.9335 -1.61313
+0.934 -1.68414
+0.9345 -1.74577
+0.935 -1.79767
+0.9355 -1.83952
+0.936 -1.87108
+0.9365 -1.89215
+0.937 -1.90259
+0.9375 -1.90233
+0.938 -1.89135
+0.9385 -1.8697
+0.939 -1.83749
+0.9395 -1.79487
+0.94 -1.74208
+0.9405 -1.67939
+0.941 -1.60715
+0.9415 -1.52575
+0.942 -1.43564
+0.9425 -1.33731
+0.943 -1.2313
+0.9435 -1.11821
+0.944 -0.998652
+0.9445 -0.8733
+0.945 -0.74287
+0.9455 -0.608061
+0.946 -0.46966
+0.9465 -0.328409
+0.947 -0.185118
+0.9475 -0.0406129
+0.948 0.104329
+0.9485 0.248854
+0.949 0.39218
+0.9495 0.53348
+0.95 0.671937
+0.9505 0.8068
+0.951 0.937269
+0.9515 1.06263
+0.952 1.18217
+0.9525 1.29517
+0.953 1.40103
+0.9535 1.4991
+0.954 1.58886
+0.9545 1.66978
+0.955 1.74137
+0.9555 1.80324
+0.956 1.85502
+0.9565 1.89642
+0.957 1.92718
+0.9575 1.94711
+0.958 1.95611
+0.9585 1.95409
+0.959 1.94107
+0.9595 1.9171
+0.96 1.88232
+0.9605 1.83689
+0.961 1.78108
+0.9615 1.71518
+0.962 1.63956
+0.9625 1.55464
+0.963 1.46088
+0.9635 1.3588
+0.964 1.24899
+0.9645 1.13203
+0.965 1.00861
+0.9655 0.879391
+0.966 0.745105
+0.9665 0.606525
+0.967 0.464396
+0.9675 0.319552
+0.968 0.172774
+0.9685 0.0249056
+0.969 -0.123203
+0.9695 -0.270749
+0.97 -0.416884
+0.9705 -0.560763
+0.971 -0.701608
+0.9715 -0.838588
+0.972 -0.97096
+0.9725 -1.09796
+0.973 -1.21884
+0.9735 -1.33297
+0.974 -1.43964
+0.9745 -1.5383
+0.975 -1.62835
+0.9755 -1.70928
+0.976 -1.78065
+0.9765 -1.84203
+0.977 -1.89308
+0.9775 -1.9335
+0.978 -1.96305
+0.9785 -1.98156
+0.979 -1.98893
+0.9795 -1.98511
+0.98 -1.97011
+0.9805 -1.94401
+0.981 -1.90695
+0.9815 -1.85913
+0.982 -1.80084
+0.9825 -1.73237
+0.983 -1.65412
+0.9835 -1.56653
+0.984 -1.47007
+0.9845 -1.36531
+0.985 -1.25282
+0.9855 -1.13324
+0.986 -1.00722
+0.9865 -0.87549
+0.987 -0.738802
+0.9875 -0.597895
+0.988 -0.453594
+0.9885 -0.306679
+0.989 -0.157996
+0.9895 -0.00839989
+0.99 0.141301
+0.9905 0.290225
+0.991 0.437569
+0.9915 0.582483
+0.992 0.724131
+0.9925 0.861749
+0.993 0.994525
+0.9935 1.12174
+0.994 1.24266
+0.9945 1.3566
+0.995 1.46292
+0.9955 1.56102
+0.996 1.65034
+0.9965 1.73039
+0.997 1.80069
+0.9975 1.86087
+0.998 1.91058
+0.9985 1.94953
+0.999 1.97752
+0.9995 1.99437
+1 2
+1.0005 1.99437
+1.001 1.97752
+1.0015 1.94953
+1.002 1.91058
+1.0025 1.86086
+1.003 1.80069
+1.0035 1.73039
+1.004 1.65035
+1.0045 1.56101
+1.005 1.46292
+1.0055 1.35661
+1.006 1.24265
+1.0065 1.12174
+1.007 0.994541
+1.0075 0.861733
+1.008 0.724131
+1.0085 0.582483
+1.009 0.437587
+1.0095 0.290225
+1.01 0.141301
+1.0105 -0.00838203
+1.011 -0.158014
+1.0115 -0.306679
+1.012 -0.453577
+1.0125 -0.597912
+1.013 -0.738802
+1.0135 -0.87549
+1.014 -1.00724
+1.0145 -1.13324
+1.015 -1.25282
+1.0155 -1.3653
+1.016 -1.47008
+1.0165 -1.56653
+1.017 -1.65411
+1.0175 -1.73238
+1.018 -1.80084
+1.0185 -1.85913
+1.019 -1.90695
+1.0195 -1.94401
+1.02 -1.97011
+1.0205 -1.98511
+1.021 -1.98893
+1.0215 -1.98156
+1.022 -1.96305
+1.0225 -1.93349
+1.023 -1.89308
+1.0235 -1.84203
+1.024 -1.78064
+1.0245 -1.70928
+1.025 -1.62835
+1.0255 -1.53829
+1.026 -1.43964
+1.0265 -1.33297
+1.027 -1.21886
+1.0275 -1.09794
+1.028 -0.97096
+1.0285 -0.838605
+1.029 -0.701591
+1.0295 -0.560763
+1.03 -0.416884
+1.0305 -0.270731
+1.031 -0.123203
+1.0315 0.0249056
+1.032 0.172756
+1.0325 0.319552
+1.033 0.464396
+1.0335 0.606508
+1.034 0.745122
+1.0345 0.879391
+1.035 1.0086
+1.0355 1.13205
+1.036 1.24899
+1.0365 1.3588
+1.037 1.46087
+1.0375 1.55464
+1.038 1.63956
+1.0385 1.71518
+1.039 1.78108
+1.0395 1.83689
+1.04 1.88231
+1.0405 1.91711
+1.041 1.94107
+1.0415 1.95409
+1.042 1.95611
+1.0425 1.94711
+1.043 1.92718
+1.0435 1.89642
+1.044 1.85502
+1.0445 1.80324
+1.045 1.74138
+1.0455 1.66977
+1.046 1.58886
+1.0465 1.49911
+1.047 1.40101
+1.0475 1.29517
+1.048 1.18217
+1.0485 1.06265
+1.049 0.937269
+1.0495 0.8068
+1.05 0.671954
+1.0505 0.533463
+1.051 0.39218
+1.0515 0.24887
+1.052 0.104311
+1.0525 -0.0406129
+1.053 -0.185118
+1.0535 -0.328425
+1.054 -0.46966
+1.0545 -0.608061
+1.055 -0.742855
+1.0555 -0.873315
+1.056 -0.998652
+1.0565 -1.1182
+1.057 -1.23131
+1.0575 -1.33731
+1.058 -1.43563
+1.0585 -1.52576
+1.059 -1.60715
+1.0595 -1.67939
+1.06 -1.74207
+1.0605 -1.79487
+1.061 -1.83749
+1.0615 -1.8697
+1.062 -1.89135
+1.0625 -1.90233
+1.063 -1.90259
+1.0635 -1.89215
+1.064 -1.87108
+1.0645 -1.83952
+1.065 -1.79766
+1.0655 -1.74577
+1.066 -1.68414
+1.0665 -1.61314
+1.067 -1.53317
+1.0675 -1.44473
+1.068 -1.34831
+1.0685 -1.24445
+1.069 -1.13379
+1.0695 -1.01695
+1.07 -0.894556
+1.0705 -0.767377
+1.071 -0.636108
+1.0715 -0.501493
+1.072 -0.364266
+1.0725 -0.22527
+1.073 -0.0852581
+1.0735 0.0550105
+1.074 0.19468
+1.0745 0.332995
+1.075 0.469215
+1.0755 0.602506
+1.076 0.732157
+1.0765 0.857477
+1.077 0.977703
+1.0775 1.0922
+1.078 1.20033
+1.0785 1.30153
+1.079 1.39519
+1.0795 1.48081
+1.08 1.55796
+1.0805 1.62617
+1.081 1.6851
+1.0815 1.73444
+1.082 1.77392
+1.0825 1.80335
+1.083 1.82257
+1.0835 1.83151
+1.084 1.83012
+1.0845 1.81845
+1.085 1.79657
+1.0855 1.76464
+1.086 1.72285
+1.0865 1.67145
+1.087 1.61078
+1.0875 1.54118
+1.088 1.46305
+1.0885 1.37688
+1.089 1.28316
+1.0895 1.18244
+1.09 1.07526
+1.0905 0.962304
+1.091 0.844192
+1.0915 0.721572
+1.092 0.595203
+1.0925 0.465778
+1.093 0.334002
+1.0935 0.200685
+1.094 0.06655
+1.0945 -0.0676429
+1.095 -0.201171
+1.0955 -0.333221
+1.096 -0.463082
+1.0965 -0.590057
+1.097 -0.713377
+1.0975 -0.832389
+1.098 -0.946458
+1.0985 -1.0549
+1.099 -1.15714
+1.0995 -1.25262
+1.1 -1.34085
+1.1005 -1.42129
+1.101 -1.49354
+1.1015 -1.55723
+1.102 -1.61198
+1.1025 -1.65753
+1.103 -1.69365
+1.1035 -1.72015
+1.104 -1.73691
+1.1045 -1.74386
+1.105 -1.74098
+1.1055 -1.72833
+1.106 -1.70599
+1.1065 -1.67411
+1.107 -1.63291
+1.1075 -1.58264
+1.108 -1.52359
+1.1085 -1.45615
+1.109 -1.3807
+1.1095 -1.29768
+1.11 -1.2076
+1.1105 -1.11099
+1.111 -1.00839
+1.1115 -0.900389
+1.112 -0.787646
+1.1125 -0.670794
+1.113 -0.550468
+1.1135 -0.427414
+1.114 -0.302305
+1.1145 -0.175824
+1.115 -0.048745
+1.1155 0.0782435
+1.116 0.204455
+1.1165 0.329119
+1.117 0.451574
+1.1175 0.571132
+1.118 0.687155
+1.1185 0.798947
+1.119 0.905916
+1.1195 1.0075
+1.12 1.10309
+1.1205 1.19219
+1.121 1.27434
+1.1215 1.34906
+1.122 1.41597
+1.1225 1.47471
+1.123 1.525
+1.1235 1.56655
+1.124 1.59916
+1.1245 1.62268
+1.125 1.63701
+1.1255 1.64209
+1.126 1.63791
+1.1265 1.62455
+1.127 1.60209
+1.1275 1.57069
+1.128 1.53057
+1.1285 1.48197
+1.129 1.4252
+1.1295 1.36058
+1.13 1.28854
+1.1305 1.20949
+1.131 1.12387
+1.1315 1.03224
+1.132 0.935104
+1.1325 0.833009
+1.133 0.726591
+1.1335 0.616442
+1.134 0.503198
+1.1345 0.387474
+1.135 0.269987
+1.1355 0.151378
+1.136 0.0322916
+1.1365 -0.0865447
+1.137 -0.20449
+1.1375 -0.320908
+1.138 -0.435094
+1.1385 -0.546444
+1.139 -0.654361
+1.1395 -0.758201
+1.14 -0.857418
+1.1405 -0.951468
+1.141 -1.03986
+1.1415 -1.12207
+1.142 -1.19769
+1.1425 -1.26632
+1.143 -1.32758
+1.1435 -1.38115
+1.144 -1.42678
+1.1445 -1.46421
+1.145 -1.49327
+1.1455 -1.51384
+1.146 -1.52583
+1.1465 -1.52919
+1.147 -1.52395
+1.1475 -1.51015
+1.148 -1.48792
+1.1485 -1.4574
+1.149 -1.4188
+1.1495 -1.37238
+1.15 -1.31841
+1.1505 -1.25722
+1.151 -1.18921
+1.1515 -1.11477
+1.152 -1.03435
+1.1525 -0.948391
+1.153 -0.857454
+1.1535 -0.762043
+1.154 -0.662691
+1.1545 -0.560018
+1.155 -0.454593
+1.1555 -0.346996
+1.156 -0.23789
+1.1565 -0.127874
+1.157 -0.0175669
+1.1575 0.0924322
+1.158 0.201454
+1.1585 0.308915
+1.159 0.414237
+1.1595 0.51679
+1.16 0.616027
+1.1605 0.711432
+1.161 0.802429
+1.1615 0.888553
+1.162 0.969336
+1.1625 1.04436
+1.163 1.11319
+1.1635 1.17549
+1.164 1.23094
+1.1645 1.27922
+1.165 1.32012
+1.1655 1.35344
+1.166 1.37901
+1.1665 1.39672
+1.167 1.40651
+1.1675 1.40834
+1.168 1.40226
+1.1685 1.38832
+1.169 1.36663
+1.1695 1.33735
+1.17 1.30068
+1.1705 1.25684
+1.171 1.20614
+1.1715 1.14888
+1.172 1.08538
+1.1725 1.01608
+1.173 0.941356
+1.1735 0.861668
+1.174 0.777462
+1.1745 0.689271
+1.175 0.597592
+1.1755 0.50293
+1.176 0.405877
+1.1765 0.306969
+1.177 0.206749
+1.1775 0.105831
+1.178 0.00476546
+1.1785 -0.0959011
+1.179 -0.195555
+1.1795 -0.293667
+1.18 -0.38969
+1.1805 -0.483112
+1.181 -0.573377
+1.1815 -0.660012
+1.182 -0.742564
+1.1825 -0.820547
+1.183 -0.893564
+1.1835 -0.961242
+1.184 -1.02319
+1.1845 -1.07911
+1.185 -1.1287
+1.1855 -1.17173
+1.186 -1.20796
+1.1865 -1.23724
+1.187 -1.25943
+1.1875 -1.27443
+1.188 -1.28221
+1.1885 -1.28273
+1.189 -1.27605
+1.1895 -1.26223
+1.19 -1.24137
+1.1905 -1.21364
+1.191 -1.17921
+1.1915 -1.13833
+1.192 -1.09123
+1.1925 -1.03824
+1.193 -0.979661
+1.1935 -0.915846
+1.194 -0.847206
+1.1945 -0.774136
+1.195 -0.697052
+1.1955 -0.616443
+1.196 -0.532762
+1.1965 -0.446498
+1.197 -0.358125
+1.1975 -0.268193
+1.198 -0.177197
+1.1985 -0.0856335
+1.199 0.00593733
+1.1995 0.0970204
+1.2 0.187126
+1.2005 0.275707
+1.201 0.362298
+1.2015 0.446438
+1.202 0.527627
+1.2025 0.605441
+1.203 0.67946
+1.2035 0.749302
+1.204 0.814559
+1.2045 0.874909
+1.205 0.930046
+1.2055 0.979661
+1.206 1.02352
+1.2065 1.0614
+1.207 1.09312
+1.2075 1.11853
+1.208 1.13752
+1.2085 1.15002
+1.209 1.15599
+1.2095 1.15544
+1.21 1.14839
+1.2105 1.13492
+1.211 1.11515
+1.2115 1.0892
+1.212 1.05728
+1.2125 1.01959
+1.213 0.976351
+1.2135 0.927868
+1.214 0.874426
+1.2145 0.816358
+1.215 0.753996
+1.2155 0.687743
+1.216 0.617984
+1.2165 0.545109
+1.217 0.469578
+1.2175 0.391821
+1.218 0.312263
+1.2185 0.231402
+1.219 0.149678
+1.2195 0.0675623
+1.22 -0.0145043
+1.2205 -0.0960186
+1.221 -0.176549
+1.2215 -0.25566
+1.222 -0.332877
+1.2225 -0.407799
+1.223 -0.480029
+1.2235 -0.549141
+1.224 -0.614785
+1.2245 -0.676604
+1.225 -0.734289
+1.2255 -0.787509
+1.226 -0.836007
+1.2265 -0.879541
+1.227 -0.917875
+1.2275 -0.950834
+1.228 -0.97827
+1.2285 -1.00004
+1.229 -1.01607
+1.2295 -1.0263
+1.23 -1.0307
+1.2305 -1.02929
+1.231 -1.02209
+1.2315 -1.00919
+1.232 -0.9907
+1.2325 -0.966745
+1.233 -0.937489
+1.2335 -0.903139
+1.234 -0.863915
+1.2345 -0.820053
+1.235 -0.771847
+1.2355 -0.719588
+1.236 -0.663592
+1.2365 -0.604181
+1.237 -0.541736
+1.2375 -0.476619
+1.238 -0.409191
+1.2385 -0.339877
+1.239 -0.269068
+1.2395 -0.197151
+1.24 -0.124573
+1.2405 -0.0517257
+1.241 0.0209906
+1.2415 0.0931338
+1.242 0.164323
+1.2425 0.234156
+1.243 0.302268
+1.2435 0.368251
+1.244 0.431768
+1.2445 0.492483
+1.245 0.550046
+1.2455 0.604168
+1.246 0.654574
+1.2465 0.700979
+1.247 0.743159
+1.2475 0.780906
+1.248 0.814037
+1.2485 0.842379
+1.249 0.865813
+1.2495 0.884239
+1.25 0.897576
+1.2505 0.905785
+1.251 0.908853
+1.2515 0.906793
+1.252 0.89965
+1.2525 0.887492
+1.253 0.870424
+1.2535 0.848573
+1.254 0.822092
+1.2545 0.791149
+1.255 0.755962
+1.2555 0.716752
+1.256 0.673753
+1.2565 0.627249
+1.257 0.57752
+1.2575 0.52485
+1.258 0.469581
+1.2585 0.412025
+1.259 0.352528
+1.2595 0.291418
+1.26 0.229077
+1.2605 0.165856
+1.261 0.102097
+1.2615 0.0381943
+1.262 -0.0255094
+1.2625 -0.0886667
+1.263 -0.150897
+1.2635 -0.211874
+1.264 -0.271271
+1.2645 -0.328739
+1.265 -0.38398
+1.2655 -0.436701
+1.266 -0.486629
+1.2665 -0.533478
+1.267 -0.57702
+1.2675 -0.617037
+1.268 -0.653309
+1.2685 -0.685668
+1.269 -0.713963
+1.2695 -0.73805
+1.27 -0.757825
+1.2705 -0.77321
+1.271 -0.784146
+1.2715 -0.790599
+1.272 -0.792564
+1.2725 -0.790061
+1.273 -0.783135
+1.2735 -0.771855
+1.274 -0.756309
+1.2745 -0.736621
+1.275 -0.712929
+1.2755 -0.685385
+1.276 -0.654184
+1.2765 -0.61952
+1.277 -0.581615
+1.2775 -0.540691
+1.278 -0.49702
+1.2785 -0.450859
+1.279 -0.402473
+1.2795 -0.35217
+1.28 -0.300241
+1.2805 -0.246972
+1.281 -0.192702
+1.2815 -0.137725
+1.282 -0.0823626
+1.2825 -0.0269121
+1.283 0.0282854
+1.2835 0.0829376
+1.284 0.136749
+1.2845 0.189396
+1.285 0.24061
+1.2855 0.290116
+1.286 0.337628
+1.2865 0.382906
+1.287 0.425706
+1.2875 0.465818
+1.288 0.503014
+1.2885 0.537117
+1.289 0.567963
+1.2895 0.595386
+1.29 0.619265
+1.2905 0.639497
+1.291 0.655982
+1.2915 0.66866
+1.292 0.67749
+1.2925 0.682445
+1.293 0.683529
+1.2935 0.680762
+1.294 0.674188
+1.2945 0.663873
+1.295 0.649903
+1.2955 0.632378
+1.296 0.611431
+1.2965 0.587203
+1.297 0.559846
+1.2975 0.529549
+1.298 0.496502
+1.2985 0.46091
+1.299 0.422982
+1.2995 0.382966
+1.3 0.341098
+1.3005 0.297615
+1.301 0.252793
+1.3015 0.206888
+1.302 0.160153
+1.3025 0.112881
+1.303 0.0653285
+1.3035 0.0177578
+1.304 -0.0295412
+1.3045 -0.0763184
+1.305 -0.12231
+1.3055 -0.167275
+1.306 -0.210947
+1.3065 -0.253103
+1.307 -0.293522
+1.3075 -0.331972
+1.308 -0.368263
+1.3085 -0.402213
+1.309 -0.433632
+1.3095 -0.462372
+1.31 -0.488293
+1.3105 -0.511273
+1.311 -0.531196
+1.3115 -0.547979
+1.312 -0.561554
+1.3125 -0.571864
+1.313 -0.578879
+1.3135 -0.582586
+1.314 -0.582988
+1.3145 -0.58011
+1.315 -0.573992
+1.3155 -0.564696
+1.316 -0.552299
+1.3165 -0.536896
+1.317 -0.518591
+1.3175 -0.497519
+1.318 -0.473817
+1.3185 -0.447633
+1.319 -0.419146
+1.3195 -0.38853
+1.32 -0.355965
+1.3205 -0.321666
+1.321 -0.285832
+1.3215 -0.248678
+1.322 -0.210415
+1.3225 -0.171283
+1.323 -0.131504
+1.3235 -0.0912962
+1.324 -0.0509088
+1.3245 -0.010559
+1.325 0.0295323
+1.3255 0.0691231
+1.326 0.108006
+1.3265 0.145975
+1.327 0.182804
+1.3275 0.218306
+1.328 0.252293
+1.3285 0.28459
+1.329 0.315015
+1.3295 0.343422
+1.33 0.36967
+1.3305 0.393617
+1.331 0.415155
+1.3315 0.434186
+1.332 0.450615
+1.3325 0.464374
+1.333 0.475409
+1.3335 0.483681
+1.334 0.489164
+1.3345 0.491851
+1.335 0.49175
+1.3355 0.488885
+1.336 0.483296
+1.3365 0.475034
+1.337 0.464172
+1.3375 0.450793
+1.338 0.434987
+1.3385 0.416873
+1.339 0.396566
+1.3395 0.374203
+1.34 0.349919
+1.3405 0.323877
+1.341 0.296237
+1.3415 0.267158
+1.342 0.236831
+1.3425 0.205431
+1.343 0.173136
+1.3435 0.140152
+1.344 0.10666
+1.3445 0.0728565
+1.345 0.0389249
+1.3455 0.00507432
+1.346 -0.0285154
+1.3465 -0.0616621
+1.347 -0.0941679
+1.3475 -0.125865
+1.348 -0.156587
+1.3485 -0.186154
+1.349 -0.21442
+1.3495 -0.241233
+1.35 -0.266463
+1.3505 -0.289968
+1.351 -0.311639
+1.3515 -0.331373
+1.352 -0.349066
+1.3525 -0.364641
+1.353 -0.378033
+1.3535 -0.389178
+1.354 -0.398036
+1.3545 -0.404581
+1.355 -0.408791
+1.3555 -0.410665
+1.356 -0.410214
+1.3565 -0.407459
+1.357 -0.402438
+1.3575 -0.395199
+1.358 -0.385801
+1.3585 -0.374318
+1.359 -0.360833
+1.3595 -0.345436
+1.36 -0.328238
+1.3605 -0.309349
+1.361 -0.28889
+1.3615 -0.266984
+1.362 -0.243779
+1.3625 -0.219413
+1.363 -0.194027
+1.3635 -0.167785
+1.364 -0.140837
+1.3645 -0.113335
+1.365 -0.0854513
+1.3655 -0.0573394
+1.366 -0.029155
+1.3665 -0.00107051
+1.367 0.0267653
+1.3675 0.0541951
+1.368 0.081076
+1.3685 0.107248
+1.369 0.132578
+1.3695 0.156935
+1.37 0.18018
+1.3705 0.202198
+1.371 0.22288
+1.3715 0.242113
+1.372 0.259807
+1.3725 0.275877
+1.373 0.290249
+1.3735 0.302851
+1.374 0.313635
+1.3745 0.322555
+1.375 0.329577
+1.3755 0.334679
+1.376 0.337853
+1.3765 0.339096
+1.377 0.338421
+1.3775 0.335848
+1.378 0.33141
+1.3785 0.325151
+1.379 0.317123
+1.3795 0.307384
+1.38 0.29601
+1.3805 0.28308
+1.381 0.268677
+1.3815 0.252901
+1.382 0.235854
+1.3825 0.217638
+1.383 0.198376
+1.3835 0.178181
+1.384 0.157178
+1.3845 0.135485
+1.385 0.113243
+1.3855 0.0905775
+1.386 0.0676144
+1.3865 0.0444974
+1.387 0.0213512
+1.3875 -0.00169693
+1.388 -0.0245075
+1.3885 -0.0469612
+1.389 -0.0689382
+1.3895 -0.0903091
+1.39 -0.110965
+1.3905 -0.130798
+1.391 -0.149706
+1.3915 -0.167583
+1.392 -0.184345
+1.3925 -0.199909
+1.393 -0.214193
+1.3935 -0.227132
+1.394 -0.238671
+1.3945 -0.248751
+1.395 -0.257333
+1.3955 -0.264384
+1.396 -0.269879
+1.3965 -0.2738
+1.397 -0.276143
+1.3975 -0.27691
+1.398 -0.276112
+1.3985 -0.273768
+1.399 -0.269907
+1.3995 -0.264566
+1.4 -0.257791
+1.4005 -0.24963
+1.401 -0.24015
+1.4015 -0.229412
+1.402 -0.217492
+1.4025 -0.204464
+1.403 -0.190419
+1.4035 -0.175444
+1.404 -0.159629
+1.4045 -0.143078
+1.405 -0.12589
+1.4055 -0.108162
+1.406 -0.0900087
+1.4065 -0.0715316
+1.407 -0.0528399
+1.4075 -0.0340354
+1.408 -0.0152348
+1.4085 0.00346174
+1.409 0.0219525
+1.4095 0.0401271
+1.41 0.0578917
+1.4105 0.075153
+1.411 0.0918109
+1.4115 0.107783
+1.412 0.122984
+1.4125 0.137342
+1.413 0.150776
+1.4135 0.163224
+1.414 0.174628
+1.4145 0.18493
+1.415 0.194085
+1.4155 0.202056
+1.416 0.208806
+1.4165 0.214311
+1.417 0.218554
+1.4175 0.221523
+1.418 0.223215
+1.4185 0.223633
+1.419 0.222789
+1.4195 0.2207
+1.42 0.217392
+1.4205 0.212893
+1.421 0.207245
+1.4215 0.200491
+1.422 0.192677
+1.4225 0.183863
+1.423 0.174107
+1.4235 0.163474
+1.424 0.152031
+1.4245 0.139855
+1.425 0.127022
+1.4255 0.113606
+1.426 0.0996952
+1.4265 0.0853719
+1.427 0.0707171
+1.4275 0.0558222
+1.428 0.0407716
+1.4285 0.0256487
+1.429 0.0105456
+1.4295 -0.00445414
+1.43 -0.0192702
+1.4305 -0.0338223
+1.431 -0.0480254
+1.4315 -0.0618046
+1.432 -0.0750923
+1.4325 -0.0878121
+1.433 -0.099901
+1.4335 -0.1113
+1.434 -0.121947
+1.4345 -0.131792
+1.435 -0.140791
+1.4355 -0.148901
+1.436 -0.156084
+1.4365 -0.16231
+1.437 -0.167557
+1.4375 -0.171803
+1.438 -0.175036
+1.4385 -0.177249
+1.439 -0.17844
+1.4395 -0.178614
+1.44 -0.17778
+1.4405 -0.175956
+1.441 -0.173161
+1.4415 -0.169423
+1.442 -0.164771
+1.4425 -0.159244
+1.443 -0.152881
+1.4435 -0.145727
+1.444 -0.137834
+1.4445 -0.129251
+1.445 -0.120034
+1.4455 -0.110245
+1.446 -0.0999452
+1.4465 -0.0891962
+1.447 -0.0780621
+1.4475 -0.0666147
+1.448 -0.0549197
+1.4485 -0.0430435
+1.449 -0.031061
+1.4495 -0.0190362
+1.45 -0.00703624
+1.4505 0.00486666
+1.451 0.0166077
+1.4515 0.0281271
+1.452 0.0393566
+1.4525 0.0502385
+1.453 0.0607141
+1.4535 0.0707331
+1.454 0.080239
+1.4545 0.089186
+1.455 0.0975316
+1.4555 0.105232
+1.456 0.112252
+1.4565 0.118563
+1.457 0.124134
+1.4575 0.128943
+1.458 0.132971
+1.4585 0.136205
+1.459 0.138635
+1.4595 0.140258
+1.46 0.141072
+1.4605 0.141083
+1.461 0.140299
+1.4615 0.138735
+1.462 0.136408
+1.4625 0.133339
+1.463 0.129555
+1.4635 0.125086
+1.464 0.119964
+1.4645 0.114225
+1.465 0.107909
+1.4655 0.10106
+1.466 0.093721
+1.4665 0.0859376
+1.467 0.0777623
+1.4675 0.0692449
+1.468 0.0604341
+1.4685 0.0513873
+1.469 0.0421565
+1.4695 0.0327961
+1.47 0.0233583
+1.4705 0.0139021
+1.471 0.00447725
+1.4715 -0.00486436
+1.472 -0.0140672
+1.4725 -0.023082
+1.473 -0.0318637
+1.4735 -0.040361
+1.474 -0.0485311
+1.4745 -0.0563309
+1.475 -0.0637239
+1.4755 -0.0706694
+1.476 -0.0771349
+1.4765 -0.0830908
+1.477 -0.0885072
+1.4775 -0.0933606
+1.478 -0.097632
+1.4785 -0.101302
+1.479 -0.104358
+1.4795 -0.106791
+1.48 -0.108593
+1.4805 -0.109762
+1.481 -0.110299
+1.4815 -0.110208
+1.482 -0.109499
+1.4825 -0.108181
+1.483 -0.106269
+1.4835 -0.103783
+1.484 -0.100741
+1.4845 -0.0971687
+1.485 -0.0930931
+1.4855 -0.088542
+1.486 -0.0835474
+1.4865 -0.0781414
+1.487 -0.0723624
+1.4875 -0.0662454
+1.488 -0.059828
+1.4885 -0.0531529
+1.489 -0.0462602
+1.4895 -0.0391887
+1.49 -0.0319838
+1.4905 -0.0246866
+1.491 -0.0173379
+1.4915 -0.00998256
+1.492 -0.00266161
+1.4925 0.00458557
+1.493 0.0117197
+1.4935 0.018699
+1.494 0.0254867
+1.4945 0.0320496
+1.495 0.03835
+1.4955 0.044357
+1.496 0.0500414
+1.4965 0.0553728
+1.497 0.060326
+1.4975 0.0648789
+1.498 0.0690109
+1.4985 0.0727022
+1.499 0.0759381
+1.4995 0.0787071
+1.5 0.0809979
+1.5005 0.082804
+1.501 0.0841215
+1.5015 0.0849485
+1.502 0.0852869
+1.5025 0.0851406
+1.503 0.0845167
+1.5035 0.0834246
+1.504 0.0818762
+1.5045 0.0798857
+1.505 0.0774705
+1.5055 0.0746493
+1.506 0.0714423
+1.5065 0.0678742
+1.507 0.0639685
+1.5075 0.0597507
+1.508 0.0552504
+1.5085 0.0504961
+1.509 0.045517
+1.5095 0.0403434
+1.51 0.0350091
+1.5105 0.0295451
+1.511 0.0239829
+1.5115 0.0183578
+1.512 0.0127003
+1.5125 0.00704203
+1.513 0.00141726
+1.5135 -0.00414326
+1.514 -0.00961118
+1.5145 -0.014954
+1.515 -0.0201444
+1.5155 -0.0251543
+1.516 -0.0299599
+1.5165 -0.0345342
+1.517 -0.0388552
+1.5175 -0.0429026
+1.518 -0.0466555
+1.5185 -0.0500969
+1.519 -0.0532128
+1.5195 -0.055988
+1.52 -0.058412
+1.5205 -0.0604755
+1.521 -0.0621721
+1.5215 -0.0634961
+1.522 -0.0644453
+1.5225 -0.0650191
+1.523 -0.065219
+1.5235 -0.065049
+1.524 -0.0645145
+1.5245 -0.0636236
+1.525 -0.0623858
+1.5255 -0.0608123
+1.526 -0.0589172
+1.5265 -0.0567147
+1.527 -0.0542215
+1.5275 -0.0514549
+1.528 -0.0484354
+1.5285 -0.0451823
+1.529 -0.0417166
+1.5295 -0.0380621
+1.53 -0.0342415
+1.5305 -0.0302771
+1.531 -0.0261952
+1.5315 -0.0220194
+1.532 -0.0177747
+1.5325 -0.0134851
+1.533 -0.00917742
+1.5335 -0.00487467
+1.534 -0.000600586
+1.5345 0.00361934
+1.535 0.00776245
+1.5355 0.011808
+1.536 0.0157324
+1.5365 0.0195159
+1.537 0.0231387
+1.5375 0.0265838
+1.538 0.0298324
+1.5385 0.0328695
+1.539 0.0356813
+1.5395 0.0382538
+1.54 0.040576
+1.5405 0.0426391
+1.541 0.0444338
+1.5415 0.0459539
+1.542 0.0471948
+1.5425 0.0481527
+1.543 0.0488265
+1.5435 0.0492159
+1.544 0.0493228
+1.5445 0.0491501
+1.545 0.0487028
+1.5455 0.0479869
+1.546 0.0470104
+1.5465 0.0457821
+1.547 0.0443122
+1.5475 0.0426129
+1.548 0.0406963
+1.5485 0.0385765
+1.549 0.0362676
+1.5495 0.0337865
+1.55 0.0311486
+1.5505 0.0283705
+1.551 0.025471
+1.5515 0.0224679
+1.552 0.0193784
+1.5525 0.0162226
+1.553 0.0130187
+1.5535 0.00978465
+1.554 0.00654057
+1.5545 0.00330456
+1.555 9.41526e-05
+1.5555 -0.00307319
+1.556 -0.00617889
+1.5565 -0.00920658
+1.557 -0.0121414
+1.5575 -0.0149667
+1.558 -0.0176684
+1.5585 -0.0202337
+1.559 -0.0226488
+1.5595 -0.0249024
+1.56 -0.0269846
+1.5605 -0.0288861
+1.561 -0.0305979
+1.5615 -0.0321132
+1.562 -0.0334268
+1.5625 -0.0345333
+1.563 -0.0354296
+1.5635 -0.0361138
+1.564 -0.0365846
+1.5645 -0.0368427
+1.565 -0.0368893
+1.5655 -0.0367274
+1.566 -0.0363606
+1.5665 -0.035794
+1.567 -0.0350334
+1.5675 -0.034086
+1.568 -0.0329599
+1.5685 -0.0316634
+1.569 -0.0302072
+1.5695 -0.028601
+1.57 -0.026856
+1.5705 -0.0249845
+1.571 -0.0229988
+1.5715 -0.0209114
+1.572 -0.0187353
+1.5725 -0.0164848
+1.573 -0.0141734
+1.5735 -0.0118144
+1.574 -0.00942313
+1.5745 -0.00701253
+1.575 -0.00459626
+1.5755 -0.00218904
+1.576 0.000195897
+1.5765 0.00254635
+1.577 0.00484833
+1.5775 0.00709001
+1.578 0.00925935
+1.5785 0.011346
+1.579 0.0133383
+1.5795 0.0152267
+1.58 0.0170024
+1.5805 0.0186564
+1.581 0.0201811
+1.5815 0.0215704
+1.582 0.0228178
+1.5825 0.0239184
+1.583 0.0248682
+1.5835 0.0256642
+1.584 0.0263037
+1.5845 0.0267857
+1.585 0.0271096
+1.5855 0.0272758
+1.586 0.0272858
+1.5865 0.0271417
+1.587 0.0268466
+1.5875 0.0264044
+1.588 0.0258195
+1.5885 0.0250978
+1.589 0.0242449
+1.5895 0.0232678
+1.59 0.0221735
+1.5905 0.0209704
+1.591 0.0196666
+1.5915 0.0182707
+1.592 0.0167925
+1.5925 0.0152414
+1.593 0.0136266
+1.5935 0.0119591
+1.594 0.0102487
+1.5945 0.00850564
+1.595 0.00673997
+1.5955 0.00496288
+1.596 0.00318388
+1.5965 0.00141286
+1.597 -0.000339552
+1.5975 -0.00206392
+1.598 -0.00375159
+1.5985 -0.00539271
+1.599 -0.00697904
+1.5995 -0.00850226
+1.6 -0.0099553
+1.6005 -0.0113302
+1.601 -0.0126208
+1.6015 -0.0138211
+1.602 -0.0149253
+1.6025 -0.0159286
+1.603 -0.0168274
+1.6035 -0.0176176
+1.604 -0.0182966
+1.6045 -0.0188622
+1.605 -0.0193128
+1.6055 -0.0196477
+1.606 -0.0198667
+1.6065 -0.0199703
+1.607 -0.0199596
+1.6075 -0.0198365
+1.608 -0.0196032
+1.6085 -0.0192629
+1.609 -0.018819
+1.6095 -0.0182756
+1.61 -0.0176373
+1.6105 -0.0169092
+1.611 -0.0160966
+1.6115 -0.0152053
+1.612 -0.0142421
+1.6125 -0.0132129
+1.613 -0.0121247
+1.6135 -0.0109847
+1.614 -0.00980029
+1.6145 -0.0085782
+1.615 -0.00732657
+1.6155 -0.00605269
+1.616 -0.00476383
+1.6165 -0.00346804
+1.617 -0.00217263
+1.6175 -0.000884652
+1.618 0.000388846
+1.6185 0.00164037
+1.619 0.00286331
+1.6195 0.00405167
+1.62 0.00519866
+1.6205 0.00629867
+1.621 0.0073464
+1.6215 0.00833631
+1.622 0.00926381
+1.6225 0.0101248
+1.623 0.0109155
+1.6235 0.0116322
+1.624 0.0122721
+1.6245 0.012833
+1.625 0.0133127
+1.6255 0.0137097
+1.626 0.0140233
+1.6265 0.0142527
+1.627 0.0143982
+1.6275 0.0144601
+1.628 0.0144394
+1.6285 0.0143375
+1.629 0.0141563
+1.6295 0.0138979
+1.63 0.0135651
+1.6305 0.013161
+1.631 0.0126887
+1.6315 0.0121524
+1.632 0.0115558
+1.6325 0.0109032
+1.633 0.0101994
+1.6335 0.00944909
+1.634 0.00865719
+1.6345 0.00782868
+1.635 0.00696918
+1.6355 0.00608386
+1.636 0.00517796
+1.6365 0.00425738
+1.637 0.00332721
+1.6375 0.00239276
+1.638 0.00145975
+1.6385 0.000533364
+1.639 -0.000381646
+1.6395 -0.00127982
+1.64 -0.00215651
+1.6405 -0.00300703
+1.641 -0.00382731
+1.6415 -0.00461278
+1.642 -0.00535969
+1.6425 -0.00606459
+1.643 -0.00672387
+1.6435 -0.00733459
+1.644 -0.00789433
+1.6445 -0.00840043
+1.645 -0.008851
+1.6455 -0.00924433
+1.646 -0.00957927
+1.6465 -0.00985468
+1.647 -0.01007
+1.6475 -0.010225
+1.648 -0.0103198
+1.6485 -0.0103547
+1.649 -0.0103306
+1.6495 -0.0102486
+1.65 -0.01011
+1.6505 -0.00991643
+1.651 -0.00967006
+1.6515 -0.00937304
+1.652 -0.00902787
+1.6525 -0.0086372
+1.653 -0.00820419
+1.6535 -0.00773181
+1.654 -0.0072233
+1.6545 -0.00668234
+1.655 -0.00611246
+1.6555 -0.00551714
+1.656 -0.00490045
+1.6565 -0.0042661
+1.657 -0.00361798
+1.6575 -0.00295985
+1.658 -0.00229592
+1.6585 -0.00162979
+1.659 -0.000965188
+1.6595 -0.00030613
+1.66 0.000343815
+1.6605 0.000981375
+1.661 0.00160282
+1.6615 0.00220503
+1.662 0.00278484
+1.6625 0.00333958
+1.663 0.00386622
+1.6635 0.00436236
+1.664 0.00482578
+1.6645 0.00525422
+1.665 0.00564587
+1.6655 0.00599927
+1.666 0.00631287
+1.6665 0.00658563
+1.667 0.0068167
+1.6675 0.00700537
+1.668 0.00715136
+1.6685 0.00725453
+1.669 0.007315
+1.6695 0.00733311
+1.67 0.00730949
+1.6705 0.00724495
+1.671 0.00714054
+1.6715 0.00699752
+1.672 0.0068173
+1.6725 0.00660161
+1.673 0.0063522
+1.6735 0.00607104
+1.674 0.00576021
+1.6745 0.0054221
+1.675 0.00505899
+1.6755 0.00467327
+1.676 0.00426768
+1.6765 0.0038448
+1.677 0.00340716
+1.6775 0.0029577
+1.678 0.00249906
+1.6785 0.00203391
+1.679 0.00156519
+1.6795 0.00109555
+1.68 0.000627586
+1.6805 0.000163868
+1.681 -0.000292861
+1.6815 -0.000740179
+1.682 -0.00117589
+1.6825 -0.0015975
+1.683 -0.00200295
+1.6835 -0.00239029
+1.684 -0.00275748
+1.6845 -0.00310282
+1.685 -0.00342479
+1.6855 -0.003722
+1.686 -0.00399306
+1.6865 -0.00423691
+1.687 -0.00445273
+1.6875 -0.00463965
+1.688 -0.00479717
+1.6885 -0.00492489
+1.689 -0.00502256
+1.6895 -0.00509018
+1.69 -0.00512787
+1.6905 -0.00513592
+1.691 -0.00511479
+1.6915 -0.00506511
+1.692 -0.00498762
+1.6925 -0.00488328
+1.693 -0.00475312
+1.6935 -0.00459828
+1.694 -0.00442015
+1.6945 -0.00422009
+1.695 -0.00399955
+1.6955 -0.00376024
+1.696 -0.00350382
+1.6965 -0.00323199
+1.697 -0.00294652
+1.6975 -0.00264937
+1.698 -0.00234237
+1.6985 -0.00202738
+1.699 -0.00170647
+1.6995 -0.00138144
+1.7 -0.00105416
+1.7005 -0.000726663
+1.701 -0.000400775
+1.7015 -7.81849e-05
+1.702 0.000239175
+1.7025 0.000549661
+1.703 0.000851603
+1.7035 0.00114356
+1.704 0.0014239
+1.7045 0.00169129
+1.705 0.0019445
+1.7055 0.00218224
+1.706 0.00240346
+1.7065 0.00260728
+1.707 0.00279274
+1.7075 0.00295915
+1.708 0.0031059
+1.7085 0.00323254
+1.709 0.00333865
+1.7095 0.00342401
+1.71 0.00348852
+1.7105 0.00353213
+1.711 0.00355501
+1.7115 0.00355737
+1.712 0.00353956
+1.7125 0.00350205
+1.713 0.00344537
+1.7135 0.00337022
+1.714 0.00327733
+1.7145 0.00316754
+1.715 0.00304176
+1.7155 0.00290102
+1.716 0.00274636
+1.7165 0.00257887
+1.717 0.0023998
+1.7175 0.00221035
+1.718 0.0020117
+1.7185 0.00180524
+1.719 0.00159225
+1.7195 0.00137404
+1.72 0.0011519
+1.7205 0.000927272
+1.721 0.000701385
+1.7215 0.00047552
+1.722 0.000251046
+1.7225 2.91893e-05
+1.723 -0.000188927
+1.7235 -0.000402025
+1.724 -0.000609027
+1.7245 -0.000808851
+1.725 -0.00100057
+1.7255 -0.00118314
+1.726 -0.00135574
+1.7265 -0.00151759
+1.727 -0.00166791
+1.7275 -0.00180607
+1.728 -0.00193156
+1.7285 -0.00204382
+1.729 -0.0021425
+1.7295 -0.00222728
+1.73 -0.0022979
+1.7305 -0.00235424
+1.731 -0.00239625
+1.7315 -0.00242393
+1.732 -0.00243738
+1.7325 -0.0024368
+1.733 -0.00242243
+1.7335 -0.00239462
+1.734 -0.00235376
+1.7345 -0.0023003
+1.735 -0.00223481
+1.7355 -0.00215786
+1.736 -0.0020701
+1.7365 -0.0019722
+1.737 -0.00186495
+1.7375 -0.00174909
+1.738 -0.00162542
+1.7385 -0.00149484
+1.739 -0.00135819
+1.7395 -0.00121632
+1.74 -0.00107018
+1.7405 -0.000920672
+1.741 -0.000768657
+1.7415 -0.000615112
+1.742 -0.000460919
+1.7425 -0.000306936
+1.743 -0.000154016
+1.7435 -3.06876e-06
+1.744 0.000145101
+1.7445 0.000289763
+1.745 0.000430088
+1.7455 0.000565389
+1.746 0.000695016
+1.7465 0.000818285
+1.747 0.000934631
+1.7475 0.00104354
+1.748 0.00114455
+1.7485 0.00123719
+1.749 0.00132109
+1.7495 0.00139598
+1.75 0.00146156
+1.7505 0.00151765
+1.751 0.0015641
+1.7515 0.00160082
+1.752 0.0016278
+1.7525 0.00164506
+1.753 0.00165268
+1.7535 0.00165079
+1.754 0.0016396
+1.7545 0.00161932
+1.755 0.00159025
+1.7555 0.00155272
+1.756 0.00150709
+1.7565 0.00145379
+1.757 0.00139325
+1.7575 0.00132594
+1.758 0.00125239
+1.7585 0.00117314
+1.759 0.00108873
+1.7595 0.000999717
+1.76 0.000906734
+1.7605 0.000810364
+1.761 0.000711199
+1.7615 0.000609903
+1.762 0.000507054
+1.7625 0.000403251
+1.763 0.000299144
+1.7635 0.000195321
+1.764 9.23221e-05
+1.7645 -9.23019e-06
+1.765 -0.000108808
+1.7655 -0.000205873
+1.766 -0.000299961
+1.7665 -0.000390545
+1.767 -0.000477198
+1.7675 -0.000559518
+1.768 -0.000637087
+1.7685 -0.000709563
+1.769 -0.000776661
+1.7695 -0.000838068
+1.77 -0.000893556
+1.7705 -0.000942918
+1.771 -0.000986009
+1.7715 -0.00102268
+1.772 -0.00105286
+1.7725 -0.0010765
+1.773 -0.00109358
+1.7735 -0.00110414
+1.774 -0.00110824
+1.7745 -0.00110598
+1.775 -0.00109749
+1.7755 -0.00108295
+1.776 -0.00106255
+1.7765 -0.00103652
+1.777 -0.00100512
+1.7775 -0.00096862
+1.778 -0.000927342
+1.7785 -0.0008816
+1.779 -0.000831732
+1.7795 -0.000778123
+1.78 -0.000721143
+1.7805 -0.000661158
+1.781 -0.000598597
+1.7815 -0.000533853
+1.782 -0.000467336
+1.7825 -0.000399443
+1.783 -0.000330622
+1.7835 -0.000261255
+1.784 -0.000191737
+1.7845 -0.000122496
+1.785 -5.39127e-05
+1.7855 1.36643e-05
+1.786 7.98362e-05
+1.7865 0.000144268
+1.787 0.000206621
+1.7875 0.000266607
+1.788 0.000323899
+1.7885 0.000378238
+1.789 0.000429382
+1.7895 0.000477082
+1.79 0.000521141
+1.7905 0.000561396
+1.791 0.000597673
+1.7915 0.00062985
+1.792 0.000657832
+1.7925 0.000681526
+1.793 0.000700895
+1.7935 0.000715909
+1.794 0.000726571
+1.7945 0.0007329
+1.795 0.000734951
+1.7955 0.000732793
+1.796 0.000726522
+1.7965 0.000716255
+1.797 0.000702125
+1.7975 0.000684297
+1.798 0.000662939
+1.7985 0.000638244
+1.799 0.000610412
+1.7995 0.000579676
+1.8 0.000546258
+1.8005 0.000510397
+1.801 0.000472359
+1.8015 0.0004324
+1.802 0.000390768
+1.8025 0.000347756
+1.803 0.000303625
+1.8035 0.00025864
+1.804 0.000213091
+1.8045 0.000167245
+1.805 0.000121358
+1.8055 7.56883e-05
+1.806 3.05086e-05
+1.8065 -1.39384e-05
+1.807 -5.74324e-05
+1.8075 -9.97231e-05
+1.808 -0.000140603
+1.8085 -0.000179876
+1.809 -0.000217334
+1.8095 -0.000252807
+1.81 -0.000286138
+1.8105 -0.000317184
+1.811 -0.000345801
+1.8115 -0.000371879
+1.812 -0.000395332
+1.8125 -0.000416065
+1.813 -0.000434021
+1.8135 -0.000449157
+1.814 -0.000461434
+1.8145 -0.000470848
+1.815 -0.000477401
+1.8155 -0.000481113
+1.816 -0.000482019
+1.8165 -0.000480173
+1.817 -0.000475638
+1.8175 -0.000468496
+1.818 -0.000458841
+1.8185 -0.000446775
+1.819 -0.000432421
+1.8195 -0.000415904
+1.82 -0.000397357
+1.8205 -0.000376935
+1.821 -0.000354791
+1.8215 -0.000331082
+1.822 -0.00030597
+1.8225 -0.000279638
+1.823 -0.000252254
+1.8235 -0.000223991
+1.824 -0.00019504
+1.8245 -0.00016557
+1.825 -0.000135756
+1.8255 -0.000105786
+1.826 -7.58303e-05
+1.8265 -4.60475e-05
+1.827 -1.66184e-05
+1.8275 1.23028e-05
+1.828 4.05593e-05
+1.8285 6.8015e-05
+1.829 9.45162e-05
+1.8295 0.000119937
+1.83 0.000144161
+1.8305 0.000167064
+1.831 0.000188545
+1.8315 0.000208521
+1.832 0.000226898
+1.8325 0.000243609
+1.833 0.000258591
+1.8335 0.0002718
+1.834 0.000283191
+1.8345 0.000292739
+1.835 0.00030043
+1.8355 0.000306253
+1.836 0.000310218
+1.8365 0.000312341
+1.837 0.000312645
+1.8375 0.000311168
+1.838 0.000307953
+1.8385 0.000303058
+1.839 0.000296543
+1.8395 0.00028848
+1.84 0.000278943
+1.8405 0.000268024
+1.841 0.000255809
+1.8415 0.000242393
+1.842 0.000227882
+1.8425 0.00021238
+1.843 0.000195991
+1.8435 0.000178834
+1.844 0.000161019
+1.8445 0.000142662
+1.845 0.000123874
+1.8455 0.000104781
+1.846 8.54898e-05
+1.8465 6.61132e-05
+1.847 4.67707e-05
+1.8475 2.75697e-05
+1.848 8.60894e-06
+1.8485 -9.9992e-06
+1.849 -2.816e-05
+1.8495 -4.57777e-05
+1.85 -6.27703e-05
+1.8505 -7.90457e-05
+1.851 -9.45297e-05
+1.8515 -0.000109154
+1.852 -0.000122847
+1.8525 -0.000135552
+1.853 -0.000147222
+1.8535 -0.000157807
+1.854 -0.000167273
+1.8545 -0.00017559
+1.855 -0.000182733
+1.8555 -0.000188686
+1.856 -0.000193441
+1.8565 -0.000196997
+1.857 -0.000199357
+1.8575 -0.000200535
+1.858 -0.000200548
+1.8585 -0.000199421
+1.859 -0.000197186
+1.8595 -0.000193877
+1.86 -0.000189537
+1.8605 -0.000184212
+1.861 -0.000177954
+1.8615 -0.000170816
+1.862 -0.000162861
+1.8625 -0.000154151
+1.863 -0.000144748
+1.8635 -0.000134726
+1.864 -0.000124152
+1.8645 -0.000113095
+1.865 -0.000101635
+1.8655 -8.98416e-05
+1.866 -7.77878e-05
+1.8665 -6.55524e-05
+1.867 -5.32067e-05
+1.8675 -4.08257e-05
+1.868 -2.8471e-05
+1.8685 -1.62269e-05
+1.869 -4.15112e-06
+1.8695 7.69111e-06
+1.87 1.92326e-05
+1.8705 3.04165e-05
+1.871 4.11889e-05
+1.8715 5.14929e-05
+1.872 6.12822e-05
+1.8725 7.051e-05
+1.873 7.91416e-05
+1.8735 8.71353e-05
+1.874 9.44609e-05
+1.8745 0.000101092
+1.875 0.000107004
+1.8755 0.00011218
+1.876 0.000116607
+1.8765 0.000120274
+1.877 0.000123178
+1.8775 0.000125318
+1.878 0.000126699
+1.8785 0.00012733
+1.879 0.000127223
+1.8795 0.000126395
+1.88 0.000124867
+1.8805 0.000122661
+1.881 0.000119806
+1.8815 0.000116332
+1.882 0.000112273
+1.8825 0.000107661
+1.883 0.000102541
+1.8835 9.69478e-05
+1.884 9.0926e-05
+1.8845 8.45172e-05
+1.885 7.77691e-05
+1.8855 7.07265e-05
+1.886 6.34342e-05
+1.8865 5.59424e-05
+1.887 4.82981e-05
+1.8875 4.05437e-05
+1.888 3.27304e-05
+1.8885 2.49024e-05
+1.889 1.71032e-05
+1.8895 9.37968e-06
+1.89 1.77265e-06
+1.8905 -5.67709e-06
+1.891 -1.2932e-05
+1.8915 -1.9952e-05
+1.892 -2.67025e-05
+1.8925 -3.31548e-05
+1.893 -3.92749e-05
+1.8935 -4.50365e-05
+1.894 -5.04156e-05
+1.8945 -5.53879e-05
+1.895 -5.99352e-05
+1.8955 -6.40408e-05
+1.896 -6.76919e-05
+1.8965 -7.08762e-05
+1.897 -7.35861e-05
+1.8975 -7.58183e-05
+1.898 -7.75691e-05
+1.8985 -7.88397e-05
+1.899 -7.96335e-05
+1.8995 -7.99564e-05
+1.9 -7.98172e-05
+1.9005 -7.92267e-05
+1.901 -7.81986e-05
+1.9015 -7.67485e-05
+1.902 -7.4894e-05
+1.9025 -7.26541e-05
+1.903 -7.00511e-05
+1.9035 -6.71076e-05
+1.904 -6.38472e-05
+1.9045 -6.02969e-05
+1.905 -5.64828e-05
+1.9055 -5.24317e-05
+1.906 -4.81737e-05
+1.9065 -4.37376e-05
+1.907 -3.91513e-05
+1.9075 -3.44439e-05
+1.908 -2.96471e-05
+1.9085 -2.47891e-05
+1.909 -1.98981e-05
+1.9095 -1.50047e-05
+1.91 -1.01359e-05
+1.9105 -5.31799e-06
+1.911 -5.79145e-07
+1.9115 4.05536e-06
+1.912 8.56329e-06
+1.9125 1.29217e-05
+1.913 1.71074e-05
+1.9135 2.11013e-05
+1.914 2.48856e-05
+1.9145 2.8442e-05
+1.915 3.1756e-05
+1.9155 3.48149e-05
+1.916 3.76052e-05
+1.9165 4.01187e-05
+1.917 4.23474e-05
+1.9175 4.4284e-05
+1.918 4.59245e-05
+1.9185 4.72662e-05
+1.919 4.83086e-05
+1.9195 4.90519e-05
+1.92 4.94991e-05
+1.9205 4.96542e-05
+1.921 4.95229e-05
+1.9215 4.91127e-05
+1.922 4.8432e-05
+1.9225 4.74911e-05
+1.923 4.63011e-05
+1.9235 4.48746e-05
+1.924 4.32248e-05
+1.9245 4.13667e-05
+1.925 3.93155e-05
+1.9255 3.70868e-05
+1.926 3.46986e-05
+1.9265 3.21671e-05
+1.927 2.95098e-05
+1.9275 2.67458e-05
+1.928 2.38928e-05
+1.9285 2.09685e-05
+1.929 1.79924e-05
+1.9295 1.49822e-05
+1.93 1.19563e-05
+1.9305 8.93009e-06
+1.931 5.92437e-06
+1.9315 2.95345e-06
+1.932 3.35029e-08
+1.9325 -2.8188e-06
+1.933 -5.58933e-06
+1.9335 -8.26467e-06
+1.934 -1.08307e-05
+1.9345 -1.32758e-05
+1.935 -1.55883e-05
+1.9355 -1.77594e-05
+1.936 -1.97788e-05
+1.9365 -2.16387e-05
+1.937 -2.33327e-05
+1.9375 -2.48541e-05
+1.938 -2.61987e-05
+1.9385 -2.7363e-05
+1.939 -2.83441e-05
+1.9395 -2.9141e-05
+1.94 -2.97534e-05
+1.9405 -3.01817e-05
+1.941 -3.04283e-05
+1.9415 -3.04957e-05
+1.942 -3.03877e-05
+1.9425 -3.0109e-05
+1.943 -2.96653e-05
+1.9435 -2.90626e-05
+1.944 -2.83084e-05
+1.9445 -2.74107e-05
+1.945 -2.63771e-05
+1.9455 -2.52179e-05
+1.946 -2.39418e-05
+1.9465 -2.2559e-05
+1.947 -2.10797e-05
+1.9475 -1.95152e-05
+1.948 -1.7876e-05
+1.9485 -1.61729e-05
+1.949 -1.44179e-05
+1.9495 -1.26222e-05
+1.95 -1.07959e-05
+1.9505 -8.95136e-06
+1.951 -7.09906e-06
+1.9515 -5.24942e-06
+1.952 -3.4137e-06
+1.9525 -1.60169e-06
+1.953 1.76813e-07
+1.9535 1.91279e-06
+1.954 3.59662e-06
+1.9545 5.21993e-06
+1.955 6.77584e-06
+1.9555 8.2561e-06
+1.956 9.65433e-06
+1.9565 1.09648e-05
+1.957 1.21814e-05
+1.9575 1.32999e-05
+1.958 1.4316e-05
+1.9585 1.52266e-05
+1.959 1.60287e-05
+1.9595 1.67201e-05
+1.96 1.73001e-05
+1.9605 1.77676e-05
+1.961 1.81226e-05
+1.9615 1.83659e-05
+1.962 1.84986e-05
+1.9625 1.85226e-05
+1.963 1.84404e-05
+1.9635 1.82549e-05
+1.964 1.79698e-05
+1.9645 1.7589e-05
+1.965 1.71167e-05
+1.9655 1.65582e-05
+1.966 1.59186e-05
+1.9665 1.52032e-05
+1.967 1.44184e-05
+1.9675 1.357e-05
+1.968 1.26642e-05
+1.9685 1.17081e-05
+1.969 1.07082e-05
+1.9695 9.67102e-06
+1.97 8.60324e-06
+1.9705 7.51217e-06
+1.971 6.40439e-06
+1.9715 5.2864e-06
+1.972 4.1653e-06
+1.9725 3.04734e-06
+1.973 1.93862e-06
+1.9735 8.45705e-07
+1.974 -2.25546e-07
+1.9745 -1.26996e-06
+1.975 -2.28218e-06
+1.9755 -3.25681e-06
+1.976 -4.18937e-06
+1.9765 -5.07572e-06
+1.977 -5.91155e-06
+1.9775 -6.69348e-06
+1.978 -7.41846e-06
+1.9785 -8.0833e-06
+1.979 -8.68609e-06
+1.9795 -9.22484e-06
+1.98 -9.69779e-06
+1.9805 -1.01039e-05
+1.981 -1.04426e-05
+1.9815 -1.07135e-05
+1.982 -1.09166e-05
+1.9825 -1.10524e-05
+1.983 -1.11219e-05
+1.9835 -1.11262e-05
+1.984 -1.10668e-05
+1.9845 -1.09457e-05
+1.985 -1.07651e-05
+1.9855 -1.05275e-05
+1.986 -1.02355e-05
+1.9865 -9.89205e-06
+1.987 -9.5006e-06
+1.9875 -9.06445e-06
+1.988 -8.58707e-06
+1.9885 -8.07249e-06
+1.989 -7.5243e-06
+1.9895 -6.94641e-06
+1.99 -6.34309e-06
+1.9905 -5.7183e-06
+1.991 -5.07601e-06
+1.9915 -4.42057e-06
+1.992 -3.75593e-06
+1.9925 -3.08625e-06
+1.993 -2.41497e-06
+1.9935 -1.74674e-06
+1.994 -1.08481e-06
+1.9945 -4.32789e-07
+1.995 2.0556e-07
+1.9955 8.27053e-07
+1.996 1.42867e-06
+1.9965 2.0072e-06
+1.997 2.56005e-06
+1.9975 3.08454e-06
+1.998 3.57871e-06
+1.9985 4.04017e-06
+1.999 4.46717e-06
+1.9995 4.85819e-06
+2 5.21174e-06
+&
local rotation axis of the slab and the Gaussian-weighted positions.
+\section{\normindex{Electric fields}}
+A pulsed and oscillating electric field can be applied according to:
+\begin{equation}
+E(t) = E_0 \exp\left[-\frac{(t-t_0)^2}{2\sigma^2}\right]\cos\left[\omega (t-t_0)\right]
+\label{eq_efield}
+\end{equation}
+where $E_0$ is the field strength, the angular frequency \mbox{$\omega = 2\pi c/\lambda$}, $t_0$ is
+the time at of the peak in the field strength and $\sigma$ is the with
+of the pulse. Special cases occur when $\sigma$ = 0 (non-pulsed field)
+and for $\omega$ is 0 (static field).
+
+This simulated \normindex{laser}-pulse was applied to
+simulations of melting ice~\cite{Caleman2008a}. A pulsed electric field may
+look ike Fig.~\ref{fig:field}. In the supporting
+information of that paper the impact of an applied electric field on a
+system under periodic boundary conditions is analyzed. It is described
+that the effective electric field under PBC is larger than the applied
+field, by a factor depending on the size of the box and the dielectric
+properties of molecules in the box. For a system with static dielectric
+properties this factor can be corrected for. But for a system where
+the dielectric varies over time, for example a membrane protein with
+a pore that opens and closes during the simulatippn, this way of applying
+an electric field is not useful. In such cases one can use the computational
+electrophysiology protocol described in the next section (\secref{compel}).
+\begin{figure}[ht]
+\centerline{\includegraphics[width=8cm]{plots/field}}
+\caption {A simulated laser pulse in GROMACS.}
+\label{fig:field}
+\end{figure}
+
+Electric fields are applied when the following options are specified
+in the {\tt grompp.mdp} file. You specify, in order, $E_0$, $\omega$,
+$t_0$ and $\sigma$:
+\begin{verbatim}
+ElectricField-x = 0.04 0 0 0
+\end{verbatim}
+yields a static field with $E_0$ = 0.04 V/nm in the X-direction. In contrast,
+\begin{verbatim}
+ElectricField-x = 2.0 150 5 0
+\end{verbatim}
+yields an oscillating electric field with $E_0$ = 2 V/nm, $\omega$ = 150/ps and
+$t_0$ = 5 ps. Finally
+\begin{verbatim}
+ElectricField-x = 2.0 150 5 1
+\end{verbatim}
+yields an pulsed-oscillating electric field with $E_0$ = 2 V/nm, $\omega$ = 150/ps and
+$t_0$ = 5 ps and $\sigma$ = 1 ps. Read more in ref.~\cite{Caleman2008a}.
+Note that the input file format is changed from the undocumented older
+version. A figure like Fig.~\ref{fig:field} may be produced by passing
+the {\tt -field} option to {\tt gmx mdrun}.
+
+
\section{\normindex{Computational Electrophysiology}}
\label{sec:compel}
This section lists only major changes; minor changes like additional/removed
options or bug fixes are not typically included.
+Version 2017
+^^^^^^^^^^^^
+
+gmx trajectory
+..............
+
+**new**
+
+:ref:`gmx trajectory` has been introduced as a selection-enabled version of
+:ref:`gmx traj`. It supports output of coordinates, velocities, and/or forces
+for positions calculated for selections.
+
Version 2016
^^^^^^^^^^^^
#
# 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.
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)
/** 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
/* Define if we have feenableexcept */
#cmakedefine01 HAVE_FEENABLEEXCEPT
-/* Define if we have zlib */
-#cmakedefine01 HAVE_ZLIB
-
/*! \endcond */
#endif
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
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)
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
\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.
\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);
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.
\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);
\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);
\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);
\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);
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
#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)
{
tMPI_Coll_root_xfer(comm, sendtype, recvtype,
sendtype->size*sendcount,
recvtype->size*recvcount,
- sendbuf,
+ (void*)sendbuf,
(char*)recvbuf+myrank*recvcount*recvtype->size,
&ret);
}
/* 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;
-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)
{
tMPI_Coll_root_xfer(comm, sendtype, recvtype,
sendtype->size*sendcount,
recvtype->size*recvcounts[myrank],
- sendbuf,
+ (void*)sendbuf,
(char*)recvbuf+displs[myrank]*recvtype->size,
&ret);
}
/* 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;
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
/* 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;
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;
-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)
}
/* 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)
{
/* 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();
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;
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
-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)
{
-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)
{
set(TNG_ROOT_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR})
file(RELATIVE_PATH TNG_ROOT_BINARY_DIR ${CMAKE_SOURCE_DIR} ${TNG_ROOT_SOURCE_DIR})
+if ("${TNG_ROOT_BINARY_DIR}" MATCHES "^\.\.")
+ set(TNG_ROOT_BINARY_DIR tng)
+endif()
set(TNG_ROOT_BINARY_DIR ${CMAKE_BINARY_DIR}/${TNG_ROOT_BINARY_DIR})
function (TNG_GENERATE_VERSION_H)
set(TNG_MAJOR_VERSION "1")
set(TNG_MINOR_VERSION "7")
- set(TNG_VERSION_PATCH_LEVEL "6")
+ set(TNG_VERSION_PATCH_LEVEL "9")
set(TNG_IO_VERSION "${TNG_MAJOR_VERSION}.${TNG_MINOR_VERSION}.${TNG_VERSION_PATCH_LEVEL}")
set(TNG_API_VERSION "7")
configure_file(${TNG_ROOT_SOURCE_DIR}/include/tng/version.h.in
set(TNG_IO_VERSION ${TNG_IO_VERSION} PARENT_SCOPE)
endfunction()
-tng_generate_version_h()
-
include(TestBigEndian)
test_big_endian(TNG_INTEGER_BIG_ENDIAN)
include(CheckIncludeFile)
check_include_file(inttypes.h TNG_HAVE_INTTYPES_H)
+include(CMakeParseArguments)
+
+function(add_tng_io_library NAME)
+ tng_generate_version_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)
- 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_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})
- set(${TNG_COMPILEDEFS})
+ set(_sources)
foreach(_file ${_tng_compression_sources})
- list(APPEND ${TNG_SOURCELIST} ${TNG_ROOT_SOURCE_DIR}/src/compression/${_file})
+ list(APPEND _sources ${TNG_ROOT_SOURCE_DIR}/src/compression/${_file})
endforeach()
foreach(_file ${_tng_io_sources})
- list(APPEND ${TNG_SOURCELIST} ${TNG_ROOT_SOURCE_DIR}/src/lib/${_file})
+ list(APPEND _sources ${TNG_ROOT_SOURCE_DIR}/src/lib/${_file})
endforeach()
if(TNG_BUILD_FORTRAN)
- list(APPEND ${TNG_SOURCELIST} ${TNG_ROOT_SOURCE_DIR}/src/lib/tng_io_fortran.c)
+ list(APPEND _sources ${TNG_ROOT_SOURCE_DIR}/src/lib/tng_io_fortran.c)
endif()
- if (TNG_HAVE_INTTYPES_H)
- list(APPEND ${TNG_COMPILEDEFS} USE_STD_INTTYPES_H)
+
+ set(_options OBJECT OWN_ZLIB)
+ cmake_parse_arguments(ARG "${_options}" "" "" ${ARGN})
+
+ set(_build_target ${NAME})
+ set(_link_type PRIVATE)
+ if (ARG_OBJECT)
+ set(_build_target tng_io_obj)
+ set(_link_type INTERFACE)
+ add_library(${_build_target} OBJECT ${_sources})
+ # PIC is only on by default for SHARED libraries, but in case the
+ # object library is going to get used in such a library, the objects
+ # should be compiled with PIC as well.
+ if (BUILD_SHARED_LIBS)
+ set_target_properties(${_build_target} PROPERTIES POSITION_INDEPENDENT_CODE ON)
+ endif()
+ add_library(${NAME} INTERFACE)
+ target_sources(${NAME} INTERFACE $<TARGET_OBJECTS:tng_io_obj>)
+ else()
+ add_library(${NAME} ${_sources})
+ set_target_properties(${NAME} PROPERTIES
+ VERSION ${TNG_IO_VERSION}
+ SOVERSION ${TNG_MAJOR_VERSION})
+ target_include_directories(${NAME} INTERFACE $<INSTALL_INTERFACE:include>)
endif()
-endmacro()
+ target_include_directories(${_build_target} PRIVATE
+ $<BUILD_INTERFACE:${TNG_ROOT_SOURCE_DIR}/include>
+ $<BUILD_INTERFACE:${TNG_ROOT_BINARY_DIR}/include>)
+ target_include_directories(${NAME} INTERFACE
+ $<BUILD_INTERFACE:${TNG_ROOT_SOURCE_DIR}/include>
+ $<BUILD_INTERFACE:${TNG_ROOT_BINARY_DIR}/include>)
-macro(TNG_SET_SOURCE_PROPERTIES)
- set(_tng_with_zlib OFF)
- set(_curr_var)
- foreach (_arg ${ARGN})
- if (_arg STREQUAL "WITH_ZLIB")
- set(_curr_var with_zlib)
- elseif (_curr_var)
- set(_tng_${_curr_var} ${_arg})
- set(_curr_var "")
- else()
- message(FATAL_ERROR "Invalid argument ${_arg} to TNG_SET_SOURCE_PROPERTIES")
+ if (UNIX)
+ target_link_libraries(${NAME} ${_link_type} m)
+ endif()
+
+ if (ARG_OWN_ZLIB)
+ set(_zlib_dir ${TNG_ROOT_SOURCE_DIR}/external/zlib)
+ set(_zlib_sources)
+ # Add minimal necessary number of TNG source files
+ foreach(_file adler32.c compress.c crc32.c deflate.c inffast.c inflate.c inftrees.c trees.c uncompr.c zutil.c)
+ list(APPEND _zlib_sources ${_zlib_dir}/${_file})
+ endforeach()
+ add_library(tng_io_zlib OBJECT ${_zlib_sources})
+ if (BUILD_SHARED_LIBS)
+ set_target_properties(tng_io_zlib PROPERTIES POSITION_INDEPENDENT_CODE ON)
endif()
- endforeach()
- if (_tng_with_zlib)
- set_property(SOURCE ${TNG_ROOT_SOURCE_DIR}/src/lib/tng_io.c
- APPEND PROPERTY COMPILE_DEFINITIONS USE_ZLIB)
+ target_include_directories(tng_io_zlib PUBLIC ${_zlib_dir})
+ target_include_directories(${_build_target} PRIVATE ${_zlib_dir})
+ target_sources(${NAME} ${_link_type} $<TARGET_OBJECTS:tng_io_zlib>)
+ else()
+ target_link_libraries(${NAME} ${_link_type} ZLIB::ZLIB)
endif()
+
if (TNG_HAVE_INTTYPES_H)
+ target_compile_definitions(${NAME} INTERFACE USE_STD_INTTYPES_H)
set_property(SOURCE ${TNG_ROOT_SOURCE_DIR}/src/lib/tng_io.c
APPEND PROPERTY COMPILE_DEFINITIONS USE_STD_INTTYPES_H)
endif()
set_property(SOURCE ${TNG_ROOT_SOURCE_DIR}/src/lib/md5.c
APPEND PROPERTY COMPILE_DEFINITIONS TNG_INTEGER_BIG_ENDIAN)
endif()
-endmacro()
+endfunction()
-cmake_minimum_required(VERSION 2.8.8)
+cmake_minimum_required(VERSION 3.1)
project(TNG_IO)
-
if("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wall")
elseif(WIN32)
endif()
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
option(BUILD_SHARED_LIBS "Enable shared libraries" ON)
option(TNG_BUILD_TEST "Build TNG testing binary." ON)
option(TNG_BUILD_COMPRESSION_TESTS "Build tests of the TNG compression library" OFF)
-find_package(ZLIB QUIET)
-option(TNG_BUILD_WITH_ZLIB "Build TNG with zlib compression" ${ZLIB_FOUND})
+option(TNG_BUILD_OWN_ZLIB "Build and use the internal zlib library" OFF)
+if(NOT TNG_BUILD_OWN_ZLIB)
+ find_package(ZLIB QUIET)
+endif()
include(CheckIncludeFile)
check_include_file(inttypes.h HAVE_INTTYPES_H)
include(BuildTNG.cmake)
-tng_get_source_list(TNG_SOURCES TNG_COMPILE_DEFS)
-
-tng_set_source_properties(WITH_ZLIB ${ZLIB_FOUND})
-
-add_library(tng_io ${TNG_SOURCES})
-
-if (ZLIB_FOUND)
- list(APPEND EXTRA_LIBRARIES ${ZLIB_LIBRARIES})
- include_directories(${ZLIB_INCLUDE_DIRS})
-endif()
-
-if (UNIX)
- list(APPEND EXTRA_LIBRARIES m)
+if (ZLIB_FOUND AND NOT TNG_BUILD_OWN_ZLIB)
+ add_tng_io_library(tng_io)
+else()
+ add_tng_io_library(tng_io OWN_ZLIB)
endif()
-target_link_libraries(tng_io ${EXTRA_LIBRARIES})
-
-set_target_properties(tng_io PROPERTIES VERSION ${TNG_IO_VERSION} SOVERSION ${TNG_MAJOR_VERSION})
+# Use GNUInstallDirs to set paths on multiarch systems
+include(GNUInstallDirs)
# Create the tng_ioConfig.cmake and tng_ioConfigVersion.cmake files for the install tree
-set(CONF_INCLUDE_DIRS "${CMAKE_INSTALL_PREFIX}/include")
configure_file( src/lib/tng_io-config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-config.cmake" @ONLY)
configure_file( src/lib/tng_io-configVersion.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-configVersion.cmake" @ONLY)
-# Use GNUInstallDirst to set paths on multiarch systems
-include(GNUInstallDirs)
+install(TARGETS tng_io
+ EXPORT tng_io
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}")
-# Install the tng_ioConfig.cmake and tng_ioConfigVersion.cmake
-install(FILES
- "${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-config.cmake"
- "${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-configVersion.cmake"
- DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tng_io")
+install(EXPORT tng_io FILE tng_io.cmake
+ NAMESPACE tng_io::
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tng_io")
-install(TARGETS tng_io
- LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
- ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
+install(FILES
+ "${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-config.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/cmake/tng_io-configVersion.cmake"
+ DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/tng_io")
-install(FILES include/tng/tng_io.h include/tng/tng_io_fwd.h ${CMAKE_CURRENT_BINARY_DIR}/include/tng/version.h
+install(FILES
+ include/tng/tng_io.h include/tng/tng_io_fwd.h
+ ${CMAKE_CURRENT_BINARY_DIR}/include/tng/version.h
DESTINATION include/tng)
#-- Add an Option to toggle the generation of the API documentation
endif()
add_subdirectory(src)
-
--- /dev/null
+The libraries included in the external directory are not supported by the TNG developers.
+
+zlib: version 1.2.8, with content not necessary for TNG build removed.
+
+Modifications within source files were
+* minor refactoring in crc32.c to make clear that some code should sometimes be unreachable
+* replacing some undefined behaviour (-1L << 16) with well defined value (~0xFFFFL) in inflate.c
+* commenting out unused zlibCompileFlags() declaration and definition
+* removing unnecessary configurability from zconf.h
+* removing #include of unused gzguts.h
--- /dev/null
+ZLIB DATA COMPRESSION LIBRARY
+
+zlib 1.2.8 is a general purpose data compression library. All the code is
+thread safe. The data format used by the zlib library is described by RFCs
+(Request for Comments) 1950 to 1952 in the files
+http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
+rfc1952 (gzip format).
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
+of the library is given in the file test/example.c which also tests that
+the library is working correctly. Another example is given in the file
+test/minigzip.c. The compression library itself is composed of all source
+files in the root directory.
+
+To compile all files and run the test program, follow the instructions given at
+the top of Makefile.in. In short "./configure; make test", and if that goes
+well, "make install" should work for most flavors of Unix. For Windows, use
+one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use
+make_vms.com.
+
+Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
+<info@winimage.com> for the Windows DLL version. The zlib home page is
+http://zlib.net/ . Before reporting a problem, please check this site to
+verify that you have the latest version of zlib; otherwise get the latest
+version and check whether the problem still exists or not.
+
+PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help.
+
+Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
+issue of Dr. Dobb's Journal; a copy of the article is available at
+http://marknelson.us/1997/01/01/zlib-engine/ .
+
+The changes made in version 1.2.8 are documented in the file ChangeLog.
+
+Unsupported third party contributions are provided in directory contrib/ .
+
+zlib is available in Java using the java.util.zip package, documented at
+http://java.sun.com/developer/technicalArticles/Programming/compression/ .
+
+A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is available
+at CPAN (Comprehensive Perl Archive Network) sites, including
+http://search.cpan.org/~pmqs/IO-Compress-Zlib/ .
+
+A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
+available in Python 1.5 and later versions, see
+http://docs.python.org/library/zlib.html .
+
+zlib is built into tcl: http://wiki.tcl.tk/4610 .
+
+An experimental package to read and write files in .zip format, written on top
+of zlib by Gilles Vollant <info@winimage.com>, is available in the
+contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- For Windows DLL versions, please see win32/DLL_FAQ.txt
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization. With
+ -O, one libpng test fails. The test works in 32 bit mode (with the -n32
+ compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
+ when compiled with cc.
+
+- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+ necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
+ other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS or BEOS.
+
+- For PalmOs, see http://palmzlib.sourceforge.net/
+
+
+Acknowledgments:
+
+ The deflate format used by zlib was defined by Phil Katz. The deflate and
+ zlib specifications were written by L. Peter Deutsch. Thanks to all the
+ people who reported problems and suggested various improvements in zlib; they
+ are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not* receiving
+lengthy legal documents to sign. The sources are provided for free but without
+warranty of any kind. The library has been entirely written by Jean-loup
+Gailly and Mark Adler; it does not include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include in
+the file ChangeLog history information documenting your changes. Please read
+the FAQ for more information on the distribution of modified source versions.
--- /dev/null
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2011 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#define local static
+
+local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
+
+#define BASE 65521 /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware --
+ try it both ways to see which is faster */
+#ifdef NO_DIVIDE
+/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
+ (thank you to John Reiser for pointing this out) */
+# define CHOP(a) \
+ do { \
+ unsigned long tmp = a >> 16; \
+ a &= 0xffffUL; \
+ a += (tmp << 4) - tmp; \
+ } while (0)
+# define MOD28(a) \
+ do { \
+ CHOP(a); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD(a) \
+ do { \
+ CHOP(a); \
+ MOD28(a); \
+ } while (0)
+# define MOD63(a) \
+ do { /* this assumes a is not negative */ \
+ z_off64_t tmp = a >> 32; \
+ a &= 0xffffffffL; \
+ a += (tmp << 8) - (tmp << 5) + tmp; \
+ tmp = a >> 16; \
+ a &= 0xffffL; \
+ a += (tmp << 4) - tmp; \
+ tmp = a >> 16; \
+ a &= 0xffffL; \
+ a += (tmp << 4) - tmp; \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD28(a) a %= BASE
+# define MOD63(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD28(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+local uLong adler32_combine_(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* for negative len, return invalid adler32 as a clue for debugging */
+ if (len2 < 0)
+ return 0xffffffffUL;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ MOD63(len2); /* assumes len2 >= 0 */
+ rem = (unsigned)len2;
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 >= BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
+
+uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
--- /dev/null
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+ int level;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (z_const Bytef *)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+ If the default memLevel or windowBits for deflateInit() is changed, then
+ this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+ uLong sourceLen;
+{
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+ (sourceLen >> 25) + 13;
+}
--- /dev/null
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+
+ DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h.
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Definitions for doing the crc four data bytes at a time. */
+#if !defined(NOBYFOUR) && defined(Z_U4)
+# define BYFOUR
+#endif
+#ifdef BYFOUR
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2));
+
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local z_crc_t FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const z_crc_t FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ z_crc_t c;
+ int n, k;
+ z_crc_t poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0;
+ for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)
+ poly |= (z_crc_t)1 << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (z_crc_t)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = ZSWAP32(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = ZSWAP32(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const z_crc_t FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const z_crc_t FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ",
+ (unsigned long)(table[n]),
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const z_crc_t FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const z_crc_t FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ uInt len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ z_crc_t endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+ /* Minor modifications follow that make clear to compilers that
+ * it is intended that some code is unreachable. */
+ else
+#endif /* BYFOUR */
+ {
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+ }
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register z_crc_t c;
+ register const z_crc_t FAR *buf4;
+
+ c = (z_crc_t)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register z_crc_t c;
+ register const z_crc_t FAR *buf4;
+
+ c = ZSWAP32((z_crc_t)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(ZSWAP32(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+local uLong crc32_combine_(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off64_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case (also disallow negative lengths) */
+ if (len2 <= 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ return crc32_combine_(crc1, crc2, len2);
+}
+
+uLong ZEXPORT crc32_combine64(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off64_t len2;
+{
+ return crc32_combine_(crc1, crc2, len2);
+}
--- /dev/null
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const z_crc_t FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
--- /dev/null
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://tools.ietf.org/html/rfc1951
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local block_state deflate_rle OF((deflate_state *s, int flush));
+local block_state deflate_huff OF((deflate_state *s, int flush));
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */
+#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0))
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+#endif
+ }
+ if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zfree = zcfree;
+#endif
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->gzhead = Z_NULL;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->high_water = 0; /* nothing written to s->window yet */
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt str, n;
+ int wrap;
+ unsigned avail;
+ z_const unsigned char *next;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+ return Z_STREAM_ERROR;
+ s = strm->state;
+ wrap = s->wrap;
+ if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)
+ return Z_STREAM_ERROR;
+
+ /* when using zlib wrappers, compute Adler-32 for provided dictionary */
+ if (wrap == 1)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+ s->wrap = 0; /* avoid computing Adler-32 in read_buf */
+
+ /* if dictionary would fill window, just replace the history */
+ if (dictLength >= s->w_size) {
+ if (wrap == 0) { /* already empty otherwise */
+ CLEAR_HASH(s);
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->insert = 0;
+ }
+ dictionary += dictLength - s->w_size; /* use the tail */
+ dictLength = s->w_size;
+ }
+
+ /* insert dictionary into window and hash */
+ avail = strm->avail_in;
+ next = strm->next_in;
+ strm->avail_in = dictLength;
+ strm->next_in = (z_const Bytef *)dictionary;
+ fill_window(s);
+ while (s->lookahead >= MIN_MATCH) {
+ str = s->strstart;
+ n = s->lookahead - (MIN_MATCH-1);
+ do {
+ UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
+#ifndef FASTEST
+ s->prev[str & s->w_mask] = s->head[s->ins_h];
+#endif
+ s->head[s->ins_h] = (Pos)str;
+ str++;
+ } while (--n);
+ s->strstart = str;
+ s->lookahead = MIN_MATCH-1;
+ fill_window(s);
+ }
+ s->strstart += s->lookahead;
+ s->block_start = (long)s->strstart;
+ s->insert = s->lookahead;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ strm->next_in = next;
+ strm->avail_in = avail;
+ s->wrap = wrap;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateResetKeep (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ int ret;
+
+ ret = deflateResetKeep(strm);
+ if (ret == Z_OK)
+ lm_init(strm->state);
+ return ret;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+ z_streamp strm;
+ gz_headerp head;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ strm->state->gzhead = head;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePending (strm, pending, bits)
+ unsigned *pending;
+ int *bits;
+ z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (pending != Z_NULL)
+ *pending = strm->state->pending;
+ if (bits != Z_NULL)
+ *bits = strm->state->bi_valid;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ deflate_state *s;
+ int put;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))
+ return Z_BUF_ERROR;
+ do {
+ put = Buf_size - s->bi_valid;
+ if (put > bits)
+ put = bits;
+ s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);
+ s->bi_valid += put;
+ _tr_flush_bits(s);
+ value >>= put;
+ bits -= put;
+ } while (bits);
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if ((strategy != s->strategy || func != configuration_table[level].func) &&
+ strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_BLOCK);
+ if (err == Z_BUF_ERROR && s->pending == 0)
+ err = Z_OK;
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+ z_streamp strm;
+ int good_length;
+ int max_lazy;
+ int nice_length;
+ int max_chain;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ s->good_match = good_length;
+ s->max_lazy_match = max_lazy;
+ s->nice_match = nice_length;
+ s->max_chain_length = max_chain;
+ return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds for
+ * every combination of windowBits and memLevel. But even the conservative
+ * upper bound of about 14% expansion does not seem onerous for output buffer
+ * allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong complen, wraplen;
+ Bytef *str;
+
+ /* conservative upper bound for compressed data */
+ complen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
+
+ /* if can't get parameters, return conservative bound plus zlib wrapper */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return complen + 6;
+
+ /* compute wrapper length */
+ s = strm->state;
+ switch (s->wrap) {
+ case 0: /* raw deflate */
+ wraplen = 0;
+ break;
+ case 1: /* zlib wrapper */
+ wraplen = 6 + (s->strstart ? 4 : 0);
+ break;
+ case 2: /* gzip wrapper */
+ wraplen = 18;
+ if (s->gzhead != Z_NULL) { /* user-supplied gzip header */
+ if (s->gzhead->extra != Z_NULL)
+ wraplen += 2 + s->gzhead->extra_len;
+ str = s->gzhead->name;
+ if (str != Z_NULL)
+ do {
+ wraplen++;
+ } while (*str++);
+ str = s->gzhead->comment;
+ if (str != Z_NULL)
+ do {
+ wraplen++;
+ } while (*str++);
+ if (s->gzhead->hcrc)
+ wraplen += 2;
+ }
+ break;
+ default: /* for compiler happiness */
+ wraplen = 6;
+ }
+
+ /* if not default parameters, return conservative bound */
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return complen + wraplen;
+
+ /* default settings: return tight bound for that case */
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+ (sourceLen >> 25) + 13 - 6 + wraplen;
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len;
+ deflate_state *s = strm->state;
+
+ _tr_flush_bits(s);
+ len = s->pending;
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, s->pending_out, len);
+ strm->next_out += len;
+ s->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ s->pending -= len;
+ if (s->pending == 0) {
+ s->pending_out = s->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_BLOCK || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == Z_NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
+ s->status = BUSY_STATE;
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != Z_NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+ }
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
+ }
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+#ifdef GZIP
+ if (s->status == EXTRA_STATE) {
+ if (s->gzhead->extra != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+
+ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size)
+ break;
+ }
+ put_byte(s, s->gzhead->extra[s->gzindex]);
+ s->gzindex++;
+ }
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (s->gzindex == s->gzhead->extra_len) {
+ s->gzindex = 0;
+ s->status = NAME_STATE;
+ }
+ }
+ else
+ s->status = NAME_STATE;
+ }
+ if (s->status == NAME_STATE) {
+ if (s->gzhead->name != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->name[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0) {
+ s->gzindex = 0;
+ s->status = COMMENT_STATE;
+ }
+ }
+ else
+ s->status = COMMENT_STATE;
+ }
+ if (s->status == COMMENT_STATE) {
+ if (s->gzhead->comment != Z_NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->comment[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0)
+ s->status = HCRC_STATE;
+ }
+ else
+ s->status = HCRC_STATE;
+ }
+ if (s->status == HCRC_STATE) {
+ if (s->gzhead->hcrc) {
+ if (s->pending + 2 > s->pending_buf_size)
+ flush_pending(strm);
+ if (s->pending + 2 <= s->pending_buf_size) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ }
+ }
+ else
+ s->status = BUSY_STATE;
+ }
+#endif
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
+ (s->strategy == Z_RLE ? deflate_rle(s, flush) :
+ (*(configuration_table[s->level].func))(s, flush));
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ if (s->lookahead == 0) {
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->insert = 0;
+ }
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE &&
+ status != EXTRA_STATE &&
+ status != NAME_STATE &&
+ status != COMMENT_STATE &&
+ status != HCRC_STATE &&
+ status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ zmemcpy(buf, strm->next_in, len);
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, buf, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, buf, len);
+ }
+#endif
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->insert = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+ * for insufficient lookahead only occur occasionally for performance
+ * reasons. Therefore uninitialized memory will be accessed, and
+ * conditional jumps will be made that depend on those values.
+ * However the length of the match is limited to the lookahead, so
+ * the output of deflate is not affected by the uninitialized values.
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+
+#else /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for FASTEST only
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#endif /* FASTEST */
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) break;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead + s->insert >= MIN_MATCH) {
+ uInt str = s->strstart - s->insert;
+ s->ins_h = s->window[str];
+ UPDATE_HASH(s, s->ins_h, s->window[str + 1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ while (s->insert) {
+ UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);
+#ifndef FASTEST
+ s->prev[str & s->w_mask] = s->head[s->ins_h];
+#endif
+ s->head[s->ins_h] = (Pos)str;
+ str++;
+ s->insert--;
+ if (s->lookahead + s->insert < MIN_MATCH)
+ break;
+ }
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+
+ /* If the WIN_INIT bytes after the end of the current data have never been
+ * written, then zero those bytes in order to avoid memory check reports of
+ * the use of uninitialized (or uninitialised as Julian writes) bytes by
+ * the longest match routines. Update the high water mark for the next
+ * time through here. WIN_INIT is set to MAX_MATCH since the longest match
+ * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
+ */
+ if (s->high_water < s->window_size) {
+ ulg curr = s->strstart + (ulg)(s->lookahead);
+ ulg init;
+
+ if (s->high_water < curr) {
+ /* Previous high water mark below current data -- zero WIN_INIT
+ * bytes or up to end of window, whichever is less.
+ */
+ init = s->window_size - curr;
+ if (init > WIN_INIT)
+ init = WIN_INIT;
+ zmemzero(s->window + curr, (unsigned)init);
+ s->high_water = curr + init;
+ }
+ else if (s->high_water < (ulg)curr + WIN_INIT) {
+ /* High water mark at or above current data, but below current data
+ * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
+ * to end of window, whichever is less.
+ */
+ init = (ulg)curr + WIN_INIT - s->high_water;
+ if (init > s->window_size - s->high_water)
+ init = s->window_size - s->high_water;
+ zmemzero(s->window + s->high_water, (unsigned)init);
+ s->high_water += init;
+ }
+ }
+
+ Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
+ "not enough room for search");
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, last) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (last)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, last) { \
+ FLUSH_BLOCK_ONLY(s, last); \
+ if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ s->insert = 0;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if ((long)s->strstart > s->block_start)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ hash_head = NIL;
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ s->match_length = longest_match (s, hash_head);
+ /* longest_match() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ hash_head = NIL;
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ s->match_length = longest_match (s, hash_head);
+ /* longest_match() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+#endif /* FASTEST */
+
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one. Do not maintain a hash table. (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+ uInt prev; /* byte at distance one to match */
+ Bytef *scan, *strend; /* scan goes up to strend for length of run */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the longest run, plus one for the unrolled loop.
+ */
+ if (s->lookahead <= MAX_MATCH) {
+ fill_window(s);
+ if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* See how many times the previous byte repeats */
+ s->match_length = 0;
+ if (s->lookahead >= MIN_MATCH && s->strstart > 0) {
+ scan = s->window + s->strstart - 1;
+ prev = *scan;
+ if (prev == *++scan && prev == *++scan && prev == *++scan) {
+ strend = s->window + s->strstart + MAX_MATCH;
+ do {
+ } while (prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ prev == *++scan && prev == *++scan &&
+ scan < strend);
+ s->match_length = MAX_MATCH - (int)(strend - scan);
+ if (s->match_length > s->lookahead)
+ s->match_length = s->lookahead;
+ }
+ Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
+ }
+
+ /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->strstart - 1, s->match_length);
+
+ _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ s->insert = 0;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
+
+/* ===========================================================================
+ * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
+ * (It will be regenerated if this run of deflate switches away from Huffman.)
+ */
+local block_state deflate_huff(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we have a literal to write. */
+ if (s->lookahead == 0) {
+ fill_window(s);
+ if (s->lookahead == 0) {
+ if (flush == Z_NO_FLUSH)
+ return need_more;
+ break; /* flush the current block */
+ }
+ }
+
+ /* Output a literal byte */
+ s->match_length = 0;
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ s->insert = 0;
+ if (flush == Z_FINISH) {
+ FLUSH_BLOCK(s, 1);
+ return finish_done;
+ }
+ if (s->last_lit)
+ FLUSH_BLOCK(s, 0);
+ return block_done;
+}
--- /dev/null
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2012 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define Buf_size 16
+/* size of bit buffer in bi_buf */
+
+#define INIT_STATE 42
+#define EXTRA_STATE 69
+#define NAME_STATE 73
+#define COMMENT_STATE 91
+#define HCRC_STATE 103
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ uInt pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ gz_headerp gzhead; /* gzip header information to write */
+ uInt gzindex; /* where in extra, name, or comment */
+ Byte method; /* can only be DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to suppress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ uInt insert; /* bytes at end of window left to insert */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+ ulg high_water;
+ /* High water mark offset in window for initialized bytes -- bytes above
+ * this are set to zero in order to avoid memory check warnings when
+ * longest match routines access bytes past the input. This is then
+ * updated to the new high water mark.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+#define WIN_INIT MAX_MATCH
+/* Number of bytes after end of data in window to initialize in order to avoid
+ memory checker errors from longest match routines */
+
+ /* in trees.c */
+void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
+int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
+ ulg stored_len, int last));
+void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
+void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
+ ulg stored_len, int last));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch ZLIB_INTERNAL _length_code[];
+ extern uch ZLIB_INTERNAL _dist_code[];
+#else
+ extern const uch ZLIB_INTERNAL _length_code[];
+ extern const uch ZLIB_INTERNAL _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
--- /dev/null
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2008, 2010, 2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void ZLIB_INTERNAL inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ z_const unsigned char FAR *in; /* local strm->next_in */
+ z_const unsigned char FAR *last; /* have enough input while in < last */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned wnext; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code here; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ wnext = state->wnext;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ here = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(here.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(here.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ PUP(out) = (unsigned char)(here.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(here.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ here = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(here.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(here.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(here.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ if (state->sane) {
+ strm->msg =
+ (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ if (len <= op - whave) {
+ do {
+ PUP(out) = 0;
+ } while (--len);
+ continue;
+ }
+ len -= op - whave;
+ do {
+ PUP(out) = 0;
+ } while (--op > whave);
+ if (op == 0) {
+ from = out - dist;
+ do {
+ PUP(out) = PUP(from);
+ } while (--len);
+ continue;
+ }
+#endif
+ }
+ from = window - OFF;
+ if (wnext == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (wnext < op) { /* wrap around window */
+ from += wsize + wnext - op;
+ op -= wnext;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (wnext < len) { /* some from start of window */
+ op = wnext;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += wnext - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ here = dcode[here.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ here = lcode[here.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and wnext == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
--- /dev/null
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
--- /dev/null
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications.
+ It is part of the implementation of this library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
--- /dev/null
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2012 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common wnext == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
+ unsigned copy));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateResetKeep(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ if (state->wrap) /* to support ill-conceived Java test suite */
+ strm->adler = state->wrap & 1;
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ state->sane = 1;
+ state->back = -1;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ state->wsize = 0;
+ state->whave = 0;
+ state->wnext = 0;
+ return inflateResetKeep(strm);
+}
+
+int ZEXPORT inflateReset2(strm, windowBits)
+z_streamp strm;
+int windowBits;
+{
+ int wrap;
+ struct inflate_state FAR *state;
+
+ /* get the state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* extract wrap request from windowBits parameter */
+ if (windowBits < 0) {
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48)
+ windowBits &= 15;
+#endif
+ }
+
+ /* set number of window bits, free window if different */
+ if (windowBits && (windowBits < 8 || windowBits > 15))
+ return Z_STREAM_ERROR;
+ if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) {
+ ZFREE(strm, state->window);
+ state->window = Z_NULL;
+ }
+
+ /* update state and reset the rest of it */
+ state->wrap = wrap;
+ state->wbits = (unsigned)windowBits;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ int ret;
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+#endif
+ }
+ if (strm->zfree == (free_func)0)
+#ifdef Z_SOLO
+ return Z_STREAM_ERROR;
+#else
+ strm->zfree = zcfree;
+#endif
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->window = Z_NULL;
+ ret = inflateReset2(strm, windowBits);
+ if (ret != Z_OK) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ }
+ return ret;
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits < 0) {
+ state->hold = 0;
+ state->bits = 0;
+ return Z_OK;
+ }
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,
+ state.lencode[low].bits, state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, end, copy)
+z_streamp strm;
+const Bytef *end;
+unsigned copy;
+{
+ struct inflate_state FAR *state;
+ unsigned dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->wnext = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, end - state->wsize, state->wsize);
+ state->wnext = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->wnext;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->wnext, end - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, end - copy, copy);
+ state->wnext = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->wnext += dist;
+ if (state->wnext == state->wsize) state->wnext = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ z_const unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code here; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (state->wbits == 0)
+ state->wbits = len;
+ else if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = ZSWAP32(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN_; /* decode codes */
+ if (flush == Z_TREES) {
+ DROPBITS(2);
+ goto inf_leave;
+ }
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY_;
+ if (flush == Z_TREES) goto inf_leave;
+ case COPY_:
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (const code FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.val < 16) {
+ DROPBITS(here.bits);
+ state->lens[state->have++] = here.val;
+ }
+ else {
+ if (here.val == 16) {
+ NEEDBITS(here.bits + 2);
+ DROPBITS(here.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (here.val == 17) {
+ NEEDBITS(here.bits + 3);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(here.bits + 7);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* check for end-of-block code (better have one) */
+ if (state->lens[256] == 0) {
+ strm->msg = (char *)"invalid code -- missing end-of-block";
+ state->mode = BAD;
+ break;
+ }
+
+ /* build code tables -- note: do not change the lenbits or distbits
+ values here (9 and 6) without reading the comments in inftrees.h
+ concerning the ENOUGH constants, which depend on those values */
+ state->next = state->codes;
+ state->lencode = (const code FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (const code FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN_;
+ if (flush == Z_TREES) goto inf_leave;
+ case LEN_:
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ if (state->mode == TYPE)
+ state->back = -1;
+ break;
+ }
+ state->back = 0;
+ for (;;) {
+ here = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.op && (here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ state->back += last.bits;
+ }
+ DROPBITS(here.bits);
+ state->back += here.bits;
+ state->length = (unsigned)here.val;
+ if ((int)(here.op) == 0) {
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ state->mode = LIT;
+ break;
+ }
+ if (here.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->back = -1;
+ state->mode = TYPE;
+ break;
+ }
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(here.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ state->back += state->extra;
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->was = state->length;
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ here = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ state->back += last.bits;
+ }
+ DROPBITS(here.bits);
+ state->back += here.bits;
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)here.val;
+ state->extra = (unsigned)(here.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ state->back += state->extra;
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->whave) {
+ if (state->sane) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ Trace((stderr, "inflate.c too far\n"));
+ copy -= state->whave;
+ if (copy > state->length) copy = state->length;
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = 0;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+#endif
+ }
+ if (copy > state->wnext) {
+ copy -= state->wnext;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->wnext - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ ZSWAP32(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (out != strm->avail_out && state->mode < BAD &&
+ (state->mode < CHECK || flush != Z_FINISH)))
+ if (updatewindow(strm, strm->next_out, out - strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0) +
+ (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+Bytef *dictionary;
+uInt *dictLength;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* copy dictionary */
+ if (state->whave && dictionary != Z_NULL) {
+ zmemcpy(dictionary, state->window + state->wnext,
+ state->whave - state->wnext);
+ zmemcpy(dictionary + state->whave - state->wnext,
+ state->window, state->wnext);
+ }
+ if (dictLength != Z_NULL)
+ *dictLength = state->whave;
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long dictid;
+ int ret;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary identifier */
+ if (state->mode == DICT) {
+ dictid = adler32(0L, Z_NULL, 0);
+ dictid = adler32(dictid, dictionary, dictLength);
+ if (dictid != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window using updatewindow(), which will amend the
+ existing dictionary if appropriate */
+ ret = updatewindow(strm, dictionary + dictLength, dictLength);
+ if (ret) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+const unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
+ zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
+
+int ZEXPORT inflateUndermine(strm, subvert)
+z_streamp strm;
+int subvert;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ state->sane = !subvert;
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ return Z_OK;
+#else
+ state->sane = 1;
+ return Z_DATA_ERROR;
+#endif
+}
+
+long ZEXPORT inflateMark(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return ~0xFFFFL; /* Original code returned -1L << 16, but that is undefined behaviour */
+ state = (struct inflate_state FAR *)strm->state;
+ return ((long)(state->back) << 16) +
+ (state->mode == COPY ? state->length :
+ (state->mode == MATCH ? state->was - state->length : 0));
+}
--- /dev/null
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2009 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY_, /* i/o: same as COPY below, but only first time in */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN_, /* i: same as LEN below, but only first time in */
+ LEN, /* i: waiting for length/lit/eob code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to BAD or MEM on error -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib) or (raw)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT ->
+ HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ (raw) -> TYPEDO
+ Read deflate blocks:
+ TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK
+ STORED -> COPY_ -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN_
+ LEN_ -> LEN
+ Read deflate codes in fixed or dynamic block:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 10K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned wnext; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+ int sane; /* if false, allow invalid distance too far */
+ int back; /* bits back of last unprocessed length/lit */
+ unsigned was; /* initial length of match */
+};
--- /dev/null
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.8 Copyright 1995-2013 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code here; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ here.op = (unsigned char)64; /* invalid code marker */
+ here.bits = (unsigned char)1;
+ here.val = (unsigned short)0;
+ *(*table)++ = here; /* make a table to force an error */
+ *(*table)++ = here;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min < max; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked for LENS and DIST tables against
+ the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+ the initial root table size constants. See the comments in inftrees.h
+ for more information.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if ((type == LENS && used > ENOUGH_LENS) ||
+ (type == DISTS && used > ENOUGH_DISTS))
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ here.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ here.op = (unsigned char)0;
+ here.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ here.op = (unsigned char)(extra[work[sym]]);
+ here.val = base[work[sym]];
+ }
+ else {
+ here.op = (unsigned char)(32 + 64); /* end of block */
+ here.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = here;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if ((type == LENS && used > ENOUGH_LENS) ||
+ (type == DISTS && used > ENOUGH_DISTS))
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /* fill in remaining table entry if code is incomplete (guaranteed to have
+ at most one remaining entry, since if the code is incomplete, the
+ maximum code length that was allowed to get this far is one bit) */
+ if (huff != 0) {
+ here.op = (unsigned char)64; /* invalid code marker */
+ here.bits = (unsigned char)(len - drop);
+ here.val = (unsigned short)0;
+ next[huff] = here;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
--- /dev/null
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005, 2010 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of the dynamic table. The maximum number of code structures is
+ 1444, which is the sum of 852 for literal/length codes and 592 for distance
+ codes. These values were found by exhaustive searches using the program
+ examples/enough.c found in the zlib distribtution. The arguments to that
+ program are the number of symbols, the initial root table size, and the
+ maximum bit length of a code. "enough 286 9 15" for literal/length codes
+ returns returns 852, and "enough 30 6 15" for distance codes returns 592.
+ The initial root table size (9 or 6) is found in the fifth argument of the
+ inflate_table() calls in inflate.c and infback.c. If the root table size is
+ changed, then these maximum sizes would be need to be recalculated and
+ updated. */
+#define ENOUGH_LENS 852
+#define ENOUGH_DISTS 592
+#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
+
+/* Type of code to build for inflate_table() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
--- /dev/null
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2012 Jean-loup Gailly
+ * detect_data_type() function provided freely by Cosmin Truta, 2006
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, const ct_data *ltree,
+ const ct_data *dtree));
+local int detect_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (ush)value << s->bi_valid;
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= (ush)value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (ush)val << s->bi_valid;\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (ush)(value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+#ifdef NO_INIT_GLOBAL_POINTERS
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+#endif
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header,
+ "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void ZLIB_INTERNAL _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if ((unsigned) tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int last; /* one if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Flush the bits in the bit buffer to pending output (leaves at most 7 bits)
+ */
+void ZLIB_INTERNAL _tr_flush_bits(s)
+ deflate_state *s;
+{
+ bi_flush(s);
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ */
+void ZLIB_INTERNAL _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int last; /* one if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is binary or text */
+ if (s->strm->data_type == Z_UNKNOWN)
+ s->strm->data_type = detect_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, last);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+last, 3);
+ compress_block(s, (const ct_data *)static_ltree,
+ (const ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+last, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (const ct_data *)s->dyn_ltree,
+ (const ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (last) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*last));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int ZLIB_INTERNAL _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ const ct_data *ltree; /* literal tree */
+ const ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+}
+
+/* ===========================================================================
+ * Check if the data type is TEXT or BINARY, using the following algorithm:
+ * - TEXT if the two conditions below are satisfied:
+ * a) There are no non-portable control characters belonging to the
+ * "black list" (0..6, 14..25, 28..31).
+ * b) There is at least one printable character belonging to the
+ * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
+ * - BINARY otherwise.
+ * - The following partially-portable control characters form a
+ * "gray list" that is ignored in this detection algorithm:
+ * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local int detect_data_type(s)
+ deflate_state *s;
+{
+ /* black_mask is the bit mask of black-listed bytes
+ * set bits 0..6, 14..25, and 28..31
+ * 0xf3ffc07f = binary 11110011111111111100000001111111
+ */
+ unsigned long black_mask = 0xf3ffc07fUL;
+ int n;
+
+ /* Check for non-textual ("black-listed") bytes. */
+ for (n = 0; n <= 31; n++, black_mask >>= 1)
+ if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))
+ return Z_BINARY;
+
+ /* Check for textual ("white-listed") bytes. */
+ if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
+ || s->dyn_ltree[13].Freq != 0)
+ return Z_TEXT;
+ for (n = 32; n < LITERALS; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ return Z_TEXT;
+
+ /* There are no "black-listed" or "white-listed" bytes:
+ * this stream either is empty or has tolerated ("gray-listed") bytes only.
+ */
+ return Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
--- /dev/null
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
--- /dev/null
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003, 2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (z_const Bytef *)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
--- /dev/null
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+#if defined(ZLIB_CONST) && !defined(z_const)
+# define z_const const
+#else
+# define z_const
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+#ifndef Z_ARG /* function prototypes for stdarg */
+# if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# define Z_ARG(args) args
+# else
+# define Z_ARG(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)
+# include <limits.h>
+# if (UINT_MAX == 0xffffffffUL)
+# define Z_U4 unsigned
+# elif (ULONG_MAX == 0xffffffffUL)
+# define Z_U4 unsigned long
+# elif (USHRT_MAX == 0xffffffffUL)
+# define Z_U4 unsigned short
+# endif
+#endif
+
+#ifdef Z_U4
+ typedef Z_U4 z_crc_t;
+#else
+ typedef unsigned long z_crc_t;
+#endif
+
+#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
+# define Z_HAVE_UNISTD_H
+#endif
+
+#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */
+# define Z_HAVE_STDARG_H
+#endif
+
+#ifdef STDC
+# ifndef Z_SOLO
+# include <sys/types.h> /* for off_t */
+# endif
+#endif
+
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# ifndef Z_SOLO
+# include <stdarg.h> /* for va_list */
+# endif
+#endif
+
+#ifdef _WIN32
+# ifndef Z_SOLO
+# include <stddef.h> /* for wchar_t */
+# endif
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1
+# undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
+# define Z_HAVE_UNISTD_H
+#endif
+#ifndef Z_SOLO
+# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# ifndef z_off_t
+# define z_off_t off_t
+# endif
+# endif
+#endif
+
+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0
+# define Z_LFS64
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)
+# define Z_LARGE64
+#endif
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)
+# define Z_WANT64
+#endif
+
+#if !defined(SEEK_SET) && !defined(Z_SOLO)
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if !defined(_WIN32) && defined(Z_LARGE64)
+# define z_off64_t off64_t
+#else
+# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
+# define z_off64_t __int64
+# else
+# define z_off64_t z_off_t
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+ #pragma map(deflateInit_,"DEIN")
+ #pragma map(deflateInit2_,"DEIN2")
+ #pragma map(deflateEnd,"DEEND")
+ #pragma map(deflateBound,"DEBND")
+ #pragma map(inflateInit_,"ININ")
+ #pragma map(inflateInit2_,"ININ2")
+ #pragma map(inflateEnd,"INEND")
+ #pragma map(inflateSync,"INSY")
+ #pragma map(inflateSetDictionary,"INSEDI")
+ #pragma map(compressBound,"CMBND")
+ #pragma map(inflate_table,"INTABL")
+ #pragma map(inflate_fast,"INFA")
+ #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
--- /dev/null
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.8, April 28th, 2013
+
+ Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950
+ (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.8"
+#define ZLIB_VERNUM 0x1280
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 8
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed data.
+ This version of the library supports only one compression method (deflation)
+ but other algorithms will be added later and will have the same stream
+ interface.
+
+ Compression can be done in a single step if the buffers are large enough,
+ or can be done by repeated calls of the compression function. In the latter
+ case, the application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never crash
+ even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ z_const Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total number of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total number of bytes output so far */
+
+ z_const char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has dropped
+ to zero. It must update next_out and avail_out when avail_out has dropped
+ to zero. The application must initialize zalloc, zfree and opaque before
+ calling the init function. All other fields are set by the compression
+ library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this if
+ the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers
+ returned by zalloc for objects of exactly 65536 bytes *must* have their
+ offset normalized to zero. The default allocation function provided by this
+ library ensures this (see zutil.c). To reduce memory requirements and avoid
+ any allocation of 64K objects, at the expense of compression ratio, compile
+ the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or progress
+ reports. After compression, total_in holds the total size of the
+ uncompressed data and may be saved for use in the decompressor (particularly
+ if the decompressor wants to decompress everything in a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+#define Z_TREES 6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is not
+ compatible with the zlib.h header file used by the application. This check
+ is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller. If
+ zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+ allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at all
+ (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION
+ requests a default compromise between speed and compression (currently
+ equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if level is not a valid compression level, or
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION). msg is set to null
+ if there is no error message. deflateInit does not perform any compression:
+ this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications). Some
+ output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating avail_in or avail_out accordingly; avail_out should
+ never be zero before the call. The application can consume the compressed
+ output when it wants, for example when the output buffer is full (avail_out
+ == 0), or after each call of deflate(). If deflate returns Z_OK and with
+ zero avail_out, it must be called again after making room in the output
+ buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumulate before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In
+ particular avail_in is zero after the call if enough output space has been
+ provided before the call.) Flushing may degrade compression for some
+ compression algorithms and so it should be used only when necessary. This
+ completes the current deflate block and follows it with an empty stored block
+ that is three bits plus filler bits to the next byte, followed by four bytes
+ (00 00 ff ff).
+
+ If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+ output buffer, but the output is not aligned to a byte boundary. All of the
+ input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+ This completes the current deflate block and follows it with an empty fixed
+ codes block that is 10 bits long. This assures that enough bytes are output
+ in order for the decompressor to finish the block before the empty fixed code
+ block.
+
+ If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+ for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+ seven bits of the current block are held to be written as the next byte after
+ the next deflate block is completed. In this case, the decompressor may not
+ be provided enough bits at this point in order to complete decompression of
+ the data provided so far to the compressor. It may need to wait for the next
+ block to be emitted. This is for advanced applications that need to control
+ the emission of deflate blocks.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there was
+ enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the stream
+ are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least the
+ value returned by deflateBound (see below). Then deflate is guaranteed to
+ return Z_STREAM_END. If not enough output space is provided, deflate will
+ not return Z_STREAM_END, and it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect the
+ compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case, msg
+ may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the
+ exact value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit() does not process any header information -- that is deferred
+ until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing will
+ resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there is
+ no more input data or no more space in the output buffer (see below about
+ the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating the next_* and avail_* values accordingly. The
+ application can consume the uncompressed output when it wants, for example
+ when the output buffer is full (avail_out == 0), or after each call of
+ inflate(). If inflate returns Z_OK and with zero avail_out, it must be
+ called again after making room in the output buffer because there might be
+ more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+ Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate()
+ stop if and when it gets to the next deflate block boundary. When decoding
+ the zlib or gzip format, this will cause inflate() to return immediately
+ after the header and before the first block. When doing a raw inflate,
+ inflate() will go ahead and process the first block, and will return when it
+ gets to the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64 if
+ inflate() is currently decoding the last block in the deflate stream, plus
+ 128 if inflate() returned immediately after decoding an end-of-block code or
+ decoding the complete header up to just before the first byte of the deflate
+ stream. The end-of-block will not be indicated until all of the uncompressed
+ data from that block has been written to strm->next_out. The number of
+ unused bits may in general be greater than seven, except when bit 7 of
+ data_type is set, in which case the number of unused bits will be less than
+ eight. data_type is set as noted here every time inflate() returns for all
+ flush options, and so can be used to determine the amount of currently
+ consumed input in bits.
+
+ The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+ end of each deflate block header is reached, before any actual data in that
+ block is decoded. This allows the caller to determine the length of the
+ deflate block header for later use in random access within a deflate block.
+ 256 is added to the value of strm->data_type when inflate() returns
+ immediately after reaching the end of the deflate block header.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step (a
+ single call of inflate), the parameter flush should be set to Z_FINISH. In
+ this case all pending input is processed and all pending output is flushed;
+ avail_out must be large enough to hold all of the uncompressed data for the
+ operation to complete. (The size of the uncompressed data may have been
+ saved by the compressor for this purpose.) The use of Z_FINISH is not
+ required to perform an inflation in one step. However it may be used to
+ inform inflate that a faster approach can be used for the single inflate()
+ call. Z_FINISH also informs inflate to not maintain a sliding window if the
+ stream completes, which reduces inflate's memory footprint. If the stream
+ does not complete, either because not all of the stream is provided or not
+ enough output space is provided, then a sliding window will be allocated and
+ inflate() can be called again to continue the operation as if Z_NO_FLUSH had
+ been used.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the effects of the flush parameter in this implementation are
+ on the return value of inflate() as noted below, when inflate() returns early
+ when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of
+ memory for a sliding window when Z_FINISH is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the Adler-32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the Adler-32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically, if requested when
+ initializing with inflateInit2(). Any information contained in the gzip
+ header is not retained, so applications that need that information should
+ instead use raw inflate, see inflateInit2() below, or inflateBack() and
+ perform their own processing of the gzip header and trailer. When processing
+ gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
+ producted so far. The CRC-32 is checked against the gzip trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may
+ then call inflateSync() to look for a good compression block if a partial
+ recovery of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by the
+ caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero), no
+ header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but is
+ slow and reduces compression ratio; memLevel=9 uses maximum memory for
+ optimal speed. The default value is 8. See zconf.h for total memory usage
+ as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as
+ fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The
+ strategy parameter only affects the compression ratio but not the
+ correctness of the compressed output even if it is not set appropriately.
+ Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+ decoder for special applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+ method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+ incompatible with the version assumed by the caller (ZLIB_VERSION). msg is
+ set to null if there is no error message. deflateInit2 does not perform any
+ compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. When using the zlib format, this
+ function must be called immediately after deflateInit, deflateInit2 or
+ deflateReset, and before any call of deflate. When doing raw deflate, this
+ function must be called either before any call of deflate, or immediately
+ after the completion of a deflate block, i.e. after all input has been
+ consumed and all output has been delivered when using any of the flush
+ options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The
+ compressor and decompressor must use exactly the same dictionary (see
+ inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size
+ provided in deflateInit or deflateInit2. Thus the strings most likely to be
+ useful should be put at the end of the dictionary, not at the front. In
+ addition, the current implementation of deflate will use at most the window
+ size minus 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if not at a block boundary for raw deflate). deflateSetDictionary does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and can
+ consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state. The
+ stream will keep the same compression level and any other attributes that
+ may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different strategy.
+ If the compression level is changed, the input available so far is
+ compressed with the old level (and may be flushed); the new level will take
+ effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to be
+ compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+ strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit() or
+ deflateInit2(), and after deflateSetHeader(), if used. This would be used
+ to allocate an output buffer for deflation in a single pass, and so would be
+ called before deflate(). If that first deflate() call is provided the
+ sourceLen input bytes, an output buffer allocated to the size returned by
+ deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed
+ to return Z_STREAM_END. Note that it is possible for the compressed size to
+ be larger than the value returned by deflateBound() if flush options other
+ than Z_FINISH or Z_NO_FLUSH are used.
+*/
+
+ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,
+ unsigned *pending,
+ int *bits));
+/*
+ deflatePending() returns the number of bytes and bits of output that have
+ been generated, but not yet provided in the available output. The bytes not
+ provided would be due to the available output space having being consumed.
+ The number of bits of output not provided are between 0 and 7, where they
+ await more bits to join them in order to fill out a full byte. If pending
+ or bits are Z_NULL, then those values are not set.
+
+ deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+ */
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the bits
+ leftover from a previous deflate stream when appending to it. As such, this
+ function can only be used for raw deflate, and must be used before the first
+ deflate() call after a deflateInit2() or deflateReset(). bits must be less
+ than or equal to 16, and that many of the least significant bits of value
+ will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough
+ room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the
+ source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be zero to request that inflate use the window size in
+ the zlib header of the compressed stream.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a
+ crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit2 does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit2() does not process any header information -- that is
+ deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called at any
+ time to set the dictionary. If the provided dictionary is smaller than the
+ window and there is already data in the window, then the provided dictionary
+ will amend what's there. The application must insure that the dictionary
+ that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,
+ Bytef *dictionary,
+ uInt *dictLength));
+/*
+ Returns the sliding dictionary being maintained by inflate. dictLength is
+ set to the number of bytes in the dictionary, and that many bytes are copied
+ to dictionary. dictionary must have enough space, where 32768 bytes is
+ always enough. If inflateGetDictionary() is called with dictionary equal to
+ Z_NULL, then only the dictionary length is returned, and nothing is copied.
+ Similary, if dictLength is Z_NULL, then it is not set.
+
+ inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
+ stream state is inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a possible full flush point (see above
+ for the description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync searches for a 00 00 FF FF pattern in the compressed data.
+ All full flush points have this pattern, but not all occurrences of this
+ pattern are full flush points.
+
+ inflateSync returns Z_OK if a possible full flush point has been found,
+ Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point
+ has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.
+ In the success case, the application may save the current current value of
+ total_in which indicates where valid compressed data was found. In the
+ error case, the application may repeatedly call inflateSync, providing more
+ input each time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state. The
+ stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+ int windowBits));
+/*
+ This function is the same as inflateReset, but it also permits changing
+ the wrap and window size requests. The windowBits parameter is interpreted
+ the same as it is for inflateInit2.
+
+ inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+ the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ If bits is negative, then the input stream bit buffer is emptied. Then
+ inflatePrime() can be called again to put bits in the buffer. This is used
+ to clear out bits leftover after feeding inflate a block description prior
+ to feeding inflate codes.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+ This function returns two values, one in the lower 16 bits of the return
+ value, and the other in the remaining upper bits, obtained by shifting the
+ return value down 16 bits. If the upper value is -1 and the lower value is
+ zero, then inflate() is currently decoding information outside of a block.
+ If the upper value is -1 and the lower value is non-zero, then inflate is in
+ the middle of a stored block, with the lower value equaling the number of
+ bytes from the input remaining to copy. If the upper value is not -1, then
+ it is the number of bits back from the current bit position in the input of
+ the code (literal or length/distance pair) currently being processed. In
+ that case the lower value is the number of bytes already emitted for that
+ code.
+
+ A code is being processed if inflate is waiting for more input to complete
+ decoding of the code, or if it has completed decoding but is waiting for
+ more output space to write the literal or match data.
+
+ inflateMark() is used to mark locations in the input data for random
+ access, which may be at bit positions, and to note those cases where the
+ output of a code may span boundaries of random access blocks. The current
+ location in the input stream can be determined from avail_in and data_type
+ as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+ inflateMark returns the value noted above or -1 << 16 if the provided
+ source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be
+ used to force inflate() to return immediately after header processing is
+ complete and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When any
+ of extra, name, or comment are not Z_NULL and the respective field is not
+ present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the parameters are invalid, Z_MEM_ERROR if the internal state could not be
+ allocated, or Z_VERSION_ERROR if the version of the library does not match
+ the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *,
+ z_const unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is potentially more efficient than
+ inflate() for file i/o applications, in that it avoids copying between the
+ output and the sliding window by simply making the window itself the output
+ buffer. inflate() can be faster on modern CPUs when used with large
+ buffers. inflateBack() trusts the application to not change the output
+ buffer passed by the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free the
+ allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects only
+ the raw deflate stream to decompress. This is different from the normal
+ behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+ in the deflate stream (in which case strm->msg is set to indicate the nature
+ of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+ In the case of Z_BUF_ERROR, an input or output error can be distinguished
+ using strm->next_in which will be Z_NULL only if in() returned an error. If
+ strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+ non-zero. (in() will always be called before out(), so strm->next_in is
+ assured to be defined if out() returns non-zero.) Note that inflateBack()
+ cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+/* Declaration not used by TNG is not available */
+/*ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));*/
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+#ifndef Z_SOLO
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the basic
+ stream-oriented functions. To simplify the interface, some default options
+ are assumed (compression level and memory usage, standard memory allocation
+ functions). The source code of these utility functions can be modified if
+ you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before a
+ compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be large enough to hold the entire
+ uncompressed data. (The size of the uncompressed data must have been saved
+ previously by the compressor and transmitted to the decompressor by some
+ mechanism outside the scope of this compression library.) Upon exit, destLen
+ is the actual size of the uncompressed buffer.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In
+ the case where there is not enough room, uncompress() will fill the output
+ buffer with the uncompressed data up to that point.
+*/
+
+ /* gzip file access functions */
+
+/*
+ This library supports reading and writing files in gzip (.gz) format with
+ an interface similar to that of stdio, using the functions that start with
+ "gz". The gzip format is different from the zlib format. gzip is a gzip
+ wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+ Opens a gzip (.gz) file for reading or writing. The mode parameter is as
+ in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+ a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+ compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+ for fixed code compression as in "wb9F". (See the description of
+ deflateInit2 for more information about the strategy parameter.) 'T' will
+ request transparent writing or appending with no compression and not using
+ the gzip format.
+
+ "a" can be used instead of "w" to request that the gzip stream that will
+ be written be appended to the file. "+" will result in an error, since
+ reading and writing to the same gzip file is not supported. The addition of
+ "x" when writing will create the file exclusively, which fails if the file
+ already exists. On systems that support it, the addition of "e" when
+ reading or writing will set the flag to close the file on an execve() call.
+
+ These functions, as well as gzip, will read and decode a sequence of gzip
+ streams in a file. The append function of gzopen() can be used to create
+ such a file. (Also see gzflush() for another way to do this.) When
+ appending, gzopen does not test whether the file begins with a gzip stream,
+ nor does it look for the end of the gzip streams to begin appending. gzopen
+ will simply append a gzip stream to the existing file.
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression. When
+ reading, this will be detected automatically by looking for the magic two-
+ byte gzip header.
+
+ gzopen returns NULL if the file could not be opened, if there was
+ insufficient memory to allocate the gzFile state, or if an invalid mode was
+ specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+ errno can be checked to determine if the reason gzopen failed was that the
+ file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen associates a gzFile with the file descriptor fd. File descriptors
+ are obtained from calls like open, dup, creat, pipe or fileno (if the file
+ has been previously opened with fopen). The mode parameter is as in gzopen.
+
+ The next call of gzclose on the returned gzFile will also close the file
+ descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+ fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+ mode);. The duplicated descriptor should be saved to avoid a leak, since
+ gzdopen does not close fd if it fails. If you are using fileno() to get the
+ file descriptor from a FILE *, then you will have to use dup() to avoid
+ double-close()ing the file descriptor. Both gzclose() and fclose() will
+ close the associated file descriptor, so they need to have different file
+ descriptors.
+
+ gzdopen returns NULL if there was insufficient memory to allocate the
+ gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+ provided, or '+' was provided), or if fd is -1. The file descriptor is not
+ used until the next gz* read, write, seek, or close operation, so gzdopen
+ will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+ Set the internal buffer size used by this library's functions. The
+ default buffer size is 8192 bytes. This function must be called after
+ gzopen() or gzdopen(), and before any other calls that read or write the
+ file. The buffer memory allocation is always deferred to the first read or
+ write. Two buffers are allocated, either both of the specified size when
+ writing, or one of the specified size and the other twice that size when
+ reading. A larger buffer size of, for example, 64K or 128K bytes will
+ noticeably increase the speed of decompression (reading).
+
+ The new buffer size also affects the maximum length for gzprintf().
+
+ gzbuffer() returns 0 on success, or -1 on failure, such as being called
+ too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file. If
+ the input file is not in gzip format, gzread copies the given number of
+ bytes into the buffer directly from the file.
+
+ After reaching the end of a gzip stream in the input, gzread will continue
+ to read, looking for another gzip stream. Any number of gzip streams may be
+ concatenated in the input file, and will all be decompressed by gzread().
+ If something other than a gzip stream is encountered after a gzip stream,
+ that remaining trailing garbage is ignored (and no error is returned).
+
+ gzread can be used to read a gzip file that is being concurrently written.
+ Upon reaching the end of the input, gzread will return with the available
+ data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then
+ gzclearerr can be used to clear the end of file indicator in order to permit
+ gzread to be tried again. Z_OK indicates that a gzip stream was completed
+ on the last gzread. Z_BUF_ERROR indicates that the input file ended in the
+ middle of a gzip stream. Note that gzread does not return -1 in the event
+ of an incomplete gzip stream. This error is deferred until gzclose(), which
+ will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip
+ stream. Alternatively, gzerror can be used before gzclose to detect this
+ case.
+
+ gzread returns the number of uncompressed bytes actually read, less than
+ len for end of file, or -1 for error.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes written or 0 in case of
+ error.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the arguments to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written, or 0 in case of error. The number of
+ uncompressed bytes written is limited to 8191, or one less than the buffer
+ size given to gzbuffer(). The caller should assure that this limit is not
+ exceeded. If it is exceeded, then gzprintf() will return an error (0) with
+ nothing written. In this case, there may also be a buffer overflow with
+ unpredictable consequences, which is possible only if zlib was compiled with
+ the insecure functions sprintf() or vsprintf() because the secure snprintf()
+ or vsnprintf() functions were not available. This can be determined using
+ zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or a
+ newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. If any characters are read or if len == 1, the
+ string is terminated with a null character. If no characters are read due
+ to an end-of-file or len < 1, then the buffer is left untouched.
+
+ gzgets returns buf which is a null-terminated string, or it returns NULL
+ for end-of-file or in case of error. If there was an error, the contents at
+ buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file. gzputc
+ returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte or -1
+ in case of end of file or error. This is implemented as a macro for speed.
+ As such, it does not do all of the checking the other functions do. I.e.
+ it does not check to see if file is NULL, nor whether the structure file
+ points to has been clobbered or not.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read as the first character
+ on the next read. At least one character of push-back is allowed.
+ gzungetc() returns the character pushed, or -1 on failure. gzungetc() will
+ fail if c is -1, and may fail if a character has been pushed but not read
+ yet. If gzungetc is used immediately after gzopen or gzdopen, at least the
+ output buffer size of pushed characters is allowed. (See gzbuffer above.)
+ The pushed character will be discarded if the stream is repositioned with
+ gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter flush
+ is as in the deflate() function. The return value is the zlib error number
+ (see function gzerror below). gzflush is only permitted when writing.
+
+ If the flush parameter is Z_FINISH, the remaining data is written and the
+ gzip stream is completed in the output. If gzwrite() is called again, a new
+ gzip stream will be started in the output. gzread() is able to read such
+ concatented gzip streams.
+
+ gzflush should be called only when strictly necessary because it will
+ degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+
+ Returns the starting position for the next gzread or gzwrite on the given
+ compressed file. This position represents a number of bytes in the
+ uncompressed data stream, and is zero when starting, even if appending or
+ reading a gzip stream from the middle of a file using gzdopen().
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+ Returns the current offset in the file being read or written. This offset
+ includes the count of bytes that precede the gzip stream, for example when
+ appending or when using gzdopen() for reading. When reading, the offset
+ does not include as yet unused buffered input. This information can be used
+ for a progress indicator. On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns true (1) if the end-of-file indicator has been set while reading,
+ false (0) otherwise. Note that the end-of-file indicator is set only if the
+ read tried to go past the end of the input, but came up short. Therefore,
+ just like feof(), gzeof() may return false even if there is no more data to
+ read, in the event that the last read request was for the exact number of
+ bytes remaining in the input file. This will happen if the input file size
+ is an exact multiple of the buffer size.
+
+ If gzeof() returns true, then the read functions will return no more data,
+ unless the end-of-file indicator is reset by gzclearerr() and the input file
+ has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns true (1) if file is being copied directly while reading, or false
+ (0) if file is a gzip stream being decompressed.
+
+ If the input file is empty, gzdirect() will return true, since the input
+ does not contain a gzip stream.
+
+ If gzdirect() is used immediately after gzopen() or gzdopen() it will
+ cause buffers to be allocated to allow reading the file to determine if it
+ is a gzip file. Therefore if gzbuffer() is used, it should be called before
+ gzdirect().
+
+ When writing, gzdirect() returns true (1) if transparent writing was
+ requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note:
+ gzdirect() is not needed when writing. Transparent writing must be
+ explicitly requested, so the application already knows the answer. When
+ linking statically, using gzdirect() will include all of the zlib code for
+ gzip file reading and decompression, which may not be desired.)
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file and
+ deallocates the (de)compression state. Note that once file is closed, you
+ cannot call gzerror with file, since its structures have been deallocated.
+ gzclose must not be called more than once on the same file, just as free
+ must not be called more than once on the same allocation.
+
+ gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+ file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the
+ last read ended in the middle of a gzip stream, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+ Same as gzclose(), but gzclose_r() is only for use when reading, and
+ gzclose_w() is only for use when writing or appending. The advantage to
+ using these instead of gzclose() is that they avoid linking in zlib
+ compression or decompression code that is not used when only reading or only
+ writing respectively. If gzclose() is used, then both compression and
+ decompression code will be included the application when linking to a static
+ zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the given
+ compressed file. errnum is set to zlib error number. If an error occurred
+ in the file system and not in the compression library, errnum is set to
+ Z_ERRNO and the application may consult errno to get the exact error code.
+
+ The application must not modify the returned string. Future calls to
+ this function may invalidate the previously returned string. If file is
+ closed, then the string previously returned by gzerror will no longer be
+ available.
+
+ gzerror() should be used to distinguish errors from end-of-file for those
+ functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+#endif /* !Z_SOLO */
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the compression
+ library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is Z_NULL, this function returns the
+ required initial value for the checksum.
+
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster.
+
+ Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note
+ that the z_off_t type (like off_t) is a signed integer. If len2 is
+ negative, the result has no meaning or utility.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is Z_NULL, this function returns the required
+ initial value for the crc. Pre- and post-conditioning (one's complement) is
+ performed within this function so it shouldn't be done by the application.
+
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
+ (int)sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, (int)sizeof(z_stream))
+
+#ifndef Z_SOLO
+
+/* gzgetc() macro and its supporting function and exposed data structure. Note
+ * that the real internal state is much larger than the exposed structure.
+ * This abbreviated structure exposes just enough for the gzgetc() macro. The
+ * user should not mess with these exposed elements, since their names or
+ * behavior could change in the future, perhaps even capriciously. They can
+ * only be used by the gzgetc() macro. You have been warned.
+ */
+struct gzFile_s {
+ unsigned have;
+ unsigned char *next;
+ z_off64_t pos;
+};
+ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
+#ifdef Z_PREFIX_SET
+# undef z_gzgetc
+# define z_gzgetc(g) \
+ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#else
+# define gzgetc(g) \
+ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+#endif
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#ifdef Z_LARGE64
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+ ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)
+# ifdef Z_PREFIX_SET
+# define z_gzopen z_gzopen64
+# define z_gzseek z_gzseek64
+# define z_gztell z_gztell64
+# define z_gzoffset z_gzoffset64
+# define z_adler32_combine z_adler32_combine64
+# define z_crc32_combine z_crc32_combine64
+# else
+# define gzopen gzopen64
+# define gzseek gzseek64
+# define gztell gztell64
+# define gzoffset gzoffset64
+# define adler32_combine adler32_combine64
+# define crc32_combine crc32_combine64
+# endif
+# ifndef Z_LARGE64
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+# endif
+#else
+ ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+#else /* Z_SOLO */
+
+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+
+#endif /* !Z_SOLO */
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void));
+ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));
+ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp));
+ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp));
+#if defined(_WIN32) && !defined(Z_SOLO)
+ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path,
+ const char *mode));
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# ifndef Z_SOLO
+ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file,
+ const char *format,
+ va_list va));
+# endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
--- /dev/null
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+z_const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+/* This function is not used by TNG
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch ((int)(sizeof(uInt))) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch ((int)(sizeof(uLong))) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch ((int)(sizeof(voidpf))) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch ((int)(sizeof(z_off_t))) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#if defined(STDC) || defined(Z_HAVE_STDARG_H)
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+*/
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int ZLIB_INTERNAL z_verbose = verbose;
+
+void ZLIB_INTERNAL z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void ZLIB_INTERNAL zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int ZLIB_INTERNAL zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void ZLIB_INTERNAL zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+#ifndef Z_SOLO
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void ZLIB_INTERNAL zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
+
+#endif /* !Z_SOLO */
--- /dev/null
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#ifdef HAVE_HIDDEN
+# define ZLIB_INTERNAL __attribute__((visibility ("hidden")))
+#else
+# define ZLIB_INTERNAL
+#endif
+
+#include "zlib.h"
+
+#if defined(STDC) && !defined(Z_SOLO)
+# if !(defined(_WIN32_WCE) && defined(_MSC_VER))
+# include <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#ifdef Z_SOLO
+ typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# ifndef Z_SOLO
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+# if defined(M_I86) && !defined(Z_SOLO)
+# include <malloc.h>
+# endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# ifndef Z_SOLO
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+#if defined(__BORLANDC__) && !defined(MSDOS)
+ #pragma warn -8004
+ #pragma warn -8008
+ #pragma warn -8066
+#endif
+
+/* provide prototypes for these when building zlib without LFS */
+#if !defined(_WIN32) && \
+ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(pyr) || defined(Z_SOLO)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int ZLIB_INTERNAL z_verbose;
+ extern void ZLIB_INTERNAL z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+#ifndef Z_SOLO
+ voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
+ unsigned size));
+ void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
+#endif
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+/* Reverse the bytes in a 32-bit value */
+#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+#endif /* ZUTIL_H */
#define TNG_GMX_ENERGY_TEMPERATURE 0x1000000010000011LL
#define TNG_GMX_ENERGY_PRESSURE 0x1000000010000012LL
#define TNG_GMX_ENERGY_CONSTR_RMSD 0x1000000010000013LL
-#define TNG_GMX_ENERGY_BOX_X 0x1000000010000014LL
-#define TNG_GMX_ENERGY_BOX_Y 0x1000000010000015LL
-#define TNG_GMX_ENERGY_BOX_Z 0x1000000010000016LL
-#define TNG_GMX_ENERGY_VOLUME 0x1000000010000017LL
-#define TNG_GMX_ENERGY_DENSITY 0x1000000010000018LL
-#define TNG_GMX_ENERGY_PV 0x1000000010000019LL
-#define TNG_GMX_ENERGY_ENTHALPY 0x1000000010000020LL
-#define TNG_GMX_ENERGY_VIR_XX 0x1000000010000021LL
-#define TNG_GMX_ENERGY_VIR_XY 0x1000000010000022LL
-#define TNG_GMX_ENERGY_VIR_XZ 0x1000000010000023LL
-#define TNG_GMX_ENERGY_VIR_YX 0x1000000010000024LL
-#define TNG_GMX_ENERGY_VIR_YY 0x1000000010000025LL
-#define TNG_GMX_ENERGY_VIR_YZ 0x1000000010000026LL
-#define TNG_GMX_ENERGY_VIR_ZX 0x1000000010000027LL
-#define TNG_GMX_ENERGY_VIR_ZY 0x1000000010000028LL
-#define TNG_GMX_ENERGY_VIR_ZZ 0x1000000010000029LL
-#define TNG_GMX_ENERGY_PRES_XX 0x1000000010000030LL
-#define TNG_GMX_ENERGY_PRES_XY 0x1000000010000031LL
-#define TNG_GMX_ENERGY_PRES_XZ 0x1000000010000032LL
-#define TNG_GMX_ENERGY_PRES_YX 0x1000000010000033LL
-#define TNG_GMX_ENERGY_PRES_YY 0x1000000010000034LL
-#define TNG_GMX_ENERGY_PRES_YZ 0x1000000010000035LL
-#define TNG_GMX_ENERGY_PRES_ZX 0x1000000010000036LL
-#define TNG_GMX_ENERGY_PRES_ZY 0x1000000010000037LL
-#define TNG_GMX_ENERGY_PRES_ZZ 0x1000000010000038LL
-#define TNG_GMX_ENERGY_SURFXSURFTEN 0x1000000010000039LL
-#define TNG_GMX_ENERGY_T_SYSTEM 0x1000000010000040LL
-#define TNG_GMX_ENERGY_LAMB_SYSTEM 0x1000000010000041LL
-#define TNG_GMX_SELECTION_GROUP_NAMES 0x1000000010000042LL
-#define TNG_GMX_ATOM_SELECTION_GROUP 0x1000000010000043LL
+#define TNG_GMX_ENERGY_CONSTR2_RMSD 0x1000000010000014LL
+#define TNG_GMX_ENERGY_BOX_X 0x1000000010000015LL
+#define TNG_GMX_ENERGY_BOX_Y 0x1000000010000016LL
+#define TNG_GMX_ENERGY_BOX_Z 0x1000000010000017LL
+#define TNG_GMX_ENERGY_BOXXX 0x1000000010000018LL
+#define TNG_GMX_ENERGY_BOXYY 0x1000000010000019LL
+#define TNG_GMX_ENERGY_BOXZZ 0x1000000010000020LL
+#define TNG_GMX_ENERGY_BOXYX 0x1000000010000021LL
+#define TNG_GMX_ENERGY_BOXZX 0x1000000010000022LL
+#define TNG_GMX_ENERGY_BOXZY 0x1000000010000023LL
+#define TNG_GMX_ENERGY_BOXVELXX 0x1000000010000024LL
+#define TNG_GMX_ENERGY_BOXVELYY 0x1000000010000025LL
+#define TNG_GMX_ENERGY_BOXVELZZ 0x1000000010000026LL
+#define TNG_GMX_ENERGY_BOXVELYX 0x1000000010000027LL
+#define TNG_GMX_ENERGY_BOXVELZX 0x1000000010000028LL
+#define TNG_GMX_ENERGY_BOXVELZY 0x1000000010000029LL
+#define TNG_GMX_ENERGY_VOLUME 0x1000000010000030LL
+#define TNG_GMX_ENERGY_DENSITY 0x1000000010000031LL
+#define TNG_GMX_ENERGY_PV 0x1000000010000032LL
+#define TNG_GMX_ENERGY_ENTHALPY 0x1000000010000033LL
+#define TNG_GMX_ENERGY_VIR_XX 0x1000000010000034LL
+#define TNG_GMX_ENERGY_VIR_XY 0x1000000010000035LL
+#define TNG_GMX_ENERGY_VIR_XZ 0x1000000010000036LL
+#define TNG_GMX_ENERGY_VIR_YX 0x1000000010000037LL
+#define TNG_GMX_ENERGY_VIR_YY 0x1000000010000038LL
+#define TNG_GMX_ENERGY_VIR_YZ 0x1000000010000039LL
+#define TNG_GMX_ENERGY_VIR_ZX 0x1000000010000040LL
+#define TNG_GMX_ENERGY_VIR_ZY 0x1000000010000041LL
+#define TNG_GMX_ENERGY_VIR_ZZ 0x1000000010000042LL
+#define TNG_GMX_ENERGY_SHAKEVIR_XX 0x1000000010000043LL
+#define TNG_GMX_ENERGY_SHAKEVIR_XY 0x1000000010000044LL
+#define TNG_GMX_ENERGY_SHAKEVIR_XZ 0x1000000010000045LL
+#define TNG_GMX_ENERGY_SHAKEVIR_YX 0x1000000010000046LL
+#define TNG_GMX_ENERGY_SHAKEVIR_YY 0x1000000010000047LL
+#define TNG_GMX_ENERGY_SHAKEVIR_YZ 0x1000000010000048LL
+#define TNG_GMX_ENERGY_SHAKEVIR_ZX 0x1000000010000049LL
+#define TNG_GMX_ENERGY_SHAKEVIR_ZY 0x1000000010000050LL
+#define TNG_GMX_ENERGY_SHAKEVIR_ZZ 0x1000000010000051LL
+#define TNG_GMX_ENERGY_FORCEVIR_XX 0x1000000010000052LL
+#define TNG_GMX_ENERGY_FORCEVIR_XY 0x1000000010000053LL
+#define TNG_GMX_ENERGY_FORCEVIR_XZ 0x1000000010000054LL
+#define TNG_GMX_ENERGY_FORCEVIR_YX 0x1000000010000055LL
+#define TNG_GMX_ENERGY_FORCEVIR_YY 0x1000000010000056LL
+#define TNG_GMX_ENERGY_FORCEVIR_YZ 0x1000000010000057LL
+#define TNG_GMX_ENERGY_FORCEVIR_ZX 0x1000000010000058LL
+#define TNG_GMX_ENERGY_FORCEVIR_ZY 0x1000000010000059LL
+#define TNG_GMX_ENERGY_FORCEVIR_ZZ 0x1000000010000060LL
+#define TNG_GMX_ENERGY_PRES_XX 0x1000000010000061LL
+#define TNG_GMX_ENERGY_PRES_XY 0x1000000010000062LL
+#define TNG_GMX_ENERGY_PRES_XZ 0x1000000010000063LL
+#define TNG_GMX_ENERGY_PRES_YX 0x1000000010000064LL
+#define TNG_GMX_ENERGY_PRES_YY 0x1000000010000065LL
+#define TNG_GMX_ENERGY_PRES_YZ 0x1000000010000066LL
+#define TNG_GMX_ENERGY_PRES_ZX 0x1000000010000067LL
+#define TNG_GMX_ENERGY_PRES_ZY 0x1000000010000068LL
+#define TNG_GMX_ENERGY_PRES_ZZ 0x1000000010000069LL
+#define TNG_GMX_ENERGY_SURFXSURFTEN 0x1000000010000070LL
+#define TNG_GMX_ENERGY_MUX 0x1000000010000071LL
+#define TNG_GMX_ENERGY_MUY 0x1000000010000072LL
+#define TNG_GMX_ENERGY_MUZ 0x1000000010000073LL
+#define TNG_GMX_ENERGY_VCOS 0x1000000010000074LL
+#define TNG_GMX_ENERGY_VISC 0x1000000010000075LL
+#define TNG_GMX_ENERGY_BAROSTAT 0x1000000010000076LL
+#define TNG_GMX_ENERGY_T_SYSTEM 0x1000000010000077LL
+#define TNG_GMX_ENERGY_LAMB_SYSTEM 0x1000000010000078LL
+#define TNG_GMX_SELECTION_GROUP_NAMES 0x1000000010000079LL
+#define TNG_GMX_ATOM_SELECTION_GROUP 0x1000000010000080LL
/** @} */
/** Flag to specify if a data block contains data related to particles or not.*/
* opened.
* @param block_id is the id number of the particle data block to read.
* @param values is a pointer to a 1-dimensional array (memory unallocated), which
- * will be filled with data. The length of the array will be (n_frames * n_values_per_frame).
+ * will be filled with data. The length of the array will be
+ * (n_frames_with_data (see stride_length) * n_values_per_frame).
* Since **values is allocated in this function it is the callers
* responsibility to free the memory.
* @param n_frames is set to the number of particles in the returned data. This is
* If hash_mode == TNG_USE_HASH the md5 hash in the file will be
* compared to the md5 hash of the read contents to ensure valid data.
* @param values is a pointer to a 1-dimensional array (memory unallocated), which
- * will be filled with data. The length of the array will be (n_frames * n_values_per_frame).
+ * will be filled with data. The length of the array will be
+ * (n_frames_with_data (see stride_length) * n_values_per_frame).
* Since **values is allocated in this function it is the callers
* responsibility to free the memory.
* @param stride_length is set to the stride length (writing interval) of
* @param block_id is the id number of the particle data block to read.
* @param values is a pointer to a 1-dimensional array (memory unallocated), which
* will be filled with data. The length of the array will be
- * (n_frames * n_particles * n_values_per_frame).
+ * (n_frames_with_data (see stride_length) * n_particles * n_values_per_frame).
* Since **values is allocated in this function it is the callers
* responsibility to free the memory.
* @param n_frames is set to the number of frames in the returned data. This is
* compared to the md5 hash of the read contents to ensure valid data.
* @param values is a pointer to a 1-dimensional array (memory unallocated), which
* will be filled with data. The length of the array will be
- * (n_frames * n_particles * n_values_per_frame).
+ * (n_frames_with_data (see stride_length) * n_particles * n_values_per_frame).
* Since **values is allocated in this function it is the callers
* responsibility to free the memory.
* @param stride_length is set to the stride length (writing interval) of
# - Config file for the TNG_IO package
-# It defines the following variables
-# TNG_IO_INCLUDE_DIRS - include directories for TNG_IO
-# TNG_IO_LIBRARIES - libraries to link against
-# TNG_IO_DEFINITIONS - definitions used when compiling
-# Compute paths
-get_filename_component(TNG_IO_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
-set(TNG_IO_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@")
-set(TNG_IO_DEFINITIONS "@TNG_COMPILE_DEFS@")
+include(${CMAKE_CURRENT_LIST_DIR}/tng_io.cmake)
-set(TNG_IO_LIBRARIES tng_io)
+get_target_property(_libs tng_io::tng_io INTERFACE_LINK_LIBRARIES)
+if (_libs MATCHES "ZLIB::")
+ include(CMakeFindDependencyMacro)
+ find_dependency(ZLIB)
+endif()
+unset(_libs)
+# Provide information in variables as well for backwards compatibility
+set(TNG_IO_LIBRARIES tng_io::tng_io)
+get_target_property(TNG_IO_INCLUDE_DIRS tng_io::tng_io INTERFACE_INCLUDE_DIRECTORIES)
+get_target_property(TNG_IO_DEFINITIONS tng_io::tng_io INTERFACE_COMPILE_DEFINITIONS)
#include <string.h>
#include <time.h>
#include <math.h>
-#ifdef USE_ZLIB
#include <zlib.h>
-#endif
#include "tng/md5.h"
#include "compression/tng_compress.h"
FILE *output_file;
/** Function to swap 32 bit values to and from the endianness of the
* input file */
- tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
+ tng_function_status (*input_endianness_swap_func_32)(const tng_trajectory_t, uint32_t *);
/** Function to swap 64 bit values to and from the endianness of the
* input file */
- tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
+ tng_function_status (*input_endianness_swap_func_64)(const tng_trajectory_t, uint64_t *);
/** Function to swap 32 bit values to and from the endianness of the
* input file */
- tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, int32_t *);
+ tng_function_status (*output_endianness_swap_func_32)(const tng_trajectory_t, uint32_t *);
/** Function to swap 64 bit values to and from the endianness of the
* input file */
- tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, int64_t *);
+ tng_function_status (*output_endianness_swap_func_64)(const tng_trajectory_t, uint64_t *);
/** The endianness of 32 bit values of the current computer */
char endianness_32;
/** The endianness of 64 bit values of the current computer */
* byte order is not recognised.
*/
static tng_function_status tng_swap_byte_order_big_endian_32
- (const tng_trajectory_t tng_data, int32_t *v)
+ (const tng_trajectory_t tng_data, uint32_t *v)
{
switch(tng_data->endianness_32)
{
* byte order is not recognised.
*/
static tng_function_status tng_swap_byte_order_big_endian_64
- (const tng_trajectory_t tng_data, int64_t *v)
+ (const tng_trajectory_t tng_data, uint64_t *v)
{
switch(tng_data->endianness_64)
{
* byte order is not recognised.
*/
static tng_function_status tng_swap_byte_order_little_endian_32
- (const tng_trajectory_t tng_data, int32_t *v)
+ (const tng_trajectory_t tng_data, uint32_t *v)
{
switch(tng_data->endianness_32)
{
* byte order is not recognised.
*/
static tng_function_status tng_swap_byte_order_little_endian_64
- (const tng_trajectory_t tng_data, int64_t *v)
+ (const tng_trajectory_t tng_data, uint64_t *v)
{
switch(tng_data->endianness_64)
{
}
} while ((temp[count-1] != '\0') && (count < TNG_MAX_STR_LEN));
- temp_alloc = realloc(*str, count);
+ temp_alloc = (char *)realloc(*str, count);
if(!temp_alloc)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", count,
- __FILE__, line_nr);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, line_nr);
free(*str);
*str = 0;
return TNG_FAILURE;
{
case 8:
if(tng_data->input_endianness_swap_func_64 &&
- tng_data->input_endianness_swap_func_64(tng_data, dest) != TNG_SUCCESS)
+ tng_data->input_endianness_swap_func_64(tng_data, (uint64_t *)dest) != TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
__FILE__, line_nr);
break;
case 4:
if(tng_data->input_endianness_swap_func_32 &&
- tng_data->input_endianness_swap_func_32(tng_data, dest) != TNG_SUCCESS)
+ tng_data->input_endianness_swap_func_32(tng_data, (uint32_t *)dest) != TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
__FILE__, line_nr);
md5_state_t *md5_state,
const int line_nr)
{
- int32_t temp_i32;
- int64_t temp_i64;
+ uint32_t temp_i32;
+ uint64_t temp_i64;
switch(len)
{
case 8:
- temp_i64 = *((int64_t *)src);
+ temp_i64 = *((uint64_t *)src);
if(tng_data->output_endianness_swap_func_64 &&
tng_data->output_endianness_swap_func_64(tng_data, &temp_i64) != TNG_SUCCESS)
{
}
break;
case 4:
- temp_i32 = *((int32_t *)src);
+ temp_i32 = *((uint32_t *)src);
if(tng_data->output_endianness_swap_func_32 &&
tng_data->output_endianness_swap_func_32(tng_data, &temp_i32) != TNG_SUCCESS)
{
curr_file_pos = ftello(tng_data->input_file);
if(curr_file_pos < start_pos + block->block_contents_size)
{
- temp_data = malloc(start_pos + block->block_contents_size - curr_file_pos);
+ temp_data = (char *)malloc(start_pos + block->block_contents_size - curr_file_pos);
if(!temp_data)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- start_pos + block->block_contents_size - curr_file_pos, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
if(fread(temp_data, start_pos + block->block_contents_size - curr_file_pos,
{
tng_gen_block_t block;
- *block_p = malloc(sizeof(struct tng_gen_block));
+ *block_p = (struct tng_gen_block *)malloc(sizeof(struct tng_gen_block));
if(!*block_p)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
- sizeof(struct tng_gen_block), __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
if(tng_data->input_endianness_swap_func_64 &&
- tng_data->input_endianness_swap_func_64(tng_data, &block->header_contents_size) != TNG_SUCCESS)
+ tng_data->input_endianness_swap_func_64(tng_data, (uint64_t *)&block->header_contents_size) != TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
__FILE__, __LINE__);
free(block->block_contents);
}
- block->block_contents = malloc(block->block_contents_size);
+ block->block_contents = (char *)malloc(block->block_contents_size);
if(!block->block_contents)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- block->block_contents_size, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
return(TNG_CRITICAL);
}
{
tng_gen_block_t block;
FILE *temp = tng_data->input_file;
- int64_t output_file_pos, pos, contents_start_pos;
+ uint64_t output_file_pos, pos, contents_start_pos;
if(tng_output_file_init(tng_data) != TNG_SUCCESS)
{
tng_gen_block_t block;
tng_trajectory_frame_set_t frame_set;
FILE *temp = tng_data->input_file;
- int64_t pos, output_file_pos, contents_start_pos;
+ uint64_t pos, output_file_pos, contents_start_pos;
if(tng_output_file_init(tng_data) != TNG_SUCCESS)
{
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", pos,
__FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_FAILURE);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", *pos,
__FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_FAILURE);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", *pos,
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", *pos,
__FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
fseeko(tng_data->input_file, block_start_pos, SEEK_SET);
- contents = malloc(block_len);
+ contents = (char *)malloc(block_len);
if(!contents)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- block_len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
tng_data->current_trajectory_frame_set_output_file_pos = new_pos;
+ if(tng_data->input_file == tng_data->output_file)
+ {
+ tng_data->current_trajectory_frame_set_input_file_pos = new_pos;
+ }
tng_frame_set_pointers_update(tng_data, hash_mode);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
curr_frame_set_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_FAILURE);
* termination */
if(!block->name)
{
- block->name = malloc(1);
+ block->name = (char *)malloc(1);
if(!block->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
* termination */
if(!tng_data->first_program_name)
{
- tng_data->first_program_name = malloc(1);
+ tng_data->first_program_name = (char *)malloc(1);
if(!tng_data->first_program_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
if(!tng_data->last_program_name)
{
- tng_data->last_program_name = malloc(1);
+ tng_data->last_program_name = (char *)malloc(1);
if(!tng_data->last_program_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
if(!tng_data->first_user_name)
{
- tng_data->first_user_name = malloc(1);
+ tng_data->first_user_name = (char *)malloc(1);
if(!tng_data->first_user_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
if(!tng_data->last_user_name)
{
- tng_data->last_user_name = malloc(1);
+ tng_data->last_user_name = (char *)malloc(1);
if(!tng_data->last_user_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
if(!tng_data->first_computer_name)
{
- tng_data->first_computer_name = malloc(1);
+ tng_data->first_computer_name = (char *)malloc(1);
if(!tng_data->first_computer_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
if(!tng_data->last_computer_name)
{
- tng_data->last_computer_name = malloc(1);
+ tng_data->last_computer_name = (char *)malloc(1);
if(!tng_data->last_computer_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
if(!tng_data->first_pgp_signature)
{
- tng_data->first_pgp_signature = malloc(1);
+ tng_data->first_pgp_signature = (char *)malloc(1);
if(!tng_data->first_pgp_signature)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
if(!tng_data->last_pgp_signature)
{
- tng_data->last_pgp_signature = malloc(1);
+ tng_data->last_pgp_signature = (char *)malloc(1);
if(!tng_data->last_pgp_signature)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
if(!tng_data->forcefield_name)
{
- tng_data->forcefield_name = malloc(1);
+ tng_data->forcefield_name = (char *)malloc(1);
if(!tng_data->forcefield_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
name_len = strlen("GENERAL INFO");
- block->name = malloc(name_len + 1);
+ block->name = (char *)malloc(name_len + 1);
if(!block->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n",
- (unsigned int)(name_len+1), __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
}
molecule = &tng_data->molecules[i];
if(!molecule->name)
{
- molecule->name = malloc(1);
+ molecule->name = (char *)malloc(1);
if(!molecule->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
if(!chain->name)
{
- chain->name = malloc(1);
+ chain->name = (char *)malloc(1);
if(!chain->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
if(!residue->name)
{
- residue->name = malloc(1);
+ residue->name = (char *)malloc(1);
if(!residue->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
*len += sizeof(atom->id);
if(!atom->name)
{
- atom->name = malloc(1);
+ atom->name = (char *)malloc(1);
if(!atom->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
if(!atom->atom_type)
{
- atom->atom_type = malloc(1);
+ atom->atom_type = (char *)malloc(1);
if(!atom->atom_type)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (1 byte). %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
return(TNG_CRITICAL);
}
tng_data->n_particles = 0;
- tng_data->molecules = malloc(tng_data->n_molecules *
- sizeof(struct tng_molecule));
+ tng_data->molecules = (struct tng_molecule *)malloc(tng_data->n_molecules *
+ sizeof(struct tng_molecule));
if(!tng_data->molecules)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- tng_data->n_molecules * sizeof(struct tng_molecule),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
return(TNG_CRITICAL);
}
{
free(tng_data->molecule_cnt_list);
}
- tng_data->molecule_cnt_list = malloc(sizeof(int64_t) *
- tng_data->n_molecules);
+ tng_data->molecule_cnt_list = (int64_t *)malloc(sizeof(int64_t) *
+ tng_data->n_molecules);
if(!tng_data->molecule_cnt_list)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- tng_data->n_molecules * sizeof(struct tng_molecule),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
return(TNG_CRITICAL);
}
-/* fprintf(stderr, "TNG library: Read id: %"PRId64" offset: %d\n", molecule->id, offset);*/
+/* fprintf(stderr, "TNG library: Read id: %" PRId64 " offset: %d\n", molecule->id, offset);*/
tng_freadstr(tng_data, &molecule->name, hash_mode, &md5_state, __LINE__);
if(tng_file_input_numerical(tng_data, &molecule->quaternary_str,
if(molecule->n_chains > 0)
{
- molecule->chains = malloc(molecule->n_chains *
- sizeof(struct tng_chain));
+ molecule->chains = (struct tng_chain *)malloc(molecule->n_chains *
+ sizeof(struct tng_chain));
if(!molecule->chains)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- molecule->n_chains * sizeof(struct tng_chain),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
if(molecule->n_residues > 0)
{
- molecule->residues = malloc(molecule->n_residues *
- sizeof(struct tng_residue));
+ molecule->residues = (struct tng_residue *)malloc(molecule->n_residues *
+ sizeof(struct tng_residue));
if(!molecule->residues)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- molecule->n_residues * sizeof(struct tng_residue),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
if(molecule->chains)
{
free(molecule->chains);
residue = 0;
}
- molecule->atoms = malloc(molecule->n_atoms *
- sizeof(struct tng_atom));
+ molecule->atoms = (struct tng_atom *)malloc(molecule->n_atoms *
+ sizeof(struct tng_atom));
if(!molecule->atoms)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- molecule->n_atoms * sizeof(struct tng_atom),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
if(molecule->chains)
{
free(molecule->chains);
if(molecule->n_bonds > 0)
{
- tng_data->molecules[i].bonds = malloc(molecule->n_bonds *
- sizeof(struct tng_bond));
+ tng_data->molecules[i].bonds = (struct tng_bond *)malloc(molecule->n_bonds *
+ sizeof(struct tng_bond));
if(!molecule->bonds)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- molecule->n_bonds * sizeof(struct tng_bond),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
if(molecule->chains)
{
free(molecule->chains);
name_len = (unsigned int)strlen("MOLECULES");
- block->name = malloc(name_len + 1);
+ block->name = (char *)malloc(name_len + 1);
if(!block->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
- name_len+1, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n", __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
}
if(!frame_set->molecule_cnt_list)
{
frame_set->molecule_cnt_list =
- malloc(sizeof(int64_t) * tng_data->n_molecules);
+ (int64_t *)malloc(sizeof(int64_t) * tng_data->n_molecules);
if(!frame_set->molecule_cnt_list)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(int64_t) * tng_data->n_molecules,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
{
if(strncmp(block->md5_hash, hash, TNG_MD5_HASH_LEN) != 0)
{
- fprintf(stderr, "TNG library: Frame set block contents corrupt (first frame %"PRId64"). Hashes do not match. "
+ fprintf(stderr, "TNG library: Frame set block contents corrupt (first frame %" PRId64 "). Hashes do not match. "
"%s: %d\n", frame_set->first_frame, __FILE__, __LINE__);
}
}
if(!block->name || strlen(block->name) < name_len)
{
- temp_name = realloc(block->name, name_len + 1);
+ temp_name = (char *)realloc(block->name, name_len + 1);
if(!temp_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n",
- name_len+1, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(block->name);
block->name = 0;
return(TNG_CRITICAL);
* size or if the contents can be read. */
frame_set->n_mapping_blocks++;
- mappings = realloc(frame_set->mappings,
- sizeof(struct tng_particle_mapping) *
- frame_set->n_mapping_blocks);
+ mappings = (tng_particle_mapping_t)realloc(frame_set->mappings,
+ sizeof(struct tng_particle_mapping) *
+ frame_set->n_mapping_blocks);
if(!mappings)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- block->block_contents_size, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(frame_set->mappings);
frame_set->mappings = 0;
return(TNG_CRITICAL);
return(TNG_CRITICAL);
}
- mapping->real_particle_numbers = malloc(mapping->n_particles *
- sizeof(int64_t));
+ mapping->real_particle_numbers = (int64_t *)malloc(mapping->n_particles *
+ sizeof(int64_t));
if(!mapping->real_particle_numbers)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- mapping->n_particles * sizeof(int64_t), __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
if(!block->name || strlen(block->name) < name_len)
{
- temp_name = realloc(block->name, name_len + 1);
+ temp_name = (char *)realloc(block->name, name_len + 1);
if(!temp_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%u bytes). %s: %d\n",
- name_len+1, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(block->name);
block->name = 0;
return(TNG_CRITICAL);
if(block_type_flag == TNG_TRAJECTORY_BLOCK)
{
frame_set->n_particle_data_blocks++;
- data = realloc(frame_set->tr_particle_data,
- sizeof(struct tng_data) *
- frame_set->n_particle_data_blocks);
+ data = (tng_data_t)realloc(frame_set->tr_particle_data,
+ sizeof(struct tng_data) *
+ frame_set->n_particle_data_blocks);
if(!data)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
- sizeof(struct tng_data) *
- frame_set->n_particle_data_blocks,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(frame_set->tr_particle_data);
frame_set->tr_particle_data = 0;
return(TNG_CRITICAL);
else
{
tng_data->n_particle_data_blocks++;
- data = realloc(tng_data->non_tr_particle_data,
- sizeof(struct tng_data) *
- tng_data->n_particle_data_blocks);
+ data = (tng_data_t)realloc(tng_data->non_tr_particle_data,
+ sizeof(struct tng_data) *
+ tng_data->n_particle_data_blocks);
if(!data)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
- sizeof(struct tng_data) *
- tng_data->n_particle_data_blocks,
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
free(tng_data->non_tr_particle_data);
tng_data->non_tr_particle_data = 0;
if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
{
nalgo = tng_compress_nalgo();
- alt_algo = malloc(nalgo * sizeof *tng_data->compress_algo_pos);
+ alt_algo = (int *)malloc(nalgo * sizeof *tng_data->compress_algo_pos);
/* If we have already determined the initial coding and
* initial coding parameter do not determine them again. */
if(!tng_data->compress_algo_pos)
{
nalgo = tng_compress_nalgo();
- tng_data->compress_algo_pos=malloc(nalgo *
- sizeof *tng_data->compress_algo_pos);
+ tng_data->compress_algo_pos = (int *)malloc(nalgo *
+ sizeof *tng_data->compress_algo_pos);
tng_data->compress_algo_pos[0] = alt_algo[0];
tng_data->compress_algo_pos[1] = alt_algo[1];
tng_data->compress_algo_pos[2] = -1;
if(!tng_data->compress_algo_pos)
{
nalgo = tng_compress_nalgo();
- tng_data->compress_algo_pos=malloc(nalgo *
- sizeof *tng_data->compress_algo_pos);
+ tng_data->compress_algo_pos = (int *)malloc(nalgo *
+ sizeof *tng_data->compress_algo_pos);
tng_data->compress_algo_pos[0] = -1;
tng_data->compress_algo_pos[1] = -1;
tng_data->compress_algo_pos[2] = -1;
if(n_frames == 1 && tng_data->frame_set_n_frames > 1)
{
nalgo = tng_compress_nalgo();
- alt_algo=malloc(nalgo * sizeof *tng_data->compress_algo_vel);
+ alt_algo = (int *)malloc(nalgo * sizeof *tng_data->compress_algo_vel);
/* If we have already determined the initial coding and
* initial coding parameter do not determine them again. */
if(!tng_data->compress_algo_vel)
{
nalgo = tng_compress_nalgo();
- tng_data->compress_algo_vel=malloc(nalgo *
- sizeof *tng_data->compress_algo_vel);
+ tng_data->compress_algo_vel = (int *)malloc(nalgo *
+ sizeof *tng_data->compress_algo_vel);
tng_data->compress_algo_vel[0] = alt_algo[0];
tng_data->compress_algo_vel[1] = alt_algo[1];
tng_data->compress_algo_vel[2] = -1;
if(!tng_data->compress_algo_vel)
{
nalgo = tng_compress_nalgo();
- tng_data->compress_algo_vel=malloc(nalgo *
- sizeof *tng_data->compress_algo_vel);
+ tng_data->compress_algo_vel = (int *)malloc(nalgo *
+ sizeof *tng_data->compress_algo_vel);
tng_data->compress_algo_vel[0] = -1;
tng_data->compress_algo_vel[1] = -1;
tng_data->compress_algo_vel[2] = -1;
if(type == TNG_FLOAT_DATA)
{
- f_dest = malloc(uncompressed_len);
+ f_dest = (float *)malloc(uncompressed_len);
if(!f_dest)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- uncompressed_len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
result = tng_compress_uncompress_float(*data, f_dest);
}
else
{
- d_dest = malloc(uncompressed_len);
+ d_dest = (double *)malloc(uncompressed_len);
if(!d_dest)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- uncompressed_len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
result = tng_compress_uncompress(*data, d_dest);
return(TNG_SUCCESS);
}
-#ifdef USE_ZLIB
static tng_function_status tng_gzip_compress(const tng_trajectory_t tng_data,
char **data, const int64_t len,
int64_t *new_len)
(void)tng_data;
max_len = compressBound(len);
- dest = malloc(max_len);
+ dest = (Bytef *)malloc(max_len);
if(!dest)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%lu bytes). %s: %d\n",
- max_len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
(void)tng_data;
uLongf new_len = uncompressed_len;
- dest = malloc(uncompressed_len);
+ dest = (Bytef *)malloc(uncompressed_len);
if(!dest)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- uncompressed_len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
return(TNG_SUCCESS);
}
-#endif
/**
* @brief Allocate memory for storing particle data.
if(data->datatype == TNG_CHAR_DATA)
{
- data->strings = malloc(sizeof(char ***) * frame_alloc);
+ data->strings = (char ****)malloc(sizeof(char ***) * frame_alloc);
for(i = 0; i < frame_alloc; i++)
{
- data->strings[i] = malloc(sizeof(char **) *
+ data->strings[i] = (char ***)malloc(sizeof(char **) *
n_particles);
if(!data->strings[i])
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(union data_values *) * n_particles,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
for(j = 0; j < n_particles; j++)
{
- data->strings[i][j] = malloc(sizeof(char *) *
+ data->strings[i][j] = (char **)malloc(sizeof(char *) *
n_values_per_frame);
if(!data->strings[i][j])
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(union data_values) * n_values_per_frame,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
for(k = 0; k < n_values_per_frame; k++)
size = sizeof(double);
}
- values = realloc(data->values,
- size * frame_alloc *
- n_particles * n_values_per_frame);
+ values = (void ***)realloc(data->values,
+ size * frame_alloc *
+ n_particles * n_values_per_frame);
if(!values)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- size * frame_alloc *
- n_particles * n_values_per_frame,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(data->values);
data->values = 0;
return(TNG_CRITICAL);
if(block_type_flag == TNG_TRAJECTORY_BLOCK)
{
frame_set->n_data_blocks++;
- data = realloc(frame_set->tr_data, sizeof(struct tng_data) *
- frame_set->n_data_blocks);
+ data = (tng_data_t)realloc(frame_set->tr_data, sizeof(struct tng_data) *
+ frame_set->n_data_blocks);
if(!data)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
- sizeof(struct tng_data) * frame_set->n_data_blocks,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(frame_set->tr_data);
frame_set->tr_data = 0;
return(TNG_CRITICAL);
else
{
tng_data->n_data_blocks++;
- data = realloc(tng_data->non_tr_data, sizeof(struct tng_data) *
- tng_data->n_data_blocks);
+ data = (tng_data_t)realloc(tng_data->non_tr_data, sizeof(struct tng_data) *
+ tng_data->n_data_blocks);
if(!data)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
- sizeof(struct tng_data) * tng_data->n_data_blocks,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(tng_data->non_tr_data);
tng_data->non_tr_data = 0;
return(TNG_CRITICAL);
if(data->datatype == TNG_CHAR_DATA)
{
- data->strings = malloc(sizeof(char ***));
- data->strings[0] = malloc(sizeof(char **) * frame_alloc);
+ data->strings = (char ****)malloc(sizeof(char ***));
+ data->strings[0] = (char ***)malloc(sizeof(char **) * frame_alloc);
for(i = 0; i < frame_alloc; i++)
{
- data->strings[0][i] = malloc(sizeof(char *) * n_values_per_frame);
+ data->strings[0][i] = (char **)malloc(sizeof(char *) * n_values_per_frame);
if(!data->strings[0][i])
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- n_values_per_frame,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
for(j = 0; j < n_values_per_frame; j++)
size = sizeof(double);
}
- values = realloc(data->values,
- size * frame_alloc *
- n_values_per_frame);
+ values = (void **)realloc(data->values,
+ size * frame_alloc *
+ n_values_per_frame);
if(!values)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- size * frame_alloc *
- n_values_per_frame,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(data->values);
data->values = 0;
return(TNG_CRITICAL);
/* fprintf(stderr, "TNG library: %s\n", block->name);*/
- /* This must be caught early to avoid creating a data block if not necessary. */
-#ifndef USE_ZLIB
- if(codec_id == TNG_GZIP_COMPRESSION)
- {
- fprintf(stderr, "TNG library: Cannot uncompress data block. %s: %d\n", __FILE__,
- __LINE__);
- return(TNG_FAILURE);
- }
-#endif
-
switch(datatype)
{
case TNG_CHAR_DATA:
data->block_id = block->id;
- data->block_name = malloc(strlen(block->name) + 1);
+ data->block_name = (char *)malloc(strlen(block->name) + 1);
if(!data->block_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
- (unsigned int)strlen(block->name)+1, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
strcpy(data->block_name, block->name);
n_frames_div = (n_frames % stride_length) ? n_frames / stride_length + 1 : n_frames / stride_length;
- contents = malloc(block_data_len);
+ contents = (char *)malloc(block_data_len);
if(!contents)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- block_data_len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
fprintf(stderr, "TNG library: XTC compression not implemented yet.\n");
break;
case TNG_TNG_COMPRESSION:
-/* fprintf(stderr, "TNG library: Before TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
+/* fprintf(stderr, "TNG library: Before TNG uncompression: %" PRId64 "\n", block->block_contents_size);*/
if(tng_uncompress(tng_data, block, datatype,
&contents, full_data_len) != TNG_SUCCESS)
{
free(contents);
return(TNG_CRITICAL);
}
-/* fprintf(stderr, "TNG library: After TNG uncompression: %"PRId64"\n", block->block_contents_size);*/
+/* fprintf(stderr, "TNG library: After TNG uncompression: %" PRId64 "\n", block->block_contents_size);*/
break;
-#ifdef USE_ZLIB
case TNG_GZIP_COMPRESSION:
- /* fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
+ /* fprintf(stderr, "TNG library: Before compression: %" PRId64 "\n", block->block_contents_size); */
if(tng_gzip_uncompress(tng_data, &contents,
block_data_len, full_data_len) != TNG_SUCCESS)
{
free(contents);
return(TNG_CRITICAL);
}
- /* fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
+ /* fprintf(stderr, "TNG library: After compression: %" PRId64 "\n", block->block_contents_size); */
break;
-#endif
}
}
else
{
free(second_dim_values[k]);
}
- second_dim_values[k] = malloc(len);
+ second_dim_values[k] = (char *)malloc(len);
if(!second_dim_values[k])
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
- len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(contents);
return(TNG_CRITICAL);
}
{
free(data->strings[0][i][j]);
}
- data->strings[0][i][j] = malloc(len);
+ data->strings[0][i][j] = (char *)malloc(len);
if(!data->strings[0][i][j])
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
- len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(contents);
return(TNG_CRITICAL);
}
for(i = 0; i < full_data_len; i+=size)
{
if(tng_data->input_endianness_swap_func_32(tng_data,
- (int32_t *)((char *)data->values + i))
+ (uint32_t *)((char *)data->values + i))
!= TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
for(i = 0; i < full_data_len; i+=size)
{
if(tng_data->input_endianness_swap_func_64(tng_data,
- (int64_t *)((char *)data->values + i))
+ (uint64_t *)((char *)data->values + i))
!= TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
if(!block->name || strlen(block->name) < len)
{
- temp_name = realloc(block->name, len);
+ temp_name = (char *)realloc(block->name, len);
if(!temp_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n", len+1,
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
free(block->name);
block->name = 0;
{
full_data_len = size * frame_step * data->n_values_per_frame;
}
- contents = malloc(full_data_len);
+ contents = (char *)malloc(full_data_len);
if(!contents)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- full_data_len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
for(i = 0; i < full_data_len; i+=size)
{
if(tng_data->output_endianness_swap_func_32(tng_data,
- (int32_t *)(contents + i))
+ (uint32_t *)(contents + i))
!= TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
if(fabs(multiplier - 1.0) > 0.00001 ||
tng_data->output_endianness_swap_func_32)
{
- for(i = 0; full_data_len; i+=size)
+ for(i = 0; i < full_data_len; i+=size)
{
*(float *)(contents + i) *= (float)multiplier;
if(tng_data->output_endianness_swap_func_32 &&
tng_data->output_endianness_swap_func_32(tng_data,
- (int32_t *)(contents + i))
+ (uint32_t *)(contents + i))
!= TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
for(i = 0; i < full_data_len; i+=size)
{
if(tng_data->output_endianness_swap_func_64(tng_data,
- (int64_t *)(contents + i))
+ (uint64_t *)(contents + i))
!= TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
for(i = 0; i < full_data_len; i+=size)
{
if(tng_data->output_endianness_swap_func_64(tng_data,
- (int64_t *)(contents + i))
+ (uint64_t *)(contents + i))
!= TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
*(double *)(contents + i) *= multiplier;
if(tng_data->output_endianness_swap_func_64 &&
tng_data->output_endianness_swap_func_64(tng_data,
- (int64_t *)(contents + i))
+ (uint64_t *)(contents + i))
!= TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
return(stat);
}
break;
-#ifdef USE_ZLIB
case TNG_GZIP_COMPRESSION:
- /* fprintf(stderr, "TNG library: Before compression: %"PRId64"\n", block->block_contents_size); */
+ /* fprintf(stderr, "TNG library: Before compression: %" PRId64 "\n", block->block_contents_size); */
stat = tng_gzip_compress(tng_data,
&contents,
full_data_len,
}
data->codec_id = TNG_UNCOMPRESSED;
}
- /* fprintf(stderr, "TNG library: After compression: %"PRId64"\n", block->block_contents_size); */
+ /* fprintf(stderr, "TNG library: After compression: %" PRId64 "\n", block->block_contents_size); */
break;
-#endif
}
if(block_data_len != full_data_len)
{
// {
// if(tng_block_header_read(tng_data, block) != TNG_SUCCESS)
// {
-// fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", pos,
+// fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", pos,
// __FILE__, __LINE__);
// tng_data->input_file = temp;
// tng_block_destroy(&block);
// }
// if(!block->name)
// {
-// block->name = malloc(len);
+// block->name = (char *)malloc(len);
// if(!block->name)
// {
-// fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
+// fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
// __FILE__, __LINE__);
// return(TNG_CRITICAL);
// }
}
if(!atom->name)
{
- atom->name = malloc(len);
+ atom->name = (char *)malloc(len);
if(!atom->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
}
if(!atom->atom_type)
{
- atom->atom_type = malloc(len);
+ atom->atom_type = (char *)malloc(len);
if(!atom->atom_type)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
- new_molecules = realloc(tng_data->molecules,
- sizeof(struct tng_molecule) *
- (tng_data->n_molecules + 1));
+ new_molecules = (tng_molecule_t)realloc(tng_data->molecules,
+ sizeof(struct tng_molecule) *
+ (tng_data->n_molecules + 1));
if(!new_molecules)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(tng_data->molecules);
tng_data->molecules = 0;
return(TNG_CRITICAL);
}
- new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
- sizeof(int64_t) *
- (tng_data->n_molecules + 1));
+ new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list,
+ sizeof(int64_t) *
+ (tng_data->n_molecules + 1));
if(!new_molecule_cnt_list)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(int64_t) * (tng_data->n_molecules + 1),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(tng_data->molecule_cnt_list);
tng_data->molecule_cnt_list = 0;
free(new_molecules);
id = 1;
}
- new_molecules = realloc(tng_data->molecules,
- sizeof(struct tng_molecule) *
- (tng_data->n_molecules + 1));
+ new_molecules = (tng_molecule_t)realloc(tng_data->molecules,
+ sizeof(struct tng_molecule) *
+ (tng_data->n_molecules + 1));
if(!new_molecules)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(struct tng_molecule) * (tng_data->n_molecules + 1),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(tng_data->molecules);
tng_data->molecules = 0;
return(TNG_CRITICAL);
}
- new_molecule_cnt_list = realloc(tng_data->molecule_cnt_list,
- sizeof(int64_t) *
- (tng_data->n_molecules + 1));
+ new_molecule_cnt_list = (int64_t *)realloc(tng_data->molecule_cnt_list,
+ sizeof(int64_t) *
+ (tng_data->n_molecules + 1));
if(!new_molecule_cnt_list)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(int64_t) * (tng_data->n_molecules + 1),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(tng_data->molecule_cnt_list);
tng_data->molecule_cnt_list = 0;
free(new_molecules);
}
if(!molecule->name)
{
- molecule->name = malloc(len);
+ molecule->name = (char *)malloc(len);
if(!molecule->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
tng_data_dest->n_molecules = 0;
tng_data_dest->n_particles = 0;
- molecule_temp = realloc(tng_data_dest->molecules,
- sizeof(struct tng_molecule) * tng_data_src->n_molecules);
+ molecule_temp = (tng_molecule_t)realloc(tng_data_dest->molecules,
+ sizeof(struct tng_molecule) * tng_data_src->n_molecules);
if(!molecule_temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(struct tng_molecule) * tng_data_src->n_molecules,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(tng_data_dest->molecules);
tng_data_dest->molecules = 0;
return(TNG_CRITICAL);
}
- list_temp = realloc(tng_data_dest->molecule_cnt_list,
- sizeof(int64_t) * tng_data_src->n_molecules);
+ list_temp = (int64_t *)realloc(tng_data_dest->molecule_cnt_list,
+ sizeof(int64_t) * tng_data_src->n_molecules);
if(!list_temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(int64_t) * tng_data_src->n_molecules,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(tng_data_dest->molecule_cnt_list);
tng_data_dest->molecule_cnt_list = 0;
free(molecule_temp);
molecule_temp->n_bonds = molecule->n_bonds;
if(molecule->n_bonds > 0)
{
- bond_temp = realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
- molecule->n_bonds);
+ bond_temp = (tng_bond_t)realloc(molecule_temp->bonds, sizeof(struct tng_bond) *
+ molecule->n_bonds);
if(!bond_temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(struct tng_bond) * molecule->n_bonds,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(molecule_temp->bonds);
molecule_temp->n_bonds = 0;
return(TNG_CRITICAL);
TNG_ASSERT(tng_data, "TNG library: Trajectory container not properly setup.");
TNG_ASSERT(name, "TNG library: name must not be a NULL pointer.");
- new_chains = realloc(molecule->chains,
- sizeof(struct tng_chain) *
- (molecule->n_chains + 1));
+ new_chains = (tng_chain_t)realloc(molecule->chains,
+ sizeof(struct tng_chain) *
+ (molecule->n_chains + 1));
if(!new_chains)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(struct tng_chain) * (molecule->n_chains + 1),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(molecule->chains);
molecule->chains = 0;
return(TNG_CRITICAL);
tng_bond_t new_bonds;
(void)tng_data;
- new_bonds = realloc(molecule->bonds,
- sizeof(struct tng_bond) *
- (molecule->n_bonds + 1));
+ new_bonds = (tng_bond_t)realloc(molecule->bonds,
+ sizeof(struct tng_bond) *
+ (molecule->n_bonds + 1));
if(!new_bonds)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(struct tng_bond) * (molecule->n_bonds + 1),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
*bond = 0;
free(molecule->bonds);
molecule->bonds = 0;
}
if(!chain->name)
{
- chain->name = malloc(len);
+ chain->name = (char *)malloc(len);
if(!chain->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
curr_index = -1;
}
- new_residues = realloc(molecule->residues,
- sizeof(struct tng_residue) *
- (molecule->n_residues + 1));
+ new_residues = (tng_residue_t)realloc(molecule->residues,
+ sizeof(struct tng_residue) *
+ (molecule->n_residues + 1));
if(!new_residues)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(struct tng_residue) * (molecule->n_residues + 1),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(molecule->residues);
molecule->residues = 0;
return(TNG_CRITICAL);
}
if(!residue->name)
{
- residue->name = malloc(len);
+ residue->name = (char *)malloc(len);
if(!residue->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
residue->atoms_offset = molecule->n_atoms;
}
- new_atoms = realloc(molecule->atoms,
- sizeof(struct tng_atom) *
- (molecule->n_atoms + 1));
+ new_atoms = (tng_atom_t)realloc(molecule->atoms,
+ sizeof(struct tng_atom) *
+ (molecule->n_atoms + 1));
if(!new_atoms)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(struct tng_atom) * (molecule->n_atoms + 1),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(molecule->atoms);
molecule->atoms = 0;
return(TNG_CRITICAL);
tng_function_status DECLSPECDLLEXPORT tng_molecule_alloc(const tng_trajectory_t tng_data,
tng_molecule_t *molecule_p)
{
- *molecule_p = malloc(sizeof(struct tng_molecule));
+ *molecule_p = (tng_molecule_t)malloc(sizeof(struct tng_molecule));
if(!*molecule_p)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
- sizeof(struct tng_molecule), __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
return(TNG_SUCCESS);
}
- *from_atoms = malloc(sizeof(int64_t) * (*n_bonds));
+ *from_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds));
if(!*from_atoms)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
- *to_atoms = malloc(sizeof(int64_t) * (*n_bonds));
+ *to_atoms = (int64_t *)malloc(sizeof(int64_t) * (*n_bonds));
if(!*to_atoms)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(int64_t) * (*n_bonds), __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(*from_atoms);
*from_atoms = 0;
return(TNG_CRITICAL);
frame_set->n_mapping_blocks++;
- mapping = realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
- frame_set->n_mapping_blocks);
+ mapping = (tng_particle_mapping_t)realloc(frame_set->mappings, sizeof(struct tng_particle_mapping) *
+ frame_set->n_mapping_blocks);
if(!mapping)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(struct tng_particle_mapping)*frame_set->n_mapping_blocks,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(frame_set->mappings);
frame_set->mappings = 0;
return(TNG_CRITICAL);
frame_set->mappings[frame_set->n_mapping_blocks - 1].num_first_particle = num_first_particle;
frame_set->mappings[frame_set->n_mapping_blocks - 1].n_particles = n_particles;
- frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = malloc(sizeof(int64_t) * n_particles);
+ frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers = (int64_t *)malloc(sizeof(int64_t) * n_particles);
if(!frame_set->mappings[frame_set->n_mapping_blocks - 1].real_particle_numbers)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(int64_t) * n_particles, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
tng_trajectory_frame_set_t frame_set;
tng_trajectory_t tng_data;
- *tng_data_p = malloc(sizeof(struct tng_trajectory));
+ *tng_data_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory));
if(!*tng_data_p)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
- sizeof(struct tng_trajectory), __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
TNG_ASSERT(src != 0, "TNG library: Source trajectory must not be NULL.");
- *dest_p = malloc(sizeof(struct tng_trajectory));
+ *dest_p = (tng_trajectory_t)malloc(sizeof(struct tng_trajectory));
if(!*dest_p)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIuPTR" bytes). %s: %d\n",
- sizeof(struct tng_trajectory), __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
if(src->input_file_path)
{
- dest->input_file_path = malloc(strlen(src->input_file_path) + 1);
+ dest->input_file_path = (char *)malloc(strlen(src->input_file_path) + 1);
if(!dest->input_file_path)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
- (unsigned int)strlen(src->input_file_path) + 1, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
strcpy(dest->input_file_path, src->input_file_path);
dest->input_file = 0;
if(src->output_file_path)
{
- dest->output_file_path = malloc(strlen(src->output_file_path) + 1);
+ dest->output_file_path = (char *)malloc(strlen(src->output_file_path) + 1);
if(!dest->output_file_path)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
- (unsigned int)strlen(src->output_file_path) + 1, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
strcpy(dest->output_file_path, src->output_file_path);
}
len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
- temp = realloc(tng_data->input_file_path, len);
+ temp = (char *)realloc(tng_data->input_file_path, len);
if(!temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(tng_data->input_file_path);
tng_data->input_file_path = 0;
return(TNG_CRITICAL);
}
len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
- temp = realloc(tng_data->output_file_path, len);
+ temp = (char *)realloc(tng_data->output_file_path, len);
if(!temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(tng_data->output_file_path);
tng_data->output_file_path = 0;
return(TNG_CRITICAL);
}
len = tng_min_size(strlen(file_name) + 1, TNG_MAX_STR_LEN);
- temp = realloc(tng_data->output_file_path, len);
+ temp = (char *)realloc(tng_data->output_file_path, len);
if(!temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(tng_data->output_file_path);
tng_data->output_file_path = 0;
return(TNG_CRITICAL);
}
if(!tng_data->first_program_name)
{
- tng_data->first_program_name = malloc(len);
+ tng_data->first_program_name = (char *)malloc(len);
if(!tng_data->first_program_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
}
if(!tng_data->last_program_name)
{
- tng_data->last_program_name = malloc(len);
+ tng_data->last_program_name = (char *)malloc(len);
if(!tng_data->last_program_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
}
if(!tng_data->first_user_name)
{
- tng_data->first_user_name = malloc(len);
+ tng_data->first_user_name = (char *)malloc(len);
if(!tng_data->first_user_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
}
if(!tng_data->last_user_name)
{
- tng_data->last_user_name = malloc(len);
+ tng_data->last_user_name = (char *)malloc(len);
if(!tng_data->last_user_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
}
if(!tng_data->first_computer_name)
{
- tng_data->first_computer_name = malloc(len);
+ tng_data->first_computer_name = (char *)malloc(len);
if(!tng_data->first_computer_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
}
if(!tng_data->last_computer_name)
{
- tng_data->last_computer_name = malloc(len);
+ tng_data->last_computer_name = (char *)malloc(len);
if(!tng_data->last_computer_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
}
if(!tng_data->first_pgp_signature)
{
- tng_data->first_pgp_signature = malloc(len);
+ tng_data->first_pgp_signature = (char *)malloc(len);
if(!tng_data->first_pgp_signature)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
}
if(!tng_data->last_pgp_signature)
{
- tng_data->last_pgp_signature = malloc(len);
+ tng_data->last_pgp_signature = (char *)malloc(len);
if(!tng_data->last_pgp_signature)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
}
if(!tng_data->forcefield_name)
{
- tng_data->forcefield_name = malloc(len);
+ tng_data->forcefield_name = (char *)malloc(len);
if(!tng_data->forcefield_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n", len,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
}
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", last_file_pos,
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", last_file_pos,
__FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_FAILURE);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos,
__FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n", file_pos,
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n", file_pos,
__FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
}
tng_block_init(&block);
- block->name = malloc(TNG_MAX_STR_LEN);
+ block->name = (char *)malloc(TNG_MAX_STR_LEN);
if(!block->name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
- TNG_MAX_STR_LEN, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
}
if(tot_len > orig_len)
{
tng_migrate_data_in_file(tng_data, orig_len+1, tot_len - orig_len, hash_mode);
+ tng_data->last_trajectory_frame_set_input_file_pos = tng_data->last_trajectory_frame_set_output_file_pos;
}
stat = tng_reread_frame_set_at_file_pos(tng_data, tng_data->last_trajectory_frame_set_input_file_pos);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET ||
block->id == -1)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
}
if(stat == TNG_CRITICAL)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(stat);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
}
if(stat == TNG_CRITICAL)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(stat);
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
return(TNG_CRITICAL);
if(tng_data->input_endianness_swap_func_64)
{
if(tng_data->input_endianness_swap_func_64(tng_data,
- &frame_set->medium_stride_prev_frame_set_file_pos)
+ (uint64_t *)&frame_set->medium_stride_prev_frame_set_file_pos)
!= TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
if(tng_data->input_endianness_swap_func_64)
{
if(tng_data->input_endianness_swap_func_64(tng_data,
- &frame_set->long_stride_prev_frame_set_file_pos)
+ (uint64_t *)&frame_set->long_stride_prev_frame_set_file_pos)
!= TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL || block->id != TNG_TRAJECTORY_FRAME_SET)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
return(TNG_CRITICAL);
}
char ***first_dim_values, **second_dim_values;
tng_trajectory_frame_set_t frame_set;
tng_data_t data;
- char *new_data_c=new_data;
+ char *new_data_c = (char *)new_data;
tng_function_status stat;
frame_set = &tng_data->current_trajectory_frame_set;
}
data->block_id = id;
- data->block_name = malloc(strlen(block_name) + 1);
+ data->block_name = (char *)malloc(strlen(block_name) + 1);
if(!data->block_name)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%ud bytes). %s: %d\n",
- (unsigned int)strlen(block_name)+1, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
strncpy(data->block_name, block_name, strlen(block_name) + 1);
{
free(second_dim_values[k]);
}
- second_dim_values[k] = malloc(len);
+ second_dim_values[k] = (char *)malloc(len);
if(!second_dim_values[k])
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
- len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
strncpy(second_dim_values[k],
{
free(second_dim_values[j]);
}
- second_dim_values[j] = malloc(len);
+ second_dim_values[j] = (char *)malloc(len);
if(!second_dim_values[j])
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%d bytes). %s: %d\n",
- len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
strncpy(second_dim_values[j],
stat = tng_block_header_read(tng_data, block);
if(stat == TNG_CRITICAL)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
tng_data->input_file = temp;
}
if(stat == TNG_CRITICAL)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
tng_data->input_file = temp;
}
if(stat == TNG_CRITICAL)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
tng_block_destroy(&block);
tng_data->input_file = temp;
data.datatype == TNG_DOUBLE_DATA) &&
tng_data->output_endianness_swap_func_64)
{
- copy = malloc(write_n_particles * n_values_per_frame * size);
+ copy = (char *)malloc(write_n_particles * n_values_per_frame * size);
memcpy(copy, values, write_n_particles * n_values_per_frame * size);
for(i = 0; i < write_n_particles * n_values_per_frame; i++)
{
if(tng_data->output_endianness_swap_func_64(tng_data,
- (int64_t *) copy+i)
+ (uint64_t *) copy+i)
!= TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
else if(data.datatype == TNG_FLOAT_DATA &&
tng_data->output_endianness_swap_func_32)
{
- copy = malloc(write_n_particles * n_values_per_frame * size);
+ copy = (char *)malloc(write_n_particles * n_values_per_frame * size);
memcpy(copy, values, write_n_particles * n_values_per_frame * size);
for(i = 0; i < write_n_particles * n_values_per_frame; i++)
{
if(tng_data->output_endianness_swap_func_32(tng_data,
- (int32_t *) copy+i)
+ (uint32_t *) copy+i)
!= TNG_SUCCESS)
{
fprintf(stderr, "TNG library: Cannot swap byte order. %s: %d\n",
return(stat);
}
}
- *values = malloc(sizeof(union data_values *) * n_frames);
+ *values = (union data_values **)malloc(sizeof(union data_values *) * n_frames);
if(!*values)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(union data_values **) * n_frames,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
for(i = 0; i < n_frames; i++)
{
- (*values)[i] = malloc(sizeof(union data_values) *
+ (*values)[i] = (union data_values *)malloc(sizeof(union data_values) *
n_values_per_frame);
if(!(*values)[i])
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(union data_values) * n_values_per_frame,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(values);
values = 0;
return(TNG_CRITICAL);
return(stat);
}
}
- *values = malloc(sizeof(union data_values **) * n_frames);
+ *values = (union data_values ***)malloc(sizeof(union data_values **) * n_frames);
if(!*values)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(union data_values **) * n_frames,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
return(TNG_CRITICAL);
}
for(i = 0; i < n_frames; i++)
{
- (*values)[i] = malloc(sizeof(union data_values *) *
+ (*values)[i] = (union data_values **)malloc(sizeof(union data_values *) *
n_particles);
if(!(*values)[i])
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(union data_values *) * n_particles,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(*values);
*values = 0;
return(TNG_CRITICAL);
}
for(j = 0; j < n_particles; j++)
{
- (*values)[i][j] = malloc(sizeof(union data_values) *
+ (*values)[i][j] = (union data_values *)malloc(sizeof(union data_values) *
n_values_per_frame);
if(!(*values)[i][j])
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(union data_values *) * n_particles,
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
tng_particle_data_values_free(tng_data, *values, n_frames,
n_particles, n_values_per_frame,
type);
tng_block_destroy(&block);
if(stat == TNG_CRITICAL)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
return(stat);
}
for(k = 0; k < *n_values_per_frame; k++)
{
len = strlen(data->strings[i][j][k]) + 1;
- (*values)[i][mapping][k].c = malloc(len);
+ (*values)[i][mapping][k].c = (char *)malloc(len);
strncpy((*values)[i][mapping][k].c,
data->strings[i][j][k], len);
}
for(j = 0; j < *n_values_per_frame; j++)
{
len = strlen(data->strings[0][i][j]) + 1;
- (*values)[0][i][j].c = malloc(len);
+ (*values)[0][i][j].c = (char *)malloc(len);
strncpy((*values)[0][i][j].c, data->strings[0][i][j], len);
}
}
tng_block_destroy(&block);
if(stat == TNG_CRITICAL)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
return(stat);
}
full_data_len *= (*n_particles);
}
- temp = realloc(*values, full_data_len);
+ temp = (char *)realloc(*values, full_data_len);
if(!temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- full_data_len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(*values);
*values = 0;
return(TNG_CRITICAL);
tng_block_destroy(&block);
if(stat == TNG_CRITICAL)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
return(stat);
}
if(block_index < 0)
{
- fprintf(stderr, "TNG library: Could not find particle data block with id %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Could not find particle data block with id %" PRId64 ". %s: %d\n",
block_id, __FILE__, __LINE__);
return(TNG_FAILURE);
}
for(k = 0; k < *n_values_per_frame; k++)
{
len = strlen(data->strings[current_frame_pos][j][k]) + 1;
- (*values)[i][mapping][k].c = malloc(len);
+ (*values)[i][mapping][k].c = (char *)malloc(len);
strncpy((*values)[i][mapping][k].c, data->strings[current_frame_pos][j][k], len);
}
}
for(j = 0; j < *n_values_per_frame; j++)
{
len = strlen(data->strings[0][current_frame_pos][j]) + 1;
- (*values)[0][i][j].c = malloc(len);
+ (*values)[0][i][j].c = (char *)malloc(len);
strncpy((*values)[0][i][j].c, data->strings[0][current_frame_pos][j], len);
}
}
tng_block_destroy(&block);
if(stat == TNG_CRITICAL)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
return(stat);
}
full_data_len *= (*n_particles);
}
- temp = realloc(*values, full_data_len);
+ temp = (char *)realloc(*values, full_data_len);
if(!temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- full_data_len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(*values);
*values = 0;
return(TNG_CRITICAL);
tng_output_append_file_set(*tng_data_p, filename);
fseeko((*tng_data_p)->output_file, 0, SEEK_END);
+
+ (*tng_data_p)->output_endianness_swap_func_32 = (*tng_data_p)->input_endianness_swap_func_32;
+ (*tng_data_p)->output_endianness_swap_func_64 = (*tng_data_p)->input_endianness_swap_func_64;
}
return(stat);
stat = tng_frame_set_of_frame_find(tng_data, frame_nr);
if(stat != TNG_SUCCESS)
{
- fprintf(stderr, "TNG library: Cannot find frame nr %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot find frame nr %" PRId64 ". %s: %d\n",
frame_nr, __FILE__, __LINE__);
return(stat);
}
*n_particles = mol->n_atoms;
- *names = malloc(sizeof(char *) * *n_particles);
- *types = malloc(sizeof(char *) * *n_particles);
- *res_names = malloc(sizeof(char *) * *n_particles);
- *chain_names = malloc(sizeof(char *) * *n_particles);
- *res_ids = malloc(sizeof(int64_t) * *n_particles);
- *chain_ids = malloc(sizeof(int64_t) * *n_particles);
+ *names = (char **)malloc(sizeof(char *) * *n_particles);
+ *types = (char **)malloc(sizeof(char *) * *n_particles);
+ *res_names = (char **)malloc(sizeof(char *) * *n_particles);
+ *chain_names = (char **)malloc(sizeof(char *) * *n_particles);
+ *res_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles);
+ *chain_ids = (int64_t *)malloc(sizeof(int64_t) * *n_particles);
for(i = 0; i < *n_particles; i++)
{
atom = &mol->atoms[i];
res = atom->residue;
chain = res->chain;
- (*names)[i] = malloc(strlen(atom->name));
+ (*names)[i] = (char *)malloc(strlen(atom->name));
strcpy(*names[i], atom->name);
- (*types)[i] = malloc(strlen(atom->atom_type));
+ (*types)[i] = (char *)malloc(strlen(atom->atom_type));
strcpy(*types[i], atom->atom_type);
- (*res_names)[i] = malloc(strlen(res->name));
+ (*res_names)[i] = (char *)malloc(strlen(res->name));
strcpy(*res_names[i], res->name);
- (*chain_names)[i] = malloc(strlen(chain->name));
+ (*chain_names)[i] = (char *)malloc(strlen(chain->name));
strcpy(*chain_names[i], chain->name);
(*res_ids)[i] = res->id;
(*chain_ids)[i] = chain->id;
&n_values_per_frame,
&type);
+ if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
+ {
+ return(TNG_FAILURE);
+ }
+
return(stat);
}
&n_values_per_frame,
&type);
+ if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
+ {
+ return(TNG_FAILURE);
+ }
+
return(stat);
}
&n_values_per_frame,
&type);
+ if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
+ {
+ return(TNG_FAILURE);
+ }
+
return(stat);
}
&n_values_per_frame,
&type);
+ if(stat == TNG_SUCCESS && type != TNG_FLOAT_DATA)
+ {
+ return(TNG_FAILURE);
+ }
+
return(stat);
}
full_data_len = size * n_particles * data->n_values_per_frame;
-// fprintf(stderr, "TNG library: TEMP: i = %"PRId64", full_data_len = %"PRId64", size = %d, n_particles = %"PRId64", n_values_per_frame = %"PRId64"\n",
+// fprintf(stderr, "TNG library: TEMP: i = %" PRId64 ", full_data_len = %" PRId64 ", size = %d, n_particles = %" PRId64 ", n_values_per_frame = %" PRId64 "\n",
// i, full_data_len, size, n_particles, data->n_values_per_frame);
- temp = realloc(*values, full_data_len);
+ temp = (char *)realloc(*values, full_data_len);
if(!temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- full_data_len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(*values);
*values = 0;
return(TNG_CRITICAL);
full_data_len = size * data->n_values_per_frame;
- temp = realloc(*values, full_data_len);
+ temp = (char *)realloc(*values, full_data_len);
if(!temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRId64" bytes). %s: %d\n",
- full_data_len, __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(*values);
*values = 0;
return(TNG_CRITICAL);
if(i <= 0)
{
- fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n",
i, __FILE__, __LINE__);
return(TNG_FAILURE);
}
if(i <= 0)
{
- fprintf(stderr, "TNG library: Cannot set writing frequency to %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot set writing frequency to %" PRId64 ". %s: %d\n",
i, __FILE__, __LINE__);
return(TNG_FAILURE);
}
{
TNG_ASSERT(requested_data_block_ids, "TNG library: If the number of requested data blocks is > 0 then the array of data block IDs must not be NULL.");
size = sizeof(int64_t) * n_requested_data_block_ids;
- temp = realloc(*data_block_ids_in_next_frame, size);
+ temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
if(!temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(int64_t) * (*n_data_blocks_in_next_frame),
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
__FILE__, __LINE__);
free(*data_block_ids_in_next_frame);
*data_block_ids_in_next_frame = 0;
tng_block_destroy(&block);
if(stat == TNG_CRITICAL)
{
- fprintf(stderr, "TNG library: Cannot read block header at pos %"PRId64". %s: %d\n",
+ fprintf(stderr, "TNG library: Cannot read block header at pos %" PRId64 ". %s: %d\n",
file_pos, __FILE__, __LINE__);
return(stat);
}
if(n_requested_data_block_ids <= 0)
{
size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
- temp = realloc(*data_block_ids_in_next_frame, size);
+ temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
if(!temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(int64_t) * (*n_data_blocks_in_next_frame),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(*data_block_ids_in_next_frame);
*data_block_ids_in_next_frame = 0;
return(TNG_CRITICAL);
if(n_requested_data_block_ids <= 0)
{
size = sizeof(int64_t) * (*n_data_blocks_in_next_frame);
- temp = realloc(*data_block_ids_in_next_frame, size);
+ temp = (int64_t *)realloc(*data_block_ids_in_next_frame, size);
if(!temp)
{
- fprintf(stderr, "TNG library: Cannot allocate memory (%"PRIu64" bytes). %s: %d\n",
- sizeof(int64_t) * (*n_data_blocks_in_next_frame),
- __FILE__, __LINE__);
+ fprintf(stderr, "TNG library: Cannot allocate memory. %s: %d\n",
+ __FILE__, __LINE__);
free(*data_block_ids_in_next_frame);
*data_block_ids_in_next_frame = 0;
return(TNG_CRITICAL);
* modify it under the terms of the Revised BSD License.
*/
-#include "../../include/tng_io.h"
+#include "tng/tng_io.h"
/* The following is for calling the library from fortran */
add_subdirectory(compression)
endif()
-link_directories(${TNG_IO_BINARY_DIR}/src/lib)
-
add_definitions(-DTNG_EXAMPLE_FILES_DIR="${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/tests/example_files/") # Directory where to find input test files and save output files.
if(TNG_BUILD_TEST)
if(${CMAKE_Fortran_COMPILER_WORKS})
get_filename_component (Fortran_COMPILER_NAME ${CMAKE_Fortran_COMPILER} NAME)
if (Fortran_COMPILER_NAME STREQUAL "gfortran")
- set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fcray-pointer ${OpenMP_C_FLAGS} -std=legacy")
+ set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -fcray-pointer ${OpenMP_C_FLAGS} -std=legacy -cpp -ffixed-line-length-none")
endif()
if(OPENMP_FOUND)
add_executable(md_openmp_f md_openmp.f)
c
c The program uses Open MP directives to allow parallel computation.
c
-c The velocity Verlet time integration scheme is used.
+c The velocity Verlet time integration scheme is used.
c
c The particles interact with a central pair potential.
c
c
c Licensing:
c
-c This code is distributed under the GNU LGPL license.
+c This code is distributed under the GNU LGPL license.
c
c Modified:
c
write ( *, '(a)' ) ' '
write ( *, '(a)' ) ' A molecular dynamics program.'
write ( *, '(a)' ) ' '
- write ( *, '(a,i8)' )
+ write ( *, '(a,i8)' )
& ' NP, the number of particles in the simulation is ', np
- write ( *, '(a,i8)' )
+ write ( *, '(a,i8)' )
& ' STEP_NUM, the number of time steps, is ', step_num
- write ( *, '(a,g14.6)' )
+ write ( *, '(a,g14.6)' )
& ' DT, the size of each time step, is ', dt
write ( *, '(a)' ) ' '
- write ( *, '(a,i8)' )
+ write ( *, '(a,i8)' )
& ' The number of processors = ', omp_get_num_procs ( )
- write ( *, '(a,i8)' )
+ write ( *, '(a,i8)' )
& ' The number of threads = ', omp_get_max_threads ( )
- write ( *, '(a)' ) ' '
+ write ( *, '(a)' ) ' '
write ( *, '(a)' ) ' Initializing trajectory storage.'
call tng_trajectory_init(traj_p)
c
c N.B. The TNG output file should be modified according to needs
-c
- call tng_output_file_set(traj, TNG_EXAMPLE_FILES_DIR "tng_md_out_f77.tng")
+c
+ call tng_output_file_set(traj, TNG_EXAMPLE_FILES_DIR"tng_md_out_f77.tng")
write ( *, '(a)' ) ' Creating molecules in trajectory.'
tng_n_particles = np
c
c Add the box shape data block
-c
+c
call tng_data_block_add(traj, TNG_TRAJ_BOX_SHAPE, "BOX SHAPE",
& TNG_DOUBLE_DATA, TNG_NON_TRAJECTORY_BLOCK, int(1, 8),
& int(9, 8), int(1, 8), TNG_UNCOMPRESSED, box_shape)
c
c Write the file headers
-c
+c
call tng_file_headers_write(traj, TNG_USE_HASH)
-
+
c
c Set initial positions, velocities, and accelerations.
-c
- write ( *, '(a)' )
+c
+ write ( *, '(a)' )
& ' Initializing positions, velocities, and accelerations.'
seed = 123456789
call initialize ( np, nd, box, seed, pos, vel, acc )
write ( *, '(a)' ) ' '
write ( *, '(a)' ) ' Computing initial forces and energies.'
- call compute ( np, nd, pos, vel, mass, force, potential,
+ call compute ( np, nd, pos, vel, mass, force, potential,
& kinetic )
e0 = potential + kinetic
c Saving frequency
c
step_save = 5
-
+
step_print = 0
step_print_index = 0
step_print_num = 10
& ' steps particle positions, velocities and forces are'
write ( *, '(a)' ) ' saved to a TNG trajectory file.'
write ( *, '(a)' )
- write ( *, '(a)' )
+ write ( *, '(a)' )
& ' At each step, we report the potential and kinetic energies.'
- write ( *, '(a)' )
+ write ( *, '(a)' )
& ' The sum of these energies should be a constant.'
- write ( *, '(a)' )
+ write ( *, '(a)' )
& ' As an accuracy check, we also print the relative error'
write ( *, '(a)' ) ' in the total energy.'
write ( *, '(a)' ) ' '
- write ( *, '(a)' )
+ write ( *, '(a)' )
& ' Step Potential Kinetic (P+K-E0)/E0'
- write ( *, '(a)' )
+ write ( *, '(a)' )
& ' Energy P Energy K ' //
& 'Relative Energy Error'
write ( *, '(a)' ) ' '
step = 0
- write ( *, '(2x,i8,2x,g14.6,2x,g14.6,2x,g14.6)' )
+ write ( *, '(2x,i8,2x,g14.6,2x,g14.6,2x,g14.6)' )
& step, potential, kinetic, ( potential + kinetic - e0 ) / e0
step_print_index = step_print_index + 1
step_print = ( step_print_index * step_num ) / step_print_num
-c
-c Create a frame set for writing data
+c
+c Create a frame set for writing data
c
call tng_num_frames_per_frame_set_get(traj,
& n_frames_per_frame_set)
& "POSITIONS", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
& n_frames_per_frame_set, int(3, 8), int(1, 8), int(0, 8),
& tng_n_particles, TNG_UNCOMPRESSED, %VAL(int(0, 8)))
-
+
call tng_particle_data_block_add(traj, TNG_TRAJ_VELOCITIES,
& "VELOCITIES", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
& n_frames_per_frame_set, int(3, 8), int(1, 8), int(0, 8),
& tng_n_particles, TNG_UNCOMPRESSED, %VAL(int(0, 8)))
-
+
call tng_particle_data_block_add(traj, TNG_TRAJ_FORCES,
& "FORCES", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
& n_frames_per_frame_set, int(3, 8), int(1, 8), int(0, 8),
c
c The potential energy data block is saved sparsely.
-c
+c
call tng_data_block_add(traj, int(10101, 8),
& "POTENTIAL ENERGY", TNG_DOUBLE_DATA, TNG_TRAJECTORY_BLOCK,
& n_frames_per_frame_set, int(1, 8), sparse_save,
& TNG_UNCOMPRESSED, %VAL(int(0, 8)))
-
+
c
c Write the frame set to disk
c
call tng_frame_set_write(traj, TNG_USE_HASH)
-
+
wtime = omp_get_wtime ( )
do step = 1, step_num
- call compute ( np, nd, pos, vel, mass, force, potential,
+ call compute ( np, nd, pos, vel, mass, force, potential,
& kinetic )
if ( step .eq. step_print ) then
- write ( *, '(2x,i8,2x,g14.6,2x,g14.6,2x,g14.6)' )
+ write ( *, '(2x,i8,2x,g14.6,2x,g14.6,2x,g14.6)' )
& step, potential, kinetic, ( potential + kinetic - e0 ) / e0
step_print_index = step_print_index + 1
& TNG_TRAJ_FORCES, int(0, 8), tng_n_particles, force,
& TNG_USE_HASH)
frames_saved_cnt = frames_saved_cnt + 1
-
+
if (mod(step, step_save * sparse_save) .EQ. 0) then
call tng_frame_data_write(traj, frames_saved_cnt,
& int(10101, 8), potential, TNG_USE_HASH)
end if
-
+
end if
call update ( np, nd, pos, vel, force, acc, mass, dt )
wtime = omp_get_wtime ( ) - wtime
write ( *, '(a)' ) ' '
- write ( *, '(a)' )
+ write ( *, '(a)' )
& ' Elapsed time for main computation:'
write ( *, '(2x,g14.6,a)' ) wtime, ' seconds'
c
c
c Licensing:
c
-c This code is distributed under the GNU LGPL license.
+c This code is distributed under the GNU LGPL license.
c
c Modified:
c
pot = 0.0D+00
kin = 0.0D+00
-c$omp parallel
-c$omp& shared ( f, nd, np, pos, vel )
-c$omp& private ( d, d2, i, j, k, rij )
+c$omp parallel
+c$omp& shared ( f, nd, np, pos, vel )
+c$omp& private ( d, d2, i, j, k, rij )
c$omp do reduction ( + : pot, kin )
do i = 1, np
c$omp end parallel
kin = kin * 0.5D+00 * mass
-
+
return
end
subroutine dist ( nd, r1, r2, dr, d )
c
c Licensing:
c
-c This code is distributed under the GNU LGPL license.
+c This code is distributed under the GNU LGPL license.
c
c Modified:
c
c
c Licensing:
c
-c This code is distributed under the GNU LGPL license.
+c This code is distributed under the GNU LGPL license.
c
c Modified:
c
end do
end do
-c$omp parallel
+c$omp parallel
c$omp& shared ( acc, box, nd, np, pos, vel )
c$omp& private ( i, j )
c
c Licensing:
c
-c This code is distributed under the GNU LGPL license.
+c This code is distributed under the GNU LGPL license.
c
c Modified:
c
c
c Licensing:
c
-c This code is distributed under the GNU LGPL license.
+c This code is distributed under the GNU LGPL license.
c
c Modified:
c
save month
data month /
- & 'January ', 'February ', 'March ', 'April ',
- & 'May ', 'June ', 'July ', 'August ',
+ & 'January ', 'February ', 'March ', 'April ',
+ & 'May ', 'June ', 'July ', 'August ',
& 'September', 'October ', 'November ', 'December ' /
call date_and_time ( date, time )
end if
end if
- write ( *,
- & '(i2,1x,a,1x,i4,2x,i2,a1,i2.2,a1,i2.2,a1,i3.3,1x,a)' )
+ write ( *,
+ & '(i2,1x,a,1x,i4,2x,i2,a1,i2.2,a1,i2.2,a1,i3.3,1x,a)' )
& d, month(m), y, h, ':', n, ':', s, '.', mm, ampm
return
c
c Licensing:
c
-c This code is distributed under the GNU LGPL license.
+c This code is distributed under the GNU LGPL license.
c
c Modified:
c
rmass = 1.0D+00 / mass
-c$omp parallel
+c$omp parallel
c$omp& shared ( acc, dt, f, nd, np, pos, rmass, vel )
c$omp& private ( i, j )
do j = 1, np
do i = 1, nd
- pos(i,j) = pos(i,j)
+ pos(i,j) = pos(i,j)
& + vel(i,j) * dt + 0.5D+00 * acc(i,j) * dt * dt
- vel(i,j) = vel(i,j)
+ vel(i,j) = vel(i,j)
& + 0.5D+00 * dt * ( f(i,j) * rmass + acc(i,j) )
acc(i,j) = f(i,j) * rmass
__FILE__, __LINE__);
return(TNG_FAILURE);
}
-
stat = tng_util_trajectory_close(&traj);
if(stat != TNG_SUCCESS)
{
--- /dev/null
+# Test project to test building with libtng_io
+#
+# Combinations to test for full coverage:
+# TEST_ZLIB=ON (22 combinations)
+# ZLIB_LIBRARY=shared/static
+# TEST_BUNDLING=ON (4 combinations)
+# BUILD_SHARED_LIBS=ON/OFF
+# TEST_EXECUTABLE=ON/OFF
+# TEST_BUNDLING=OFF (7 combinations)
+# TEST_EXECUTABLE=ON
+# TNG_IO_DIR=sh.sh/st.sh/st.st
+# TEST_EXECUTABLE=OFF
+# BUILD_SHARED_LIBS=ON
+# TNG_IO_DIR=sh.sh/st.sh/st.st
+# BUILD_SHARED_LIBS=OFF
+# TNG_IO_DIR=sh.sh
+# TEST_ZLIB=OFF (27 combinations)
+# TEST_BUNDLING=ON (12 combinations)
+# ZLIB_LIBRARY=shared/static/none
+# BUILD_SHARED_LIBS=ON/OFF
+# TEST_EXECUTABLE=ON/OFF
+# TEST_BUNDLING=OFF (15 combinations)
+# TEST_EXECUTABLE=ON
+# TNG_IO_DIR=sh.sh/sh.st/sh.int/st.sh/st.st/st.int
+# TEST_EXECUTABLE=OFF
+# BUILD_SHARED_LIBS=ON
+# TNG_IO_DIR=sh.sh/sh.st/sh.int/st.sh/st.st/st.int
+# BUILD_SHARED_LIBS=OFF
+# TNG_IO_DIR=sh.sh/sh.st/sh.int
+#
+# Combinations that cannot work:
+# TEST_ZLIB=ON, tng built with internal zlib
+# TEST_ZLIB=ON, tng built with BUILD_SHARED_LIBS=ON + static zlib
+# BUILD_SHARED_LIBS=ON, tng built as static (unless compiled with PIC)
+
+cmake_minimum_required(VERSION 3.1)
+
+project(tng_io_test)
+
+option(BUILD_SHARED_LIBS "Test building a shared library" ON)
+option(TEST_EXECUTABLE "Test building an executable instead of a library" OFF)
+option(TEST_BUNDLING "Test bundling tng" OFF)
+option(TEST_ZLIB "Test with zlib in using code" OFF)
+option(TEST_BUNDLED_ZLIB "Test bundling zlib with tng" OFF)
+if (NOT TEST_BUNDLING)
+ set(TEST_BUNDLED_ZLIB OFF)
+endif()
+
+if (TEST_ZLIB OR NOT TEST_BUNDLED_ZLIB)
+ find_package(ZLIB REQUIRED)
+endif()
+
+if (TEST_BUNDLING)
+ include(../../../BuildTNG.cmake)
+ if (TEST_BUNDLED_ZLIB)
+ message(STATUS "Bundling tng_io with internal ZLIB")
+ add_tng_io_library(tng_io OBJECT OWN_ZLIB)
+ else()
+ message(STATUS "Bundling tng_io with external ZLIB")
+ add_tng_io_library(tng_io OBJECT)
+ endif()
+ add_library(tng_io::tng_io ALIAS tng_io)
+else()
+ message(STATUS "Using external tng_io")
+ find_package(TNG_IO REQUIRED)
+endif()
+
+set(SOURCES use_tng.c)
+if (TEST_ZLIB)
+ message(STATUS "Using zlib in test application")
+ list(APPEND SOURCES use_zlib.c)
+else()
+ message(STATUS "Not using zlib in test application")
+ list(APPEND SOURCES dummy_zlib.c)
+endif()
+
+if (TEST_EXECUTABLE)
+ message(STATUS "Building an executable linked against tng_io")
+ add_executable(test_target main.c ${SOURCES})
+else()
+ message(STATUS "Building a library linked against tng_io")
+ add_library(test_target ${SOURCES})
+ install(TARGETS test_target EXPORT test DESTINATION lib)
+ install(EXPORT test DESTINATION lib/cmake/test)
+ add_executable(test_exe main.c)
+ target_link_libraries(test_exe PRIVATE test_target)
+endif()
+
+if (TEST_BUNDLING)
+ target_link_libraries(test_target PRIVATE $<BUILD_INTERFACE:tng_io::tng_io>)
+else()
+ target_link_libraries(test_target PRIVATE tng_io::tng_io)
+endif()
+if (TEST_ZLIB)
+ target_link_libraries(test_target PRIVATE ZLIB::ZLIB)
+endif()
--- /dev/null
+void test_zlib(void)
+{
+}
--- /dev/null
+extern void test_tng(void);
+extern void test_zlib(void);
+
+int main(int argc, char *argv[])
+{
+ test_tng();
+ test_zlib();
+ return 0;
+}
--- /dev/null
+#include "tng/tng_io.h"
+
+void test_tng(void)
+{
+ tng_trajectory_t data;
+ char buf[256];
+ tng_version(data, buf, 256);
+}
--- /dev/null
+#include "zlib.h"
+
+void test_zlib(void)
+{
+ zlibVersion();
+}
add_subdirectory(gmxlib)
add_subdirectory(mdlib)
+add_subdirectory(applied-forces)
add_subdirectory(listed-forces)
add_subdirectory(commandline)
add_subdirectory(domdec)
tmpi_get_source_list(THREAD_MPI_SOURCES ${CMAKE_SOURCE_DIR}/src/external/thread_mpi/src)
list(APPEND LIBGROMACS_SOURCES ${THREAD_MPI_SOURCES})
-if(GMX_USE_TNG)
- list(APPEND LIBGROMACS_SOURCES ${TNG_SOURCES})
- if (NOT GMX_EXTERNAL_TNG)
- tng_set_source_properties(WITH_ZLIB ${HAVE_ZLIB})
- endif()
-endif()
-
get_lmfit_properties(LMFIT_SOURCES LMFIT_LIBRARIES_TO_LINK LMFIT_INCLUDE_DIRECTORY LMFIT_INCLUDE_DIR_ORDER)
include_directories(${LMFIT_INCLUDE_DIR_ORDER} SYSTEM "${LMFIT_INCLUDE_DIRECTORY}")
list(APPEND LIBGROMACS_SOURCES ${LMFIT_SOURCES})
list(APPEND LIBGROMACS_SOURCES ${GENERATED_VERSION_FILE})
if (GMX_USE_CUDA)
+ # Work around FindCUDA that prevents using target_link_libraries()
+ # with keywords otherwise...
+ set(CUDA_LIBRARIES PRIVATE ${CUDA_LIBRARIES})
cuda_add_library(libgromacs ${LIBGROMACS_SOURCES})
else()
add_library(libgromacs ${LIBGROMACS_SOURCES})
endif()
set_source_files_properties(selection/scanner.cpp PROPERTIES COMPILE_FLAGS "${_scanner_cpp_compiler_flags}")
-target_link_libraries(libgromacs
+gmx_setup_tng_for_libgromacs()
+
+target_link_libraries(libgromacs PRIVATE
${EXTRAE_LIBRARIES}
${GMX_EXTRA_LIBRARIES}
- ${TNG_IO_LIBRARIES}
${FFT_LIBRARIES} ${LINEAR_ALGEBRA_LIBRARIES}
- ${XML_LIBRARIES}
${LMFIT_LIBRARIES_TO_LINK}
${THREAD_LIB} ${GMX_SHARED_LINKER_FLAGS} ${OPENCL_LIBRARIES}
${GMX_STDLIB_LIBRARIES})
/*
* 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.
void
-AnalysisDataHandle::setPoints(int firstColumn, int count, const real *values)
+AnalysisDataHandle::setPoints(int firstColumn, int count, const real *values,
+ bool bPresent)
{
GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
"setPoints() called without calling startFrame()");
for (int i = 0; i < count; ++i)
{
- impl_->currentFrame_->setValue(firstColumn + i, values[i]);
+ impl_->currentFrame_->setValue(firstColumn + i, values[i], bPresent);
}
}
/*
* 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.
* \param[in] firstColumn Zero-based column index.
* \param[in] count Number of columns to set.
* \param[in] values Value array of \p column items.
+ * \param[in] bPresent Present flag to set for the column.
*
- * Equivalent to calling setPoint(firstColumn + i, values[i]) for
+ * Equivalent to calling setPoint(firstColumn + i, values[i], bPresent) for
* i from 0 to count.
*
* Does not throw.
*/
- void setPoints(int firstColumn, int count, const real *values);
+ void setPoints(int firstColumn, int count, const real *values, bool bPresent = true);
/*! \brief
* Finish data for the current point set.
*
/*
* 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.
{
impl_->bAllowMissing_ = false;
}
- impl_->modules_.push_back(Impl::ModuleInfo(module));
+ impl_->modules_.emplace_back(module);
}
void
/*
* 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.
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;
}
}
}
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_));
}
}
/*
* 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.
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)
{
- _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_));
}
/*
* 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.
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();
}
}
/*
* 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.
void
AbstractPlotModule::appendLegend(const char *setname)
{
- impl_->legend_.push_back(setname);
+ impl_->legend_.emplace_back(setname);
}
{
for (int d = 0; d < DIM; ++d)
{
- if (bWrite_[i])
+ if (bWrite_[d])
{
writeValue(points.values()[i + d]);
}
/*
* 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.
}
//! 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:
--- /dev/null
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# 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.
+#
+# 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_libgromacs_sources(
+ electricfield.cpp
+ )
+
+if (BUILD_TESTING)
+ add_subdirectory(tests)
+endif()
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * 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.
+ *
+ * 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
+ * Declares data structure and utilities for electric fields
+ *
+ * \author David van der Spoel <david.vanderspoel@icm.uu.se>
+ * \ingroup module_applied_forces
+ */
+#include "gmxpre.h"
+
+#include "electricfield.h"
+
+#include <cmath>
+
+#include "gromacs/commandline/filenm.h"
+#include "gromacs/fileio/gmxfio.h"
+#include "gromacs/fileio/gmxfio-xdr.h"
+#include "gromacs/fileio/readinp.h"
+#include "gromacs/fileio/warninp.h"
+#include "gromacs/fileio/xvgr.h"
+#include "gromacs/gmxlib/network.h"
+#include "gromacs/math/units.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/ioptionscontainerwithsections.h"
+#include "gromacs/options/optionsection.h"
+#include "gromacs/utility/compare.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/keyvaluetreetransform.h"
+#include "gromacs/utility/pleasecite.h"
+#include "gromacs/utility/strconvert.h"
+#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/txtdump.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+/*! \internal
+ * \brief Declaration of storage unit for fields
+ */
+class ElectricFieldData
+{
+ public:
+ ElectricFieldData() : a_(0), omega_(0), t0_(0), sigma_(0)
+ {
+ }
+
+ /*! \brief
+ * Adds an option section to specify parameters for this field component.
+ */
+ void initMdpOptions(IOptionsContainerWithSections *options, const char *sectionName)
+ {
+ auto section = options->addSection(OptionSection(sectionName));
+ section.addOption(RealOption("E0").store(&a_));
+ section.addOption(RealOption("omega").store(&omega_));
+ section.addOption(RealOption("t0").store(&t0_));
+ section.addOption(RealOption("sigma").store(&sigma_));
+ }
+
+ /*! \brief Evaluates this field component at given time.
+ *
+ * \param[in] t The time to evualate at
+ * \return The electric field
+ */
+ real evaluate(real t) const
+ {
+ if (sigma_ > 0)
+ {
+ return a_ * (std::cos(omega_*(t-t0_))
+ * std::exp(-square(t-t0_)/(2.0*square(sigma_))));
+ }
+ else
+ {
+ return a_ * std::cos(omega_*t);
+ }
+ }
+
+ /*! \brief Initiate the field values
+ *
+ * \param[in] a Amplitude
+ * \param[in] omega Frequency
+ * \param[in] t0 Peak of the pulse
+ * \param[in] sigma Width of the pulse
+ */
+ void setField(real a, real omega, real t0, real sigma)
+ {
+ a_ = a;
+ omega_ = omega;
+ t0_ = t0;
+ sigma_ = sigma;
+ }
+
+ //! Return the amplitude
+ real a() const { return a_; }
+ //! Return the frequency
+ real omega() const { return omega_; }
+ //! Return the time for the peak of the pulse
+ real t0() const { return t0_; }
+ //! Return the width of the pulse (0 means inifinite)
+ real sigma() const { return sigma_; }
+
+ private:
+ //! Coeffient (V / nm)
+ real a_;
+ //! Frequency (1/ps)
+ real omega_;
+ //! Central time point (ps) for pulse
+ real t0_;
+ //! Width of pulse (ps, if zero there is no pulse)
+ real sigma_;
+};
+
+/*! \internal
+ * \brief Describe time dependent electric field
+ *
+ * Class that implements a force to be evaluated in mdrun.
+ * The electric field can be pulsed and oscillating, simply
+ * oscillating, or static, in each of X,Y,Z directions.
+ */
+class ElectricField : public IInputRecExtension, public IForceProvider
+{
+ public:
+ ElectricField() : fpField_(nullptr) {}
+
+ // From IInputRecExtension
+ virtual void doTpxIO(t_fileio *fio, bool bRead);
+ virtual void initMdpTransform(IKeyValueTreeTransformRules *transform);
+ virtual void initMdpOptions(IOptionsContainerWithSections *options);
+ virtual void broadCast(const t_commrec *cr);
+ virtual void compare(FILE *fp,
+ const IInputRecExtension *field2,
+ real reltol,
+ real abstol);
+ virtual void printParameters(FILE *fp, int indent);
+ virtual void initOutput(FILE *fplog, int nfile, const t_filenm fnm[],
+ bool bAppendFiles, const gmx_output_env_t *oenv);
+ virtual void finishOutput();
+ virtual void initForcerec(t_forcerec *fr);
+
+ //! \copydoc gmx::IForceProvider::calculateForces
+ virtual void calculateForces(const t_commrec *cr,
+ const t_mdatoms *atoms,
+ PaddedRVecVector *force,
+ double t);
+
+ private:
+ //! Return whether or not to apply a field
+ bool isActive() const;
+
+ /*! \brief Add a component to the electric field
+ *
+ * The electric field has three spatial dimensions that are
+ * added to the data structure one at a time.
+ * \param[in] dim Dimension, XX, YY, ZZ (0, 1, 2)
+ * \param[in] a Amplitude of the field in V/nm
+ * \param[in] omega Frequency (1/ps)
+ * \param[in] t0 Time of pulse peak (ps)
+ * \param[in] sigma Width of peak (ps)
+ */
+ void setFieldTerm(int dim, real a, real omega, real t0, real sigma);
+
+ /*! \brief Return the field strength
+ *
+ * \param[in] dim The spatial direction
+ * \param[in] t The time (ps)
+ * \return The field strength in V/nm units
+ */
+ real field(int dim, real t) const;
+
+ /*! \brief Return amplitude of field
+ *
+ * \param[in] dim Direction of the field (XX, YY, ZZ)
+ * \return Amplitude of the field
+ */
+ real a(int dim) const { return efield_[dim].a(); }
+ /*! \brief Return frequency of field (1/ps)
+ *
+ * \param[in] dim Direction of the field (XX, YY, ZZ)
+ * \return Frequency of the field
+ */
+ real omega(int dim) const { return efield_[dim].omega(); }
+ /*! \brief Return time of pulse peak
+ *
+ * \param[in] dim Direction of the field (XX, YY, ZZ)
+ * \return Time of pulse peak
+ */
+ real t0(int dim) const { return efield_[dim].t0(); }
+ /*! \brief Return width of the pulse
+ *
+ * \param[in] dim Direction of the field (XX, YY, ZZ)
+ * \return Width of the pulse
+ */
+ real sigma(int dim) const { return efield_[dim].sigma(); }
+
+ /*! \brief Print the field components to a file
+ *
+ * \param[in] t The time
+ * Will throw and exit with fatal error if file is not open.
+ */
+ void printComponents(double t) const;
+
+ //! The field strength in each dimension
+ ElectricFieldData efield_[DIM];
+ //! File pointer for electric field
+ FILE *fpField_;
+};
+
+void ElectricField::doTpxIO(t_fileio *fio, bool bRead)
+{
+ // The content of the tpr file for this feature has
+ // been the same since gromacs 4.0 that was used for
+ // developing.
+ for (int j = 0; (j < DIM); j++)
+ {
+ int n = 0, nt = 0;
+ if (!bRead)
+ {
+ n = 1;
+ if (omega(j) != 0 || sigma(j) != 0 || t0(j) != 0)
+ {
+ nt = 1;
+ }
+ }
+ gmx_fio_do_int(fio, n);
+ gmx_fio_do_int(fio, nt);
+ std::vector<real> aa, phi, at, phit;
+ if (!bRead)
+ {
+ aa.push_back(a(j));
+ phi.push_back(t0(j));
+ at.push_back(omega(j));
+ phit.push_back(sigma(j));
+ }
+ else
+ {
+ aa.resize(n+1);
+ phi.resize(nt+1);
+ at.resize(nt+1);
+ phit.resize(nt+1);
+ }
+ gmx_fio_ndo_real(fio, aa.data(), n);
+ gmx_fio_ndo_real(fio, phi.data(), n);
+ gmx_fio_ndo_real(fio, at.data(), nt);
+ gmx_fio_ndo_real(fio, phit.data(), nt);
+ if (bRead && n > 0)
+ {
+ setFieldTerm(j, aa[0], at[0], phi[0], phit[0]);
+ if (n > 1 || nt > 1)
+ {
+ gmx_fatal(FARGS, "Can not handle tpr files with more than one electric field term per direction.");
+ }
+ }
+ }
+}
+
+//! Converts static parameters from mdp format to E0.
+real convertStaticParameters(const std::string &value)
+{
+ // TODO: Better context for the exceptions here (possibly
+ // also convert them to warning_errors or such).
+ const std::vector<std::string> sx = splitString(value);
+ if (sx.empty())
+ {
+ return 0.0;
+ }
+ const int n = fromString<int>(sx[0]);
+ if (n <= 0)
+ {
+ return 0.0;
+ }
+ if (n != 1)
+ {
+ GMX_THROW(InvalidInputError("Only one electric field term supported for each dimension"));
+ }
+ if (sx.size() != 3)
+ {
+ GMX_THROW(InvalidInputError("Expected exactly one electric field amplitude value"));
+ }
+ return fromString<real>(sx[1]);
+}
+
+//! Converts dynamic parameters from mdp format to (omega, t0, sigma).
+void convertDynamicParameters(gmx::KeyValueTreeObjectBuilder *builder,
+ const std::string &value)
+{
+ const std::vector<std::string> sxt = splitString(value);
+ if (sxt.empty())
+ {
+ return;
+ }
+ const int n = fromString<int>(sxt[0]);
+ switch (n)
+ {
+ case 1:
+ if (sxt.size() != 3)
+ {
+ GMX_THROW(InvalidInputError("Please specify 1 omega 0 for non-pulsed fields"));
+ }
+ builder->addValue<real>("omega", fromString<real>(sxt[1]));
+ break;
+ case 3:
+ if (sxt.size() != 7)
+ {
+ GMX_THROW(InvalidInputError("Please specify 1 omega 0 t0 0 sigma 0 for pulsed fields"));
+ }
+ builder->addValue<real>("omega", fromString<real>(sxt[1]));
+ builder->addValue<real>("t0", fromString<real>(sxt[3]));
+ builder->addValue<real>("sigma", fromString<real>(sxt[5]));
+ break;
+ default:
+ GMX_THROW(InvalidInputError("Incomprehensible input for electric field"));
+ }
+}
+
+void ElectricField::initMdpTransform(IKeyValueTreeTransformRules *rules)
+{
+ rules->addRule().from<std::string>("/E-x").to<real>("/electric-field/x/E0")
+ .transformWith(&convertStaticParameters);
+ rules->addRule().from<std::string>("/E-xt").toObject("/electric-field/x")
+ .transformWith(&convertDynamicParameters);
+ rules->addRule().from<std::string>("/E-y").to<real>("/electric-field/y/E0")
+ .transformWith(&convertStaticParameters);
+ rules->addRule().from<std::string>("/E-yt").toObject("/electric-field/y")
+ .transformWith(&convertDynamicParameters);
+ rules->addRule().from<std::string>("/E-z").to<real>("/electric-field/z/E0")
+ .transformWith(&convertStaticParameters);
+ rules->addRule().from<std::string>("/E-zt").toObject("/electric-field/z")
+ .transformWith(&convertDynamicParameters);
+}
+
+void ElectricField::initMdpOptions(IOptionsContainerWithSections *options)
+{
+ //CTYPE ("Format is E0 (V/nm), omega (1/ps), t0 (ps), sigma (ps) ");
+ auto section = options->addSection(OptionSection("electric-field"));
+ efield_[XX].initMdpOptions(§ion, "x");
+ efield_[YY].initMdpOptions(§ion, "y");
+ efield_[ZZ].initMdpOptions(§ion, "z");
+}
+
+void ElectricField::broadCast(const t_commrec *cr)
+{
+ rvec a1, omega1, sigma1, t01;
+
+ if (MASTER(cr))
+ {
+ // Load the parameters read from tpr into temp vectors
+ for (int m = 0; m < DIM; m++)
+ {
+ a1[m] = a(m);
+ omega1[m] = omega(m);
+ sigma1[m] = sigma(m);
+ t01[m] = t0(m);
+ }
+ }
+ // Broadcasting the parameters
+ gmx_bcast(DIM*sizeof(a1[0]), a1, cr);
+ gmx_bcast(DIM*sizeof(omega1[0]), omega1, cr);
+ gmx_bcast(DIM*sizeof(t01[0]), t01, cr);
+ gmx_bcast(DIM*sizeof(sigma1[0]), sigma1, cr);
+
+ // And storing them locally
+ if (!MASTER(cr))
+ {
+ for (int m = 0; m < DIM; m++)
+ {
+ setFieldTerm(m, a1[m], omega1[m], t01[m], sigma1[m]);
+ }
+ }
+}
+
+void ElectricField::initOutput(FILE *fplog, int nfile, const t_filenm fnm[],
+ bool bAppendFiles, const gmx_output_env_t *oenv)
+{
+ if (isActive())
+ {
+ please_cite(fplog, "Caleman2008a");
+
+ // Optional outpuf file showing the field, see manual.
+ if (opt2bSet("-field", nfile, fnm))
+ {
+ if (bAppendFiles)
+ {
+ fpField_ = gmx_fio_fopen(opt2fn("-field", nfile, fnm), "a+");
+ }
+ else
+ {
+ fpField_ = xvgropen(opt2fn("-field", nfile, fnm),
+ "Applied electric field", "Time (ps)",
+ "E (V/nm)", oenv);
+ }
+ }
+ }
+}
+
+void ElectricField::finishOutput()
+{
+ if (fpField_ != nullptr)
+ {
+ // This is opened sometimes with xvgropen, sometimes with
+ // gmx_fio_fopen, so we use the least common denominator for closing.
+ gmx_fio_fclose(fpField_);
+ fpField_ = nullptr;
+ }
+}
+
+void ElectricField::initForcerec(t_forcerec *fr)
+{
+ if (isActive())
+ {
+ fr->bF_NoVirSum = TRUE;
+ fr->efield = this;
+ }
+}
+
+void ElectricField::printParameters(FILE *fp, int indent)
+{
+ const char *const dimension[DIM] = { "X", "Y", "Z" };
+ indent = pr_title(fp, indent, "ElectricField");
+ for (int m = 0; m < DIM; m++)
+ {
+ pr_indent(fp, indent);
+ fprintf(fp, "-%s E0 = %g omega = %g t0 = %g sigma = %g\n",
+ dimension[m], a(m), omega(m), t0(m), sigma(m));
+ }
+}
+
+void ElectricField::setFieldTerm(int dim, real a, real omega, real t0, real sigma)
+{
+ range_check(dim, 0, DIM);
+ efield_[dim].setField(a, omega, t0, sigma);
+}
+
+real ElectricField::field(int dim, real t) const
+{
+ return efield_[dim].evaluate(t);
+}
+
+bool ElectricField::isActive() const
+{
+ return (efield_[XX].a() != 0 ||
+ efield_[YY].a() != 0 ||
+ efield_[ZZ].a() != 0);
+}
+
+void ElectricField::compare(FILE *fp,
+ const IInputRecExtension *other,
+ real reltol,
+ real abstol)
+{
+ GMX_ASSERT(dynamic_cast<const ElectricField *>(other) != nullptr,
+ "Invalid other type");
+ const ElectricField *f2 = static_cast<const ElectricField *>(other);
+ for (int m = 0; (m < DIM); m++)
+ {
+ char buf[256];
+
+ sprintf(buf, "inputrec->field[%d]", m);
+ cmp_real(fp, buf, -1, a(m), f2->a(m), reltol, abstol);
+ cmp_real(fp, buf, -1, omega(m), f2->omega(m), reltol, abstol);
+ cmp_real(fp, buf, -1, t0(m), f2->t0(m), reltol, abstol);
+ cmp_real(fp, buf, -1, sigma(m), f2->sigma(m), reltol, abstol);
+ }
+}
+
+void ElectricField::printComponents(double t) const
+{
+ fprintf(fpField_, "%10g %10g %10g %10g\n", t,
+ field(XX, t), field(YY, t), field(ZZ, t));
+}
+
+void ElectricField::calculateForces(const t_commrec *cr,
+ const t_mdatoms *mdatoms,
+ PaddedRVecVector *force,
+ double t)
+{
+ if (isActive())
+ {
+ rvec *f = as_rvec_array(force->data());
+
+ for (int m = 0; (m < DIM); m++)
+ {
+ real Ext = FIELDFAC*field(m, t);
+
+ if (Ext != 0)
+ {
+ // TODO: Check parallellism
+ for (int i = 0; i < mdatoms->homenr; ++i)
+ {
+ // NOTE: Not correct with perturbed charges
+ f[i][m] += mdatoms->chargeA[i]*Ext;
+ }
+ }
+ }
+ if (MASTER(cr) && fpField_ != nullptr)
+ {
+ printComponents(t);
+ }
+ }
+}
+
+} // namespace
+
+std::unique_ptr<IInputRecExtension> createElectricFieldModule()
+{
+ return std::unique_ptr<IInputRecExtension>(new ElectricField());
+}
+
+} // namespace gmx
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * 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.
+ *
+ * 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_APPLIED_FORCES_ELECTRICFIELD_H
+#define GMX_APPLIED_FORCES_ELECTRICFIELD_H
+
+#include <memory>
+
+namespace gmx
+{
+
+class IInputRecExtension;
+
+/*! \brief
+ * Creates a module for an external electric field.
+ *
+ * The returned class describes the time dependent electric field that can
+ * be applied to all charges in a simulation. The field is described
+ * by the following:
+ * E(t) = A cos(omega*(t-t0))*exp(-sqr(t-t0)/(2.0*sqr(sigma)));
+ * If sigma = 0 there is no pulse and we have instead
+ * E(t) = A cos(omega*t)
+ *
+ * force is kJ mol^-1 nm^-1 = e * kJ mol^-1 nm^-1 / e
+ *
+ * WARNING:
+ * There can be problems with the virial.
+ * Since the field is not self-consistent this is unavoidable.
+ * For neutral molecules the virial is correct within this approximation.
+ * For neutral systems with many charged molecules the error is small.
+ * But for systems with a net charge or a few charged molecules
+ * the error can be significant when the field is high.
+ * Solution: implement a self-consistent electric field into PME.
+ */
+std::unique_ptr<IInputRecExtension> createElectricFieldModule();
+
+} // namespace gmx
+
+#endif
--- /dev/null
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# 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.
+#
+# 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(AppliedForcesUnitTest applied-forces-test
+ electricfield.cpp
+ )
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * 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.
+ *
+ * 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 functionality of the "angle" trajectory analysis module.
+ *
+ * \author David van der Spoel <david.vanderspoel@icm.uu.se>
+ * \ingroup module_applied_forces
+ */
+#include "gmxpre.h"
+
+#include "gromacs/applied-forces/electricfield.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/gmxlib/network.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/mdlib/forcerec.h"
+#include "gromacs/mdrunutility/mdmodules.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/treesupport.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/keyvaluetreetransform.h"
+#include "gromacs/utility/real.h"
+#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringcompare.h"
+#include "gromacs/utility/stringutil.h"
+
+#include "testutils/testasserts.h"
+
+namespace
+{
+
+/********************************************************************
+ * ElectricFieldTest
+ */
+
+class ElectricFieldTest : public ::testing::Test
+{
+ public:
+ ElectricFieldTest() {}
+
+ void test(int dim,
+ real E0,
+ real omega,
+ real t0,
+ real sigma,
+ real expectedValue)
+ {
+ gmx::test::FloatingPointTolerance tolerance(
+ gmx::test::relativeToleranceAsFloatingPoint(1.0, 0.005));
+ gmx::MDModules module;
+ t_inputrec *inputrec = module.inputrec();
+
+ // Prepare MDP inputs
+ const char *dimXYZ[3] = { "x", "y", "z" };
+ GMX_RELEASE_ASSERT((dim >= 0 && dim < 3), "Dimension should be 0, 1 or 2");
+
+ gmx::KeyValueTreeBuilder mdpValues;
+ mdpValues.rootObject().addValue(gmx::formatString("E%s", dimXYZ[dim]),
+ gmx::formatString("1 %g 0", E0));
+ mdpValues.rootObject().addValue(gmx::formatString("E%s-t", dimXYZ[dim]),
+ gmx::formatString("3 %g 0 %g 0 %g 0", omega, t0, sigma));
+
+ gmx::KeyValueTreeTransformer transform;
+ transform.rules()->addRule()
+ .keyMatchType("/", gmx::StringCompareType::CaseAndDashInsensitive);
+ inputrec->efield->initMdpTransform(transform.rules());
+ gmx::Options options;
+ inputrec->efield->initMdpOptions(&options);
+ auto result = transform.transform(mdpValues.build(), nullptr);
+ gmx::assignOptionsFromKeyValueTree(&options, result.object(), nullptr);
+
+ t_mdatoms md;
+ PaddedRVecVector f = { { 0, 0, 0 } };
+ md.homenr = 1;
+ snew(md.chargeA, md.homenr);
+ md.chargeA[0] = 1;
+
+ t_commrec *cr = init_commrec();
+ t_forcerec *forcerec = mk_forcerec();
+ inputrec->efield->initForcerec(forcerec);
+ forcerec->efield->calculateForces(cr, &md, &f, 0);
+ done_commrec(cr);
+ EXPECT_REAL_EQ_TOL(f[0][dim], expectedValue, tolerance);
+ sfree(forcerec);
+ sfree(md.chargeA);
+ }
+};
+
+TEST_F(ElectricFieldTest, Static)
+{
+ test(0, 1, 0, 0, 0, 96.4853363);
+}
+
+TEST_F(ElectricFieldTest, Oscillating)
+{
+ test(0, 1, 5, 0.2, 0, 96.4853363);
+}
+
+TEST_F(ElectricFieldTest, Pulsed)
+{
+ test(0, 1, 5, 0.5, 1, -68.215782);
+}
+
+} // namespace
/*
* 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.
{
if (bExported)
{
- exportedTopics_.push_back(topic->name());
+ exportedTopics_.emplace_back(topic->name());
}
addSubTopic(std::move(topic));
}
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
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);
/*
* 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.
IOptionsFormatter *formatter,
const Options &options);
- virtual void visitSubSection(const Options §ion);
+ virtual void visitSection(const OptionSectionInfo §ion);
virtual void visitOption(const OptionInfo &option);
private:
{
formatter_ = formatter;
filterType_ = type;
- visitSubSection(options);
+ visitSection(options.rootSection());
}
-void OptionsFilter::visitSubSection(const Options §ion)
+void OptionsFilter::visitSection(const OptionSectionInfo §ion)
{
OptionsIterator iterator(section);
- iterator.acceptSubSections(this);
+ iterator.acceptSections(this);
iterator.acceptOptions(this);
}
}
//! Formats the default option value as a string.
-std::string
-defaultOptionValue(const OptionInfo &option)
+std::string defaultOptionValue(const OptionInfo &option)
{
- if (option.valueCount() == 0
- || (option.valueCount() == 1 && option.formatValue(0).empty()))
- {
- return option.formatDefaultValueIfSet();
- }
- else
- {
- std::string result;
- for (int i = 0; i < option.valueCount(); ++i)
- {
- if (i != 0)
- {
- result.append(" ");
- }
- result.append(option.formatValue(i));
- }
- return result;
- }
+ return joinStrings(option.defaultValuesAsStrings(), " ");
}
//! Formats the flags for a file option as a string.
*/
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)
/*
* 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.
moduleGuard = factory_();
module = moduleGuard.get();
}
- Options options(name(), shortDescription());
+ Options options;
OptionsBehaviorCollection behaviors(&options);
CommandLineOptionsModuleSettings settings(&behaviors);
module->initOptions(&options, &settings);
void CommandLineOptionsModule::parseOptions(int argc, char *argv[])
{
FileNameOptionManager fileoptManager;
- Options options(name_, description_);
+ Options options;
options.addManager(&fileoptManager);
*
* 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.
std::find(xvgFormats.begin(), xvgFormats.end(), std::string(select));
if (i != xvgFormats.end())
{
- return i - xvgFormats.begin();
+ return std::distance(xvgFormats.begin(), i);
}
else
{
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)
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)
{
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;
*
* 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 "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"
public:
const std::string &optionList() const { return optionList_; }
- virtual void visitSubSection(const Options §ion)
+ virtual void visitSection(const OptionSectionInfo §ion)
{
OptionsIterator iterator(section);
- iterator.acceptSubSections(this);
+ iterator.acceptSections(this);
iterator.acceptOptions(this);
}
virtual void visitOption(const OptionInfo &option)
public:
explicit OptionCompletionWriter(TextWriter *out) : out_(*out) {}
- virtual void visitSubSection(const Options §ion)
+ virtual void visitSection(const OptionSectionInfo §ion)
{
OptionsIterator iterator(section);
- iterator.acceptSubSections(this);
+ iterator.acceptSections(this);
iterator.acceptOptions(this);
}
virtual void visitOption(const OptionInfo &option);
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 }");
}
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)
#
# 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.
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()
/*
* 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.
{
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")
{
using namespace gmx;
- Options options("test", "Short Description");
+ Options options;
bool bValue = true;
options.addOption(BooleanOption("bool").description("Boolean option")
.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());
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()
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));
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 "
using gmx::SelectionFileOption;
using gmx::SelectionOption;
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
gmx::SelectionCollection selections;
gmx::SelectionOptionManager manager(&selections);
options.addManager(&manager);
{
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"));
};
using gmx::IntegerOption;
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
options.addOption(IntegerOption("int").description("Integer option")
.defaultValue(2));
/*
* 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.
};
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;
TEST_F(CommandLineProgramContextTest, FindsBinaryFromCurrentDirectory)
{
env_->workingDirectory_ = Path::join(env_->getWorkingDirectory(), "bin");
- env_->path_.push_back("");
+ env_->path_.emplace_back("");
testBinaryPathSearch("test-exe");
}
/*
* 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.
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));
"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);
}
"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);
}
};
/*! \brief Routine to compute ACF using FFT. */
-static void low_do_four_core(int nfour, int nframes, real c1[], real cfour[],
+static void low_do_four_core(int nframes, real c1[], real cfour[],
int nCos)
{
int i = 0;
-
+ std::vector<std::vector<real> > data;
+ data.resize(1);
+ data[0].resize(nframes, 0);
switch (nCos)
{
case enNorm:
for (i = 0; (i < nframes); i++)
{
- cfour[i] = c1[i];
+ data[0][i] = c1[i];
}
break;
case enCos:
for (i = 0; (i < nframes); i++)
{
- cfour[i] = cos(c1[i]);
+ data[0][i] = cos(c1[i]);
}
break;
case enSin:
for (i = 0; (i < nframes); i++)
{
- cfour[i] = sin(c1[i]);
+ data[0][i] = sin(c1[i]);
}
break;
default:
gmx_fatal(FARGS, "nCos = %d, %s %d", nCos, __FILE__, __LINE__);
}
- many_auto_correl(1, nframes, nfour, &cfour);
+ many_auto_correl(&data);
+ for (i = 0; (i < nframes); i++)
+ {
+ cfour[i] = data[0][i];
+ }
}
/*! \brief Routine to comput ACF without FFT. */
}
/*! \brief High level ACF routine. */
-void do_four_core(unsigned long mode, int nfour, int nf2, int nframes,
- real c1[], real csum[], real ctmp[])
+static void do_four_core(unsigned long mode, int nframes,
+ real c1[], real csum[], real ctmp[])
{
real *cfour;
char buf[32];
real fac;
int j, m, m1;
- snew(cfour, nfour);
+ snew(cfour, nframes);
if (MODE(eacNormal))
{
/********************************************
* N O R M A L
********************************************/
- low_do_four_core(nfour, nf2, c1, csum, enNorm);
+ low_do_four_core(nframes, c1, csum, enNorm);
}
else if (MODE(eacCos))
{
/* Copy the data to temp array. Since we need it twice
* we can't overwrite original.
*/
- for (j = 0; (j < nf2); j++)
+ for (j = 0; (j < nframes); j++)
{
ctmp[j] = c1[j];
}
/* Cosine term of AC function */
- low_do_four_core(nfour, nf2, ctmp, cfour, enCos);
- for (j = 0; (j < nf2); j++)
+ low_do_four_core(nframes, ctmp, cfour, enCos);
+ for (j = 0; (j < nframes); j++)
{
c1[j] = cfour[j];
}
/* Sine term of AC function */
- low_do_four_core(nfour, nf2, ctmp, cfour, enSin);
- for (j = 0; (j < nf2); j++)
+ low_do_four_core(nframes, ctmp, cfour, enSin);
+ for (j = 0; (j < nframes); j++)
{
c1[j] += cfour[j];
csum[j] = c1[j];
/* Because of normalization the number of -0.5 to subtract
* depends on the number of data points!
*/
- for (j = 0; (j < nf2); j++)
+ for (j = 0; (j < nframes); j++)
{
- csum[j] = -0.5*(nf2-j);
+ csum[j] = -0.5*(nframes-j);
}
/***** DIAGONAL ELEMENTS ************/
for (m = 0; (m < DIM); m++)
{
/* Copy the vector data in a linear array */
- for (j = 0; (j < nf2); j++)
+ for (j = 0; (j < nframes); j++)
{
ctmp[j] = gmx::square(c1[DIM*j+m]);
}
if (debug)
{
sprintf(buf, "c1diag%d.xvg", m);
- dump_tmp(buf, nf2, ctmp);
+ dump_tmp(buf, nframes, ctmp);
}
- low_do_four_core(nfour, nf2, ctmp, cfour, enNorm);
+ low_do_four_core(nframes, ctmp, cfour, enNorm);
if (debug)
{
sprintf(buf, "c1dfout%d.xvg", m);
- dump_tmp(buf, nf2, cfour);
+ dump_tmp(buf, nframes, cfour);
}
fac = 1.5;
- for (j = 0; (j < nf2); j++)
+ for (j = 0; (j < nframes); j++)
{
csum[j] += fac*(cfour[j]);
}
{
/* Copy the vector data in a linear array */
m1 = (m+1) % DIM;
- for (j = 0; (j < nf2); j++)
+ for (j = 0; (j < nframes); j++)
{
ctmp[j] = c1[DIM*j+m]*c1[DIM*j+m1];
}
if (debug)
{
sprintf(buf, "c1off%d.xvg", m);
- dump_tmp(buf, nf2, ctmp);
+ dump_tmp(buf, nframes, ctmp);
}
- low_do_four_core(nfour, nf2, ctmp, cfour, enNorm);
+ low_do_four_core(nframes, ctmp, cfour, enNorm);
if (debug)
{
sprintf(buf, "c1ofout%d.xvg", m);
- dump_tmp(buf, nf2, cfour);
+ dump_tmp(buf, nframes, cfour);
}
fac = 3.0;
- for (j = 0; (j < nf2); j++)
+ for (j = 0; (j < nframes); j++)
{
csum[j] += fac*cfour[j];
}
* First for XX, then for YY, then for ZZ
* After that we sum them and normalise
*/
- for (j = 0; (j < nf2); j++)
+ for (j = 0; (j < nframes); j++)
{
csum[j] = 0.0;
}
for (m = 0; (m < DIM); m++)
{
/* Copy the vector data in a linear array */
- for (j = 0; (j < nf2); j++)
+ for (j = 0; (j < nframes); j++)
{
ctmp[j] = c1[DIM*j+m];
}
- low_do_four_core(nfour, nf2, ctmp, cfour, enNorm);
- for (j = 0; (j < nf2); j++)
+ low_do_four_core(nframes, ctmp, cfour, enNorm);
+ for (j = 0; (j < nframes); j++)
{
csum[j] += cfour[j];
}
}
sfree(cfour);
- for (j = 0; (j < nf2); j++)
+ for (j = 0; (j < nframes); j++)
{
c1[j] = csum[j]/(real)(nframes-j);
}
int eFitFn)
{
FILE *fp, *gp = NULL;
- int i, nfour;
+ int i;
real *csum;
real *ctmp, *fit;
real sum, Ct2av, Ctav;
gmx::boolToString(bNormalize));
printf("mode = %lu, dt = %g, nrestart = %d\n", mode, dt, nrestart);
}
- if (bFour)
- {
- /* For FTT corr., we need to pad the data with at least nframes zeros */
- nfour = 2;
- while (2*nframes > nfour)
- {
- nfour *= 2;
- }
- if (debug)
- {
- fprintf(debug, "Using FFT to calculate %s, #points for FFT = %d\n",
- title, nfour);
- }
-
- /* Allocate temp arrays */
- snew(csum, nfour);
- snew(ctmp, nfour);
- }
- else
- {
- nfour = 0; /* To keep the compiler happy */
- snew(csum, nframes);
- snew(ctmp, nframes);
- }
+ /* Allocate temp arrays */
+ snew(csum, nframes);
+ snew(ctmp, nframes);
/* Loop over items (e.g. molecules or dihedrals)
* In this loop the actual correlation functions are computed, but without
if (bFour)
{
- do_four_core(mode, nfour, nframes, nframes, c1[i], csum, ctmp);
+ do_four_core(mode, nframes, c1[i], csum, ctmp);
}
else
{
#include "manyautocorrelation.h"
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cmath>
-
#include <algorithm>
#include "gromacs/fft/fft.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxomp.h"
-#include "gromacs/utility/smalloc.h"
-int many_auto_correl(int nfunc, int ndata, int nfft, real **c)
+int many_auto_correl(std::vector<std::vector<real> > *c)
{
+ size_t nfunc = (*c).size();
+ if (nfunc == 0)
+ {
+ GMX_THROW(gmx::InconsistentInputError("Empty array of vectors supplied"));
+ }
+ size_t ndata = (*c)[0].size();
+ if (ndata == 0)
+ {
+ GMX_THROW(gmx::InconsistentInputError("Empty vector supplied"));
+ }
+#ifndef NDEBUG
+ for (size_t i = 1; i < nfunc; i++)
+ {
+ if ((*c)[i].size() != ndata)
+ {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "Vectors of different lengths supplied (%d %d)",
+ static_cast<int>((*c)[i].size()),
+ static_cast<int>(ndata));
+ GMX_THROW(gmx::InconsistentInputError(buf));
+ }
+ }
+#endif
+ // Add buffer size to the arrays.
+ size_t nfft = (3*ndata/2) + 1;
+ // Pad arrays with zeros
+ for (auto &i : *c)
+ {
+ i.resize(nfft, 0);
+ }
#pragma omp parallel
{
try
{
- typedef real complex[2];
- int i, j;
- gmx_fft_t fft1;
- complex *in, *out;
- int i0, i1;
- int nthreads, thread_id;
+ gmx_fft_t fft1;
+ std::vector<real> in, out;
- nthreads = gmx_omp_get_max_threads();
- thread_id = gmx_omp_get_thread_num();
- if ((0 == thread_id))
- {
- // fprintf(stderr, "There are %d threads for correlation functions\n", nthreads);
- }
- i0 = thread_id*nfunc/nthreads;
- i1 = std::min(nfunc, (thread_id+1)*nfunc/nthreads);
+ int nthreads = gmx_omp_get_max_threads();
+ int thread_id = gmx_omp_get_thread_num();
+ int i0 = (thread_id*nfunc)/nthreads;
+ int i1 = std::min(nfunc, ((thread_id+1)*nfunc)/nthreads);
gmx_fft_init_1d(&fft1, nfft, GMX_FFT_FLAG_CONSERVATIVE);
/* Allocate temporary arrays */
- snew(in, nfft);
- snew(out, nfft);
- for (i = i0; (i < i1); i++)
+ in.resize(2*nfft, 0);
+ out.resize(2*nfft, 0);
+ for (int i = i0; (i < i1); i++)
{
- for (j = 0; j < ndata; j++)
- {
- in[j][0] = c[i][j];
- in[j][1] = 0;
- }
- for (; (j < nfft); j++)
+ for (size_t j = 0; j < ndata; j++)
{
- in[j][0] = in[j][1] = 0;
+ in[2*j+0] = (*c)[i][j];
+ in[2*j+1] = 0;
}
-
- gmx_fft_1d(fft1, GMX_FFT_BACKWARD, (void *)in, (void *)out);
- for (j = 0; j < nfft; j++)
+ gmx_fft_1d(fft1, GMX_FFT_BACKWARD, (void *)in.data(), (void *)out.data());
+ for (size_t j = 0; j < nfft; j++)
{
- in[j][0] = (out[j][0]*out[j][0] + out[j][1]*out[j][1])/nfft;
- in[j][1] = 0;
+ in[2*j+0] = (out[2*j+0]*out[2*j+0] + out[2*j+1]*out[2*j+1])/nfft;
+ in[2*j+1] = 0;
}
- for (; (j < nfft); j++)
+ gmx_fft_1d(fft1, GMX_FFT_FORWARD, (void *)in.data(), (void *)out.data());
+ for (size_t j = 0; (j < nfft); j++)
{
- in[j][0] = in[j][1] = 0;
- }
-
- gmx_fft_1d(fft1, GMX_FFT_FORWARD, (void *)in, (void *)out);
- for (j = 0; (j < nfft); j++)
- {
- c[i][j] = out[j][0];
+ (*c)[i][j] = out[2*j+0];
}
}
/* Free the memory */
gmx_fft_destroy(fft1);
- sfree(in);
- sfree(out);
}
GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
}
- // gmx_fft_cleanup();
+ for (auto &i : *c)
+ {
+ i.resize(ndata);
+ }
+
return 0;
}
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2014, by the GROMACS development team, led by
+ * 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.
#ifndef GMX_MANYAUTOCORRELATION_H
#define GMX_MANYAUTOCORRELATION_H
+#include <vector>
+
#include "gromacs/fft/fft.h"
#include "gromacs/utility/real.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/*! \brief
* Perform many autocorrelation calculations.
*
* This routine performs many autocorrelation function calculations using FFTs.
- * The GROMACS FFT library wrapper is employed. On return the c[] arrays contain
+ * The GROMACS FFT library wrapper is employed. On return the c vector contain
* a symmetric function that is useful for further FFT:ing, for instance in order to
* compute spectra.
*
+ * The vectors c[i] should all have the same length, but this is not checked for.
+ *
+ * The c arrays will be extend and filled with zero beyond ndata before
+ * computing the correlation.
+ *
* The functions uses OpenMP parallellization.
*
- * \param[in] nfunc Number of data functions to autocorrelate
- * \param[in] ndata Number of valid data points in the data
- * \param[in] nfft Length of the data arrays, this should at least be 50% larger than ndata. The c arrays will filled with zero beyond ndata before computing the correlation.
- * \param[inout] c Data array of size nfunc x nfft, will also be used for output
+ * \param[inout] c Data array
* \return fft error code, or zero if everything went fine (see fft/fft.h)
+ * \throws gmx::InconsistentInputError if the input is inconsistent.
*/
-int many_auto_correl(int nfunc, int ndata, int nfft, real **c);
-
-#ifdef __cplusplus
-}
-#endif
+int many_auto_correl(std::vector<std::vector<real> > *c);
#endif
#
# This file is part of the GROMACS molecular simulation package.
#
-# Copyright (c) 2014, by the GROMACS development team, led by
+# 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.
gmx_add_unit_test(CorrelationsTest correlations-test
autocorr.cpp
+ manyautocorrelation.cpp
correlationdataset.cpp
expfit.cpp)
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * 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.
+ *
+ * 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 low level test of manyautocorrelation routines
+ *
+ * \author David van der Spoel <david.vanderspoel@icm.uu.se>
+ * \ingroup module_correlationfunctions
+ */
+#include "gmxpre.h"
+
+#include "gromacs/correlationfunctions/manyautocorrelation.h"
+
+#include <cmath>
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/exceptions.h"
+
+#include "testutils/testasserts.h"
+#include "testutils/testfilemanager.h"
+
+namespace gmx
+{
+namespace
+{
+
+class ManyAutocorrelationTest : public ::testing::Test
+{
+};
+
+TEST_F (ManyAutocorrelationTest, Empty)
+{
+ std::vector<std::vector<real> > c;
+ EXPECT_THROW_GMX(many_auto_correl(&c), gmx::InconsistentInputError);
+}
+
+#ifndef NDEBUG
+TEST_F (ManyAutocorrelationTest, DifferentLength)
+{
+ std::vector<std::vector<real> > c;
+ c.resize(3);
+ c[0].resize(10);
+ c[1].resize(10);
+ c[2].resize(8);
+ EXPECT_THROW_GMX(many_auto_correl(&c), gmx::InconsistentInputError);
+}
+#endif
+
+}
+
+}
#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"
#include "gromacs/topology/block.h"
#include "gromacs/topology/idef.h"
#include "gromacs/topology/ifunc.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/basedefinitions.h"
gmx_incons("The state does not the domain decomposition state");
}
- state->ncg_gl = dd->ncg_home;
- if (state->ncg_gl > state->cg_gl_nalloc)
- {
- state->cg_gl_nalloc = over_alloc_dd(state->ncg_gl);
- srenew(state->cg_gl, state->cg_gl_nalloc);
- }
- for (i = 0; i < state->ncg_gl; i++)
+ state->cg_gl.resize(dd->ncg_home);
+ for (i = 0; i < dd->ncg_home; i++)
{
state->cg_gl[i] = dd->index_gl[i];
}
}
}
+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];
cgs_gl = &dd->comm->cgs_gl;
- ncg_home = state_local->ncg_gl;
- cg = state_local->cg_gl;
+ ncg_home = state_local->cg_gl.size();
+ cg = state_local->cg_gl.data();
nat_home = 0;
for (i = 0; i < ncg_home; i++)
{
}
static void dd_collect_vec_sendrecv(gmx_domdec_t *dd,
- rvec *lv, rvec *v)
+ const rvec *lv, rvec *v)
{
gmx_domdec_master_t *ma;
int n, i, c, a, nalloc = 0;
if (!DDMASTER(dd))
{
#if GMX_MPI
- MPI_Send(lv, dd->nat_home*sizeof(rvec), MPI_BYTE, DDMASTERRANK(dd),
- dd->rank, dd->mpi_comm_all);
+ MPI_Send(const_cast<void *>(static_cast<const void *>(lv)), dd->nat_home*sizeof(rvec), MPI_BYTE,
+ DDMASTERRANK(dd), dd->rank, dd->mpi_comm_all);
#endif
}
else
}
static void dd_collect_vec_gatherv(gmx_domdec_t *dd,
- rvec *lv, rvec *v)
+ const rvec *lv, rvec *v)
{
gmx_domdec_master_t *ma;
int *rcounts = NULL, *disps = NULL;
}
}
-void dd_collect_vec(gmx_domdec_t *dd,
- t_state *state_local, rvec *lv, rvec *v)
+void dd_collect_vec(gmx_domdec_t *dd,
+ t_state *state_local,
+ const PaddedRVecVector *localVector,
+ rvec *v)
{
dd_collect_cg(dd, state_local);
+ const rvec *lv = as_rvec_array(localVector->data());
+
if (dd->nnodes <= GMX_DD_NNODES_SENDRECV)
{
dd_collect_vec_sendrecv(dd, lv, v);
}
}
+void dd_collect_vec(gmx_domdec_t *dd,
+ t_state *state_local,
+ const PaddedRVecVector *localVector,
+ PaddedRVecVector *vector)
+{
+ dd_collect_vec(dd, state_local, localVector, as_rvec_array(vector->data()));
+}
+
void dd_collect_state(gmx_domdec_t *dd,
t_state *state_local, t_state *state)
switch (est)
{
case estX:
- dd_collect_vec(dd, state_local, state_local->x, state->x);
+ dd_collect_vec(dd, state_local, &state_local->x, &state->x);
break;
case estV:
- dd_collect_vec(dd, state_local, state_local->v, state->v);
+ dd_collect_vec(dd, state_local, &state_local->v, &state->v);
break;
case est_SDX_NOTSUPPORTED:
break;
case estCGP:
- dd_collect_vec(dd, state_local, state_local->cg_p, state->cg_p);
+ dd_collect_vec(dd, state_local, &state_local->cg_p, &state->cg_p);
break;
case estDISRE_INITF:
case estDISRE_RM3TAV:
}
}
-static void dd_realloc_state(t_state *state, rvec **f, int nalloc)
+static void dd_resize_state(t_state *state, PaddedRVecVector *f, int natoms)
{
int est;
if (debug)
{
- fprintf(debug, "Reallocating state: currently %d, required %d, allocating %d\n", state->nalloc, nalloc, over_alloc_dd(nalloc));
+ fprintf(debug, "Resizing state: currently %d, required %d\n", state->natoms, natoms);
}
- state->nalloc = over_alloc_dd(nalloc);
-
for (est = 0; est < estNR; est++)
{
if (EST_DISTR(est) && (state->flags & (1<<est)))
switch (est)
{
case estX:
- srenew(state->x, state->nalloc + 1);
+ state->x.resize(natoms + 1);
break;
case estV:
- srenew(state->v, state->nalloc + 1);
+ state->v.resize(natoms + 1);
break;
case est_SDX_NOTSUPPORTED:
break;
case estCGP:
- srenew(state->cg_p, state->nalloc + 1);
+ state->cg_p.resize(natoms + 1);
break;
case estDISRE_INITF:
case estDISRE_RM3TAV:
/* No reallocation required */
break;
default:
- gmx_incons("Unknown state entry encountered in dd_realloc_state");
+ gmx_incons("Unknown state entry encountered in dd_resize_state");
}
}
}
if (f != NULL)
{
- srenew(*f, state->nalloc);
+ (*f).resize(natoms + 1);
}
}
-static void dd_check_alloc_ncg(t_forcerec *fr, t_state *state, rvec **f,
- int nalloc)
+static void dd_check_alloc_ncg(t_forcerec *fr,
+ t_state *state,
+ PaddedRVecVector *f,
+ int numChargeGroups)
{
- if (nalloc > fr->cg_nalloc)
+ if (numChargeGroups > fr->cg_nalloc)
{
if (debug)
{
- fprintf(debug, "Reallocating forcerec: currently %d, required %d, allocating %d\n", fr->cg_nalloc, nalloc, over_alloc_dd(nalloc));
+ fprintf(debug, "Reallocating forcerec: currently %d, required %d, allocating %d\n", fr->cg_nalloc, numChargeGroups, over_alloc_dd(numChargeGroups));
}
- fr->cg_nalloc = over_alloc_dd(nalloc);
+ fr->cg_nalloc = over_alloc_dd(numChargeGroups);
srenew(fr->cginfo, fr->cg_nalloc);
if (fr->cutoff_scheme == ecutsGROUP)
{
srenew(fr->cg_cm, fr->cg_nalloc);
}
}
- if (fr->cutoff_scheme == ecutsVERLET && nalloc > state->nalloc)
+ if (fr->cutoff_scheme == ecutsVERLET)
{
/* We don't use charge groups, we use x in state to set up
* the atom communication.
*/
- dd_realloc_state(state, f, nalloc);
+ dd_resize_state(state, f, numChargeGroups);
}
}
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);
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]);
static void dd_distribute_state(gmx_domdec_t *dd, t_block *cgs,
t_state *state, t_state *state_local,
- rvec **f)
+ PaddedRVecVector *f)
{
int i, j, nh;
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++)
}
}
}
- dd_bcast(dd, ((efptNR)*sizeof(real)), state_local->lambda);
+ dd_bcast(dd, ((efptNR)*sizeof(real)), state_local->lambda.data());
dd_bcast(dd, sizeof(int), &state_local->fep_state);
dd_bcast(dd, sizeof(real), &state_local->veta);
dd_bcast(dd, sizeof(real), &state_local->vol0);
dd_bcast(dd, sizeof(state_local->boxv), state_local->boxv);
dd_bcast(dd, sizeof(state_local->svir_prev), state_local->svir_prev);
dd_bcast(dd, sizeof(state_local->fvir_prev), state_local->fvir_prev);
- dd_bcast(dd, ((state_local->ngtc*nh)*sizeof(double)), state_local->nosehoover_xi);
- dd_bcast(dd, ((state_local->ngtc*nh)*sizeof(double)), state_local->nosehoover_vxi);
- dd_bcast(dd, state_local->ngtc*sizeof(double), state_local->therm_integral);
- dd_bcast(dd, ((state_local->nnhpres*nh)*sizeof(double)), state_local->nhpres_xi);
- dd_bcast(dd, ((state_local->nnhpres*nh)*sizeof(double)), state_local->nhpres_vxi);
+ dd_bcast(dd, ((state_local->ngtc*nh)*sizeof(double)), state_local->nosehoover_xi.data());
+ dd_bcast(dd, ((state_local->ngtc*nh)*sizeof(double)), state_local->nosehoover_vxi.data());
+ dd_bcast(dd, state_local->ngtc*sizeof(double), state_local->therm_integral.data());
+ dd_bcast(dd, ((state_local->nnhpres*nh)*sizeof(double)), state_local->nhpres_xi.data());
+ dd_bcast(dd, ((state_local->nnhpres*nh)*sizeof(double)), state_local->nhpres_vxi.data());
/* communicate df_history -- required for restarting from checkpoint */
- dd_distribute_dfhist(dd, &state_local->dfhist);
+ dd_distribute_dfhist(dd, state_local->dfhist);
+
+ dd_resize_state(state_local, f, dd->nat_home);
- if (dd->nat_home > state_local->nalloc)
- {
- dd_realloc_state(state_local, f, dd->nat_home);
- }
for (i = 0; i < estNR; i++)
{
if (EST_DISTR(i) && (state_local->flags & (1<<i)))
switch (i)
{
case estX:
- dd_distribute_vec(dd, cgs, state->x, state_local->x);
+ dd_distribute_vec(dd, cgs, as_rvec_array(state->x.data()), as_rvec_array(state_local->x.data()));
break;
case estV:
- dd_distribute_vec(dd, cgs, state->v, state_local->v);
+ dd_distribute_vec(dd, cgs, as_rvec_array(state->v.data()), as_rvec_array(state_local->v.data()));
break;
case est_SDX_NOTSUPPORTED:
break;
case estCGP:
- dd_distribute_vec(dd, cgs, state->cg_p, state_local->cg_p);
+ dd_distribute_vec(dd, cgs, as_rvec_array(state->cg_p.data()), as_rvec_array(state_local->cg_p.data()));
break;
case estDISRE_INITF:
case estDISRE_RM3TAV:
char fname[STRLEN], buf[22];
FILE *out;
int i, ii, resnr, c;
- char *atomname, *resname;
+ const char *atomname, *resname;
real b;
gmx_domdec_t *dd;
fprintf(out, "TITLE %s\n", title);
gmx_write_pdb_box(out, dd->bScrewPBC ? epbcSCREW : epbcXYZ, box);
+ int molb = 0;
for (i = 0; i < natoms; i++)
{
ii = dd->gatindex[i];
- gmx_mtop_atominfo_global(mtop, ii, &atomname, &resnr, &resname);
+ mtopGetAtomAndResidueName(mtop, ii, &molb, &atomname, &resnr, &resname, nullptr);
if (i < dd->comm->nat[ddnatZONE])
{
c = 0;
}
static void rebuild_cgindex(gmx_domdec_t *dd,
- const int *gcgs_index, t_state *state)
+ const int *gcgs_index, const t_state *state)
{
- int nat, i, *ind, *dd_cg_gl, *cgindex, cg_gl;
+ int * gmx_restrict dd_cg_gl = dd->index_gl;
+ int * gmx_restrict cgindex = dd->cgindex;
+ int nat = 0;
- ind = state->cg_gl;
- dd_cg_gl = dd->index_gl;
- cgindex = dd->cgindex;
- nat = 0;
+ /* Copy back the global charge group indices from state
+ * and rebuild the local charge group to atom index.
+ */
cgindex[0] = nat;
- for (i = 0; i < state->ncg_gl; i++)
+ for (unsigned int i = 0; i < state->cg_gl.size(); i++)
{
cgindex[i] = nat;
- cg_gl = ind[i];
+ int cg_gl = state->cg_gl[i];
dd_cg_gl[i] = cg_gl;
nat += gcgs_index[cg_gl+1] - gcgs_index[cg_gl];
}
- cgindex[i] = nat;
+ cgindex[state->cg_gl.size()] = nat;
- dd->ncg_home = state->ncg_gl;
+ dd->ncg_home = state->cg_gl.size();
dd->nat_home = nat;
set_zones_ncg_home(dd);
if (pos_d >= limit1[d])
{
cg_move_error(fplog, dd, step, cg, d, 1,
- cg_cm != state->x, limitd[d],
+ cg_cm != as_rvec_array(state->x.data()), limitd[d],
cg_cm[cg], cm_new, pos_d);
}
dev[d] = 1;
if (pos_d < limit0[d])
{
cg_move_error(fplog, dd, step, cg, d, -1,
- cg_cm != state->x, limitd[d],
+ cg_cm != as_rvec_array(state->x.data()), limitd[d],
cg_cm[cg], cm_new, pos_d);
}
dev[d] = -1;
static void dd_redistribute_cg(FILE *fplog, gmx_int64_t step,
gmx_domdec_t *dd, ivec tric_dir,
- t_state *state, rvec **f,
+ t_state *state, PaddedRVecVector *f,
t_forcerec *fr,
gmx_bool bCompact,
t_nrnb *nrnb,
cgindex,
( thread *dd->ncg_home)/nthread,
((thread+1)*dd->ncg_home)/nthread,
- fr->cutoff_scheme == ecutsGROUP ? cg_cm : state->x,
+ fr->cutoff_scheme == ecutsGROUP ? cg_cm : as_rvec_array(state->x.data()),
move);
}
GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
*/
home_pos_cg =
compact_and_copy_vec_cg(dd->ncg_home, move, cgindex,
- nvec, state->x, comm, FALSE);
+ nvec, as_rvec_array(state->x.data()), comm, FALSE);
if (bCompact)
{
home_pos_cg -= *ncg_moved;
vec = 0;
home_pos_at =
compact_and_copy_vec_at(dd->ncg_home, move, cgindex,
- nvec, vec++, state->x, comm, bCompact);
+ nvec, vec++, as_rvec_array(state->x.data()),
+ comm, bCompact);
if (bV)
{
compact_and_copy_vec_at(dd->ncg_home, move, cgindex,
- nvec, vec++, state->v, comm, bCompact);
+ nvec, vec++, as_rvec_array(state->v.data()),
+ comm, bCompact);
}
if (bCGP)
{
compact_and_copy_vec_at(dd->ncg_home, move, cgindex,
- nvec, vec++, state->cg_p, comm, bCompact);
+ nvec, vec++, as_rvec_array(state->cg_p.data()),
+ comm, bCompact);
}
if (bCompact)
nvr += i;
}
+ dd_check_alloc_ncg(fr, state, f, home_pos_cg + ncg_recv);
+ if (fr->cutoff_scheme == ecutsGROUP)
+ {
+ /* Here we resize to more than necessary and shrink later */
+ dd_resize_state(state, f, home_pos_at + ncg_recv*MAX_CGCGSIZE);
+ }
+
/* Process the received charge groups */
buf_pos = 0;
for (cg = 0; cg < ncg_recv; cg++)
dd->index_gl[home_pos_cg] = comm->buf_int[cg*DD_CGIBS];
dd->cgindex[home_pos_cg+1] = dd->cgindex[home_pos_cg] + nrcg;
/* Copy the state from the buffer */
- dd_check_alloc_ncg(fr, state, f, home_pos_cg+1);
if (fr->cutoff_scheme == ecutsGROUP)
{
cg_cm = fr->cg_cm;
comm->bLocalCG[dd->index_gl[home_pos_cg]] = TRUE;
}
- if (home_pos_at+nrcg > state->nalloc)
- {
- dd_realloc_state(state, f, home_pos_at+nrcg);
- }
for (i = 0; i < nrcg; i++)
{
copy_rvec(comm->vbuf.v[buf_pos++],
dd->ncg_home = home_pos_cg;
dd->nat_home = home_pos_at;
+ if (fr->cutoff_scheme == ecutsGROUP && !bCompact)
+ {
+ /* We overallocated before, we need to set the right size here */
+ dd_resize_state(state, f, dd->nat_home);
+ }
+
if (debug)
{
fprintf(debug,
dd = cr->dd;
set_ddbox(dd, FALSE, cr, ir, state->box,
- TRUE, &dd->comm->cgs_gl, state->x, &ddbox);
+ TRUE, &dd->comm->cgs_gl, as_rvec_array(state->x.data()), &ddbox);
LocallyLimited = 0;
static void setup_dd_communication(gmx_domdec_t *dd,
matrix box, gmx_ddbox_t *ddbox,
- t_forcerec *fr, t_state *state, rvec **f)
+ t_forcerec *fr,
+ t_state *state, PaddedRVecVector *f)
{
int dim_ind, dim, dim0, dim1, dim2, dimd, p, nat_tot;
int nzone, nzone_send, zone, zonei, cg0, cg1;
cg_cm = fr->cg_cm;
break;
case ecutsVERLET:
- cg_cm = state->x;
+ cg_cm = as_rvec_array(state->x.data());
break;
default:
gmx_incons("unimplemented");
}
else
{
- cg_cm = state->x;
+ cg_cm = as_rvec_array(state->x.data());
}
/* Communicate cg_cm */
if (cd->bInPlace)
switch (i)
{
case estX:
- order_vec_atom(dd->ncg_home, cgindex, cgsort, state->x, vbuf);
+ order_vec_atom(dd->ncg_home, cgindex, cgsort, as_rvec_array(state->x.data()), vbuf);
break;
case estV:
- order_vec_atom(dd->ncg_home, cgindex, cgsort, state->v, vbuf);
+ order_vec_atom(dd->ncg_home, cgindex, cgsort, as_rvec_array(state->v.data()), vbuf);
break;
case est_SDX_NOTSUPPORTED:
break;
case estCGP:
- order_vec_atom(dd->ncg_home, cgindex, cgsort, state->cg_p, vbuf);
+ order_vec_atom(dd->ncg_home, cgindex, cgsort, as_rvec_array(state->cg_p.data()), vbuf);
break;
case estLD_RNG:
case estLD_RNGI:
const gmx_mtop_t *top_global,
const t_inputrec *ir,
t_state *state_local,
- rvec **f,
+ PaddedRVecVector *f,
t_mdatoms *mdatoms,
gmx_localtop_t *top_local,
t_forcerec *fr,
ncgindex_set = 0;
set_ddbox(dd, bMasterState, cr, ir, state_global->box,
- TRUE, cgs_gl, state_global->x, &ddbox);
+ TRUE, cgs_gl, as_rvec_array(state_global->x.data()), &ddbox);
get_cg_distribution(fplog, dd, cgs_gl,
- state_global->box, &ddbox, state_global->x);
+ state_global->box, &ddbox, as_rvec_array(state_global->x.data()));
dd_distribute_state(dd, cgs_gl,
state_global, state_local, f);
if (fr->cutoff_scheme == ecutsGROUP)
{
calc_cgcm(fplog, 0, dd->ncg_home,
- &top_local->cgs, state_local->x, fr->cg_cm);
+ &top_local->cgs, as_rvec_array(state_local->x.data()), fr->cg_cm);
}
inc_nrnb(nrnb, eNR_CGCM, dd->nat_home);
{
/* Redetermine the cg COMs */
calc_cgcm(fplog, 0, dd->ncg_home,
- &top_local->cgs, state_local->x, fr->cg_cm);
+ &top_local->cgs, as_rvec_array(state_local->x.data()), fr->cg_cm);
}
inc_nrnb(nrnb, eNR_CGCM, dd->nat_home);
dd_set_cginfo(dd->index_gl, 0, dd->ncg_home, fr, comm->bLocalCG);
set_ddbox(dd, bMasterState, cr, ir, state_local->box,
- TRUE, &top_local->cgs, state_local->x, &ddbox);
+ TRUE, &top_local->cgs, as_rvec_array(state_local->x.data()), &ddbox);
bRedist = dlbIsOn(comm);
}
copy_rvec(comm->box_size, ddbox.box_size);
}
set_ddbox(dd, bMasterState, cr, ir, state_local->box,
- bNStGlobalComm, &top_local->cgs, state_local->x, &ddbox);
+ bNStGlobalComm, &top_local->cgs, as_rvec_array(state_local->x.data()), &ddbox);
bBoxChanged = TRUE;
bRedist = TRUE;
0, dd->ncg_home,
comm->zones.dens_zone0,
fr->cginfo,
- state_local->x,
+ as_rvec_array(state_local->x.data()),
ncg_moved, bRedist ? comm->moved : NULL,
fr->nbv->grp[eintLocal].kernel_type,
fr->nbv->grp[eintLocal].nbat);
}
dd_sort_state(dd, fr->cg_cm, fr, state_local,
bResortAll ? -1 : ncg_home_old);
+
+ /* After sorting and compacting we set the correct size */
+ dd_resize_state(state_local, f, dd->nat_home);
+
/* Rebuild all the indices */
ga2la_clear(dd->ga2la);
ncgindex_set = 0;
/*
write_dd_pdb("dd_home",step,"dump",top_global,cr,
- -1,state_local->x,state_local->box);
+ -1,as_rvec_array(state_local->x.data()),state_local->box);
*/
wallcycle_sub_start(wcycle, ewcsDD_MAKETOP);
dd_make_local_top(dd, &comm->zones, dd->npbcdim, state_local->box,
comm->cellsize_min, np,
fr,
- fr->cutoff_scheme == ecutsGROUP ? fr->cg_cm : state_local->x,
+ fr->cutoff_scheme == ecutsGROUP ? fr->cg_cm : as_rvec_array(state_local->x.data()),
vsite, top_global, top_local);
wallcycle_sub_stop(wcycle, ewcsDD_MAKETOP);
* or constraint communication.
*/
state_local->natoms = comm->nat[ddnatNR-1];
- if (state_local->natoms > state_local->nalloc)
- {
- dd_realloc_state(state_local, f, state_local->natoms);
- }
+
+ dd_resize_state(state_local, f, state_local->natoms);
if (fr->bF_NoVirSum)
{
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 */
* the last vsite construction, we need to communicate the constructing
* atom coordinates again (for spreading the forces this MD step).
*/
- dd_move_x_vsites(dd, state_local->box, state_local->x);
+ dd_move_x_vsites(dd, state_local->box, as_rvec_array(state_local->x.data()));
wallcycle_sub_stop(wcycle, ewcsDD_TOPOTHER);
if (comm->nstDDDump > 0 && step % comm->nstDDDump == 0)
{
- dd_move_x(dd, state_local->box, state_local->x);
+ dd_move_x(dd, state_local->box, as_rvec_array(state_local->x.data()));
write_dd_pdb("dd_dump", step, "dump", top_global, cr,
- -1, state_local->x, state_local->box);
+ -1, as_rvec_array(state_local->x.data()), state_local->box);
}
/* Store the partitioning step */
/*
* 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.
struct t_commrec;
struct t_inputrec;
-#ifdef __cplusplus
-extern "C" {
-#endif
-
/*! \brief Returns the global topology atom number belonging to local atom index i.
*
* This function is intended for writing ASCII output
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);
/*! \brief Collects local rvec arrays \p lv to \p v on the master rank */
void dd_collect_vec(struct gmx_domdec_t *dd,
- t_state *state_local, rvec *lv, rvec *v);
+ t_state *state_local, const PaddedRVecVector *lv, rvec *v);
+
+/*! \brief Collects local rvec arrays \p lv to \p v on the master rank */
+void dd_collect_vec(struct gmx_domdec_t *dd,
+ t_state *state_local, const PaddedRVecVector *lv, PaddedRVecVector *v);
/*! \brief Collects the local state \p state_local to \p state on the master rank */
void dd_collect_state(struct gmx_domdec_t *dd,
const gmx_mtop_t *top_global,
const t_inputrec *ir,
t_state *state_local,
- rvec **f,
+ PaddedRVecVector *f,
t_mdatoms *mdatoms,
gmx_localtop_t *top_local,
t_forcerec *fr,
const t_block *cgs, const rvec *x,
gmx_ddbox_t *ddbox);
-#ifdef __cplusplus
-}
-#endif
-
#endif
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2006,2007,2008,2009,2010,2012,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 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.
#include "gromacs/mdlib/gmx_omp_nthreads.h"
#include "gromacs/mdtypes/commrec.h"
#include "gromacs/pbcutil/ishift.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/gmxassert.h"
t_ilist *ils_local,
ind_req_t *ireq)
{
- gmx_ga2la_t *ga2la;
- gmx_mtop_atomlookup_t alook;
- int settle;
- int nral, sa;
- int cg, a, a_gl, a_glsa, a_gls[3], a_locs[3];
- int mb, molnr, a_mol, offset;
- const gmx_molblock_t *molb;
- const t_iatom *ia1;
- gmx_bool a_home[3];
- int nlocal;
- gmx_bool bAssign;
+ gmx_ga2la_t *ga2la = dd->ga2la;
+ int nral = NRAL(F_SETTLE);
- ga2la = dd->ga2la;
-
- alook = gmx_mtop_atomlookup_settle_init(mtop);
-
- nral = NRAL(F_SETTLE);
-
- for (cg = cg_start; cg < cg_end; cg++)
+ int mb = 0;
+ for (int cg = cg_start; cg < cg_end; cg++)
{
if (GET_CGINFO_SETTLE(cginfo[cg]))
{
- for (a = dd->cgindex[cg]; a < dd->cgindex[cg+1]; a++)
+ for (int a = dd->cgindex[cg]; a < dd->cgindex[cg+1]; a++)
{
- a_gl = dd->gatindex[a];
-
- gmx_mtop_atomnr_to_molblock_ind(alook, a_gl, &mb, &molnr, &a_mol);
- molb = &mtop->molblock[mb];
+ int a_gl = dd->gatindex[a];
+ int a_mol;
+ mtopGetMolblockIndex(mtop, a_gl, &mb, NULL, &a_mol);
- settle = at2settle_mt[molb->type][a_mol];
+ const gmx_molblock_t *molb = &mtop->molblock[mb];
+ int settle = at2settle_mt[molb->type][a_mol];
if (settle >= 0)
{
- offset = a_gl - a_mol;
+ int offset = a_gl - a_mol;
- ia1 = mtop->moltype[molb->type].ilist[F_SETTLE].iatoms;
+ t_iatom *ia1 = mtop->moltype[molb->type].ilist[F_SETTLE].iatoms;
- bAssign = FALSE;
- nlocal = 0;
- for (sa = 0; sa < nral; sa++)
+ int a_gls[3], a_locs[3];
+ gmx_bool bAssign = FALSE;
+ int nlocal = 0;
+ for (int sa = 0; sa < nral; sa++)
{
- a_glsa = offset + ia1[settle*(1+nral)+1+sa];
+ int a_glsa = offset + ia1[settle*(1+nral)+1+sa];
a_gls[sa] = a_glsa;
- a_home[sa] = ga2la_get_home(ga2la, a_glsa, &a_locs[sa]);
- if (a_home[sa])
+ if (ga2la_get_home(ga2la, a_glsa, &a_locs[sa]))
{
if (nlocal == 0 && a_gl == a_glsa)
{
ils_local->iatoms[ils_local->nr++] = ia1[settle*4];
- for (sa = 0; sa < nral; sa++)
+ for (int sa = 0; sa < nral; sa++)
{
if (ga2la_get_home(ga2la, a_gls[sa], &a_locs[sa]))
{
}
}
}
-
- gmx_mtop_atomlookup_destroy(alook);
}
/*! \brief Looks up constraint for the local atoms */
ind_req_t *ireq)
{
const t_blocka *at2con;
- gmx_ga2la_t *ga2la;
- gmx_mtop_atomlookup_t alook;
int ncon1;
- gmx_molblock_t *molb;
t_iatom *ia1, *ia2, *iap;
- int nhome, cg, a, a_gl, a_mol, a_loc, b_lo, offset, mb, molnr, b_mol, i, con, con_offset;
- gmx_domdec_constraints_t *dc;
- gmx_domdec_specat_comm_t *dcc;
+ int a_loc, b_lo, offset, b_mol, i, con, con_offset;
- dc = dd->constraints;
- dcc = dd->constraint_comm;
+ gmx_domdec_constraints_t *dc = dd->constraints;
+ gmx_domdec_specat_comm_t *dcc = dd->constraint_comm;
- ga2la = dd->ga2la;
+ gmx_ga2la_t *ga2la = dd->ga2la;
- alook = gmx_mtop_atomlookup_init(mtop);
-
- nhome = 0;
- for (cg = 0; cg < dd->ncg_home; cg++)
+ int mb = 0;
+ int nhome = 0;
+ for (int cg = 0; cg < dd->ncg_home; cg++)
{
if (GET_CGINFO_CONSTR(cginfo[cg]))
{
- for (a = dd->cgindex[cg]; a < dd->cgindex[cg+1]; a++)
+ for (int a = dd->cgindex[cg]; a < dd->cgindex[cg+1]; a++)
{
- a_gl = dd->gatindex[a];
+ int a_gl = dd->gatindex[a];
+ int molnr, a_mol;
+ mtopGetMolblockIndex(mtop, a_gl, &mb, &molnr, &a_mol);
- gmx_mtop_atomnr_to_molblock_ind(alook, a_gl, &mb, &molnr, &a_mol);
- molb = &mtop->molblock[mb];
+ const gmx_molblock_t *molb = &mtop->molblock[mb];
ncon1 = mtop->moltype[molb->type].ilist[F_CONSTR].nr/NRAL(F_SETTLE);
}
}
- gmx_mtop_atomlookup_destroy(alook);
-
if (debug)
{
fprintf(debug,
#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
}
#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
}
-void dd_scatter(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, void gmx_unused *src, void *dest)
+void dd_scatter(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, const void gmx_unused *src, void *dest)
{
#if GMX_MPI
if (dd->nnodes > 1)
{
- MPI_Scatter(src, nbytes, MPI_BYTE,
+ /* Some MPI implementions don't specify const */
+ MPI_Scatter(const_cast<void *>(src), nbytes, MPI_BYTE,
dest, nbytes, MPI_BYTE,
DDMASTERRANK(dd), dd->mpi_comm_all);
}
}
}
-void dd_gather(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, void gmx_unused *src, void gmx_unused *dest)
+void dd_gather(gmx_domdec_t gmx_unused *dd, int gmx_unused nbytes, const void gmx_unused *src, void gmx_unused *dest)
{
#if GMX_MPI
- MPI_Gather(src, nbytes, MPI_BYTE,
+ /* Some MPI implementions don't specify const */
+ MPI_Gather(const_cast<void *>(src), nbytes, MPI_BYTE,
dest, nbytes, MPI_BYTE,
DDMASTERRANK(dd), dd->mpi_comm_all);
#endif
}
void dd_scatterv(gmx_domdec_t gmx_unused *dd,
- int gmx_unused *scounts, int gmx_unused *disps, void *sbuf,
+ int gmx_unused *scounts, int gmx_unused *disps, const void *sbuf,
int rcount, void *rbuf)
{
#if GMX_MPI
/* MPI does not allow NULL pointers */
rbuf = &dum;
}
- MPI_Scatterv(sbuf, scounts, disps, MPI_BYTE,
+ /* Some MPI implementions don't specify const */
+ MPI_Scatterv(const_cast<void *>(sbuf), scounts, disps, MPI_BYTE,
rbuf, rcount, MPI_BYTE,
DDMASTERRANK(dd), dd->mpi_comm_all);
}
}
void dd_gatherv(gmx_domdec_t gmx_unused *dd,
- int gmx_unused scount, void gmx_unused *sbuf,
+ int gmx_unused scount, const void gmx_unused *sbuf,
int gmx_unused *rcounts, int gmx_unused *disps, void gmx_unused *rbuf)
{
#if GMX_MPI
/* MPI does not allow NULL pointers */
sbuf = &dum;
}
- MPI_Gatherv(sbuf, scount, MPI_BYTE,
+ /* Some MPI implementions don't specify const */
+ MPI_Gatherv(const_cast<void *>(sbuf), scount, MPI_BYTE,
rbuf, rcounts, disps, MPI_BYTE,
DDMASTERRANK(dd), dd->mpi_comm_all);
#endif
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2008,2009,2010,2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2008,2009,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.
/*! \brief Scatters \p nbytes from \p src on \p DDMASTERRANK to all PP ranks, received in \p dest */
void
-dd_scatter(struct gmx_domdec_t *dd, int nbytes, void *src, void *dest);
+dd_scatter(struct gmx_domdec_t *dd, int nbytes, const void *src, void *dest);
/*! \brief Gathers \p nbytes from \p src on all PP ranks, received in \p dest on \p DDMASTERRANK */
void
-dd_gather(struct gmx_domdec_t *dd, int nbytes, void *src, void *dest);
+dd_gather(struct gmx_domdec_t *dd, int nbytes, const void *src, void *dest);
/*! \brief Scatters \p scounts bytes from \p src on \p DDMASTERRANK to all PP ranks, receiving \p rcount bytes in \p dest.
*
* If rcount==0, rbuf is allowed to be NULL */
void
dd_scatterv(struct gmx_domdec_t *dd,
- int *scounts, int *disps, void *sbuf,
+ int *scounts, int *disps, const void *sbuf,
int rcount, void *rbuf);
/*! \brief Gathers \p rcount bytes from \p src on all PP ranks, received in \p scounts bytes in \p dest on \p DDMASTERRANK.
* If scount==0, sbuf is allowed to be NULL */
void
dd_gatherv(struct gmx_domdec_t *dd,
- int scount, void *sbuf,
+ int scount, const void *sbuf,
int *rcounts, int *disps, void *rbuf);
#endif
#include <stdlib.h>
#include <string.h>
+#include <cassert>
+
#include <algorithm>
#include <string>
print_missing_interactions_atoms(fplog, cr, top_global, &top_local->idef);
write_dd_pdb("dd_dump_err", 0, "dump", top_global, cr,
- -1, state_local->x, state_local->box);
+ -1, as_rvec_array(state_local->x.data()), state_local->box);
std::string errorMessage;
}
}
-/*! \brief Run the reverse ilist generation and store it when \p bAssign = TRUE */
+/*! \brief Run the reverse ilist generation and store it in r_il when \p bAssign = TRUE */
static int low_make_reverse_ilist(const t_ilist *il_mt, const t_atom *atom,
const int * const * vsite_pbc,
int *count,
a = ia[1+link];
if (bAssign)
{
+ assert(r_il); //with bAssign not allowed to be null
+ assert(r_index);
r_il[r_index[a]+count[a]] =
(ftype == F_CONSTRNC ? F_CONSTR : ftype);
r_il[r_index[a]+count[a]+1] = ia[0];
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);
*
* 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 "gromacs/math/utilities.h"
#include "gromacs/math/vec.h"
#include "gromacs/math/vectypes.h"
+#include "gromacs/mdlib/broadcaststructs.h"
#include "gromacs/mdlib/groupcoord.h"
#include "gromacs/mdlib/mdrun.h"
#include "gromacs/mdlib/sim_util.h"
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/md_enums.h"
#include "gromacs/pbcutil/pbc.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/smalloc.h"
-/* We use the same defines as in broadcaststructs.cpp here */
-#define block_bc(cr, d) gmx_bcast( sizeof(d), &(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)); }}
-
/* enum to identify the type of ED: none, normal ED, flooding */
enum {
eEDnone, eEDedsam, eEDflood, eEDnr
#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;
/* 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;
int i;
real totalmass = 0.0;
rvec com;
- gmx_mtop_atomlookup_t alook = NULL;
- t_atom *atom;
/* NOTE Init_edi is executed on the master process only
* The initialized data sets are then transmitted to the
* other nodes in broadcast_ed_data */
- alook = gmx_mtop_atomlookup_init(mtop);
-
/* evaluate masses (reference structure) */
snew(edi->sref.m, edi->sref.nr);
+ int molb = 0;
for (i = 0; i < edi->sref.nr; i++)
{
if (edi->fitmas)
{
- gmx_mtop_atomnr_to_atom(alook, edi->sref.anrs[i], &atom);
- edi->sref.m[i] = atom->m;
+ edi->sref.m[i] = mtopGetAtomMass(mtop, edi->sref.anrs[i], &molb);
}
else
{
snew(edi->sav.m, edi->sav.nr );
for (i = 0; i < edi->sav.nr; i++)
{
- gmx_mtop_atomnr_to_atom(alook, edi->sav.anrs[i], &atom);
- edi->sav.m[i] = atom->m;
+ edi->sav.m[i] = mtopGetAtomMass(mtop, edi->sav.anrs[i], &molb);
if (edi->pcamas)
{
- edi->sav.sqrtm[i] = sqrt(atom->m);
+ edi->sav.sqrtm[i] = sqrt(edi->sav.m[i]);
}
else
{
"For ED with mass-weighting, all average structure atoms need to have a mass >0.\n"
"Either make the covariance analysis non-mass-weighted, or exclude massless\n"
"atoms from the average structure by creating a proper index group.\n",
- i, edi->sav.anrs[i]+1, atom->m);
+ i, edi->sav.anrs[i] + 1, edi->sav.m[i]);
}
}
- gmx_mtop_atomlookup_destroy(alook);
-
/* put reference structure in origin */
get_center(edi->sref.x, edi->sref.m, edi->sref.nr, com);
com[XX] = -com[XX];
*
* 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.
* 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.
* \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.
*
* 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 "gromacs/math/utilities.h"
#include "gromacs/math/vec.h"
#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/smalloc.h"
#include "pme-internal.h"
-static void make_dft_mod(real *mod, real *data, int ndata)
+static void make_dft_mod(real *mod,
+ const double *data, int splineOrder, int ndata)
{
- int i, j;
- real sc, ss, arg;
-
- for (i = 0; i < ndata; i++)
+ for (int i = 0; i < ndata; i++)
{
- sc = ss = 0;
- for (j = 0; j < ndata; j++)
+ /* We use double precision, since this is only called once per grid.
+ * But for single precision bsp_mod, single precision also seems
+ * to give full accuracy.
+ */
+ double sc = 0;
+ double ss = 0;
+ for (int j = 0; j < splineOrder; j++)
{
- arg = (2.0*M_PI*i*j)/ndata;
- sc += data[j]*cos(arg);
- ss += data[j]*sin(arg);
+ double arg = (2.0*M_PI*i*(j + 1))/ndata;
+ sc += data[j]*cos(arg);
+ ss += data[j]*sin(arg);
}
- mod[i] = sc*sc+ss*ss;
+ mod[i] = sc*sc + ss*ss;
}
- for (i = 0; i < ndata; i++)
+ if (splineOrder % 2 == 0 && ndata % 2 == 0)
{
- if (mod[i] < 1e-7)
- {
- mod[i] = (mod[i-1]+mod[i+1])*0.5;
- }
+ /* Note that pme_order = splineOrder + 1 */
+ GMX_RELEASE_ASSERT(mod[ndata/2] < GMX_DOUBLE_EPS, "With even spline order and even grid size (ndata), dft_mod[ndata/2] should first come out as zero");
+ /* This factor causes a division by zero. But since this occurs in
+ * the tail of the distribution, the term with this factor can
+ * be ignored (see Essmann et al. JCP 103, 8577).
+ * Using the average of the neighbors probably originates from
+ * Tom Darden's original PME code. It seems to give slighlty better
+ * accuracy than using a large value.
+ */
+ mod[ndata/2] = (mod[ndata/2 - 1] + mod[ndata/2 + 1])*0.5;
}
}
void make_bspline_moduli(splinevec bsp_mod,
- int nx, int ny, int nz, int order)
+ int nx, int ny, int nz, int pme_order)
{
- int nmax = std::max(nx, std::max(ny, nz));
- real *data, *ddata, *bsp_data;
- int i, k, l;
- real div;
+ /* We use double precision, since this is only called once per grid.
+ * But for single precision bsp_mod, single precision also seems
+ * to give full accuracy.
+ */
+ double *data;
- snew(data, order);
- snew(ddata, order);
- snew(bsp_data, nmax);
+ /* In GROMACS we, confusingly, defined pme-order as the order
+ * of the cardinal B-spline + 1. This probably happened because
+ * the smooth PME paper only talks about "n" which is the number
+ * of points we spread to and that was chosen to be pme-order.
+ */
+ const int splineOrder = pme_order - 1;
- data[order-1] = 0;
- data[1] = 0;
- data[0] = 1;
+ snew(data, splineOrder);
- for (k = 3; k < order; k++)
+ data[0] = 1;
+ for (int k = 1; k < splineOrder; k++)
{
- div = 1.0/(k-1.0);
- data[k-1] = 0;
- for (l = 1; l < (k-1); l++)
- {
- data[k-l-1] = div*(l*data[k-l-2]+(k-l)*data[k-l-1]);
- }
- data[0] = div*data[0];
+ data[k] = 0;
}
- /* differentiate */
- ddata[0] = -data[0];
- for (k = 1; k < order; k++)
- {
- ddata[k] = data[k-1]-data[k];
- }
- div = 1.0/(order-1);
- data[order-1] = 0;
- for (l = 1; l < (order-1); l++)
- {
- data[order-l-1] = div*(l*data[order-l-2]+(order-l)*data[order-l-1]);
- }
- data[0] = div*data[0];
- for (i = 0; i < nmax; i++)
+ for (int k = 2; k <= splineOrder; k++)
{
- bsp_data[i] = 0;
- }
- for (i = 1; i <= order; i++)
- {
- bsp_data[i] = data[i-1];
+ double div = 1.0/k;
+ for (int m = k - 1; m > 0; m--)
+ {
+ data[m] = div*((k - m)*data[m - 1] + (m + 1)*data[m]);
+ }
+ data[0] = div*data[0];
}
- make_dft_mod(bsp_mod[XX], bsp_data, nx);
- make_dft_mod(bsp_mod[YY], bsp_data, ny);
- make_dft_mod(bsp_mod[ZZ], bsp_data, nz);
+ make_dft_mod(bsp_mod[XX], data, splineOrder, nx);
+ make_dft_mod(bsp_mod[YY], data, splineOrder, ny);
+ make_dft_mod(bsp_mod[ZZ], data, splineOrder, nz);
sfree(data);
- sfree(ddata);
- sfree(bsp_data);
}
/* Return the P3M optimal influence function */
tensor dxdf_q = {{0}}, dxdf_lj = {{0}};
real vol = box[XX][XX]*box[YY][YY]*box[ZZ][ZZ];
real L1_q, L1_lj, dipole_coeff, qqA, qqB, qqL, vr0_q, vr0_lj = 0;
- gmx_bool bMolPBC = fr->bMolPBC;
- gmx_bool bDoingLBRule = (fr->ljpme_combination_rule == eljpmeLB);
+ real chargecorr[2] = { 0, 0 };
+ gmx_bool bMolPBC = fr->bMolPBC;
+ gmx_bool bDoingLBRule = (fr->ljpme_combination_rule == eljpmeLB);
gmx_bool bNeedLongRangeCorrection;
/* This routine can be made faster by using tables instead of analytical interactions
}
break;
case eewg3DC:
- dipole_coeff = 2*M_PI*one_4pi_eps/vol;
- dipcorrA[ZZ] = 2*dipole_coeff*mutot[0][ZZ];
- dipcorrB[ZZ] = 2*dipole_coeff*mutot[1][ZZ];
+ dipole_coeff = 2*M_PI*one_4pi_eps/vol;
+ dipcorrA[ZZ] = 2*dipole_coeff*mutot[0][ZZ];
+ dipcorrB[ZZ] = 2*dipole_coeff*mutot[1][ZZ];
+ for (int q = 0; q < (bHaveChargeOrTypePerturbed ? 2 : 1); q++)
+ {
+ /* Avoid charge corrections with near-zero net charge */
+ if (fabs(fr->qsum[q]) > 1e-4)
+ {
+ chargecorr[q] = 2*dipole_coeff*fr->qsum[q];
+ }
+ }
break;
default:
gmx_incons("Unsupported Ewald geometry");
{
f[i][j] -= dipcorrA[j]*chargeA[i];
}
+ if (chargecorr[0] != 0)
+ {
+ f[i][ZZ] += chargecorr[0]*chargeA[i]*x[i][ZZ];
+ }
}
}
}
f[i][j] -= L1_q*dipcorrA[j]*chargeA[i]
+ lambda_q*dipcorrB[j]*chargeB[i];
}
+ if (chargecorr[0] != 0 || chargecorr[1] != 0)
+ {
+ f[i][ZZ] += (L1_q*chargecorr[0]*chargeA[i]
+ + lambda_q*chargecorr[1])*x[i][ZZ];
+ }
}
}
}
}
}
- /* Apply surface dipole correction:
- * correction = dipole_coeff * (dipole)^2
+ /* Apply surface and charged surface dipole correction:
+ * correction = dipole_coeff * ( (dipole)^2
+ * - qsum*sum_i q_i z_i^2 - qsum^2 * box_z^2 / 12 )
*/
if (dipole_coeff != 0)
{
else if (ewald_geometry == eewg3DC)
{
Vdipole[q] = dipole_coeff*mutot[q][ZZ]*mutot[q][ZZ];
+
+ if (chargecorr[q] != 0)
+ {
+ /* Here we use a non thread-parallelized loop,
+ * because this is the only loop over atoms for
+ * energies and they need reduction (unlike forces).
+ * We could implement a reduction over threads,
+ * but this case is rarely used.
+ */
+ const real *qPtr = (q == 0 ? chargeA : chargeB);
+ real sumQZ2 = 0;
+ for (int i = 0; i < numAtomsLocal; i++)
+ {
+ sumQZ2 += qPtr[i]*x[i][ZZ]*x[i][ZZ];
+ }
+ Vdipole[q] -= dipole_coeff*fr->qsum[q]*(sumQZ2 + fr->qsum[q]*box[ZZ][ZZ]*box[ZZ][ZZ]/12);
+ }
}
}
}
#include <cstdlib>
#include "gromacs/ewald/pme.h"
+#include "gromacs/fft/parallel_3dfft.h"
#include "gromacs/math/vec.h"
#include "gromacs/timing/cyclecounter.h"
#include "gromacs/utility/fatalerror.h"
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);
}
}
}
void
-make_gridindex5_to_localindex(int n, int local_start, int local_range,
- int **global_to_local,
- real **fraction_shift)
+make_gridindex_to_localindex(int n, int local_start, int local_range,
+ int **global_to_local,
+ real **fraction_shift)
{
/* Here we construct array for looking up the grid line index and
* fraction for particles. This is done because it is slighlty
* faster than the modulo operation and to because we need to take
* care of rounding issues, see below.
- * We use an array size of 5 times the grid size to allow for particles
- * to be out of the triclinic unit-cell by up to 2 box lengths, which
- * can be needed along dimension x for a very skewed unit-cell.
+ * We use an array size of c_pmeNeighborUnitcellCount times the grid size
+ * to allow for particles to be out of the triclinic unit-cell.
*/
- int * gtl;
- real * fsh;
+ const int arraySize = c_pmeNeighborUnitcellCount * n;
+ int * gtl;
+ real * fsh;
- snew(gtl, 5*n);
- snew(fsh, 5*n);
+ snew(gtl, arraySize);
+ snew(fsh, arraySize);
- for (int i = 0; i < 5*n; i++)
+ for (int i = 0; i < arraySize; i++)
{
/* Transform global grid index to the local grid index.
* Our local grid always runs from 0 to local_range-1.
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;
#include "pme-internal.h"
+
+/*! \brief
+ * We allow coordinates to be out the unit-cell by up to 2 box lengths,
+ * which might be needed along dimension x for a very skewed unit-cell.
+ */
+constexpr int c_pmeMaxUnitcellShift = 2;
+
+/*! \brief
+ * This affects the size of the lookup table of the modulo operation result,
+ * when working with PME local grid indices of the particles.
+ */
+constexpr int c_pmeNeighborUnitcellCount = 2*c_pmeMaxUnitcellShift + 1;
+
+
#if GMX_MPI
void
gmx_sum_qgrid_dd(struct gmx_pme_t *pme, real *grid, int direction);
pmegrids_destroy(pmegrids_t *grids);
void
-make_gridindex5_to_localindex(int n, int local_start, int local_range,
- int **global_to_local,
- real **fraction_shift);
+make_gridindex_to_localindex(int n, int local_start, int local_range,
+ int **global_to_local,
+ real **fraction_shift);
void
set_grid_alignment(int *pmegrid_nz, int pme_order);
#include <stdio.h>
-#include "gromacs/fft/parallel_3dfft.h"
#include "gromacs/math/gmxcomplex.h"
#include "gromacs/timing/wallcycle.h"
#include "gromacs/timing/walltime_accounting.h"
#include "gromacs/utility/gmxmpi.h"
+//! A repeat of typedef from parallel_3dfft.h
+typedef struct gmx_parallel_3dfft *gmx_parallel_3dfft_t;
+
struct t_commrec;
struct t_inputrec;
*/
#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 */
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 */
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);
#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"
#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"
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)
{
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.
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");
}
}
t_commrec *cr,
FILE *fp_err,
FILE *fp_log,
+ const gmx::MDLogger &mdlog,
const t_inputrec *ir,
t_state *state,
double cycles,
/* 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;
}
*/
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;
}
t_commrec *cr,
FILE *fp_err,
FILE *fp_log,
+ const gmx::MDLogger &mdlog,
const t_inputrec *ir,
t_forcerec *fr,
t_state *state,
{
/* 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.
* 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);
{
/* 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;
/*! \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;
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
{
}
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,
/*
* 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;
* 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);
struct t_commrec *cr,
FILE *fp_err,
FILE *fp_log,
+ const gmx::MDLogger &mdlog,
const t_inputrec *ir,
t_forcerec *fr,
t_state *state,
/*! \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
*
* 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.
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)
{
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];
}
float cycles;
int count;
gmx_bool bEnerVir;
- int pme_flags;
gmx_int64_t step;
ivec grid_switch;
&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)
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);
*
* 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)
#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)
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;
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 */
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
}
/*! \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,
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;
}
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;
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);
}
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",
(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))
}
}
}
-
- 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;
}
}
}
+
+ 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);
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;
}
{
free_work(&(*work)[thread]);
}
- sfree(work);
+ sfree(*work);
*work = NULL;
}
}
#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)
{
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;
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 */
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;
/*
* 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.
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
#include <algorithm>
#include "gromacs/ewald/pme.h"
+#include "gromacs/fft/parallel_3dfft.h"
#include "gromacs/simd/simd.h"
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/smalloc.h"
+#include "pme-grid.h"
#include "pme-internal.h"
#include "pme-simd.h"
#include "pme-spline-work.h"
}
}
+ const real shift = c_pmeMaxUnitcellShift;
+
for (i = start; i < end; i++)
{
xptr = atc->x[i];
idxptr = atc->idx[i];
fptr = atc->fractx[i];
- /* Fractional coordinates along box vectors, add 2.0 to make 100% sure we are positive for triclinic boxes */
- tx = nx * ( xptr[XX] * rxx + xptr[YY] * ryx + xptr[ZZ] * rzx + 2.0 );
- ty = ny * ( xptr[YY] * ryy + xptr[ZZ] * rzy + 2.0 );
- tz = nz * ( xptr[ZZ] * rzz + 2.0 );
+ /* Fractional coordinates along box vectors, add a positive shift to ensure tx/ty/tz are positive for triclinic boxes */
+ tx = nx * ( xptr[XX] * rxx + xptr[YY] * ryx + xptr[ZZ] * rzx + shift );
+ ty = ny * ( xptr[YY] * ryy + xptr[ZZ] * rzy + shift );
+ tz = nz * ( xptr[ZZ] * rzz + shift );
- tix = (int)(tx);
- tiy = (int)(ty);
- tiz = (int)(tz);
+ tix = static_cast<int>(tx);
+ tiy = static_cast<int>(ty);
+ tiz = static_cast<int>(tz);
/* Because decomposition only occurs in x and y,
* we never have a fraction correction in z.
}
}
-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)
{
}
}
+/*! \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,
snew(ol->recvbuf, norder*commplainsize);
}
+/*! \brief Destroy data structure for communication */
+static void
+destroy_overlap_comm(const pme_overlap_t *ol)
+{
+ sfree(ol->s2g0);
+ sfree(ol->s2g1);
+ sfree(ol->send_id);
+ sfree(ol->recv_id);
+ sfree(ol->comm_data);
+ sfree(ol->sendbuf);
+ sfree(ol->recvbuf);
+}
+
void gmx_pme_check_restrictions(int pme_order,
int nkx, int nky, int nkz,
int nnodes_major,
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;
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;
pme->pmegrid_start_iy = pme->overlap[1].s2g0[pme->nodeid_minor];
pme->pmegrid_start_iz = 0;
- make_gridindex5_to_localindex(pme->nkx,
- pme->pmegrid_start_ix,
- pme->pmegrid_nx - (pme->pme_order-1),
- &pme->nnx, &pme->fshx);
- make_gridindex5_to_localindex(pme->nky,
- pme->pmegrid_start_iy,
- pme->pmegrid_ny - (pme->pme_order-1),
- &pme->nny, &pme->fshy);
- make_gridindex5_to_localindex(pme->nkz,
- pme->pmegrid_start_iz,
- pme->pmegrid_nz_base,
- &pme->nnz, &pme->fshz);
+ make_gridindex_to_localindex(pme->nkx,
+ pme->pmegrid_start_ix,
+ pme->pmegrid_nx - (pme->pme_order-1),
+ &pme->nnx, &pme->fshx);
+ make_gridindex_to_localindex(pme->nky,
+ pme->pmegrid_start_iy,
+ pme->pmegrid_ny - (pme->pme_order-1),
+ &pme->nny, &pme->fshy);
+ make_gridindex_to_localindex(pme->nkz,
+ pme->pmegrid_start_iz,
+ pme->pmegrid_nz_base,
+ &pme->nnz, &pme->fshz);
pme->spline_work = make_pme_spline_work(pme->pme_order);
/* 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);
}
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,
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;
}
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)
{
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,
* 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
* 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;
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);
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);
/* 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)
}
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);
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)
{
if (bCalcEnerVir)
{
- if (flags & GMX_PME_DO_COULOMB)
+ if (pme->doCoulomb)
{
if (!pme->bFEP_q)
{
*energy_q = 0;
}
- if (flags & GMX_PME_DO_LJ)
+ if (pme->doLJ)
{
if (!pme->bFEP_lj)
{
}
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);
+ sfree(pme->fshx);
+ sfree(pme->fshy);
+ sfree(pme->fshz);
+
+ 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]);
+ }
+
+ destroy_overlap_comm(&pme->overlap[0]);
+ destroy_overlap_comm(&pme->overlap[1]);
+
+ 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;
+}
*
* 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.
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
/* 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)
//@}
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,
/*! \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 */
* 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.
}
}
}
- data = (t_complex *)out_data;
+ data = static_cast<t_complex *>(out_data);
/* y real-to-complex FFTs */
for (i = 0; i < nx; i++)
if (in_data != out_data)
{
memcpy(work, in_data, sizeof(t_complex)*nx*nyc);
- data = (t_complex *)work;
+ data = reinterpret_cast<t_complex *>(work);
}
else
{
/* in-place */
- data = (t_complex *)out_data;
+ data = reinterpret_cast<t_complex *>(out_data);
}
/* Transpose to get X arrays */
* 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.
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;
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;
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;
if (status == 0)
{
- if ((fft->work = (t_complex *)malloc(sizeof(t_complex)*(nx*(ny/2+1)))) == NULL)
+ void *memory = malloc(sizeof(t_complex)*(nx*(ny/2+1)));
+ if (nullptr == memory)
{
status = ENOMEM;
}
+ fft->work = static_cast<t_complex *>(memory);
}
if (status != 0)
xvgr.h
)
-if (GMX_USE_TNG AND TNG_IO_DEFINITIONS)
- set_property(SOURCE tngio.cpp
- APPEND PROPERTY COMPILE_DEFINITIONS ${TNG_IO_DEFINITIONS})
- set_property(SOURCE tngio_for_tools.cpp
- APPEND PROPERTY COMPILE_DEFINITIONS ${TNG_IO_DEFINITIONS})
-endif()
-
if (BUILD_TESTING)
add_subdirectory(tests)
endif()
#include "gromacs/gmxlib/network.h"
#include "gromacs/math/vec.h"
#include "gromacs/math/vecdump.h"
+#include "gromacs/math/vectypes.h"
#include "gromacs/mdtypes/commrec.h"
#include "gromacs/mdtypes/df_history.h"
#include "gromacs/mdtypes/energyhistory.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/futil.h"
+#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/int64_to_int.h"
#include "gromacs/utility/programcontext.h"
#include "gromacs/utility/smalloc.h"
"accumulated_plus", "accumulated_minus", "accumulated_plus_2", "accumulated_minus_2", "Tij", "Tij_empirical"
};
-enum {
- ecprREAL, ecprRVEC, ecprMATRIX
+//! Higher level vector element type, only used for formatting checkpoint dumps
+enum class CptElementType
+{
+ integer, //!< integer
+ real, //!< float or double, not linked to precision of type real
+ real3, //!< float[3] or double[3], not linked to precision of type real
+ matrix3x3 //!< float[3][3] or double[3][3], not linked to precision of type real
};
-enum {
- cptpEST, cptpEEKS, cptpEENH, cptpEDFH
+//! \brief Parts of the checkpoint state, only used for reporting
+enum class StatePart
+{
+ microState, //!< The microstate of the simulated system
+ kineticEnergy, //!< Kinetic energy, needed for T/P-coupling state
+ energyHistory, //!< Energy observable statistics
+ freeEnergyHistory //!< Free-energy state and observable statistics
};
-/* enums for the different components of checkpoint variables, replacing the hard coded ones.
- cptpEST - state variables.
- cptpEEKS - Kinetic energy state variables.
- cptpEENH - Energy history state variables.
- cptpEDFH - free energy history variables.
- */
-
-static const char *st_names(int cptp, int ecpt)
+//! \brief Return the name of a checkpoint entry based on part and part entry
+static const char *entryName(StatePart part, int ecpt)
{
- switch (cptp)
+ switch (part)
{
- case cptpEST: return est_names [ecpt];
- case cptpEEKS: return eeks_names[ecpt];
- case cptpEENH: return eenh_names[ecpt];
- case cptpEDFH: return edfh_names[ecpt];
+ case StatePart::microState: return est_names [ecpt];
+ case StatePart::kineticEnergy: return eeks_names[ecpt];
+ case StatePart::energyHistory: return eenh_names[ecpt];
+ case StatePart::freeEnergyHistory: return edfh_names[ecpt];
}
return NULL;
}
}
-/* If nval >= 0, nval is used; on read this should match the passed value.
- * If nval n<0, *nptr is used; on read the value is stored in nptr
+template <typename T>
+struct xdr_type
+{
+};
+
+template <>
+struct xdr_type<int>
+{
+ // cppcheck-suppress unusedStructMember
+ static const int value = xdr_datatype_int;
+};
+
+template <>
+struct xdr_type<float>
+{
+ // cppcheck-suppress unusedStructMember
+ static const int value = xdr_datatype_float;
+};
+
+template <>
+struct xdr_type<double>
+{
+ // cppcheck-suppress unusedStructMember
+ static const int value = xdr_datatype_double;
+};
+
+//! \brief Returns size in byte of an xdr_datatype
+static inline unsigned int sizeOfXdrType(int xdrType)
+{
+ switch (xdrType)
+ {
+ case xdr_datatype_int:
+ return sizeof(int);
+ break;
+ case xdr_datatype_float:
+ return sizeof(float);
+ break;
+ case xdr_datatype_double:
+ return sizeof(double);
+ break;
+ default: GMX_RELEASE_ASSERT(false, "XDR data type not implemented");
+ }
+
+ return 0;
+}
+
+//! \brief Returns the XDR process function for i/o of an XDR type
+static inline xdrproc_t xdrProc(int xdrType)
+{
+ switch (xdrType)
+ {
+ case xdr_datatype_int:
+ return reinterpret_cast<xdrproc_t>(xdr_int);
+ break;
+ case xdr_datatype_float:
+ return reinterpret_cast<xdrproc_t>(xdr_float);
+ break;
+ case xdr_datatype_double:
+ return reinterpret_cast<xdrproc_t>(xdr_double);
+ break;
+ default: GMX_RELEASE_ASSERT(false, "XDR data type not implemented");
+ }
+
+ return NULL;
+}
+
+/*! \brief Lists or only reads an xdr vector from checkpoint file
+ *
+ * When list!=NULL reads and lists the \p nf vector elements of type \p xdrType.
+ * The header for the print is set by \p part and \p ecpt.
+ * The formatting of the printing is set by \p cptElementType.
+ * When list==NULL only reads the elements.
*/
-static int do_cpte_reals_low(XDR *xd, int cptp, int ecpt, int sflags,
- int nval, int *nptr, real **v,
- FILE *list, int erealtype)
+static bool_t listXdrVector(XDR *xd, StatePart part, int ecpt, int nf, int xdrType,
+ FILE *list, CptElementType cptElementType)
{
- bool_t res = 0;
- const bool useDouble = GMX_DOUBLE;
- int dtc = useDouble ? xdr_datatype_double : xdr_datatype_float;
- real *vp, *va = NULL;
- float *vf;
- double *vd;
- int nf, dt, i;
+ bool_t res = 0;
- if (list == NULL)
+ const unsigned int elemSize = sizeOfXdrType(xdrType);
+ std::vector<char> data(nf*elemSize);
+ res = xdr_vector(xd, data.data(), nf, elemSize, xdrProc(xdrType));
+
+ if (list != NULL)
{
- if (nval >= 0)
+ switch (xdrType)
{
- nf = nval;
- }
- else
- {
- if (nptr == NULL)
- {
- gmx_incons("*ntpr=NULL in do_cpte_reals_low");
- }
- nf = *nptr;
+ case xdr_datatype_int:
+ pr_ivec(list, 0, entryName(part, ecpt), reinterpret_cast<const int *>(data.data()), nf, TRUE);
+ break;
+ case xdr_datatype_float:
+#if !GMX_DOUBLE
+ if (cptElementType == CptElementType::real3)
+ {
+ // cppcheck-suppress invalidPointerCast
+ pr_rvecs(list, 0, entryName(part, ecpt), reinterpret_cast<const rvec *>(data.data()), nf/3);
+ }
+ else
+#endif
+ {
+ /* Note: With double precision code dumping a single precision rvec will produce float iso rvec print, but that's a minor annoyance */
+ // cppcheck-suppress invalidPointerCast
+ pr_fvec(list, 0, entryName(part, ecpt), reinterpret_cast<const float *>(data.data()), nf, TRUE);
+ }
+ break;
+ case xdr_datatype_double:
+#if GMX_DOUBLE
+ if (cptElementType == CptElementType::real3)
+ {
+ // cppcheck-suppress invalidPointerCast
+ pr_rvecs(list, 0, entryName(part, ecpt), reinterpret_cast<const rvec *>(data.data()), nf/3);
+ }
+ else
+#endif
+ {
+ /* Note: With single precision code dumping a double precision rvec will produce float iso rvec print, but that's a minor annoyance */
+ // cppcheck-suppress invalidPointerCast
+ pr_dvec(list, 0, entryName(part, ecpt), reinterpret_cast<const double *>(data.data()), nf, TRUE);
+ }
+ break;
+ default: GMX_RELEASE_ASSERT(false, "Data type not implemented for listing");
}
}
- res = xdr_int(xd, &nf);
- if (res == 0)
+
+ return res;
+}
+
+//! \brief Convert a double array, typed char*, to float
+static void convertArrayRealPrecision(const char *c, float *v, int n)
+{
+ const double *d = reinterpret_cast<const double *>(c);
+ for (int i = 0; i < n; i++)
{
- return -1;
+ v[i] = static_cast<float>(d[i]);
}
+}
+
+//! \brief Convert a float array, typed char*, to double
+static void convertArrayRealPrecision(const char *c, double *v, int n)
+{
+ const float *f = reinterpret_cast<const float *>(c);
+ for (int i = 0; i < n; i++)
+ {
+ v[i] = static_cast<double>(f[i]);
+ }
+}
+
+//! \brief Generate an error for trying to convert to integer
+static void convertArrayRealPrecision(const char gmx_unused *c, int gmx_unused *v, int gmx_unused n)
+{
+ GMX_RELEASE_ASSERT(false, "We only expect type mismatches between float and double, not integer");
+}
+
+/*! \brief Low-level routine for reading/writing a vector of reals from/to file.
+ *
+ * This is the only routine that does the actually i/o of real vector,
+ * all other routines are intermediate level routines for specific real
+ * data types, calling this routine.
+ * Currently this routine is (too) complex, since it handles both real *
+ * and std::vector<real>. Using real * is deprecated and this routine
+ * will simplify a lot when only std::vector needs to be supported.
+ *
+ * When not listing, we use either v or vector, depending on which is !=NULL.
+ * If nval >= 0, nval is used; on read this should match the passed value.
+ * If nval n<0, *nptr (with v) or vector->size() is used. On read using v,
+ * the value is stored in nptr
+ */
+template<typename T>
+static int doVectorLow(XDR *xd, StatePart part, int ecpt, int sflags,
+ int nval, int *nptr,
+ T **v, std::vector<T> *vector,
+ FILE *list, CptElementType cptElementType)
+{
+ GMX_RELEASE_ASSERT(list != NULL || (v != NULL && vector == NULL) || (v == NULL && vector != NULL), "Without list, we should have exactly one of v and vector != NULL");
+
+ bool_t res = 0;
+
+ int numElemInTheFile;
if (list == NULL)
{
if (nval >= 0)
{
- if (nf != nval)
- {
- gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", st_names(cptp, ecpt), nval, nf);
- }
+ GMX_RELEASE_ASSERT(nptr == NULL, "With nval>=0 we should have nptr==NULL");
+ numElemInTheFile = nval;
}
else
{
- *nptr = nf;
+ if (v != NULL)
+ {
+ GMX_RELEASE_ASSERT(nptr != NULL, "With nval<0 we should have nptr!=NULL");
+ // cppcheck-suppress nullPointer
+ numElemInTheFile = *nptr;
+ }
+ else
+ {
+ numElemInTheFile = vector->size();
+ }
}
}
- dt = dtc;
- res = xdr_int(xd, &dt);
+ /* Read/write the vector element count */
+ res = xdr_int(xd, &numElemInTheFile);
if (res == 0)
{
return -1;
}
- if (dt != dtc)
- {
- fprintf(stderr, "Precision mismatch for state entry %s, code precision is %s, file precision is %s\n",
- st_names(cptp, ecpt), xdr_datatype_names[dtc],
- xdr_datatype_names[dt]);
- }
- if (list || !(sflags & (1<<ecpt)))
+ /* Read/write the element data type */
+ gmx_constexpr int xdrTypeInTheCode = xdr_type<T>::value;
+ int xdrTypeInTheFile = xdrTypeInTheCode;
+ res = xdr_int(xd, &xdrTypeInTheFile);
+ if (res == 0)
{
- snew(va, nf);
- vp = va;
+ return -1;
}
- else
+
+ if (list == NULL && (sflags & (1 << ecpt)))
{
- if (*v == NULL)
+ if (nval >= 0)
{
- snew(*v, nf);
+ if (numElemInTheFile != nval)
+ {
+ gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", entryName(part, ecpt), nval, numElemInTheFile);
+ }
}
- vp = *v;
- }
- if (dt == xdr_datatype_float)
- {
- if (!useDouble)
+ else if (nptr != NULL)
{
- // This branch is not reached unless vp is already float *.
- vf = reinterpret_cast<float *>(vp);
+ *nptr = numElemInTheFile;
}
- else
+
+ bool typesMatch = (xdrTypeInTheFile == xdrTypeInTheCode);
+ if (!typesMatch)
{
- snew(vf, nf);
+ char buf[STRLEN];
+ sprintf(buf, "mismatch for state entry %s, code precision is %s, file precision is %s",
+ entryName(part, ecpt),
+ xdr_datatype_names[xdrTypeInTheCode],
+ xdr_datatype_names[xdrTypeInTheFile]);
+
+ /* Matchting int and real should never occur, but check anyhow */
+ if (xdrTypeInTheFile == xdr_datatype_int ||
+ xdrTypeInTheCode == xdr_datatype_int)
+ {
+ gmx_fatal(FARGS, "Type %s: incompatible checkpoint formats or corrupted checkpoint file.", buf);
+ }
+ fprintf(stderr, "Precision %s\n", buf);
}
- res = xdr_vector(xd, reinterpret_cast<char *>(vf), nf,
- static_cast<unsigned int>(sizeof(float)), (xdrproc_t)xdr_float);
- if (res == 0)
+
+ T *vp;
+ if (v != NULL)
{
- return -1;
+ if (*v == NULL)
+ {
+ snew(*v, numElemInTheFile);
+ }
+ vp = *v;
}
- if (useDouble)
+ else
{
- for (i = 0; i < nf; i++)
+ /* This conditional ensures that we don't resize on write.
+ * In particular in the state where this code was written
+ * PaddedRVecVector has a size of numElemInThefile and we
+ * don't want to loose that padding here.
+ */
+ if (vector->size() < static_cast<unsigned int>(numElemInTheFile))
{
- vp[i] = vf[i];
+ vector->resize(numElemInTheFile);
}
- sfree(vf);
+ vp = vector->data();
}
- }
- else
- {
- if (useDouble)
+
+ char *vChar;
+ if (typesMatch)
{
- // This branch is not reached unless vp is already double *.
- // cppcheck-suppress invalidPointerCast
- vd = reinterpret_cast<double *>(vp);
+ vChar = reinterpret_cast<char *>(vp);
}
else
{
- snew(vd, nf);
+ snew(vChar, numElemInTheFile*sizeOfXdrType(xdrTypeInTheFile));
}
- res = xdr_vector(xd, reinterpret_cast<char *>(vd), nf,
- static_cast<unsigned int>(sizeof(double)), (xdrproc_t)xdr_double);
+ res = xdr_vector(xd, vChar,
+ numElemInTheFile, sizeOfXdrType(xdrTypeInTheFile),
+ xdrProc(xdrTypeInTheFile));
if (res == 0)
{
return -1;
}
- if (!useDouble)
- {
- for (i = 0; i < nf; i++)
- {
- vp[i] = vd[i];
- }
- sfree(vd);
- }
- }
- if (list)
- {
- switch (erealtype)
+ if (!typesMatch)
{
- case ecprREAL:
- pr_reals(list, 0, st_names(cptp, ecpt), vp, nf);
- break;
- case ecprRVEC:
- pr_rvecs(list, 0, st_names(cptp, ecpt), (rvec *)vp, nf/3);
- break;
- default:
- gmx_incons("Unknown checkpoint real type");
+ /* In the old code float-double conversion came for free.
+ * In the new code we still support it, mainly because
+ * the tip4p_continue regression test makes use of this.
+ * It's an open question if we do or don't want to allow this.
+ */
+ convertArrayRealPrecision(vChar, vp, numElemInTheFile);
+ sfree(vChar);
}
}
- if (va)
+ else
{
- sfree(va);
+ res = listXdrVector(xd, part, ecpt, numElemInTheFile, xdrTypeInTheFile,
+ list, cptElementType);
}
return 0;
}
+//! \brief Read/Write an std::vector
+template <typename T>
+static int doVector(XDR *xd, StatePart part, int ecpt, int sflags,
+ std::vector<T> *vector, FILE *list)
+{
+ return doVectorLow<T>(xd, part, ecpt, sflags, -1, NULL, NULL, vector, list, CptElementType::real);
+}
+
+//! \brief Read/Write an std::vector, on read checks the number of elements matches \p numElements
+template <typename T>
+static int doVector(XDR *xd, StatePart part, int ecpt, int sflags,
+ int numElements, std::vector<T> *vector, FILE *list)
+{
+ return doVectorLow<T>(xd, part, ecpt, sflags, numElements, NULL, NULL, vector, list, CptElementType::real);
+}
+
+//! \brief Read/Write a PaddedRVecVector, on read checks the number of elements matches \p numElements
+static int doPaddedVector(XDR *xd, StatePart part, int ecpt, int sflags,
+ int numElements, PaddedRVecVector *v, FILE *list)
+{
+ rvec *v_rvec;
+
+ if (list == NULL && (sflags & (1 << ecpt)))
+ {
+ /* We resize the vector here to avoid pointer reallocation in
+ * do_cpte_reals_low. Note the we allocate 1 element extra for SIMD.
+ */
+ v->resize(numElements + 1);
+ v_rvec = as_rvec_array(v->data());
+ }
+ else
+ {
+ v_rvec = NULL;
+ }
+
+ return doVectorLow<real>(xd, part, ecpt, sflags,
+ numElements*DIM, NULL, (real **)(&v_rvec), NULL,
+ list, CptElementType::real3);
+}
/* This function stores n along with the reals for reading,
* but on reading it assumes that n matches the value in the checkpoint file,
* a fatal error is generated when this is not the case.
*/
-static int do_cpte_reals(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_reals(XDR *xd, StatePart part, int ecpt, int sflags,
int n, real **v, FILE *list)
{
- return do_cpte_reals_low(xd, cptp, ecpt, sflags, n, NULL, v, list, ecprREAL);
+ return doVectorLow<real>(xd, part, ecpt, sflags, n, NULL, v, NULL, list, CptElementType::real);
}
/* This function does the same as do_cpte_reals,
* except that on reading it ignores the passed value of *n
- * and stored the value read from the checkpoint file in *n.
+ * and stores the value read from the checkpoint file in *n.
*/
-static int do_cpte_n_reals(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_n_reals(XDR *xd, StatePart part, int ecpt, int sflags,
int *n, real **v, FILE *list)
{
- return do_cpte_reals_low(xd, cptp, ecpt, sflags, -1, n, v, list, ecprREAL);
+ return doVectorLow<real>(xd, part, ecpt, sflags, -1, n, v, NULL, list, CptElementType::real);
}
-static int do_cpte_real(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_real(XDR *xd, StatePart part, int ecpt, int sflags,
real *r, FILE *list)
{
- return do_cpte_reals_low(xd, cptp, ecpt, sflags, 1, NULL, &r, list, ecprREAL);
+ return doVectorLow<real>(xd, part, ecpt, sflags, 1, NULL, &r, NULL, list, CptElementType::real);
}
-static int do_cpte_ints(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_ints(XDR *xd, StatePart part, int ecpt, int sflags,
int n, int **v, FILE *list)
{
- bool_t res = 0;
- int dtc = xdr_datatype_int;
- int *vp, *va = NULL;
- int nf, dt;
-
- nf = n;
- res = xdr_int(xd, &nf);
- if (res == 0)
- {
- return -1;
- }
- if (list == NULL && v != NULL && nf != n)
- {
- gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", st_names(cptp, ecpt), n, nf);
- }
- dt = dtc;
- res = xdr_int(xd, &dt);
- if (res == 0)
- {
- return -1;
- }
- if (dt != dtc)
- {
- gmx_fatal(FARGS, "Type mismatch for state entry %s, code type is %s, file type is %s\n",
- st_names(cptp, ecpt), xdr_datatype_names[dtc],
- xdr_datatype_names[dt]);
- }
- if (list || !(sflags & (1<<ecpt)) || v == NULL)
- {
- snew(va, nf);
- vp = va;
- }
- else
- {
- if (*v == NULL)
- {
- snew(*v, nf);
- }
- vp = *v;
- }
- res = xdr_vector(xd, reinterpret_cast<char *>(vp), nf,
- static_cast<unsigned int>(sizeof(int)), (xdrproc_t)xdr_int);
- if (res == 0)
- {
- return -1;
- }
- if (list)
- {
- pr_ivec(list, 0, st_names(cptp, ecpt), vp, nf, TRUE);
- }
- if (va)
- {
- sfree(va);
- }
-
- return 0;
+ return doVectorLow<int>(xd, part, ecpt, sflags, n, NULL, v, NULL, list, CptElementType::integer);
}
-static int do_cpte_int(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_int(XDR *xd, StatePart part, int ecpt, int sflags,
int *i, FILE *list)
{
- return do_cpte_ints(xd, cptp, ecpt, sflags, 1, &i, list);
+ return do_cpte_ints(xd, part, ecpt, sflags, 1, &i, list);
}
-static int do_cpte_doubles(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_doubles(XDR *xd, StatePart part, int ecpt, int sflags,
int n, double **v, FILE *list)
{
- bool_t res = 0;
- int dtc = xdr_datatype_double;
- double *vp, *va = NULL;
- int nf, dt;
-
- nf = n;
- res = xdr_int(xd, &nf);
- if (res == 0)
- {
- return -1;
- }
- if (list == NULL && nf != n)
- {
- gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", st_names(cptp, ecpt), n, nf);
- }
- dt = dtc;
- res = xdr_int(xd, &dt);
- if (res == 0)
- {
- return -1;
- }
- if (dt != dtc)
- {
- gmx_fatal(FARGS, "Precision mismatch for state entry %s, code precision is %s, file precision is %s\n",
- st_names(cptp, ecpt), xdr_datatype_names[dtc],
- xdr_datatype_names[dt]);
- }
- if (list || !(sflags & (1<<ecpt)))
- {
- snew(va, nf);
- vp = va;
- }
- else
- {
- if (*v == NULL)
- {
- snew(*v, nf);
- }
- vp = *v;
- }
- res = xdr_vector(xd, reinterpret_cast<char *>(vp), nf,
- static_cast<unsigned int>(sizeof(double)), (xdrproc_t)xdr_double);
- if (res == 0)
- {
- return -1;
- }
- if (list)
- {
- pr_doubles(list, 0, st_names(cptp, ecpt), vp, nf);
- }
- if (va)
- {
- sfree(va);
- }
-
- return 0;
+ return doVectorLow<double>(xd, part, ecpt, sflags, n, NULL, v, NULL, list, CptElementType::real);
}
-static int do_cpte_double(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_double(XDR *xd, StatePart part, int ecpt, int sflags,
double *r, FILE *list)
{
- return do_cpte_doubles(xd, cptp, ecpt, sflags, 1, &r, list);
+ return do_cpte_doubles(xd, part, ecpt, sflags, 1, &r, list);
}
-
-static int do_cpte_rvecs(XDR *xd, int cptp, int ecpt, int sflags,
- int n, rvec **v, FILE *list)
-{
- return do_cpte_reals_low(xd, cptp, ecpt, sflags,
- n*DIM, NULL, (real **)v, list, ecprRVEC);
-}
-
-static int do_cpte_matrix(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_matrix(XDR *xd, StatePart part, int ecpt, int sflags,
matrix v, FILE *list)
{
real *vr;
int ret;
vr = &(v[0][0]);
- ret = do_cpte_reals_low(xd, cptp, ecpt, sflags,
- DIM*DIM, NULL, &vr, NULL, ecprMATRIX);
+ ret = doVectorLow<real>(xd, part, ecpt, sflags,
+ DIM*DIM, NULL, &vr, NULL, NULL, CptElementType::matrix3x3);
if (list && ret == 0)
{
- pr_rvecs(list, 0, st_names(cptp, ecpt), v, DIM);
+ pr_rvecs(list, 0, entryName(part, ecpt), v, DIM);
}
return ret;
}
-static int do_cpte_nmatrix(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_nmatrix(XDR *xd, StatePart part, int ecpt, int sflags,
int n, real **v, FILE *list)
{
int i;
}
for (i = 0; i < n; i++)
{
- reti = do_cpte_reals_low(xd, cptp, ecpt, sflags, n, NULL, &(v[i]), NULL, ecprREAL);
+ reti = doVectorLow<real>(xd, part, ecpt, sflags, n, NULL, &(v[i]), NULL, NULL, CptElementType::matrix3x3);
if (list && reti == 0)
{
- sprintf(name, "%s[%d]", st_names(cptp, ecpt), i);
+ sprintf(name, "%s[%d]", entryName(part, ecpt), i);
pr_reals(list, 0, name, v[i], n);
}
if (reti != 0)
return ret;
}
-static int do_cpte_matrices(XDR *xd, int cptp, int ecpt, int sflags,
+static int do_cpte_matrices(XDR *xd, StatePart part, int ecpt, int sflags,
int n, matrix **v, FILE *list)
{
bool_t res = 0;
}
if (list == NULL && nf != n)
{
- gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", st_names(cptp, ecpt), n, nf);
+ gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", entryName(part, ecpt), n, nf);
}
if (list || !(sflags & (1<<ecpt)))
{
}
}
}
- ret = do_cpte_reals_low(xd, cptp, ecpt, sflags,
- nf*DIM*DIM, NULL, &vr, NULL, ecprMATRIX);
+ ret = doVectorLow<real>(xd, part, ecpt, sflags,
+ nf*DIM*DIM, NULL, &vr, NULL, NULL,
+ CptElementType::matrix3x3);
for (i = 0; i < nf; i++)
{
for (j = 0; j < DIM; j++)
{
for (i = 0; i < nf; i++)
{
- pr_rvecs(list, 0, st_names(cptp, ecpt), vp[i], DIM);
+ pr_rvecs(list, 0, entryName(part, ecpt), vp[i], DIM);
}
}
if (va)
{
do_cpt_int_err(xd, "swap", eSwapCoords, list);
}
+ else
+ {
+ *eSwapCoords = eswapNO;
+ }
}
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)
{
- int sflags;
- int i;
- int ret;
- int nnht, nnhtp;
+ int ret = 0;
- ret = 0;
-
- 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);
- }
+ const int nnht = state->nhchainlength*state->ngtc;
+ const int nnhtp = state->nhchainlength*state->nnhpres;
- sflags = state->flags;
- for (i = 0; (i < estNR && ret == 0); i++)
+ const StatePart part = StatePart::microState;
+ const int sflags = state->flags;
+ for (int i = 0; (i < estNR && ret == 0); i++)
{
if (fflags & (1<<i))
{
switch (i)
{
- case estLAMBDA: ret = do_cpte_reals(xd, cptpEST, i, sflags, efptNR, &(state->lambda), list); break;
- case estFEPSTATE: ret = do_cpte_int (xd, cptpEST, i, sflags, &state->fep_state, list); break;
- case estBOX: ret = do_cpte_matrix(xd, cptpEST, i, sflags, state->box, list); break;
- case estBOX_REL: ret = do_cpte_matrix(xd, cptpEST, i, sflags, state->box_rel, list); break;
- case estBOXV: ret = do_cpte_matrix(xd, cptpEST, i, sflags, state->boxv, list); break;
- case estPRES_PREV: ret = do_cpte_matrix(xd, cptpEST, i, sflags, state->pres_prev, list); break;
- case estSVIR_PREV: ret = do_cpte_matrix(xd, cptpEST, i, sflags, state->svir_prev, list); break;
- case estFVIR_PREV: ret = do_cpte_matrix(xd, cptpEST, i, sflags, state->fvir_prev, list); break;
- case estNH_XI: ret = do_cpte_doubles(xd, cptpEST, i, sflags, nnht, &state->nosehoover_xi, list); break;
- case estNH_VXI: ret = do_cpte_doubles(xd, cptpEST, i, sflags, nnht, &state->nosehoover_vxi, list); break;
- case estNHPRES_XI: ret = do_cpte_doubles(xd, cptpEST, i, sflags, nnhtp, &state->nhpres_xi, list); break;
- case estNHPRES_VXI: ret = do_cpte_doubles(xd, cptpEST, i, sflags, nnhtp, &state->nhpres_vxi, list); break;
- case estTC_INT: ret = do_cpte_doubles(xd, cptpEST, i, sflags, state->ngtc, &state->therm_integral, list); break;
- case estVETA: ret = do_cpte_real(xd, cptpEST, i, sflags, &state->veta, list); break;
- case estVOL0: ret = do_cpte_real(xd, cptpEST, i, sflags, &state->vol0, list); break;
- case estX: ret = do_cpte_rvecs(xd, cptpEST, i, sflags, state->natoms, &state->x, list); break;
- case estV: ret = do_cpte_rvecs(xd, cptpEST, i, sflags, state->natoms, &state->v, list); break;
+ case estLAMBDA: ret = doVector<real>(xd, part, i, sflags, static_cast<int>(efptNR), &state->lambda, list); break;
+ case estFEPSTATE: ret = do_cpte_int (xd, part, i, sflags, &state->fep_state, list); break;
+ case estBOX: ret = do_cpte_matrix(xd, part, i, sflags, state->box, list); break;
+ case estBOX_REL: ret = do_cpte_matrix(xd, part, i, sflags, state->box_rel, list); break;
+ case estBOXV: ret = do_cpte_matrix(xd, part, i, sflags, state->boxv, list); break;
+ case estPRES_PREV: ret = do_cpte_matrix(xd, part, i, sflags, state->pres_prev, list); break;
+ case estSVIR_PREV: ret = do_cpte_matrix(xd, part, i, sflags, state->svir_prev, list); break;
+ case estFVIR_PREV: ret = do_cpte_matrix(xd, part, i, sflags, state->fvir_prev, list); break;
+ case estNH_XI: ret = doVector<double>(xd, part, i, sflags, nnht, &state->nosehoover_xi, list); break;
+ case estNH_VXI: ret = doVector<double>(xd, part, i, sflags, nnht, &state->nosehoover_vxi, list); break;
+ case estNHPRES_XI: ret = doVector<double>(xd, part, i, sflags, nnhtp, &state->nhpres_xi, list); break;
+ case estNHPRES_VXI: ret = doVector<double>(xd, part, i, sflags, nnhtp, &state->nhpres_vxi, list); break;
+ case estTC_INT: ret = doVector<double>(xd, part, i, sflags, state->ngtc, &state->therm_integral, list); break;
+ case estVETA: ret = do_cpte_real(xd, part, i, sflags, &state->veta, list); break;
+ case estVOL0: ret = do_cpte_real(xd, part, i, sflags, &state->vol0, list); break;
+ case estX: ret = doPaddedVector(xd, part, i, sflags, state->natoms, &state->x, list); break;
+ case estV: ret = doPaddedVector(xd, part, i, sflags, state->natoms, &state->v, list); break;
/* The RNG entries are no longer written,
* the next 4 lines are only for reading old files.
*/
- case estLD_RNG: ret = do_cpte_ints(xd, cptpEST, i, sflags, 0, NULL, list); break;
- case estLD_RNGI: ret = do_cpte_ints(xd, cptpEST, i, sflags, 0, NULL, list); break;
- case estMC_RNG: ret = do_cpte_ints(xd, cptpEST, i, sflags, 0, NULL, list); break;
- case estMC_RNGI: ret = do_cpte_ints(xd, cptpEST, i, sflags, 0, NULL, list); break;
- case estDISRE_INITF: ret = do_cpte_real (xd, cptpEST, i, sflags, &state->hist.disre_initf, list); break;
- case estDISRE_RM3TAV: ret = do_cpte_n_reals(xd, cptpEST, i, sflags, &state->hist.ndisrepairs, &state->hist.disre_rm3tav, list); break;
- case estORIRE_INITF: ret = do_cpte_real (xd, cptpEST, i, sflags, &state->hist.orire_initf, list); break;
- case estORIRE_DTAV: ret = do_cpte_n_reals(xd, cptpEST, i, sflags, &state->hist.norire_Dtav, &state->hist.orire_Dtav, list); break;
+ case estLD_RNG: ret = do_cpte_ints(xd, part, i, sflags, 0, NULL, list); break;
+ case estLD_RNGI: ret = do_cpte_ints(xd, part, i, sflags, 0, NULL, list); break;
+ case estMC_RNG: ret = do_cpte_ints(xd, part, i, sflags, 0, NULL, list); break;
+ case estMC_RNGI: ret = do_cpte_ints(xd, part, i, sflags, 0, NULL, list); break;
+ case estDISRE_INITF: ret = do_cpte_real (xd, part, i, sflags, &state->hist.disre_initf, list); break;
+ case estDISRE_RM3TAV: ret = do_cpte_n_reals(xd, part, i, sflags, &state->hist.ndisrepairs, &state->hist.disre_rm3tav, list); break;
+ case estORIRE_INITF: ret = do_cpte_real (xd, part, i, sflags, &state->hist.orire_initf, list); break;
+ case estORIRE_DTAV: ret = do_cpte_n_reals(xd, part, i, sflags, &state->hist.norire_Dtav, &state->hist.orire_Dtav, list); break;
default:
gmx_fatal(FARGS, "Unknown state entry %d\n"
"You are reading a checkpoint file written by different code, which is not supported", i);
static int do_cpt_ekinstate(XDR *xd, int fflags, ekinstate_t *ekins,
FILE *list)
{
- int i;
- int ret;
+ int ret = 0;
- ret = 0;
-
- for (i = 0; (i < eeksNR && ret == 0); i++)
+ const StatePart part = StatePart::kineticEnergy;
+ for (int i = 0; (i < eeksNR && ret == 0); i++)
{
if (fflags & (1<<i))
{
switch (i)
{
- case eeksEKIN_N: ret = do_cpte_int(xd, cptpEEKS, i, fflags, &ekins->ekin_n, list); break;
- case eeksEKINH: ret = do_cpte_matrices(xd, cptpEEKS, i, fflags, ekins->ekin_n, &ekins->ekinh, list); break;
- case eeksEKINF: ret = do_cpte_matrices(xd, cptpEEKS, i, fflags, ekins->ekin_n, &ekins->ekinf, list); break;
- case eeksEKINO: ret = do_cpte_matrices(xd, cptpEEKS, i, fflags, ekins->ekin_n, &ekins->ekinh_old, list); break;
- case eeksEKINTOTAL: ret = do_cpte_matrix(xd, cptpEEKS, i, fflags, ekins->ekin_total, list); break;
- case eeksEKINSCALEF: ret = do_cpte_doubles(xd, cptpEEKS, i, fflags, ekins->ekin_n, &ekins->ekinscalef_nhc, list); break;
- case eeksVSCALE: ret = do_cpte_doubles(xd, 1, cptpEEKS, fflags, ekins->ekin_n, &ekins->vscale_nhc, list); break;
- case eeksEKINSCALEH: ret = do_cpte_doubles(xd, 1, cptpEEKS, fflags, ekins->ekin_n, &ekins->ekinscaleh_nhc, list); break;
- case eeksDEKINDL: ret = do_cpte_real(xd, 1, cptpEEKS, fflags, &ekins->dekindl, list); break;
- case eeksMVCOS: ret = do_cpte_real(xd, 1, cptpEEKS, fflags, &ekins->mvcos, list); break;
+ case eeksEKIN_N: ret = do_cpte_int(xd, part, i, fflags, &ekins->ekin_n, list); break;
+ case eeksEKINH: ret = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinh, list); break;
+ case eeksEKINF: ret = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinf, list); break;
+ case eeksEKINO: ret = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinh_old, list); break;
+ case eeksEKINTOTAL: ret = do_cpte_matrix(xd, part, i, fflags, ekins->ekin_total, list); break;
+ case eeksEKINSCALEF: ret = doVector<double>(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinscalef_nhc, list); break;
+ case eeksVSCALE: ret = doVector<double>(xd, part, i, fflags, ekins->ekin_n, &ekins->vscale_nhc, list); break;
+ case eeksEKINSCALEH: ret = doVector<double>(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinscaleh_nhc, list); break;
+ case eeksDEKINDL: ret = do_cpte_real(xd, part, i, fflags, &ekins->dekindl, list); break;
+ case eeksMVCOS: ret = do_cpte_real(xd, part, i, fflags, &ekins->mvcos, list); break;
default:
gmx_fatal(FARGS, "Unknown ekin data state entry %d\n"
"You are probably reading a new checkpoint file with old code", i);
}
-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)
do_cpt_n_rvecs_err(xd, "Ch1 whole x", swapstate->nat[eChan1], *swapstate->xc_old_whole_p[eChan1], list);
}
- return ret;
+ return 0;
}
int fflags, energyhistory_t *enerhist,
FILE *list)
{
- int i;
- int j;
- int ret;
-
- ret = 0;
+ int ret = 0;
+ /* This is stored/read for backward compatibility */
+ int energyHistoryNumEnergies = 0;
if (bRead)
{
enerhist->nsteps = 0;
enerhist->nsum = 0;
enerhist->nsteps_sim = 0;
enerhist->nsum_sim = 0;
- enerhist->dht = NULL;
-
- if (fflags & (1<< eenhENERGY_DELTA_H_NN) )
- {
- snew(enerhist->dht, 1);
- enerhist->dht->ndh = NULL;
- enerhist->dht->dh = NULL;
- enerhist->dht->start_lambda_set = FALSE;
- }
+ }
+ else
+ {
+ energyHistoryNumEnergies = enerhist->ener_sum_sim.size();
}
- for (i = 0; (i < eenhNR && ret == 0); i++)
+ delta_h_history_t *deltaH = enerhist->deltaHForeignLambdas.get();
+ const StatePart part = StatePart::energyHistory;
+ for (int i = 0; (i < eenhNR && ret == 0); i++)
{
if (fflags & (1<<i))
{
switch (i)
{
- case eenhENERGY_N: ret = do_cpte_int(xd, cptpEENH, i, fflags, &enerhist->nener, list); break;
- case eenhENERGY_AVER: ret = do_cpte_doubles(xd, cptpEENH, i, fflags, enerhist->nener, &enerhist->ener_ave, list); break;
- case eenhENERGY_SUM: ret = do_cpte_doubles(xd, cptpEENH, i, fflags, enerhist->nener, &enerhist->ener_sum, list); break;
+ case eenhENERGY_N: ret = do_cpte_int(xd, part, i, fflags, &energyHistoryNumEnergies, list); break;
+ case eenhENERGY_AVER: ret = doVector<double>(xd, part, i, fflags, energyHistoryNumEnergies, &enerhist->ener_ave, list); break;
+ case eenhENERGY_SUM: ret = doVector<double>(xd, part, i, fflags, energyHistoryNumEnergies, &enerhist->ener_sum, list); break;
case eenhENERGY_NSUM: do_cpt_step_err(xd, eenh_names[i], &enerhist->nsum, list); break;
- case eenhENERGY_SUM_SIM: ret = do_cpte_doubles(xd, cptpEENH, i, fflags, enerhist->nener, &enerhist->ener_sum_sim, list); break;
+ case eenhENERGY_SUM_SIM: ret = doVector<double>(xd, part, i, fflags, energyHistoryNumEnergies, &enerhist->ener_sum_sim, list); break;
case eenhENERGY_NSUM_SIM: do_cpt_step_err(xd, eenh_names[i], &enerhist->nsum_sim, list); break;
case eenhENERGY_NSTEPS: do_cpt_step_err(xd, eenh_names[i], &enerhist->nsteps, list); break;
case eenhENERGY_NSTEPS_SIM: do_cpt_step_err(xd, eenh_names[i], &enerhist->nsteps_sim, list); break;
- case eenhENERGY_DELTA_H_NN: do_cpt_int_err(xd, eenh_names[i], &(enerhist->dht->nndh), list);
- if (bRead) /* now allocate memory for it */
+ case eenhENERGY_DELTA_H_NN:
+ {
+ int numDeltaH = 0;
+ if (!bRead && deltaH != nullptr)
+ {
+ numDeltaH = deltaH->dh.size();
+ }
+ do_cpt_int_err(xd, eenh_names[i], &numDeltaH, list);
+ if (bRead)
{
- snew(enerhist->dht->dh, enerhist->dht->nndh);
- snew(enerhist->dht->ndh, enerhist->dht->nndh);
- for (j = 0; j < enerhist->dht->nndh; j++)
+ if (deltaH == nullptr)
{
- enerhist->dht->ndh[j] = 0;
- enerhist->dht->dh[j] = NULL;
+ enerhist->deltaHForeignLambdas.reset(new delta_h_history_t);
+ deltaH = enerhist->deltaHForeignLambdas.get();
}
+ deltaH->dh.resize(numDeltaH);
+ deltaH->start_lambda_set = FALSE;
}
break;
+ }
case eenhENERGY_DELTA_H_LIST:
- for (j = 0; j < enerhist->dht->nndh; j++)
+ for (auto dh : deltaH->dh)
{
- ret = do_cpte_n_reals(xd, cptpEENH, i, fflags, &enerhist->dht->ndh[j], &(enerhist->dht->dh[j]), list);
+ ret = doVector<real>(xd, part, i, fflags, &dh, list);
}
break;
case eenhENERGY_DELTA_H_STARTTIME:
- ret = do_cpte_double(xd, cptpEENH, i, fflags, &(enerhist->dht->start_time), list); break;
+ ret = do_cpte_double(xd, part, i, fflags, &(deltaH->start_time), list); break;
case eenhENERGY_DELTA_H_STARTLAMBDA:
- ret = do_cpte_double(xd, cptpEENH, i, fflags, &(enerhist->dht->start_lambda), list); break;
+ ret = do_cpte_double(xd, part, i, fflags, &(deltaH->start_lambda), list); break;
default:
gmx_fatal(FARGS, "Unknown energy history entry %d\n"
"You are probably reading a new checkpoint file with old code", i);
if ((fflags & (1<<eenhENERGY_SUM)) && !(fflags & (1<<eenhENERGY_SUM_SIM)))
{
/* Assume we have an old file format and copy sum to sum_sim */
- srenew(enerhist->ener_sum_sim, enerhist->nener);
- for (i = 0; i < enerhist->nener; i++)
- {
- enerhist->ener_sum_sim[i] = enerhist->ener_sum[i];
- }
+ enerhist->ener_sum_sim = enerhist->ener_sum;
}
if ( (fflags & (1<<eenhENERGY_NSUM)) &&
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;
+ int ret = 0;
+
+ 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;
- for (i = 0; (i < edfhNR && ret == 0); i++)
+ const StatePart part = StatePart::freeEnergyHistory;
+ for (int i = 0; (i < edfhNR && ret == 0); i++)
{
if (fflags & (1<<i))
{
switch (i)
{
- case edfhBEQUIL: ret = do_cpte_int(xd, cptpEDFH, i, fflags, &dfhist->bEquil, list); break;
- case edfhNATLAMBDA: ret = do_cpte_ints(xd, cptpEDFH, i, fflags, nlambda, &dfhist->n_at_lam, list); break;
- case edfhWLHISTO: ret = do_cpte_reals(xd, cptpEDFH, i, fflags, nlambda, &dfhist->wl_histo, list); break;
- case edfhWLDELTA: ret = do_cpte_real(xd, cptpEDFH, i, fflags, &dfhist->wl_delta, list); break;
- case edfhSUMWEIGHTS: ret = do_cpte_reals(xd, cptpEDFH, i, fflags, nlambda, &dfhist->sum_weights, list); break;
- case edfhSUMDG: ret = do_cpte_reals(xd, cptpEDFH, i, fflags, nlambda, &dfhist->sum_dg, list); break;
- case edfhSUMMINVAR: ret = do_cpte_reals(xd, cptpEDFH, i, fflags, nlambda, &dfhist->sum_minvar, list); break;
- case edfhSUMVAR: ret = do_cpte_reals(xd, cptpEDFH, i, fflags, nlambda, &dfhist->sum_variance, list); break;
- case edfhACCUMP: ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->accum_p, list); break;
- case edfhACCUMM: ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->accum_m, list); break;
- case edfhACCUMP2: ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->accum_p2, list); break;
- case edfhACCUMM2: ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->accum_m2, list); break;
- case edfhTIJ: ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->Tij, list); break;
- case edfhTIJEMP: ret = do_cpte_nmatrix(xd, cptpEDFH, i, fflags, nlambda, dfhist->Tij_empirical, list); break;
+ case edfhBEQUIL: ret = do_cpte_int(xd, part, i, fflags, &dfhist->bEquil, list); break;
+ case edfhNATLAMBDA: ret = do_cpte_ints(xd, part, i, fflags, nlambda, &dfhist->n_at_lam, list); break;
+ case edfhWLHISTO: ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->wl_histo, list); break;
+ case edfhWLDELTA: ret = do_cpte_real(xd, part, i, fflags, &dfhist->wl_delta, list); break;
+ case edfhSUMWEIGHTS: ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_weights, list); break;
+ case edfhSUMDG: ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_dg, list); break;
+ case edfhSUMMINVAR: ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_minvar, list); break;
+ case edfhSUMVAR: ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_variance, list); break;
+ case edfhACCUMP: ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_p, list); break;
+ case edfhACCUMM: ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_m, list); break;
+ case edfhACCUMP2: ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_p2, list); break;
+ case edfhACCUMM2: ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_m2, list); break;
+ case edfhTIJ: ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->Tij, list); break;
+ case edfhTIJEMP: ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->Tij_empirical, list); break;
default:
gmx_fatal(FARGS, "Unknown df history entry %d\n"
* 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. */
}
/* 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);
}
}
- return ret;
+ return 0;
}
ivec domdecCells, int nppnodes,
int eIntegrator, int simulation_part,
gmx_bool bExpanded, int elamstats,
- gmx_int64_t step, double t, t_state *state)
+ gmx_int64_t step, double t,
+ t_state *state, energyhistory_t *enerhist)
{
t_fileio *fp;
int file_version;
}
flags_enh = 0;
- if (state->enerhist->nsum > 0 || state->enerhist->nsum_sim > 0)
+ if (enerhist->nsum > 0 || enerhist->nsum_sim > 0)
{
flags_enh |= (1<<eenhENERGY_N) | (1<<eenhENERGY_NSTEPS) | (1<<eenhENERGY_NSTEPS_SIM);
- if (state->enerhist->nsum > 0)
+ if (enerhist->nsum > 0)
{
flags_enh |= ((1<<eenhENERGY_AVER) | (1<<eenhENERGY_SUM) |
(1<<eenhENERGY_NSUM));
}
- if (state->enerhist->nsum_sim > 0)
+ if (enerhist->nsum_sim > 0)
{
flags_enh |= ((1<<eenhENERGY_SUM_SIM) | (1<<eenhENERGY_NSUM_SIM));
}
- if (state->enerhist->dht)
+ if (enerhist->deltaHForeignLambdas != nullptr)
{
flags_enh |= ( (1<< eenhENERGY_DELTA_H_NN) |
(1<< eenhENERGY_DELTA_H_LIST) |
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);
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_enerhist(gmx_fio_getxdr(fp), FALSE, flags_enh, enerhist, 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))
{
ivec dd_nc, int *npme,
int eIntegrator, int *init_fep_state, gmx_int64_t *step, double *t,
t_state *state, gmx_bool *bReadEkin,
+ energyhistory_t *enerhist,
int *simulation_part,
gmx_bool bAppendOutputFiles, gmx_bool bForceAppend,
gmx_bool reproducibilityRequested)
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;
&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)
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 */
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)
((flags_eks & (1<<eeksEKINSCALEF)) | (flags_eks & (1<<eeksEKINSCALEH)) | (flags_eks & (1<<eeksVSCALE))));
ret = do_cpt_enerhist(gmx_fio_getxdr(fp), TRUE,
- flags_enh, state->enerhist, NULL);
+ flags_enh, enerhist, NULL);
if (ret)
{
cp_error();
{
fprintf(fplog, "\nWARNING: %s\n\n", warn);
}
- state->enerhist->nsum = *step;
- state->enerhist->nsum_sim = *step;
+ enerhist->nsum = *step;
+ 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();
const t_commrec *cr, ivec dd_nc, int *npme,
t_inputrec *ir, t_state *state,
gmx_bool *bReadEkin,
+ energyhistory_t *enerhist,
gmx_bool bAppend, gmx_bool bForceAppend,
gmx_bool reproducibilityRequested)
{
/* Read the state from the checkpoint file */
read_checkpoint(fn, fplog,
cr, dd_nc, npme,
- ir->eI, &(ir->fepvals->init_fep_state), &step, &t, state, bReadEkin,
+ ir->eI, &(ir->fepvals->init_fep_state), &step, &t,
+ state, bReadEkin, enerhist,
&ir->simulation_part, bAppend, bForceAppend,
reproducibilityRequested);
}
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 ||
&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);
}
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;
&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();
{
cp_error();
}
+
+ energyhistory_t enerhist;
ret = do_cpt_enerhist(gmx_fio_getxdr(fp), TRUE,
- flags_enh, state->enerhist, NULL);
+ flags_enh, &enerhist, NULL);
if (ret)
{
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();
fr->bX = (state.flags & (1<<estX));
if (fr->bX)
{
- fr->x = state.x;
- state.x = NULL;
+ fr->x = getRvecArrayFromPaddedRVecVector(&state.x, state.natoms);
}
fr->bV = (state.flags & (1<<estV));
if (fr->bV)
{
- fr->v = state.v;
- state.v = NULL;
+ fr->v = getRvecArrayFromPaddedRVecVector(&state.v, state.natoms);
}
fr->bF = FALSE;
fr->bBox = (state.flags & (1<<estBOX));
{
copy_mat(state.box, fr->box);
}
- done_state(&state);
}
void list_checkpoint(const char *fn, FILE *out)
gmx_int64_t step;
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;
- init_state(&state, -1, -1, -1, -1, 0);
+ t_state state = {};
+ init_state(&state, 0, 0, 0, 0, 0);
fp = gmx_fio_open(fn, "r");
do_cpt_header(gmx_fio_getxdr(fp), TRUE, &file_version,
&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();
{
cp_error();
}
+
+ energyhistory_t enerhist;
ret = do_cpt_enerhist(gmx_fio_getxdr(fp), TRUE,
- flags_enh, state.enerhist, out);
+ flags_enh, &enerhist, 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)
{
gmx_file("Cannot read/write checkpoint; corrupt file, or maybe you are out of disk space?");
}
-
- done_state(&state);
}
/* This routine cannot print tons of data, since it is called before the log file is opened. */
{
gmx_file("Cannot read/write checkpoint; corrupt file, or maybe you are out of disk space?");
}
- done_state(&state);
}
extern "C" {
#endif
+class energyhistory_t;
struct gmx_file_position_t;
struct t_commrec;
struct t_fileio;
int eIntegrator, int simulation_part,
gmx_bool bExpanded, int elamstats,
gmx_int64_t step, double t,
- t_state *state);
+ t_state *state, energyhistory_t *enerhist);
/* Loads a checkpoint from fn for run continuation.
* Generates a fatal error on system size mismatch.
const t_commrec *cr, ivec dd_nc, int *npme,
t_inputrec *ir, t_state *state,
gmx_bool *bReadEkin,
+ energyhistory_t *enerhist,
gmx_bool bAppend, gmx_bool bForceAppend,
gmx_bool reproducibilityRequested);
#include "gromacs/fileio/tpxio.h"
#include "gromacs/fileio/trxio.h"
#include "gromacs/math/vec.h"
-#include "gromacs/topology/atomprop.h"
#include "gromacs/topology/atoms.h"
#include "gromacs/topology/block.h"
#include "gromacs/topology/mtop_util.h"
#include "gromacs/trajectory/trajectoryframe.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/smalloc.h"
void write_sto_conf_indexed(const char *outfile, const char *title,
}
}
-static void read_stx_conf(const char *infile, t_topology *top,
+static void read_stx_conf(const char *infile,
+ t_symtab *symtab, char ***name, t_atoms *atoms,
rvec x[], rvec *v, int *ePBC, matrix box)
{
FILE *in;
int ftp;
char g96_line[STRLEN+1];
- if (top->atoms.nr == 0)
+ if (atoms->nr == 0)
{
fprintf(stderr, "Warning: Number of atoms in %s is 0\n", infile);
}
- else if (top->atoms.atom == NULL)
+ else if (atoms->atom == NULL)
{
gmx_mem("Uninitialized array atom");
}
switch (ftp)
{
case efGRO:
- gmx_gro_read_conf(infile, top, x, v, box);
+ gmx_gro_read_conf(infile, symtab, name, atoms, x, v, box);
break;
case efG96:
fr.title = NULL;
- fr.natoms = top->atoms.nr;
- fr.atoms = &top->atoms;
+ fr.natoms = atoms->nr;
+ fr.atoms = atoms;
fr.x = x;
fr.v = v;
fr.f = NULL;
in = gmx_fio_fopen(infile, "r");
- read_g96_conf(in, infile, &fr, &top->symtab, g96_line);
+ read_g96_conf(in, infile, &fr, symtab, g96_line);
gmx_fio_fclose(in);
copy_mat(fr.box, box);
- top->name = put_symtab(&top->symtab, fr.title);
+ *name = put_symtab(symtab, fr.title);
sfree(const_cast<char *>(fr.title));
break;
case efPDB:
case efBRK:
case efENT:
- gmx_pdb_read_conf(infile, top, x, ePBC, box);
+ gmx_pdb_read_conf(infile, symtab, name, atoms, x, ePBC, box);
break;
case efESP:
- gmx_espresso_read_conf(infile, top, x, v, box);
+ gmx_espresso_read_conf(infile, symtab, name, atoms, x, v, box);
break;
default:
gmx_incons("Not supported in read_stx_conf");
}
}
-static void done_gmx_groups_t(gmx_groups_t *g)
+static void readConfAndAtoms(const char *infile,
+ t_symtab *symtab, char ***name, t_atoms *atoms,
+ int *ePBC,
+ rvec **x, rvec **v, matrix box)
{
- int i;
+ int natoms;
+ get_stx_coordnum(infile, &natoms);
+
+ init_t_atoms(atoms, natoms, (fn2ftp(infile) == efPDB));
- for (i = 0; (i < egcNR); i++)
+ bool xIsNull = false;
+ if (x == NULL)
{
- if (NULL != g->grps[i].nm_ind)
- {
- sfree(g->grps[i].nm_ind);
- g->grps[i].nm_ind = NULL;
- }
- if (NULL != g->grpnr[i])
- {
- sfree(g->grpnr[i]);
- g->grpnr[i] = NULL;
- }
+ snew(x, 1);
+ xIsNull = true;
+ }
+ snew(*x, natoms);
+ if (v)
+ {
+ snew(*v, natoms);
+ }
+ read_stx_conf(infile,
+ symtab, name, atoms,
+ *x, (v == NULL) ? NULL : *v, ePBC, box);
+ if (xIsNull)
+ {
+ sfree(*x);
+ sfree(x);
}
- /* The contents of this array is in symtab, don't free it here */
- sfree(g->grpname);
}
-gmx_bool read_tps_conf(const char *infile, t_topology *top, int *ePBC,
- rvec **x, rvec **v, matrix box, gmx_bool bMass)
+void readConfAndTopology(const char *infile,
+ bool *haveTopology, gmx_mtop_t *mtop,
+ int *ePBC,
+ rvec **x, rvec **v, matrix box)
{
- t_tpxheader header;
- int natoms, i;
- gmx_bool bTop, bXNULL = FALSE;
- gmx_mtop_t *mtop;
- gmx_atomprop_t aps;
+ GMX_RELEASE_ASSERT(mtop != NULL, "readConfAndTopology requires mtop!=NULL");
- bTop = fn2bTPX(infile);
if (ePBC != NULL)
{
*ePBC = -1;
}
- if (bTop)
+
+ *haveTopology = fn2bTPX(infile);
+ if (*haveTopology)
{
+ t_tpxheader header;
read_tpxheader(infile, &header, TRUE);
if (x)
{
{
snew(*v, header.natoms);
}
- snew(mtop, 1);
+ int natoms;
int ePBC_tmp
= read_tpx(infile, NULL, box, &natoms,
(x == NULL) ? NULL : *x, (v == NULL) ? NULL : *v, mtop);
{
*ePBC = ePBC_tmp;
}
- *top = gmx_mtop_t_to_t_topology(mtop);
- /* In this case we need to throw away the group data too */
- done_gmx_groups_t(&mtop->groups);
- sfree(mtop);
- tpx_make_chain_identifiers(&top->atoms, &top->mols);
}
else
{
- open_symtab(&top->symtab);
- get_stx_coordnum(infile, &natoms);
- init_t_atoms(&top->atoms, natoms, (fn2ftp(infile) == efPDB));
- if (x == NULL)
- {
- snew(x, 1);
- bXNULL = TRUE;
- }
- snew(*x, natoms);
- if (v)
- {
- snew(*v, natoms);
- }
- read_stx_conf(infile, top, *x, (v == NULL) ? NULL : *v, ePBC, box);
- if (bXNULL)
- {
- sfree(*x);
- sfree(x);
- }
- if (bMass)
+ t_symtab symtab;
+ char **name;
+ t_atoms atoms;
+
+ open_symtab(&symtab);
+
+ readConfAndAtoms(infile, &symtab, &name, &atoms, ePBC, x, v, box);
+
+ init_mtop(mtop);
+ convertAtomsToMtop(&symtab, name, &atoms, mtop);
+ }
+}
+
+gmx_bool read_tps_conf(const char *infile, t_topology *top, int *ePBC,
+ rvec **x, rvec **v, matrix box, gmx_bool requireMasses)
+{
+ bool haveTopology;
+ gmx_mtop_t *mtop;
+
+ // Note: We should have an initializer instead of relying on snew
+ snew(mtop, 1);
+ readConfAndTopology(infile, &haveTopology, mtop, ePBC, x, v, box);
+
+ *top = gmx_mtop_t_to_t_topology(mtop, true);
+ sfree(mtop);
+
+ tpx_make_chain_identifiers(&top->atoms, &top->mols);
+
+ if (requireMasses && !top->atoms.haveMass)
+ {
+ atomsSetMassesBasedOnNames(&top->atoms, TRUE);
+
+ if (!top->atoms.haveMass)
{
- aps = gmx_atomprop_init();
- for (i = 0; (i < natoms); i++)
- {
- if (!gmx_atomprop_query(aps, epropMass,
- *top->atoms.resinfo[top->atoms.atom[i].resind].name,
- *top->atoms.atomname[i],
- &(top->atoms.atom[i].m)))
- {
- if (debug)
- {
- fprintf(debug, "Can not find mass for atom %s %d %s, setting to 1\n",
- *top->atoms.resinfo[top->atoms.atom[i].resind].name,
- top->atoms.resinfo[top->atoms.atom[i].resind].nr,
- *top->atoms.atomname[i]);
- }
- }
- }
- gmx_atomprop_destroy(aps);
+ gmx_fatal(FARGS, "Masses were requested, but for some atom(s) masses could not be found in the database. Use a tpr file as input, if possible, or add these atoms to the mass database.");
}
- top->idef.ntypes = -1;
}
- return bTop;
+ return haveTopology;
}
const rvec x[], const rvec *v, int ePBC, const matrix box);
/* As write_sto_conf, but uses a gmx_mtop_t struct */
-gmx_bool read_tps_conf(const char *infile, struct t_topology *top,
- int *ePBC, rvec **x, rvec **v, matrix box, gmx_bool bMass);
-/* Read title, top.atoms, x, v (if not NULL) and box from an STX file,
- * memory for atoms, x and v will be allocated.
- * Return TRUE if a complete topology was read.
- * If infile is a TPX file read the whole top,
- * else if bMass=TRUE, read the masses into top.atoms from the mass database.
+/*! \brief Read a configuration and, when available, a topology from a tpr or structure file.
+ *
+ * When reading from a tpr file, the complete topology is returned in \p mtop.
+ * When reading from a structure file, only the atoms struct in \p mtop contains data.
+ *
+ * \param[in] infile Input file name
+ * \param[out] haveTopology true when a topology was read and stored in mtop
+ * \param[out] mtop The topology, either complete or only atom data
+ * \param[out] ePBC Enum reporting the type of PBC
+ * \param[in,out] x Coordinates will be stored when *x!=NULL
+ * \param[in,out] v Velocities will be stored when *v!=NULL
+ * \param[out] box Box dimensions
+ */
+void readConfAndTopology(const char *infile,
+ bool *haveTopology, gmx_mtop_t *mtop,
+ int *ePBC,
+ rvec **x, rvec **v, matrix box);
+
+/*! \brief Read a configuration and, when available, a topology from a tpr or structure file.
+ *
+ * Deprecated, superseded by readConfAndTopology().
+ * When \p requireMasses = TRUE, this routine must return a topology with
+ * mass data. Masses are either read from a tpr input file, or otherwise
+ * looked up from the mass database, and when such lookup fails a fatal error
+ * results.
+ * When \p requireMasses = FALSE, masses will still be read from tpr input and
+ * their presence is signaled with the \p haveMass flag in t_atoms of \p top.
+ *
+ * \param[in] infile Input file name
+ * \param[out] top The topology, either complete or only atom data
+ * \param[out] ePBC Enum reporting the type of PBC
+ * \param[in,out] x Coordinates will be stored when *x!=NULL
+ * \param[in,out] v Velocities will be stored when *v!=NULL
+ * \param[out] box Box dimensions
+ * \param[in] requireMasses Require masses to be present, either from tpr or from the mass database
+ * \returns if a topology is available
*/
+gmx_bool read_tps_conf(const char *infile, struct t_topology *top,
+ int *ePBC, rvec **x, rvec **v, matrix box,
+ gmx_bool requireMasses);
#ifdef __cplusplus
}
#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"
fr->ener = NULL;
/*fr->d_alloc=0;*/
- fr->ener = NULL;
-
/*fr->ndisre=0;*/
fr->nblock = 0;
return FALSE;
}
*file_version = enx_version;
+ // cppcheck-suppress redundantPointerOp
if (!gmx_fio_do_int(ef->fio, *file_version))
{
*bOK = FALSE;
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);
+}
#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;
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
};
void gmx_espresso_read_conf(const char *infile,
- t_topology *top, rvec x[], rvec *v, matrix box)
+ t_symtab *symtab, char ***name, t_atoms *atoms,
+ rvec x[], rvec *v, matrix box)
{
- t_atoms *atoms = &top->atoms;
FILE *fp;
char word[STRLEN], buf[STRLEN];
int level, r, nprop, p, i, m, molnr;
double d;
gmx_bool bFoundParticles, bFoundProp, bFoundVariable, bMol;
- // TODO: The code does not understand titles it writes...
- top->name = put_symtab(&top->symtab, "");
+ // No title reading implemented for espresso files
+ *name = put_symtab(symtab, "");
clear_mat(box);
+ atoms->haveMass = FALSE;
+ atoms->haveCharge = FALSE;
+ atoms->haveType = FALSE;
+ atoms->haveBState = FALSE;
+ atoms->havePdbInfo = FALSE;
+
fp = gmx_fio_fopen(infile, "r");
bFoundParticles = FALSE;
{
bFoundProp = TRUE;
prop[nprop++] = p;
- /* printf(" prop[%d] = %s\n",nprop-1,esp_prop[prop[nprop-1]]); */
+ if (p == espQ)
+ {
+ atoms->haveCharge = TRUE;
+ }
+
+ if (debug)
+ {
+ fprintf(debug, " prop[%d] = %s\n", nprop-1, esp_prop[prop[nprop-1]]);
+ }
}
}
if (!bFoundProp && word[0] != '}')
}
/* Generate an atom name from the particle type */
sprintf(buf, "T%hu", atoms->atom[i].type);
- atoms->atomname[i] = put_symtab(&top->symtab, buf);
+ atoms->atomname[i] = put_symtab(symtab, buf);
if (bMol)
{
if (i == 0 || atoms->atom[i].resind != atoms->atom[i-1].resind)
{
atoms->resinfo[atoms->atom[i].resind].name =
- put_symtab(&top->symtab, "MOL");
+ put_symtab(symtab, "MOL");
}
}
else
sprintf(buf, "T%c%c",
'A'+atoms->atom[i].type/26, 'A'+atoms->atom[i].type%26);
}
- t_atoms_set_resinfo(atoms, i, &top->symtab, buf, i, ' ', 0, ' ');
+ t_atoms_set_resinfo(atoms, i, symtab, buf, i, ' ', 0, ' ');
}
if (r == 3)
#include "gromacs/math/vectypes.h"
struct t_atoms;
-struct t_topology;
+struct t_symtab;
void gmx_espresso_read_conf(const char *infile,
- t_topology *top, rvec x[], rvec *v, matrix box);
+ t_symtab *symtab, char ***name, t_atoms *atoms,
+ rvec x[], rvec *v, matrix box);
int get_espresso_coordnum(const char *infile);
nwanted = fr->natoms;
atoms = fr->atoms;
+ if (atoms != NULL)
+ {
+ atoms->haveMass = FALSE;
+ atoms->haveCharge = FALSE;
+ atoms->haveType = FALSE;
+ atoms->haveBState = FALSE;
+ atoms->havePdbInfo = FALSE;
+ }
natoms = 0;
*
* 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 "gromacs/fileio/xdrf.h"
#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/scoped_cptr.h"
#include "gromacs/utility/smalloc.h"
#include "gmxfio-impl.h"
gmx_fio_unlock(fio);
return ret;
}
+
+namespace gmx
+{
+
+bool FileIOXdrSerializer::reading() const
+{
+ return fio_->bRead;
+}
+
+void FileIOXdrSerializer::doUChar(unsigned char *value)
+{
+ gmx_fio_do_uchar(fio_, *value);
+}
+
+void FileIOXdrSerializer::doInt(int *value)
+{
+ gmx_fio_do_int(fio_, *value);
+}
+
+void FileIOXdrSerializer::doFloat(float *value)
+{
+ gmx_fio_do_float(fio_, *value);
+}
+
+void FileIOXdrSerializer::doDouble(double *value)
+{
+ gmx_fio_do_double(fio_, *value);
+}
+
+void FileIOXdrSerializer::doString(std::string *value)
+{
+ // TODO: Use an arbitrary length buffer (but that is not supported in
+ // gmx_fio, either).
+ char buf[STRLEN];
+ if (!fio_->bRead)
+ {
+ std::strncpy(buf, value->c_str(), STRLEN);
+ buf[STRLEN-1] = 0;
+ }
+ gmx_fio_do_string(fio_, buf);
+ if (fio_->bRead)
+ {
+ *value = buf;
+ }
+}
+
+} // namespace gmx
*
* 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.
#ifndef GMX_FILEIO_GMXFIO_XDR_H
#define GMX_FILEIO_GMXFIO_XDR_H
+#include <string>
+
#include "gromacs/fileio/xdrf.h"
#include "gromacs/math/vectypes.h"
#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/iserializer.h"
#include "gromacs/utility/real.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
struct t_fileio;
void gmx_fio_setprecision(struct t_fileio *fio, gmx_bool bDouble);
#define gmx_fio_ndo_ivec(fio, item, n) gmx_fio_ndoe_ivec(fio, item, n, (#item), __FILE__, __LINE__)
#define gmx_fio_ndo_string(fio, item, n) gmx_fio_ndoe_string(fio, item, n, (#item), __FILE__, __LINE__)
-#ifdef __cplusplus
-}
-#endif
+namespace gmx
+{
+
+class FileIOXdrSerializer : public ISerializer
+{
+ public:
+ explicit FileIOXdrSerializer(t_fileio *fio) : fio_(fio) {}
+
+ virtual bool reading() const;
+
+ virtual void doUChar(unsigned char *value);
+ virtual void doInt(int *value);
+ virtual void doFloat(float *value);
+ virtual void doDouble(double *value);
+ virtual void doString(std::string *value);
+
+ private:
+ t_fileio *fio_;
+};
+
+} // namespace gmx
#endif
" (%d)\n", natoms, atoms->nr);
}
+ atoms->haveMass = FALSE;
+ atoms->haveCharge = FALSE;
+ atoms->haveType = FALSE;
+ atoms->haveBState = FALSE;
+ atoms->havePdbInfo = FALSE;
+
bFirst = TRUE;
bVel = FALSE;
}
void gmx_gro_read_conf(const char *infile,
- t_topology *top, rvec x[], rvec *v, matrix box)
+ t_symtab *symtab, char ***name, t_atoms *atoms,
+ rvec x[], rvec *v, matrix box)
{
FILE *in = gmx_fio_fopen(infile, "r");
int ndec;
char title[STRLEN];
- get_w_conf(in, infile, title, &top->symtab, &top->atoms, &ndec, x, v, box);
- top->name = put_symtab(&top->symtab, title);
+ get_w_conf(in, infile, title, symtab, atoms, &ndec, x, v, box);
+ *name = put_symtab(symtab, title);
gmx_fio_fclose(in);
}
{
int i, resnr;
gmx_mtop_atomloop_all_t aloop;
- t_atom *atom;
+ const t_atom *atom;
char *atomname, *resname;
fprintf(out, "%s\n", (title && title[0]) ? title : gmx::bromacs().c_str());
struct gmx_mtop_t;
struct t_atoms;
-struct t_topology;
+struct t_symtab;
struct t_trxframe;
void get_coordnum(const char *infile, int *natoms);
void gmx_gro_read_conf(const char *infile,
- struct t_topology *top, rvec x[], rvec *v, matrix box);
+ t_symtab *symtab, char ***name, t_atoms *atoms,
+ rvec x[], rvec *v, matrix box);
gmx_bool gro_next_x_or_v(FILE *status, struct t_trxframe *fr);
int gro_first_x_or_v(FILE *status, struct t_trxframe *fr);
struct gmx_output_env_t
{
explicit gmx_output_env_t(const gmx::IProgramContext &context)
- : programContext(context)
- {
- time_unit = time_ps;
- view = FALSE;
- xvg_format = exvgNONE;
- verbosity = 0;
- }
+ : programContext(context),
+ time_unit(time_ps),
+ view(FALSE),
+ xvg_format(exvgNONE),
+ verbosity(0) {}
const gmx::IProgramContext &programContext;
{
gmx_write_pdb_box(out, ePBC, box);
}
- if (atoms->pdbinfo)
+ if (atoms->havePdbInfo)
{
/* Check whether any occupancies are set, in that case leave it as is,
* otherwise set them all to one
clear_mat(box);
}
+ atoms->haveMass = FALSE;
+ atoms->haveCharge = FALSE;
+ atoms->haveType = FALSE;
+ atoms->haveBState = FALSE;
+ atoms->havePdbInfo = (atoms->pdbinfo != NULL);
+
bCOMPND = FALSE;
title[0] = '\0';
natom = 0;
break;
case epdbANISOU:
- if (atoms->pdbinfo)
+ if (atoms->havePdbInfo)
{
read_anisou(line, natom, atoms);
}
}
void gmx_pdb_read_conf(const char *infile,
- t_topology *top, rvec x[], int *ePBC, matrix box)
+ t_symtab *symtab, char ***name, t_atoms *atoms,
+ rvec x[], int *ePBC, matrix box)
{
FILE *in = gmx_fio_fopen(infile, "r");
char title[STRLEN];
- read_pdbfile(in, title, NULL, &top->atoms, &top->symtab, x, ePBC, box, TRUE, NULL);
- top->name = put_symtab(&top->symtab, title);
+ read_pdbfile(in, title, NULL, atoms, symtab, x, ePBC, box, TRUE, NULL);
+ *name = put_symtab(symtab, title);
gmx_fio_fclose(in);
}
*/
void gmx_pdb_read_conf(const char *infile,
- struct t_topology *top, rvec x[], int *ePBC, matrix box);
+ t_symtab *symtab, char ***name, t_atoms *atoms,
+ rvec x[], int *ePBC, matrix box);
/* Read a pdb file and extract ATOM and HETATM fields.
* Read a box from the CRYST1 line, return 0 box when no CRYST1 is found.
* ePBC may be NULL.
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/futil.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
#include "gromacs/utility/programcontext.h"
#include "gromacs/utility/qsort_threadsafe.h"
#include "gromacs/utility/smalloc.h"
return inp;
}
-
+gmx::KeyValueTreeObject flatKeyValueTreeFromInpFile(int ninp, t_inpfile inp[])
+{
+ gmx::KeyValueTreeBuilder builder;
+ auto root = builder.rootObject();
+ for (int i = 0; i < ninp; ++i)
+ {
+ const char *value = inp[i].value;
+ root.addValue<std::string>(inp[i].name, value != nullptr ? value : "");
+ }
+ return builder.build();
+}
static int inp_comp(const void *a, const void *b)
return -1;
}
+void mark_einp_set(int ninp, t_inpfile *inp, const char *name)
+{
+ int i = search_einp(ninp, inp, name);
+ if (i != -1)
+ {
+ inp[i].count = inp[0].inp_count++;
+ inp[i].bSet = TRUE;
+ }
+}
+
static int get_einp(int *ninp, t_inpfile **inp, const char *name)
{
int i;
*
* 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 "gromacs/fileio/warninp.h"
#include "gromacs/utility/basedefinitions.h"
-typedef struct {
+namespace gmx
+{
+class KeyValueTreeObject;
+}
+
+typedef struct t_inpfile {
int count; /* sort order for output */
gmx_bool bObsolete; /* whether it is an obsolete param value */
gmx_bool bSet; /* whether it it has been read out */
ninp = the number of read parameters
cppopts = the cpp-style options for #include paths and #defines */
+gmx::KeyValueTreeObject flatKeyValueTreeFromInpFile(int ninp, t_inpfile inp[]);
+
void write_inpfile(const char *fn, int ninp, t_inpfile inp[],
gmx_bool bHaltOnUnknown,
warninp_t wi);
int search_einp(int ninp, const t_inpfile *inp, const char *name);
/* Return the index of an .mdp field with the given name within the
* inp array, if it exists. Return -1 if it does not exist. */
+void mark_einp_set(int ninp, t_inpfile *inp, const char *name);
int get_eint(int *ninp, t_inpfile **inp, const char *name, int def,
warninp_t wi);
/*
* 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.
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);
}
}
/*
* 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.
#include <gtest/gtest.h>
-#include "gromacs/fileio/tngio_for_tools.h"
#include "gromacs/utility/path.h"
#include "testutils/testfilemanager.h"
#ifndef GMX_FILEIO_TNGIO_H
#define GMX_FILEIO_TNGIO_H
-#include "tng/tng_io_fwd.h"
-
#include "gromacs/math/vectypes.h"
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/real.h"
struct gmx_mtop_t;
struct t_inputrec;
+struct tng_trajectory;
+typedef struct tng_trajectory *tng_trajectory_t;
/*! \brief Open a TNG trajectory file
*
#include <stdio.h>
-#include "tng/tng_io_fwd.h"
-
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/real.h"
struct gmx_mtop_t;
struct t_trxframe;
+struct tng_trajectory;
+typedef struct tng_trajectory *tng_trajectory_t;
/*! \brief Prepare to write TNG output from trajectory conversion tools */
void gmx_prepare_tng_writing(const char *filename,
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/futil.h"
+#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/smalloc.h"
#include "gromacs/utility/snprintf.h"
#include "gromacs/utility/txtdump.h"
/* 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
* 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 },
{ 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 },
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);
{
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)
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)
{
file_version, tpx_version);
}
- if (bRead)
- {
- init_inputrec(ir);
- }
-
if (file_version == 0)
{
return;
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)
* 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);
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);
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);
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);
{
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)
{
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);
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);
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);
}
{
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)
{
gmx_fio_do_real(fio, ir->shake_tol);
if (file_version < 54)
{
+ // cppcheck-suppress redundantPointerOp
gmx_fio_do_real(fio, *fudgeQQ);
}
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)
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)
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);
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);
}
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)
{
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++)
- {
- 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)
{
- 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)
ir->wall_ewald_zfac = 3;
}
/* Cosine stuff for electric fields */
- for (j = 0; (j < DIM); j++)
- {
- gmx_fio_do_int(fio, ir->ex[j].n);
- gmx_fio_do_int(fio, ir->et[j].n);
- if (bRead)
- {
- snew(ir->ex[j].a, ir->ex[j].n);
- snew(ir->ex[j].phi, ir->ex[j].n);
- snew(ir->et[j].a, ir->et[j].n);
- snew(ir->et[j].phi, ir->et[j].n);
- }
- gmx_fio_ndo_real(fio, ir->ex[j].a, ir->ex[j].n);
- gmx_fio_ndo_real(fio, ir->ex[j].phi, ir->ex[j].n);
- gmx_fio_ndo_real(fio, ir->et[j].a, ir->et[j].n);
- gmx_fio_ndo_real(fio, ir->et[j].phi, ir->et[j].n);
- }
+ ir->efield->doTpxIO(fio, bRead);
/* Swap ions */
if (file_version >= tpxv_ComputationalElectrophysiology)
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);
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);
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
{
atom->atomnumber = 0;
}
- if (file_version < 23)
- {
- myngrp = 8;
- }
- else if (file_version < 39)
+ if (file_version < 39)
{
myngrp = 9;
}
{
int j, myngrp;
- if (file_version < 23)
- {
- myngrp = 8;
- }
- else if (file_version < 39)
+ if (file_version < 39)
{
myngrp = 9;
}
}
if (bRead)
{
+ /* Since we have always written all t_atom properties in the tpr file
+ * (at least for all backward compatible versions), we don't store
+ * but simple set the booleans here.
+ */
+ atoms->haveMass = TRUE;
+ atoms->haveCharge = TRUE;
+ atoms->haveType = TRUE;
+ atoms->haveBState = TRUE;
+ atoms->havePdbInfo = FALSE;
+
snew(atoms->atom, atoms->nr);
snew(atoms->atomname, atoms->nr);
snew(atoms->atomtype, atoms->nr);
}
atoms->pdbinfo = NULL;
}
+ else
+ {
+ GMX_RELEASE_ASSERT(atoms->haveMass && atoms->haveCharge && atoms->haveType && atoms->haveBState, "Mass, charge, atomtype and B-state parameters should be present in t_atoms when writing a tpr file");
+ }
for (i = 0; (i < atoms->nr); i++)
{
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)
{
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);
}
}
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)
{
}
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);
}
static int do_tpx(t_fileio *fio, gmx_bool bRead,
- t_inputrec *ir, t_state *state, gmx_mtop_t *mtop,
- gmx_bool bXVallocated)
+ t_inputrec *ir, t_state *state, rvec *x, rvec *v,
+ gmx_mtop_t *mtop)
{
t_tpxheader tpx;
- t_inputrec dum_ir;
gmx_mtop_t dum_top;
gmx_bool TopOnlyOK;
- rvec *xptr, *vptr;
int ePBC;
gmx_bool bPeriodicMols;
if (!bRead)
{
+ GMX_RELEASE_ASSERT(x == NULL && v == NULL, "Passing separate x and v pointers to do_tpx() is not supported when writing");
+
tpx.natoms = state->natoms;
tpx.ngtc = state->ngtc;
tpx.fep_state = state->fep_state;
tpx.lambda = state->lambda[efptFEP];
tpx.bIr = (ir != NULL);
tpx.bTop = (mtop != NULL);
- tpx.bX = (state->x != NULL);
- tpx.bV = (state->v != NULL);
+ tpx.bX = (state->flags & (1 << estX));
+ tpx.bV = (state->flags & (1 << estV));
tpx.bF = FALSE;
tpx.bBox = TRUE;
}
+ else
+ {
+ GMX_RELEASE_ASSERT(!(x == NULL && v != NULL), "Passing x==NULL and v!=NULL is not supported");
+ }
TopOnlyOK = (ir == NULL);
if (bRead)
{
state->flags = 0;
- if (bXVallocated)
+ if (x != NULL)
{
- xptr = state->x;
- vptr = state->v;
init_state(state, 0, tpx.ngtc, 0, 0, 0);
- state->natoms = tpx.natoms;
- state->nalloc = tpx.natoms;
- state->x = xptr;
- state->v = vptr;
}
else
{
}
}
+ if (x == NULL)
+ {
+ x = as_rvec_array(state->x.data());
+ v = as_rvec_array(state->v.data());
+ }
+
#define do_test(fio, b, p) if (bRead && (p != NULL) && !b) gmx_fatal(FARGS, "No %s in %s",#p, gmx_fio_getname(fio))
do_test(fio, tpx.bBox, state->box);
/* 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);
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)
{
else
{
do_mtop(fio, &dum_top, bRead, fileVersion);
- done_mtop(&dum_top, TRUE);
+ done_mtop(&dum_top);
}
}
- do_test(fio, tpx.bX, state->x);
+ do_test(fio, tpx.bX, x);
if (tpx.bX)
{
if (bRead)
{
state->flags |= (1<<estX);
}
- gmx_fio_ndo_rvec(fio, state->x, state->natoms);
+ gmx_fio_ndo_rvec(fio, x, tpx.natoms);
}
- do_test(fio, tpx.bV, state->v);
+ do_test(fio, tpx.bV, v);
if (tpx.bV)
{
if (bRead)
{
state->flags |= (1<<estV);
}
- gmx_fio_ndo_rvec(fio, state->v, state->natoms);
+ gmx_fio_ndo_rvec(fio, v, tpx.natoms);
}
// No need to run do_test when the last argument is NULL
{
rvec *dummyForces;
snew(dummyForces, state->natoms);
- gmx_fio_ndo_rvec(fio, dummyForces, state->natoms);
+ gmx_fio_ndo_rvec(fio, dummyForces, tpx.natoms);
sfree(dummyForces);
}
*/
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)
fio = open_tpx(fn, "w");
do_tpx(fio, FALSE,
const_cast<t_inputrec *>(ir),
- const_cast<t_state *>(state),
- const_cast<gmx_mtop_t *>(mtop), FALSE);
+ const_cast<t_state *>(state), NULL, NULL,
+ const_cast<gmx_mtop_t *>(mtop));
close_tpx(fio);
}
t_fileio *fio;
fio = open_tpx(fn, "r");
- do_tpx(fio, TRUE, ir, state, mtop, FALSE);
+ do_tpx(fio, TRUE, ir, state, NULL, NULL, mtop);
close_tpx(fio);
}
rvec *x, rvec *v, gmx_mtop_t *mtop)
{
t_fileio *fio;
- t_state state;
+ t_state state {};
int ePBC;
- state.x = x;
- state.v = v;
fio = open_tpx(fn, "r");
- ePBC = do_tpx(fio, TRUE, ir, &state, mtop, TRUE);
+ ePBC = do_tpx(fio, TRUE, ir, &state, x, v, mtop);
close_tpx(fio);
- *natoms = state.natoms;
+ *natoms = mtop->natoms;
if (box)
{
copy_mat(state.box, box);
}
- state.x = NULL;
- state.v = NULL;
- done_state(&state);
return ePBC;
}
ePBC = read_tpx(fn, ir, box, natoms, x, v, &mtop);
- *top = gmx_mtop_t_to_t_topology(&mtop);
+ *top = gmx_mtop_t_to_t_topology(&mtop, true);
return ePBC;
}
*
* 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 "xvgr.h"
+#include <cassert>
#include <cctype>
#include <cstring>
{
if (*ny - 1 > legend_nalloc)
{
+ assert(legend);
srenew(*legend, *ny-1);
for (set = legend_nalloc; set < *ny-1; set++)
{
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2010,2011,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,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.
}
return iMin;
}
-
- else if (direction < 0)
+ else
{
while (iMax-iMin > 1)
{
}
}
return iMin-1;
-
- } /*end -ifelse direction*/
- return -1;
+ }
}
}
}
}
- else if (direction < 0)
+ else
{
for (i = stopindx; i >= startindx; i--)
{
}
}
- else
- {
- gmx_fatal(FARGS, "Startindex=stopindex=%d\n", startindx);
- }
-
return -1;
}
*
* 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.
atoms->atom[i] = atoms->atom[i+1];
}
- if (atoms->pdbinfo)
+ if (atoms->havePdbInfo)
{
/* Shift the pdbatom struct down */
for (i = inr; (i < atoms->nr-1); i++)
*/
#include "gmxpre.h"
+#include <cassert>
#include <cmath>
#include <cstdlib>
#include <cstring>
}
else
{
+ assert(sy);
ymin = sy[g][0][0];
ymax = sy[g][0][0];
for (s = 0; s < nsetspergraph; s++)
if (!parse_common_args(&argc, argv, PCA_CAN_VIEW,
NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
{
+ sfree(ppa);
return 0;
}
*
* 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.
NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs,
&oenv))
{
+ sfree(ppa);
return 0;
}
{
real x0, y0, z0;
+ atoms->havePdbInfo = TRUE;
+
if (NULL == atoms->pdbinfo)
{
snew(atoms->pdbinfo, atoms->nr);
NFILE, fnm, npargs, ppa, asize(desc), desc, asize(bugs), bugs,
&oenv))
{
+ sfree(ppa);
return 0;
}
return std::sqrt(r2);
}
-static int rms_dist_comp(const void *a, const void *b)
+static bool rms_dist_comp(const t_dist &a, const t_dist &b)
{
- t_dist *da, *db;
-
- da = (t_dist *)a;
- db = (t_dist *)b;
-
- if (da->dist - db->dist < 0)
- {
- return -1;
- }
- else if (da->dist - db->dist > 0)
- {
- return 1;
- }
- return 0;
+ return a.dist < b.dist;
}
-static int clust_id_comp(const void *a, const void *b)
+static bool clust_id_comp(const t_clustid &a, const t_clustid &b)
{
- t_clustid *da, *db;
-
- da = (t_clustid *)a;
- db = (t_clustid *)b;
-
- return da->clust - db->clust;
+ return a.clust < b.clust;
}
-static int nrnb_comp(const void *a, const void *b)
+static bool nrnb_comp(const t_nnb &a, const t_nnb &b)
{
- t_nnb *da, *db;
-
- da = (t_nnb *)a;
- db = (t_nnb *)b;
-
- /* return the b-a, we want highest first */
- return db->nr - da->nr;
+ /* return b<a, we want highest first */
+ return b.nr < a.nr;
}
void gather(t_mat *m, real cutoff, t_clusters *clust)
{
gmx_incons("gather algortihm");
}
- qsort(d, nn, sizeof(d[0]), rms_dist_comp);
+ std::sort(d, d+nn, rms_dist_comp);
/* Now we make a cluster index for all of the conformations */
c = new_clustid(n1);
while (bChange);
fprintf(stderr, "\nSorting and renumbering clusters\n");
/* Sort on cluster number */
- qsort(c, n1, sizeof(c[0]), clust_id_comp);
+ std::sort(c, c+n1, clust_id_comp);
/* Renumber clusters */
cid = 1;
row[j].j = j;
row[j].dist = mat[i][j];
}
- qsort(row, n1, sizeof(row[0]), rms_dist_comp);
+ std::sort(row, row+n1, rms_dist_comp);
if (M > 0)
{
/* Put the M nearest neighbors in the list */
fprintf(stderr, "\nSorting and renumbering clusters\n");
/* Sort on cluster number */
- qsort(c, n1, sizeof(c[0]), clust_id_comp);
+ std::sort(c, c+n1, clust_id_comp);
/* Renumber clusters */
cid = 1;
sfree(row);
/* sort neighbor list on number of neighbors, largest first */
- qsort(nnb, n1, sizeof(nnb[0]), nrnb_comp);
+ std::sort(nnb, nnb+n1, nrnb_comp);
if (debug)
{
}
/* sort again on nnb[].nr, because we have new # neighbors: */
/* but we only need to sort upto i, i.e. when nnb[].nr>0 */
- qsort(nnb, i, sizeof(nnb[0]), nrnb_comp);
+ std::sort(nnb, nnb+i, nrnb_comp);
fprintf(stderr, "\b\b\b\b%4d", k);
/* new cluster id */
*
* Copyright (c) 1991-2000, University of Groningen, The Netherlands.
* Copyright (c) 2001-2007, 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/math/vec.h"
#include "gromacs/pbcutil/pbc.h"
#include "gromacs/topology/index.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/topology.h"
#include "gromacs/trajectory/trajectoryframe.h"
#include "gromacs/utility/arraysize.h"
gmx_mtop_t *mtop = NULL;
int ePBC = -1;
t_block *mols = NULL;
- gmx_mtop_atomlookup_t alook;
- t_atom *atom;
int ii, jj;
real temp, tfac;
/* Cluster size distribution (matrix) */
rd_index(ndx, 1, &nindex, &index, &gname);
}
- alook = gmx_mtop_atomlookup_init(mtop);
-
snew(clust_index, nindex);
snew(clust_size, nindex);
cut2 = cut*cut;
}
max_clust_size = 1;
max_clust_ind = -1;
+ int molb = 0;
do
{
if ((nskip == 0) || ((nskip > 0) && ((nframe % nskip) == 0)))
{
if (clust_index[i] == max_clust_ind)
{
- ai = index[i];
- gmx_mtop_atomnr_to_atom(alook, ai, &atom);
- ekin += 0.5*atom->m*iprod(v[ai], v[ai]);
+ ai = index[i];
+ real m = mtopGetAtomMass(mtop, ai, &molb);
+ ekin += 0.5*m*iprod(v[ai], v[ai]);
}
}
temp = (ekin*2.0)/(3.0*tfac*max_clust_size*BOLTZ);
xvgrclose(hp);
xvgrclose(tp);
- gmx_mtop_atomlookup_destroy(alook);
-
if (max_clust_ind >= 0)
{
fp = gmx_ffopen(mcn, "w");
srenew(atoms1->pdbinfo, atoms1->nr);
srenew(atoms1->atom, atoms1->nr); /* Why renew atom? */
+ atoms1->havePdbInfo = TRUE;
+
/* Avoid segfaults when writing the pdb-file */
for (i = 0; i < atoms1->nr; i++)
{
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;
}
#include "gromacs/mdlib/force.h"
#include "gromacs/mdlib/mdatoms.h"
#include "gromacs/mdlib/mdrun.h"
+#include "gromacs/mdrunutility/mdmodules.h"
#include "gromacs/mdtypes/fcdata.h"
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/md_enums.h"
FILE *out = NULL, *aver = NULL, *numv = NULL, *maxxv = NULL, *xvg = NULL;
t_tpxheader header;
- t_inputrec ir;
gmx_mtop_t mtop;
rvec *xtop;
gmx_localtop_t *top;
init5(ntop);
}
+ gmx::MDModules mdModules;
+ t_inputrec *ir = mdModules.inputrec();
+
read_tpxheader(ftp2fn(efTPR, NFILE, fnm), &header, FALSE);
snew(xtop, header.natoms);
- read_tpx(ftp2fn(efTPR, NFILE, fnm), &ir, box, &ntopatoms, xtop, NULL, &mtop);
+ read_tpx(ftp2fn(efTPR, NFILE, fnm), ir, box, &ntopatoms, xtop, NULL, &mtop);
bPDB = opt2bSet("-q", NFILE, fnm);
if (bPDB)
{
{
snew(atoms->pdbinfo, atoms->nr);
}
+ atoms->havePdbInfo = TRUE;
}
- top = gmx_mtop_generate_local_top(&mtop, ir.efep != efepNO);
+ top = gmx_mtop_generate_local_top(&mtop, ir->efep != efepNO);
g = NULL;
pbc_null = NULL;
- if (ir.ePBC != epbcNONE)
+ if (ir->ePBC != epbcNONE)
{
- if (ir.bPeriodicMols)
+ if (ir->bPeriodicMols)
{
pbc_null = &pbc;
}
isize = 0;
}
- ir.dr_tau = 0.0;
- init_disres(fplog, &mtop, &ir, NULL, &fcd, NULL, FALSE);
+ ir->dr_tau = 0.0;
+ init_disres(fplog, &mtop, ir, NULL, &fcd, NULL, FALSE);
natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
snew(f, 5*natoms);
"Largest Violation", "Time (ps)", "nm", oenv);
}
- mdatoms = init_mdatoms(fplog, &mtop, ir.efep != efepNO);
- atoms2md(&mtop, &ir, 0, NULL, mtop.natoms, mdatoms);
- update_mdatoms(mdatoms, ir.fepvals->init_lambda);
+ mdatoms = init_mdatoms(fplog, &mtop, ir->efep != efepNO);
+ atoms2md(&mtop, ir, -1, NULL, mtop.natoms, mdatoms);
+ update_mdatoms(mdatoms, ir->fepvals->init_lambda);
init_nrnb(&nrnb);
- if (ir.ePBC != epbcNONE)
+ if (ir->ePBC != epbcNONE)
{
- gpbc = gmx_rmpbc_init(&top->idef, ir.ePBC, natoms);
+ gpbc = gmx_rmpbc_init(&top->idef, ir->ePBC, natoms);
}
j = 0;
do
{
- if (ir.ePBC != epbcNONE)
+ if (ir->ePBC != epbcNONE)
{
- if (ir.bPeriodicMols)
+ if (ir->bPeriodicMols)
{
- set_pbc(&pbc, ir.ePBC, box);
+ set_pbc(&pbc, ir->ePBC, box);
}
else
{
}
while (read_next_x(oenv, status, &t, x, box));
close_trj(status);
- if (ir.ePBC != epbcNONE)
+ if (ir->ePBC != epbcNONE)
{
gmx_rmpbc_done(gpbc);
}
{
write_sto_conf(opt2fn("-q", NFILE, fnm),
"Coloured by average violation in Angstrom",
- atoms, xav, NULL, ir.ePBC, box);
+ atoms, xav, NULL, ir->ePBC, box);
}
dump_disre_matrix(opt2fn_null("-x", NFILE, fnm), &dr, fcd.disres.nres,
j, &top->idef, &mtop, max_dr, nlevels, bThird);
NFILE, fnm, npargs, ppa, asize(desc), desc,
asize(bugs), bugs, &oenv))
{
+ sfree(ppa);
return 0;
}
{
snew(atoms.pdbinfo, atoms.nr);
}
- natoms = atoms.nr;
+ atoms.havePdbInfo = TRUE;
+ natoms = atoms.nr;
snew(xout, natoms);
snew(vout, natoms);
*
* 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.
{
snew(atoms.pdbinfo, atoms.nr);
}
+ atoms.havePdbInfo = TRUE;
+
if (fn2ftp(infile) == efPDB)
{
get_pdb_atomnumber(&atoms, aps);
#include "gromacs/math/units.h"
#include "gromacs/math/vec.h"
#include "gromacs/mdlib/mdebin.h"
+#include "gromacs/mdrunutility/mdmodules.h"
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/md_enums.h"
#include "gromacs/topology/ifunc.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/arraysize.h"
read_tpx(topnm, ir, box, &natoms, NULL, NULL, &mtop);
}
-static void get_orires_parms(const char *topnm,
+static void get_orires_parms(const char *topnm, t_inputrec *ir,
int *nor, int *nex, int **label, real **obs)
{
gmx_mtop_t mtop;
gmx_localtop_t *top;
- t_inputrec ir;
t_iparams *ip;
int natoms, i;
t_iatom *iatom;
int nb;
matrix box;
- read_tpx(topnm, &ir, box, &natoms, NULL, NULL, &mtop);
- top = gmx_mtop_generate_local_top(&mtop, ir.efep != efepNO);
+ read_tpx(topnm, ir, box, &natoms, NULL, NULL, &mtop);
+ top = gmx_mtop_generate_local_top(&mtop, ir->efep != efepNO);
ip = top->idef.iparams;
iatom = top->idef.il[F_ORIRES].iatoms;
int timecheck = 0;
gmx_mtop_t mtop;
gmx_localtop_t *top = NULL;
- t_inputrec ir;
enerdata_t edat;
gmx_enxnm_t *enm = NULL;
t_enxframe *frame, *fr = NULL;
gmx_bool *bIsEner = NULL;
char **pairleg, **odtleg, **otenleg;
char **leg = NULL;
- char *anm_j, *anm_k, *resnm_j, *resnm_k;
+ const char *anm_j, *anm_k, *resnm_j, *resnm_k;
int resnr_j, resnr_k;
const char *orinst_sub = "@ subtitle \"instantaneous\"\n";
char buf[256];
PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END,
NFILE, fnm, npargs, ppa, asize(desc), desc, 0, NULL, &oenv))
{
+ sfree(ppa);
return 0;
}
bVisco = opt2bSet("-vis", NFILE, fnm);
+ gmx::MDModules mdModules;
+ t_inputrec *ir = mdModules.inputrec();
+
if ((!bDisRe) && (!bDHDL))
{
if (bVisco)
if (bORIRE || bOTEN)
{
- get_orires_parms(ftp2fn(efTPR, NFILE, fnm), &nor, &nex, &or_label, &oobs);
+ get_orires_parms(ftp2fn(efTPR, NFILE, fnm), ir,
+ &nor, &nex, &or_label, &oobs);
}
if (bORIRE)
else if (bDisRe)
{
nbounds = get_bounds(ftp2fn(efTPR, NFILE, fnm), &bounds, &index, &pair, &npairs,
- &mtop, &top, &ir);
+ &mtop, &top, ir);
snew(violaver, npairs);
out = xvgropen(opt2fn("-o", NFILE, fnm), "Sum of Violations",
"Time (ps)", "nm", oenv);
if (output_env_get_print_xvgr_codes(oenv))
{
fprintf(fp_pairs, "@ subtitle \"averaged (tau=%g) and instantaneous\"\n",
- ir.dr_tau);
+ ir->dr_tau);
}
}
}
else if (bDHDL)
{
- get_dhdl_parms(ftp2fn(efTPR, NFILE, fnm), &ir);
+ get_dhdl_parms(ftp2fn(efTPR, NFILE, fnm), ir);
}
/* Initiate energies and set them to zero */
ndisre, top->idef.il[F_DISRES].nr/3);
}
snew(pairleg, ndisre);
+ int molb = 0;
for (i = 0; i < ndisre; i++)
{
snew(pairleg[i], 30);
j = fa[3*i+1];
k = fa[3*i+2];
- gmx_mtop_atominfo_global(&mtop, j, &anm_j, &resnr_j, &resnm_j);
- gmx_mtop_atominfo_global(&mtop, k, &anm_k, &resnr_k, &resnm_k);
+ mtopGetAtomAndResidueName(&mtop, j, &molb, &anm_j, &resnr_j, &resnm_j, nullptr);
+ mtopGetAtomAndResidueName(&mtop, k, &molb, &anm_k, &resnr_k, &resnm_k, nullptr);
sprintf(pairleg[i], "%d %s %d %s (%d)",
resnr_j, anm_j, resnr_k, anm_k,
ip[fa[3*i]].disres.label);
}
else if (bDHDL)
{
- do_dhdl(fr, &ir, &fp_dhdl, opt2fn("-odh", NFILE, fnm), bDp, &dh_blocks, &dh_hists, &dh_samples, &dh_lambdas, oenv);
+ do_dhdl(fr, ir, &fp_dhdl, opt2fn("-odh", NFILE, fnm), bDp, &dh_blocks, &dh_hists, &dh_samples, &dh_lambdas, oenv);
}
/*******************************************
*
* 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.
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);
#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/topology/ifunc.h"
}
}
-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,
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;
}
}
-void pbc_in_gridbox(rvec dx, matrix box)
+static void pbc_in_gridbox(rvec dx, matrix box)
{
int m;
gmx_bool bDone = FALSE;
t_trxstatus *status;
int trrStatus = 1;
t_topology top;
- t_inputrec ir;
t_pargs *ppa;
int npargs, natoms, nframes = 0, shatom;
int *isize;
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;
}
hb = mk_hbdata(bHBmap, opt2bSet("-dan", NFILE, fnm), bMerge || bContact);
/* get topology */
- read_tpx_top(ftp2fn(efTPR, NFILE, fnm), &ir, box, &natoms, NULL, NULL, &top);
+ gmx::MDModules mdModules;
+ t_inputrec *ir = mdModules.inputrec();
+ read_tpx_top(ftp2fn(efTPR, NFILE, fnm), ir, box, &natoms, NULL, NULL, &top);
snew(grpnames, grNR);
snew(index, grNR);
top.atoms.nr, natoms);
}
- bBox = ir.ePBC != epbcNONE;
+ bBox = (ir->ePBC != epbcNONE);
grid = init_grid(bBox, box, (rcut > r2cut) ? rcut : r2cut, ngrid);
nabin = static_cast<int>(acut/abin);
nrbin = static_cast<int>(rcut/rbin);
if (check_have_atoms(atoms, ostring) &&
parse_names(string, &n_names, names))
{
- if (atoms->atomtype == NULL)
+ if (!(atoms->haveType))
{
printf("Need a run input file to select atom types\n");
}
{
nmin_j++;
}
- else if (r2 > rcut2)
+ else
{
nmax_j++;
}
}
std::vector<size_t> atom_index = get_atom_index(&mtop);
- top = gmx_mtop_t_to_t_topology(&mtop);
+ top = gmx_mtop_t_to_t_topology(&mtop, true);
bM = TRUE;
int ndim = DIM*atom_index.size();
#include "gromacs/math/functions.h"
#include "gromacs/math/units.h"
#include "gromacs/math/vec.h"
+#include "gromacs/mdlib/broadcaststructs.h"
+#include "gromacs/mdrunutility/mdmodules.h"
#include "gromacs/mdtypes/commrec.h"
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/md_enums.h"
#include "gromacs/utility/pleasecite.h"
#include "gromacs/utility/smalloc.h"
-/* We use the same defines as in broadcaststructs.cpp here */
-#define block_bc(cr, d) gmx_bcast( sizeof(d), &(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)); }}
/* #define TAKETIME */
/* #define DEBUG */
int i;
int nq; /* number of charged particles */
gmx_mtop_atomloop_all_t aloop;
- t_atom *atom;
if (MASTER(cr))
nq = 0;
aloop = gmx_mtop_atomloop_all_init(mtop);
-
+ const t_atom *atom;
while (gmx_mtop_atomloop_all_next(aloop, &i, &atom))
{
if (is_charge(atom->q))
}
/* Prepare an x and q array with only the charged atoms */
- ncharges = prepare_x_q(&q, &x, mtop, state->x, cr);
+ ncharges = prepare_x_q(&q, &x, mtop, as_rvec_array(state->x.data()), cr);
if (MASTER(cr))
{
calc_q2all(mtop, &(info->q2all), &(info->q2allnr));
NFILE, fnm, asize(pa), pa, asize(desc), desc,
0, NULL, &oenv))
{
+ sfree(cr);
return 0;
}
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");
*/
#include "gmxpre.h"
+#include <cassert>
#include <cmath>
#include <cstring>
start = 0;
av = 0;
m = 0;
+ if (!f)
+ {
+ assert(U);
+ }
for (i = 0; i < isize; i++)
{
av += w_rls[index[i]]*(f != NULL ? f[i] : U[i][uind]);
refatoms = &top.atoms;
pdbx = xref;
snew(pdbatoms->pdbinfo, pdbatoms->nr);
+ pdbatoms->havePdbInfo = TRUE;
copy_mat(box, pdbbox);
}
*
* 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.
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;
}
#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"
}
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);
*
* 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.
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;
}
{
snew(atoms->pdbinfo, atoms->nr);
}
+ atoms->havePdbInfo = TRUE;
+
if (onedim == -1)
{
for (i = 0; i < isize; i++)
"(specified with [TT]-av[tt] or [TT]-af[tt]).[PAR]",
"Option [TT]-vd[tt] computes a velocity distribution, i.e. the",
"norm of the vector is plotted. In addition in the same graph",
- "the kinetic energy distribution is given."
+ "the kinetic energy distribution is given.",
+ "",
+ "See [gmx-trajectory] for plotting similar data for selections."
};
static gmx_bool bMol = FALSE, bCom = FALSE, bPBC = TRUE, bNoJump = FALSE;
static gmx_bool bX = TRUE, bY = TRUE, bZ = TRUE, bNorm = FALSE, bFP = FALSE;
"the trajectory does not match that in the [REF].xvg[ref] file then the program",
"tries to be smart. Beware."
};
- static gmx_bool bVels = TRUE;
static gmx_bool bCat = FALSE;
static gmx_bool bSort = TRUE;
static gmx_bool bKeepLast = FALSE;
{ &end }, "Last time to use (%t)" },
{ "-dt", FALSE, etTIME,
{ &dt }, "Only write frame when t MOD dt = first time (%t)" },
- { "-vel", FALSE, etBOOL,
- { &bVels }, "Read and write velocities if possible" },
{ "-settime", FALSE, etBOOL,
{ &bSetTime }, "Change starting time interactively" },
{ "-sort", FALSE, etBOOL,
/* get memory for stuff to go in .pdb file, and initialize
* the pdbinfo structure part if the input has it.
*/
- init_t_atoms(&useatoms, atoms->nr, (atoms->pdbinfo != NULL));
+ init_t_atoms(&useatoms, atoms->nr, atoms->havePdbInfo);
sfree(useatoms.resinfo);
useatoms.resinfo = atoms->resinfo;
for (i = 0; (i < nout); i++)
{
useatoms.atomname[i] = atoms->atomname[index[i]];
useatoms.atom[i] = atoms->atom[index[i]];
- if (atoms->pdbinfo != NULL)
+ if (atoms->havePdbInfo)
{
useatoms.pdbinfo[i] = atoms->pdbinfo[index[i]];
}
#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"
const char *fn_best_tpr, /* tpr file with the best performance */
const char *fn_sim_tpr) /* name of tpr file to be launched */
{
- t_inputrec *ir;
- t_state state;
- gmx_mtop_t mtop;
- char buf[200];
+ t_inputrec *ir;
+ t_state state;
+ gmx_mtop_t mtop;
+ char buf[200];
- snew(ir, 1);
+ gmx::MDModules mdModules;
+ ir = mdModules.inputrec();
read_tpx_state(fn_best_tpr, ir, &state, &mtop);
/* Reset nsteps and init_step to the value of the input .tpr file */
fprintf(stdout, buf, ir->nsteps);
fflush(stdout);
write_tpx_state(fn_sim_tpr, ir, &state, &mtop);
-
- sfree(ir);
}
static gmx_bool can_scale_rvdw(int vdwtype)
}
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 */
}
fflush(stdout);
fflush(fp);
- sfree(ir);
}
gmx_bool bFree; /* Is a free energy simulation requested? */
gmx_bool bNM; /* Is a normal mode analysis requested? */
gmx_bool bSwap; /* Is water/ion position swapping requested? */
- t_inputrec ir;
+ t_inputrec *ir;
t_state state;
gmx_mtop_t mtop;
/* Check tpr file for options that trigger extra output files */
- read_tpx_state(opt2fn("-s", nfile, fnm), &ir, &state, &mtop);
- bFree = (efepNO != ir.efep );
- bNM = (eiNM == ir.eI );
- bSwap = (eswapNO != ir.eSwapCoords);
- bTpi = EI_TPI(ir.eI);
+ gmx::MDModules mdModules;
+ ir = mdModules.inputrec();
+ read_tpx_state(opt2fn("-s", nfile, fnm), ir, &state, &mtop);
+ bFree = (efepNO != ir->efep );
+ bNM = (eiNM == ir->eI );
+ bSwap = (eswapNO != ir->eSwapCoords);
+ bTpi = EI_TPI(ir->eI);
/* Set these output files on the tuning command-line */
- if (ir.bPull)
+ if (ir->bPull)
{
setopt("-pf", nfile, fnm);
setopt("-px", nfile, fnm);
setopt("-swap", nfile, fnm);
}
- *rcoulomb = ir.rcoulomb;
+ *rcoulomb = ir->rcoulomb;
/* Return the estimate for the number of PME nodes */
- return pme_load_estimate(&mtop, &ir, state.box);
+ float npme = pme_load_estimate(&mtop, ir, state.box);
+ return npme;
}
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;
}
#include "config.h"
+#include <cassert>
#include <cctype>
#include <cmath>
#include <cstdio>
#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/mdtypes/pull-params.h"
//! Read pull groups from a tpr file (including position, force const, geometry, number of groups)
void read_tpr_header(const char *fn, t_UmbrellaHeader* header, t_UmbrellaOptions *opt, t_coordselection *coordsel)
{
- t_inputrec ir;
- int i;
- t_state state;
- static int first = 1;
+ gmx::MDModules mdModules;
+ t_inputrec *ir = mdModules.inputrec();
+ t_state state;
+ static int first = 1;
/* printf("Reading %s \n",fn); */
- read_tpx_state(fn, &ir, &state, NULL);
+ read_tpx_state(fn, ir, &state, NULL);
- if (!ir.bPull)
+ if (!ir->bPull)
{
gmx_fatal(FARGS, "This is not a tpr with COM pulling");
}
- if (ir.pull->ncoord == 0)
+ if (ir->pull->ncoord == 0)
{
gmx_fatal(FARGS, "No pull coordinates found in %s", fn);
}
/* Read overall pull info */
- header->npullcrds = ir.pull->ncoord;
- header->bPrintCOM = ir.pull->bPrintCOM;
- header->bPrintRefValue = ir.pull->bPrintRefValue;
- header->bPrintComp = ir.pull->bPrintComp;
+ header->npullcrds = ir->pull->ncoord;
+ header->bPrintCOM = ir->pull->bPrintCOM;
+ header->bPrintRefValue = ir->pull->bPrintRefValue;
+ header->bPrintComp = ir->pull->bPrintComp;
/* Read pull coordinates */
snew(header->pcrd, header->npullcrds);
- for (i = 0; i < ir.pull->ncoord; i++)
+ for (int i = 0; i < ir->pull->ncoord; i++)
{
- header->pcrd[i].pull_type = ir.pull->coord[i].eType;
- header->pcrd[i].geometry = ir.pull->coord[i].eGeom;
- header->pcrd[i].ngroup = ir.pull->coord[i].ngroup;
- header->pcrd[i].k = ir.pull->coord[i].k;
- header->pcrd[i].init_dist = ir.pull->coord[i].init;
+ header->pcrd[i].pull_type = ir->pull->coord[i].eType;
+ header->pcrd[i].geometry = ir->pull->coord[i].eGeom;
+ header->pcrd[i].ngroup = ir->pull->coord[i].ngroup;
+ header->pcrd[i].k = ir->pull->coord[i].k;
+ header->pcrd[i].init_dist = ir->pull->coord[i].init;
- copy_ivec(ir.pull->coord[i].dim, header->pcrd[i].dim);
+ copy_ivec(ir->pull->coord[i].dim, header->pcrd[i].dim);
header->pcrd[i].ndim = header->pcrd[i].dim[XX] + header->pcrd[i].dim[YY] + header->pcrd[i].dim[ZZ];
std::strcpy(header->pcrd[i].coord_unit,
- pull_coordinate_units(&ir.pull->coord[i]));
+ pull_coordinate_units(&ir->pull->coord[i]));
- if (ir.efep != efepNO && ir.pull->coord[i].k != ir.pull->coord[i].kB)
+ if (ir->efep != efepNO && ir->pull->coord[i].k != ir->pull->coord[i].kB)
{
gmx_fatal(FARGS, "Seems like you did free-energy perturbation, and you perturbed the force constant."
" This is not supported.\n");
}
- if (coordsel && (coordsel->n != ir.pull->ncoord))
+ if (coordsel && (coordsel->n != ir->pull->ncoord))
{
gmx_fatal(FARGS, "Found %d pull coordinates in %s, but %d columns in the respective line\n"
- "coordinate selection file (option -is)\n", ir.pull->ncoord, fn, coordsel->n);
+ "coordinate selection file (option -is)\n", ir->pull->ncoord, fn, coordsel->n);
}
}
int geom = -1;
ivec thedim = { 0, 0, 0 };
bool geometryIsSet = false;
- for (i = 0; i < ir.pull->ncoord; i++)
+ for (int i = 0; i < ir->pull->ncoord; i++)
{
if (coordsel == NULL || coordsel->bUse[i])
{
{
printf("\nFile %s, %d coordinates, with these options:\n", fn, header->npullcrds);
int maxlen = 0;
- for (i = 0; i < ir.pull->ncoord; i++)
+ for (int i = 0; i < ir->pull->ncoord; i++)
{
int lentmp = strlen(epullg_names[header->pcrd[i].geometry]);
maxlen = (lentmp > maxlen) ? lentmp : maxlen;
char fmt[STRLEN];
sprintf(fmt, "\tGeometry %%-%ds k = %%-8g position = %%-8g dimensions [%%s %%s %%s] (%%d dimensions). Used: %%s\n",
maxlen+1);
- for (i = 0; i < ir.pull->ncoord; i++)
+ for (int i = 0; i < ir->pull->ncoord; i++)
{
bool use = (coordsel == NULL || coordsel->bUse[i]);
printf(fmt,
epullg_names[header->pcrd[i].geometry], header->pcrd[i].k, header->pcrd[i].init_dist,
int2YN(header->pcrd[i].dim[XX]), int2YN(header->pcrd[i].dim[YY]), int2YN(header->pcrd[i].dim[ZZ]),
header->pcrd[i].ndim, use ? "Yes" : "No");
- printf("\tPull group coordinates of %d groups expected in pullx files.\n", ir.pull->bPrintCOM ? header->pcrd[i].ngroup : 0);
+ printf("\tPull group coordinates of %d groups expected in pullx files.\n", ir->pull->bPrintCOM ? header->pcrd[i].ngroup : 0);
}
printf("\tReference value of the coordinate%s expected in pullx files.\n",
header->bPrintRefValue ? "" : " not");
if (!bGetMinMax)
{
+ assert(window);
bins = opt->bins;
min = opt->min;
max = opt->max;
# 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(
# files with code for test fixtures
gmx_traj_tests.cpp
)
-gmx_register_integration_test(
- ${testname}
- ${exename}
- )
+gmx_register_gtest_test(LegacyToolsTest ${exename} INTEGRATION_TEST)
"spc2-traj.g96"
};
-#ifdef __INTEL_COMPILER
-#pragma warning( disable : 177 )
-#endif
-
INSTANTIATE_TEST_CASE_P(NoFatalErrorWhenWritingFrom,
GmxTraj,
::testing::ValuesIn(gmx::ArrayRef<const char*>(trajectoryFileNames)));
#include <cstdlib>
#include <cstring>
+#include <algorithm>
+
#include "gromacs/listed-forces/bonded.h"
#include "gromacs/pbcutil/rmpbc.h"
#include "gromacs/utility/cstringutil.h"
static const char *pp_pat[] = { "C", "N", "CA", "C", "N" };
#define NPP (sizeof(pp_pat)/sizeof(pp_pat[0]))
-static int d_comp(const void *a, const void *b)
+static bool d_comp(const t_dih &a, const t_dih &b)
{
- t_dih *da, *db;
-
- da = (t_dih *)a;
- db = (t_dih *)b;
-
- if (da->ai[1] < db->ai[1])
+ if (a.ai[1] < b.ai[1])
{
- return -1;
+ return true;
}
- else if (da->ai[1] == db->ai[1])
+ else if (a.ai[1] == b.ai[1])
{
- return (da->ai[2] - db->ai[2]);
+ return a.ai[2] < b.ai[2];
}
else
{
- return 1;
+ return false;
}
}
key.ai[1] = ia[2];
key.ai[2] = ia[3];
- if ((dd = (t_dih *)bsearch(&key, xr->dih, xr->ndih, (size_t)sizeof(key), d_comp))
- != NULL)
+ dd = std::lower_bound(xr->dih, xr->dih+xr->ndih, key, d_comp);
+ if (dd < xr->dih+xr->ndih && !d_comp(key, *dd))
{
dd->mult = idef->iparams[ft].pdihs.mult;
dd->phi0 = idef->iparams[ft].pdihs.phiA;
fclose(fp);
- return (gmx_neutron_atomic_structurefactors_t *) gnsf;
+ return gnsf;
}
gmx_sans_t *gmx_sans_init (const t_topology *top, gmx_neutron_atomic_structurefactors_t *gnsf)
}
}
- return (gmx_sans_t *) gsans;
+ return gsans;
}
gmx_radial_distribution_histogram_t *calc_radial_distribution_histogram (
pr->r[i] = (pr->binwidth*i+pr->binwidth*0.5);
}
- return (gmx_radial_distribution_histogram_t *) pr;
+ return pr;
}
gmx_static_structurefactor_t *convert_histogram_to_intensity_curve (gmx_radial_distribution_histogram_t *pr, double start_q, double end_q, double q_step)
}
}
- return (gmx_static_structurefactor_t *) sq;
+ return sq;
}
return cr;
}
+static void done_mpi_in_place_buf(mpi_in_place_buf_t *buf)
+{
+ if (NULL != buf)
+ {
+ sfree(buf->ibuf);
+ sfree(buf->libuf);
+ sfree(buf->fbuf);
+ sfree(buf->dbuf);
+ sfree(buf);
+ }
+}
+
+void done_commrec(t_commrec *cr)
+{
+ if (NULL != cr->dd)
+ {
+ // TODO: implement
+ // done_domdec(cr->dd);
+ }
+ if (NULL != cr->ms)
+ {
+ done_mpi_in_place_buf(cr->ms->mpb);
+ sfree(cr->ms);
+ }
+ done_mpi_in_place_buf(cr->mpb);
+ sfree(cr);
+}
+
t_commrec *reinitialize_commrec_for_this_thread(const t_commrec gmx_unused *cro)
{
#if GMX_THREAD_MPI
/* Any result except MPI_UNEQUAL allows us to call MPI_Finalize */
bFinalize = (result != MPI_UNEQUAL);
#else
+ GMX_UNUSED_VALUE(comm);
bFinalize = TRUE;
#endif
*
* 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.
struct t_commrec *init_commrec(void);
/* Allocate, initialize and return the commrec. */
+void done_commrec(struct t_commrec *cr);
+/* Free memory associated with the commrec. */
+
struct t_commrec *reinitialize_commrec_for_this_thread(const struct t_commrec *cro);
/* Initialize communication records for thread-parallel simulations.
Must be called on all threads before any communication takes place by
/*
* 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))
/*
* 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.
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) { \
*
* 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 <string.h>
+#include <cassert>
#include <cmath>
#include "gromacs/gmxpreprocess/gpp_atomtype.h"
/* Type==-1 is used as a signal that this interaction is all-zero and should not be added. */
if (!bNB && type >= 0)
{
+ assert(il);
nral = NRAL(ftype);
delta = nr*(nral+1);
srenew(il->iatoms, il->nr+delta);
*
* 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 "gromacs/utility/smalloc.h"
#define DIHEDRAL_WAS_SET_IN_RTP 0
-static gmx_bool was_dihedral_set_in_rtp(t_param *dih)
+static gmx_bool was_dihedral_set_in_rtp(const t_param *dih)
{
return dih->c[MAXFORCEPARAM-1] == DIHEDRAL_WAS_SET_IN_RTP;
}
static int acomp(const void *a1, const void *a2)
{
- t_param *p1, *p2;
- int ac;
+ const t_param *p1, *p2;
+ int ac;
- p1 = (t_param *)a1;
- p2 = (t_param *)a2;
+ p1 = static_cast<const t_param *>(a1);
+ p2 = static_cast<const t_param *>(a2);
if ((ac = (p1->aj()-p2->aj())) != 0)
{
return ac;
static int pcomp(const void *a1, const void *a2)
{
- t_param *p1, *p2;
- int pc;
+ const t_param *p1, *p2;
+ int pc;
- p1 = (t_param *)a1;
- p2 = (t_param *)a2;
+ p1 = static_cast<const t_param *>(a1);
+ p2 = static_cast<const t_param *>(a2);
if ((pc = (p1->ai()-p2->ai())) != 0)
{
return pc;
static int dcomp(const void *d1, const void *d2)
{
- t_param *p1, *p2;
- int dc;
+ const t_param *p1, *p2;
+ int dc;
- p1 = (t_param *)d1;
- p2 = (t_param *)d2;
+ p1 = static_cast<const t_param *>(d1);
+ p2 = static_cast<const t_param *>(d2);
/* First sort by J & K (the two central) atoms */
if ((dc = (p1->aj()-p2->aj())) != 0)
{
static int idcomp(const void *a, const void *b)
{
- t_param *pa, *pb;
- int d;
+ const t_param *pa, *pb;
+ int d;
- pa = (t_param *)a;
- pb = (t_param *)b;
+ pa = static_cast<const t_param *>(a);
+ pb = static_cast<const t_param *>(b);
if ((d = (pa->a[0]-pb->a[0])) != 0)
{
return d;
real boltz, sd;
real ekin, temp, mass, scal;
gmx_mtop_atomloop_all_t aloop;
- t_atom *atom;
+ const t_atom *atom;
gmx::TabulatedNormalDistribution<real> normalDist;
boltz = BOLTZ*tempi;
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;
}
*
* 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.
real c[MAXFORCEPARAM]; /* Force parameters (eg. b0 = c[0]) */
char s[MAXSLEN]; /* A string (instead of parameters), *
* read from the .rtp file in pdb2gmx */
+ const int &ai() const { return a[0]; }
int &ai() { return a[0]; }
+ const int &aj() const { return a[1]; }
int &aj() { return a[1]; }
+ const int &ak() const { return a[2]; }
int &ak() { return a[2]; }
+ const int &al() const { return a[3]; }
int &al() { return a[3]; }
+ const int &am() const { return a[4]; }
int &am() { return a[4]; }
real &c0() { return c[0]; }
#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"
static void check_vel(gmx_mtop_t *mtop, rvec v[])
{
gmx_mtop_atomloop_all_t aloop;
- t_atom *atom;
+ const t_atom *atom;
int a;
aloop = gmx_mtop_atomloop_all_init(mtop);
warninp_t wi)
{
gmx_mtop_atomloop_all_t aloop;
- t_atom *atom;
+ const t_atom *atom;
int a, nshells = 0;
char warn_buf[STRLEN];
}
t_topology *conftop;
+ rvec *x = NULL;
+ rvec *v = NULL;
snew(conftop, 1);
init_state(state, 0, 0, 0, 0, 0);
- read_tps_conf(confin, conftop, NULL, &state->x, &state->v, state->box, FALSE);
- state->natoms = state->nalloc = conftop->atoms.nr;
+ read_tps_conf(confin, conftop, NULL, &x, &v, state->box, FALSE);
+ state->natoms = conftop->atoms.nr;
if (state->natoms != sys->natoms)
{
gmx_fatal(FARGS, "number of coordinates in coordinate file (%s, %d)\n"
" does not match topology (%s, %d)",
confin, state->natoms, topfile, sys->natoms);
}
+ /* It would be nice to get rid of the copies below, but we don't know
+ * a priori if the number of atoms in confin matches what we expect.
+ */
+ state->flags |= (1 << estX);
+ state->x.resize(state->natoms);
+ for (int i = 0; i < state->natoms; i++)
+ {
+ copy_rvec(x[i], state->x[i]);
+ }
+ sfree(x);
+ if (v != NULL)
+ {
+ state->flags |= (1 << estV);
+ state->v.resize(state->natoms);
+ for (int i = 0; i < state->natoms; i++)
+ {
+ copy_rvec(v[i], state->v[i]);
+ }
+ sfree(v);
+ }
/* This call fixes the box shape for runs with pressure scaling */
set_box_rel(ir, state);
{
real *mass;
gmx_mtop_atomloop_all_t aloop;
- t_atom *atom;
+ const t_atom *atom;
snew(mass, state->natoms);
aloop = gmx_mtop_atomloop_all_init(sys);
opts->seed = static_cast<int>(gmx::makeRandomSeed());
fprintf(stderr, "Setting gen_seed to %d\n", opts->seed);
}
- maxwell_speed(opts->tempi, opts->seed, sys, state->v);
+ state->flags |= (1 << estV);
+ maxwell_speed(opts->tempi, opts->seed, sys, as_rvec_array(state->v.data()));
- stop_cm(stdout, state->natoms, mass, state->x, state->v);
+ stop_cm(stdout, state->natoms, mass, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()));
sfree(mass);
}
rvec *v)
{
gmx_mtop_atomloop_all_t aloop;
- t_atom *atom;
+ const t_atom *atom;
int a;
double sum_mv2 = 0;
t_inputrec *ir;
int nvsite, comb, mt;
t_params *plist;
- t_state *state;
matrix box;
real fudgeQQ;
double reppow;
"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))
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 */
{
gmx_fatal(FARGS, "%s does not exist", fn);
}
- snew(state, 1);
+
+ t_state state {};
new_status(fn, opt2fn_null("-pp", NFILE, fnm), opt2fn("-c", NFILE, fnm),
- opts, ir, bZero, bGenVel, bVerbose, state,
+ opts, ir, bZero, bGenVel, bVerbose, &state,
atype, sys, &nmi, &mi, &intermolecular_interactions,
plist, &comb, &reppow, &fudgeQQ,
opts->bMorse,
/* Check velocity for virtual sites and shells */
if (bGenVel)
{
- check_vel(sys, state->v);
+ check_vel(sys, as_rvec_array(state.v.data()));
}
/* check for shells and inpurecs */
}
else
{
- buffer_temp = calc_temp(sys, ir, state->v);
+ buffer_temp = calc_temp(sys, ir, as_rvec_array(state.v.data()));
}
if (buffer_temp > 0)
{
}
}
- set_verlet_buffer(sys, ir, buffer_temp, state->box, wi);
+ set_verlet_buffer(sys, ir, buffer_temp, state.box, wi);
}
}
}
/* Init the temperature coupling state */
- init_gtc_state(state, ir->opts.ngtc, 0, ir->opts.nhchainlength); /* need to add nnhpres here? */
+ init_gtc_state(&state, ir->opts.ngtc, 0, ir->opts.nhchainlength); /* need to add nnhpres here? */
if (bVerbose)
{
fprintf(stderr, "getting data from old trajectory ...\n");
}
cont_status(ftp2fn(efTRN, NFILE, fnm), ftp2fn_null(efEDR, NFILE, fnm),
- bNeedVel, bGenVel, fr_time, ir, state, sys, oenv);
+ bNeedVel, bGenVel, fr_time, ir, &state, sys, oenv);
}
if (ir->ePBC == epbcXY && ir->nwall != 2)
{
- clear_rvec(state->box[ZZ]);
+ clear_rvec(state.box[ZZ]);
}
if (ir->cutoff_scheme != ecutsVERLET && ir->rlist > 0)
{
set_warning_line(wi, mdparin, -1);
- check_chargegroup_radii(sys, ir, state->x, wi);
+ check_chargegroup_radii(sys, ir, as_rvec_array(state.x.data()), wi);
}
if (EEL_FULL(ir->coulombtype) || EVDW_PME(ir->vdwtype))
{
/* Calculate the optimal grid dimensions */
- copy_mat(state->box, box);
+ copy_mat(state.box, box);
if (ir->ePBC == epbcXY && ir->nwall == 2)
{
svmul(ir->wall_ewald_zfac, box[ZZ], box[ZZ]);
potentially conflict if not handled correctly. */
if (ir->efep != efepNO)
{
- state->fep_state = ir->fepvals->init_fep_state;
+ state.fep_state = ir->fepvals->init_fep_state;
for (i = 0; i < efptNR; i++)
{
/* init_lambda trumps state definitions*/
if (ir->fepvals->init_lambda >= 0)
{
- state->lambda[i] = ir->fepvals->init_lambda;
+ state.lambda[i] = ir->fepvals->init_lambda;
}
else
{
}
else
{
- state->lambda[i] = ir->fepvals->all_lambda[i][state->fep_state];
+ state.lambda[i] = ir->fepvals->all_lambda[i][state.fep_state];
}
}
}
if (ir->bPull)
{
- pull = set_pull_init(ir, sys, state->x, state->box, state->lambda[efptMASS], oenv);
+ pull = set_pull_init(ir, sys, as_rvec_array(state.x.data()), state.box, state.lambda[efptMASS], oenv);
}
/* Modules that supply external potential for pull coordinates
if (ir->bRot)
{
- set_reference_positions(ir->rot, state->x, state->box,
+ set_reference_positions(ir->rot, as_rvec_array(state.x.data()), state.box,
opt2fn("-ref", NFILE, fnm), opt2bSet("-ref", NFILE, fnm),
wi);
}
if (EEL_PME(ir->coulombtype))
{
- float ratio = pme_load_estimate(sys, ir, state->box);
+ float ratio = pme_load_estimate(sys, ir, state.box);
fprintf(stderr, "Estimate for the relative computational load of the PME mesh part: %.2f\n", ratio);
/* With free energy we might need to do PME both for the A and B state
* charges. This will double the cost, but the optimal performance will
}
done_warning(wi, FARGS);
- write_tpx_state(ftp2fn(efTPR, NFILE, fnm), ir, state, sys);
+ write_tpx_state(ftp2fn(efTPR, NFILE, fnm), ir, &state, sys);
/* Output IMD group, if bIMD is TRUE */
- write_IMDgroup_to_file(ir->bIMD, ir, state, sys, NFILE, fnm);
+ write_IMDgroup_to_file(ir->bIMD, ir, &state, sys, NFILE, fnm);
- done_state(state);
- sfree(state);
done_atomtype(atype);
- done_mtop(sys, TRUE);
+ done_mtop(sys);
done_inputrec_strings();
return 0;
*
* 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.
int compaddh(const void *a, const void *b)
{
- t_hackblock *ah, *bh;
+ const t_hackblock *ah, *bh;
- ah = (t_hackblock *)a;
- bh = (t_hackblock *)b;
+ ah = static_cast<const t_hackblock *>(a);
+ bh = static_cast<const t_hackblock *>(b);
return gmx_strcasecmp(ah->name, bh->name);
}
ahkey.name = key;
- result = (t_hackblock *)bsearch(&ahkey, ah, nh, (size_t)sizeof(ah[0]), compaddh);
+ result = static_cast<t_hackblock *>(bsearch(&ahkey, ah, nh, (size_t)sizeof(ah[0]), compaddh));
return result;
}
#include "gromacs/topology/atomprop.h"
#include "gromacs/topology/atoms.h"
#include "gromacs/topology/atomsbuilder.h"
+#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
#include "gromacs/trajectory/trajectoryframe.h"
#include "gromacs/utility/cstringutil.h"
static void insert_mols(int nmol_insrt, int ntry, int seed,
real defaultDistance, real scaleFactor,
- t_topology *top, std::vector<RVec> *x,
+ t_atoms *atoms, t_symtab *symtab, std::vector<RVec> *x,
const std::set<int> &removableAtoms,
const t_atoms &atoms_insrt, const std::vector<RVec> &x_insrt,
int ePBC, matrix box,
fprintf(stderr, "Initialising inter-atomic distances...\n");
gmx_atomprop_t aps = gmx_atomprop_init();
std::vector<real> exclusionDistances(
- makeExclusionDistances(&top->atoms, aps, defaultDistance, scaleFactor));
+ makeExclusionDistances(atoms, aps, defaultDistance, scaleFactor));
const std::vector<real> exclusionDistances_insrt(
makeExclusionDistances(&atoms_insrt, aps, defaultDistance, scaleFactor));
gmx_atomprop_destroy(aps);
nmol_insrt, posfn.c_str());
}
- gmx::AtomsBuilder builder(&top->atoms, &top->symtab);
- gmx::AtomsRemover remover(top->atoms);
+ gmx::AtomsBuilder builder(atoms, symtab);
+ gmx::AtomsRemover remover(*atoms);
{
- const int finalAtomCount = top->atoms.nr + nmol_insrt * atoms_insrt.nr;
- const int finalResidueCount = top->atoms.nres + nmol_insrt * atoms_insrt.nres;
+ const int finalAtomCount = atoms->nr + nmol_insrt * atoms_insrt.nr;
+ const int finalResidueCount = atoms->nres + nmol_insrt * atoms_insrt.nres;
builder.reserve(finalAtomCount, finalResidueCount);
x->reserve(finalAtomCount);
exclusionDistances.reserve(finalAtomCount);
gmx::AnalysisNeighborhoodPositions pos(*x);
gmx::AnalysisNeighborhoodSearch search = nb.initSearch(&pbc, pos);
if (isInsertionAllowed(&search, exclusionDistances, x_n, exclusionDistances_insrt,
- top->atoms, removableAtoms, &remover))
+ *atoms, removableAtoms, &remover))
{
x->insert(x->end(), x_n.begin(), x_n.end());
exclusionDistances.insert(exclusionDistances.end(),
fprintf(stderr, "Added %d molecules (out of %d requested)\n",
mol - failed, nmol_insrt);
- const int originalAtomCount = top->atoms.nr;
- const int originalResidueCount = top->atoms.nres;
- remover.refreshAtomCount(top->atoms);
+ const int originalAtomCount = atoms->nr;
+ const int originalResidueCount = atoms->nres;
+ remover.refreshAtomCount(*atoms);
remover.removeMarkedElements(x);
- remover.removeMarkedAtoms(&top->atoms);
- if (top->atoms.nr < originalAtomCount)
+ remover.removeMarkedAtoms(atoms);
+ if (atoms->nr < originalAtomCount)
{
fprintf(stderr, "Replaced %d residues (%d atoms)\n",
- originalResidueCount - top->atoms.nres,
- originalAtomCount - top->atoms.nr);
+ originalResidueCount - atoms->nres,
+ originalAtomCount - atoms->nr);
}
if (rpos != NULL)
{
if (top_ != NULL)
{
- done_top(top_);
+ done_mtop(top_);
sfree(top_);
}
}
// From ITopologyProvider
- virtual t_topology *getTopology(bool /*required*/) { return top_; }
+ virtual gmx_mtop_t *getTopology(bool /*required*/) { return top_; }
virtual int getAtomCount() { return 0; }
// From ICommandLineOptionsModule
RotationType enumRot_;
Selection replaceSel_;
- t_topology *top_;
+ gmx_mtop_t *top_;
std::vector<RVec> x_;
matrix box_;
int ePBC_;
{
readConformation(inputConfFile_.c_str(), top_, &x_, NULL,
&ePBC_, box_, "solute");
- if (top_->atoms.nr == 0)
+ if (top_->natoms == 0)
{
fprintf(stderr, "Note: no atoms in %s\n", inputConfFile_.c_str());
}
}
}
+ // TODO: Adapt to use mtop throughout.
+ t_atoms atoms = gmx_mtop_global_atoms(top_);
+
/* add nmol_ins molecules of atoms_ins
in random orientation at random place */
insert_mols(nmolIns_, nmolTry_, seed_, defaultDistance_, scaleFactor_,
- top_, &x_, removableAtoms, top_insrt->atoms, x_insrt,
+ &atoms, &top_->symtab, &x_, removableAtoms, top_insrt->atoms, x_insrt,
ePBC_, box_, positionFile_, deltaR_, enumRot_);
/* write new configuration to file confout */
fprintf(stderr, "Writing generated configuration to %s\n",
outputConfFile_.c_str());
- write_sto_conf(outputConfFile_.c_str(), *top_->name, &top_->atoms,
+ write_sto_conf(outputConfFile_.c_str(), *top_->name, &atoms,
as_rvec_array(x_.data()), NULL, ePBC_, box_);
/* print size of generated configuration */
fprintf(stderr, "\nOutput configuration contains %d atoms in %d residues\n",
- top_->atoms.nr, top_->atoms.nres);
+ atoms.nr, atoms.nres);
+ done_atom(&atoms);
done_top(top_insrt);
sfree(top_insrt);
*
* 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.
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
{
static int pcompar(const void *a, const void *b)
{
- t_param *pa, *pb;
- int d;
- pa = (t_param *)a;
- pb = (t_param *)b;
+ const t_param *pa, *pb;
+ int d;
+ pa = static_cast<const t_param *>(a);
+ pb = static_cast<const t_param *>(b);
d = pa->a[0] - pb->a[0];
if (d == 0)
/*
* 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.
#include "gromacs/fileio/confio.h"
#include "gromacs/topology/atomprop.h"
#include "gromacs/topology/atoms.h"
+#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/scoped_cptr.h"
return exclusionDistances;
}
+void readConformation(const char *confin, gmx_mtop_t *top,
+ std::vector<RVec> *x, std::vector<RVec> *v,
+ int *ePBC, matrix box, const char *statusTitle)
+{
+ fprintf(stderr, "Reading %s configuration%s\n", statusTitle,
+ v ? " and velocities" : "");
+ rvec *x_tmp = NULL, *v_tmp = NULL;
+ bool dummy;
+ readConfAndTopology(confin, &dummy, top, ePBC, x ? &x_tmp : NULL, v ? &v_tmp : NULL, box);
+ gmx::scoped_guard_sfree xguard(x_tmp);
+ gmx::scoped_guard_sfree vguard(v_tmp);
+ if (x && x_tmp)
+ {
+ *x = std::vector<RVec>(x_tmp, x_tmp + top->natoms);
+ }
+ if (v && v_tmp)
+ {
+ *v = std::vector<RVec>(v_tmp, v_tmp + top->natoms);
+ }
+ fprintf(stderr, "%s\nContaining %d atoms in %d residues\n",
+ *top->name, top->natoms, gmx_mtop_nres(top));
+}
+
void readConformation(const char *confin, t_topology *top,
std::vector<RVec> *x, std::vector<RVec> *v,
int *ePBC, matrix box, const char *statusTitle)
/*
* 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.
#include "gromacs/utility/real.h"
struct gmx_atomprop;
+struct gmx_mtop_t;
struct t_atoms;
struct t_topology;
makeExclusionDistances(const t_atoms *a, gmx_atomprop *aps,
real defaultDistance, real scaleFactor);
+void readConformation(const char *confin, gmx_mtop_t *top,
+ std::vector<gmx::RVec> *x, std::vector<gmx::RVec> *v,
+ int *ePBC, matrix box, const char *statusTitle);
/*! \brief Read a conformation from a file, allocate and fill data structures.
*
* Used by solvate and insert-molecules. The returned pointers *x and
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/md_enums.h"
#include "gromacs/mdtypes/pull-params.h"
+#include "gromacs/options/options.h"
+#include "gromacs/options/treesupport.h"
#include "gromacs/pbcutil/pbc.h"
#include "gromacs/topology/block.h"
#include "gromacs/topology/ifunc.h"
#include "gromacs/topology/symtab.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/ikeyvaluetreeerror.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreetransform.h"
#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringcompare.h"
+#include "gromacs/utility/stringutil.h"
#define MAXPTR 254
#define NOGID 255
char QMmethod[STRLEN], QMbasis[STRLEN], QMcharge[STRLEN], QMmult[STRLEN],
bSH[STRLEN], CASorbitals[STRLEN], CASelectrons[STRLEN], SAon[STRLEN],
SAoff[STRLEN], SAsteps[STRLEN], bTS[STRLEN], bOPT[STRLEN];
- char efield_x[STRLEN], efield_xt[STRLEN], efield_y[STRLEN],
- efield_yt[STRLEN], efield_z[STRLEN], efield_zt[STRLEN];
} gmx_inputrec_strings;
couple_lambda_value == ecouplamVDWQ);
}
+namespace
+{
+
+class MdpErrorHandler : public gmx::IKeyValueTreeErrorHandler
+{
+ public:
+ explicit MdpErrorHandler(warninp_t wi)
+ : wi_(wi), mapping_(nullptr)
+ {
+ }
+
+ void setBackMapping(const gmx::IKeyValueTreeBackMapping &mapping)
+ {
+ mapping_ = &mapping;
+ }
+
+ virtual bool onError(gmx::UserInputError *ex, const gmx::KeyValueTreePath &context)
+ {
+ ex->prependContext(gmx::formatString("Error in mdp option \"%s\":",
+ getOptionName(context).c_str()));
+ std::string message = gmx::formatExceptionMessageToString(*ex);
+ warning_error(wi_, message.c_str());
+ return true;
+ }
+
+ private:
+ std::string getOptionName(const gmx::KeyValueTreePath &context)
+ {
+ if (mapping_ != nullptr)
+ {
+ gmx::KeyValueTreePath path = mapping_->originalPath(context);
+ GMX_ASSERT(path.size() == 1, "Inconsistent mapping back to mdp options");
+ return path[0];
+ }
+ GMX_ASSERT(context.size() == 1, "Inconsistent context for mdp option parsing");
+ return context[0];
+ }
+
+ warninp_t wi_;
+ const gmx::IKeyValueTreeBackMapping *mapping_;
+};
+
+} // namespace
+
void get_ir(const char *mdparin, const char *mdparout,
t_inputrec *ir, t_gromppopts *opts,
warninp_t wi)
}
/* Electric fields */
- CCTYPE("Electric fields");
- CTYPE ("Format is number of terms (int) and for all terms an amplitude (real)");
- CTYPE ("and a phase angle (real)");
- STYPE ("E-x", is->efield_x, NULL);
- CTYPE ("Time dependent (pulsed) electric field. Format is omega, time for pulse");
- CTYPE ("peak, and sigma (width) for pulse. Sigma = 0 removes pulse, leaving");
- CTYPE ("the field to be a cosine function.");
- STYPE ("E-xt", is->efield_xt, NULL);
- STYPE ("E-y", is->efield_y, NULL);
- STYPE ("E-yt", is->efield_yt, NULL);
- STYPE ("E-z", is->efield_z, NULL);
- STYPE ("E-zt", is->efield_zt, NULL);
+ {
+ gmx::KeyValueTreeObject convertedValues = flatKeyValueTreeFromInpFile(ninp, inp);
+ gmx::KeyValueTreeTransformer transform;
+ transform.rules()->addRule()
+ .keyMatchType("/", gmx::StringCompareType::CaseAndDashInsensitive);
+ ir->efield->initMdpTransform(transform.rules());
+ for (const auto &path : transform.mappedPaths())
+ {
+ GMX_ASSERT(path.size() == 1, "Inconsistent mapping back to mdp options");
+ mark_einp_set(ninp, inp, path[0].c_str());
+ }
+ gmx::Options options;
+ ir->efield->initMdpOptions(&options);
+ MdpErrorHandler errorHandler(wi);
+ auto result
+ = transform.transform(convertedValues, &errorHandler);
+ errorHandler.setBackMapping(result.backMapping());
+ gmx::assignOptionsFromKeyValueTree(&options, result.object(),
+ &errorHandler);
+ }
/* Ion/water position swapping ("computational electrophysiology") */
CCTYPE("Ion/water position swapping for computational electrophysiology setups");
double *nrdf_tc, *nrdf_vcm, nrdf_uc, *nrdf_vcm_sub;
ivec *dof_vcm;
gmx_mtop_atomloop_all_t aloop;
- t_atom *atom;
int mb, mol, ftype, as;
gmx_molblock_t *molb;
gmx_moltype_t *molt;
snew(nrdf2, natoms);
aloop = gmx_mtop_atomloop_all_init(mtop);
+ const t_atom *atom;
while (gmx_mtop_atomloop_all_next(aloop, &i, &atom))
{
nrdf2[i] = 0;
sfree(nrdf_vcm_sub);
}
-static void decode_cos(char *s, t_cosines *cosine)
-{
- char *t;
- char format[STRLEN], f1[STRLEN];
- double a, phi;
- int i;
-
- t = gmx_strdup(s);
- trim(t);
-
- cosine->n = 0;
- cosine->a = NULL;
- cosine->phi = NULL;
- if (strlen(t))
- {
- if (sscanf(t, "%d", &(cosine->n)) != 1)
- {
- gmx_fatal(FARGS, "Cannot parse cosine multiplicity from string '%s'", t);
- }
- if (cosine->n <= 0)
- {
- cosine->n = 0;
- }
- else
- {
- snew(cosine->a, cosine->n);
- snew(cosine->phi, cosine->n);
-
- sprintf(format, "%%*d");
- for (i = 0; (i < cosine->n); i++)
- {
- double gmx_unused canary;
-
- strcpy(f1, format);
- strcat(f1, "%lf%lf%lf");
- if (sscanf(t, f1, &a, &phi, &canary) != 2)
- {
- gmx_fatal(FARGS, "Invalid input for electric field shift: '%s'", t);
- }
- cosine->a[i] = a;
- cosine->phi[i] = phi;
- strcat(format, "%*lf%*lf");
- }
- }
- }
- sfree(t);
-}
-
static gmx_bool do_egp_flag(t_inputrec *ir, gmx_groups_t *groups,
const char *option, const char *val, int flag)
{
gmx_fatal(FARGS, "Can only have energy group pair tables in combination with user tables for VdW and/or Coulomb");
}
- decode_cos(is->efield_x, &(ir->ex[XX]));
- decode_cos(is->efield_xt, &(ir->et[XX]));
- decode_cos(is->efield_y, &(ir->ex[YY]));
- decode_cos(is->efield_yt, &(ir->et[YY]));
- decode_cos(is->efield_z, &(ir->ex[ZZ]));
- decode_cos(is->efield_zt, &(ir->et[ZZ]));
-
for (i = 0; (i < grps->nr); i++)
{
sfree(gnames[i]);
rvec acc;
gmx_mtop_atomloop_block_t aloopb;
gmx_mtop_atomloop_all_t aloop;
- t_atom *atom;
ivec AbsRef;
char warn_buf[STRLEN];
bCharge = FALSE;
aloopb = gmx_mtop_atomloop_block_init(sys);
+ const t_atom *atom;
while (gmx_mtop_atomloop_block_next(aloopb, &atom, &nmol))
{
if (atom->q != 0 || atom->qB != 0)
clear_rvec(acc);
snew(mgrp, sys->groups.grps[egcACC].nr);
aloop = gmx_mtop_atomloop_all_init(sys);
+ const t_atom *atom;
while (gmx_mtop_atomloop_all_next(aloop, &i, &atom))
{
mgrp[ggrpnr(&sys->groups, egcACC, i)] += atom->m;
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);
}
}
-static int comprtp(const void *a, const void *b)
-{
- t_restp *ra, *rb;
-
- ra = (t_restp *)a;
- rb = (t_restp *)b;
-
- return gmx_strcasecmp(ra->resname, rb->resname);
-}
-
int get_bt(char* header)
{
int i;
srenew(rrtp, nrtp);
fprintf(stderr, "\nSorting it all out...\n");
- qsort(rrtp, nrtp, (size_t)sizeof(rrtp[0]), comprtp);
+ std::sort(rrtp, rrtp+nrtp, [](const t_restp &a, const t_restp &b) {return gmx_strcasecmp(a.resname, b.resname) < 0; });
check_rtp(nrtp, rrtp, rrdb);
#include "gromacs/mdlib/genborn.h"
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/pbcutil/pbc.h"
#include "gromacs/topology/block.h"
#include "gromacs/topology/ifunc.h"
#include "gromacs/topology/symtab.h"
#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/futil.h"
#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/pleasecite.h"
#include "gromacs/utility/smalloc.h"
#define OPENDIR '[' /* starting sign for directive */
gmx_bool bFEP,
gmx_bool bGenborn,
gmx_bool bZero,
- warninp_t wi)
+ gmx_bool usingFullRangeElectrostatics,
+ warninp_t wi)
{
FILE *out;
int i, sl, nb_funct;
push_molt(symtab, &nmol, molinfo, pline, wi);
srenew(block2, nmol);
- block2[nmol-1].nr = 0;
- mi0 = &((*molinfo)[nmol-1]);
+ block2[nmol-1].nr = 0;
+ mi0 = &((*molinfo)[nmol-1]);
+ mi0->atoms.haveMass = TRUE;
+ mi0->atoms.haveCharge = TRUE;
+ mi0->atoms.haveType = TRUE;
+ mi0->atoms.haveBState = TRUE;
+ mi0->atoms.havePdbInfo = FALSE;
break;
}
case d_atoms:
{
title = put_symtab(symtab, "");
}
+
if (fabs(qt) > 1e-4)
{
sprintf(warn_buf, "System has non-zero total charge: %.6f\n%s\n", qt, floating_point_arithmetic_tip);
sprintf(warn_buf, "State B has non-zero total charge: %.6f\n%s\n", qBt, floating_point_arithmetic_tip);
warning_note(wi, warn_buf);
}
+ if (usingFullRangeElectrostatics && (fabs(qt) > 1e-4 || fabs(qBt) > 1e-4))
+ {
+ warning(wi, "You are using Ewald electrostatics in a system with net charge. This can lead to severe artifacts, such as ions moving into regions with low dielectric, due to the uniform background charge. We suggest to neutralize your system with counter ions, possibly in combination with a physiological salt concentration.");
+ please_cite(stdout, "Hub2014a");
+ }
+
DS_Done (&DS);
for (i = 0; i < nmol; i++)
{
nrmols, molinfo, intermolecular_interactions,
plist, combination_rule, repulsion_power,
opts, fudgeQQ, nmolblock, molblock,
- ir->efep != efepNO, bGenborn, bZero, wi);
+ ir->efep != efepNO, bGenborn, bZero,
+ EEL_FULL(ir->coulombtype), wi);
+
if ((*combination_rule != eCOMB_GEOMETRIC) &&
(ir->vdwtype == evdwUSER))
{
/*
* 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.
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.
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;
* 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 */
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 */
};
/*! 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*/);
/*! 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);
#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
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.
*
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)
{
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.
* 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;
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;
}
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 */
}
#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)
{
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);
//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);
}
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
* 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).
* \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),
}
//! 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,
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);
include(${_gmx_import_file})
unset(_gmx_import_file)
+get_target_property(_libs libgromacs INTERFACE_LINK_LIBRARIES)
+if (_libs MATCHES "tng_io::tng_io")
+ include(CMakeFindDependencyMacro)
+ find_dependency(TNG_IO)
+endif()
+unset(_libs)
+
set(GROMACS_INCLUDE_DIRS)
set(_include_dirs "@INSTALLED_HEADER_INCLUDE_DIRS@")
foreach (_dir ${_include_dirs})
#
# 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.
gmx_add_libgromacs_sources(
cpuinfo.cpp
detecthardware.cpp
+ hardwareassign.cpp
hardwaretopology.cpp
)
#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"
#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"
#define HOSTNAMELEN 80
/* FW decl. */
-static void set_gpu_ids(gmx_gpu_opt_t *gpu_opt, int nrank, int rank);
static int gmx_count_gpu_dev_unique(const gmx_gpu_info_t *gpu_info,
const gmx_gpu_opt_t *gpu_opt);
return bGpuSharingSupported;
}
-static void sprint_gpus(char *sbuf, const gmx_gpu_info_t *gpu_info)
+std::string sprint_gpus(const gmx_gpu_info_t *gpu_info)
{
- int i, ndev;
- char stmp[STRLEN];
-
- ndev = gpu_info->n_dev;
-
- sbuf[0] = '\0';
- for (i = 0; i < ndev; i++)
+ char stmp[STRLEN];
+ std::vector<std::string> gpuStrings;
+ for (int i = 0; i < gpu_info->n_dev; i++)
{
get_gpu_device_info_string(stmp, gpu_info, i);
- strcat(sbuf, " ");
- strcat(sbuf, stmp);
- if (i < ndev - 1)
- {
- strcat(sbuf, "\n");
- }
- }
-}
-
-static void print_gpu_detection_stats(FILE *fplog,
- const gmx_gpu_info_t *gpu_info,
- const t_commrec *cr)
-{
- char onhost[HOSTNAMELEN+10], stmp[STRLEN];
- int ngpu;
-
- if (!gpu_info->bDetectGPUs)
- {
- /* We skipped the detection, so don't print detection stats */
- return;
- }
-
- ngpu = gpu_info->n_dev;
-
-#if GMX_LIB_MPI
- /* We only print the detection on one, of possibly multiple, nodes */
- std::strncpy(onhost, " on host ", 10);
- gmx_gethostname(onhost + 9, HOSTNAMELEN);
-#else
- /* We detect all relevant GPUs */
- std::strncpy(onhost, "", 1);
-#endif
-
- 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);
- }
- else
- {
- md_print_warn(cr, fplog, "No GPUs detected%s\n", onhost);
+ gpuStrings.push_back(gmx::formatString(" %s", stmp));
}
+ return gmx::joinStrings(gpuStrings, "\n");
}
/*! \brief Helper function for reporting GPU usage information
/* 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
{
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
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,
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:
{
/* 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" : "");
}
}
/* 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)
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");
}
}
}
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;
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");
{
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);
}
}
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++)
{
#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;
}
*/
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;
// 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.
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);
hwinfo->gpu_info.n_dev);
if (hwinfo->gpu_info.n_dev > 0)
{
- char buf[STRLEN];
-
- sprint_gpus(buf, &hwinfo->gpu_info);
- s += gmx::formatString("%s\n", buf);
+ s += sprint_gpus(&hwinfo->gpu_info) + "\n";
}
}
return s;
}
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;
}
/* 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
}
}
-void gmx_select_gpu_ids(FILE *fplog, const t_commrec *cr,
- const gmx_gpu_info_t *gpu_info,
- gmx_bool bForceUseGPU,
- gmx_gpu_opt_t *gpu_opt)
-{
- int i;
- char sbuf[STRLEN], stmp[STRLEN];
-
- /* Bail if binary is not compiled with GPU acceleration, but this is either
- * explicitly (-nb gpu) or implicitly (gpu ID passed) requested. */
- if (bForceUseGPU && !bGPUBinary)
- {
- gmx_fatal(FARGS, "GPU acceleration requested, but %s was compiled without GPU support!",
- gmx::getProgramContext().displayName());
- }
-
- if (!(cr->duty & DUTY_PP))
- {
- /* Our rank is not doing PP, we don't use a GPU */
- return;
- }
-
- if (gpu_opt->bUserSet)
- {
- /* Check the GPU IDs passed by the user.
- * (GPU IDs have been parsed by gmx_parse_gpu_ids before)
- */
- int *checkres;
- int res;
-
- snew(checkres, gpu_opt->n_dev_use);
-
- res = check_selected_gpus(checkres, gpu_info, gpu_opt);
-
- if (!res)
- {
- print_gpu_detection_stats(fplog, gpu_info, cr);
-
- 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++)
- {
- if (checkres[i] != egpuCompatible)
- {
- sprintf(stmp, " GPU #%d: %s\n",
- gpu_opt->dev_use[i],
- gpu_detect_res_str[checkres[i]]);
- strcat(sbuf, stmp);
- }
- }
- gmx_fatal(FARGS, "%s", sbuf);
- }
-
- sfree(checkres);
- }
- else if (getenv("GMX_EMULATE_GPU") == NULL)
- {
- pick_compatible_gpus(&hwinfo_g->gpu_info, gpu_opt);
- set_gpu_ids(gpu_opt, cr->nrank_pp_intranode, cr->rank_pp_intranode);
- }
-
- /* If the user asked for a GPU, check whether we have a GPU */
- if (bForceUseGPU && gpu_info->n_dev_compatible == 0)
- {
- gmx_fatal(FARGS, "GPU acceleration requested, but no compatible GPUs were detected.");
- }
-}
-
-/* Select the GPUs we will use. This is an operation local to each physical
- * node. If we have less MPI ranks than GPUs, we will waste some GPUs.
- * nrank and rank are the rank count and id for PP processes in our node.
- */
-static void set_gpu_ids(gmx_gpu_opt_t *gpu_opt, int nrank, int rank)
-{
- GMX_RELEASE_ASSERT(gpu_opt, "Invalid gpu_opt pointer passed");
- GMX_RELEASE_ASSERT(nrank >= 1,
- gmx::formatString("Invalid limit (%d) for the number of GPUs (detected %d compatible GPUs)",
- rank, gpu_opt->n_dev_compatible).c_str());
-
- if (gpu_opt->n_dev_compatible == 0)
- {
- char host[HOSTNAMELEN];
-
- gmx_gethostname(host, HOSTNAMELEN);
- gmx_fatal(FARGS, "A GPU was requested on host %s, but no compatible GPUs were detected. All nodes with PP ranks need to have GPUs. If you intended to use GPU acceleration in a parallel run, you can either avoid using the nodes that don't have GPUs or place PME ranks on these nodes.", host);
- }
-
- int nshare;
-
- nshare = 1;
- if (nrank > gpu_opt->n_dev_compatible)
- {
- if (nrank % gpu_opt->n_dev_compatible == 0)
- {
- nshare = gmx_gpu_sharing_supported() ? nrank/gpu_opt->n_dev_compatible : 1;
- }
- else
- {
- if (rank == 0)
- {
- gmx_fatal(FARGS, "The number of MPI ranks (%d) in a physical node is not a multiple of the number of GPUs (%d). Select a different number of MPI ranks or use the -gpu_id option to manually specify the GPU to be used.",
- nrank, gpu_opt->n_dev_compatible);
- }
-
-#if GMX_MPI
- /* We use a global barrier to prevent ranks from continuing with
- * an invalid setup.
- */
- MPI_Barrier(MPI_COMM_WORLD);
-#endif
- }
- }
-
- /* Here we will waste GPUs when nrank < gpu_opt->n_dev_compatible */
- gpu_opt->n_dev_use = std::min(gpu_opt->n_dev_compatible*nshare, nrank);
- if (!gmx_multiple_gpu_per_node_supported())
- {
- gpu_opt->n_dev_use = std::min(gpu_opt->n_dev_use, 1);
- }
- snew(gpu_opt->dev_use, gpu_opt->n_dev_use);
- for (int i = 0; i != gpu_opt->n_dev_use; ++i)
- {
- /* TODO: improve this implementation: either sort GPUs or remove the weakest here */
- gpu_opt->dev_use[i] = gpu_opt->dev_compatible[i/nshare];
- }
-}
-
void gmx_hardware_info_free(gmx_hw_info_t *hwinfo)
{
int ret;
#include <cstdio>
+#include <string>
+
#include "gromacs/utility/basedefinitions.h"
struct gmx_gpu_info_t;
namespace gmx
{
-
class HardwareTopology;
-
-} // namespace
+class MDLogger;
+}
/*! \brief Return whether mdrun can use more than one GPU per node
*
* example. */
gmx_bool gmx_gpu_sharing_supported();
+/*! \internal \brief
+ * Returns the GPU information text, one GPU per line.
+ */
+std::string sprint_gpus(const gmx_gpu_info_t *gpu_info);
+
/*! \brief Run detection, consistency checks, and make available on all ranks.
*
* This routine constructs the global hwinfo structure and returns a pointer to
* 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,
- 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,
--- /dev/null
+/*
+ * 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 "hardwareassign.h"
+
+#include "config.h"
+
+#include <cstring>
+
+#include <algorithm>
+#include <string>
+
+#include "gromacs/gmxlib/network.h"
+#include "gromacs/gpu_utils/gpu_utils.h"
+#include "gromacs/hardware/detecthardware.h"
+#include "gromacs/hardware/gpu_hw_info.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/cstringutil.h"
+#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"
+#include "gromacs/utility/sysinfo.h"
+
+#define HOSTNAMELEN 80
+
+/*! \internal \brief
+ * Prints GPU information strings on this node into the stderr and log.
+ * Only used for logging errors in heterogenous MPI configurations.
+ */
+static void print_gpu_detection_stats(const gmx::MDLogger &mdlog,
+ const gmx_gpu_info_t *gpu_info)
+{
+ char onhost[HOSTNAMELEN+10];
+ int ngpu;
+
+ if (!gpu_info->bDetectGPUs)
+ {
+ /* We skipped the detection, so don't print detection stats */
+ return;
+ }
+
+ ngpu = gpu_info->n_dev;
+
+ /* We only print the detection on one, of possibly multiple, nodes */
+ std::strncpy(onhost, " on host ", 10);
+ gmx_gethostname(onhost + 9, HOSTNAMELEN);
+
+ if (ngpu > 0)
+ {
+ std::string gpuDesc = sprint_gpus(gpu_info);
+ GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted(
+ "%d GPU%s detected%s:\n%s",
+ ngpu, (ngpu > 1) ? "s" : "", onhost, gpuDesc.c_str());
+ }
+ else
+ {
+ GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted("No GPUs detected%s", onhost);
+ }
+ // FIXME: This currently only logs on the master rank, which defeats the purpose.
+ // A new MDLogger option is required for printing to stderr on all ranks.
+ // There is also a question of MPI reduction of the outputs, see Redmine issue #1505.
+}
+
+/*! \internal \brief
+ * This function is responsible for mapping the GPUs to the processes on a single node
+ * (filling the gpu_opt->dev_use array).
+ *
+ * \param[in,out] gpu_opt Input/output GPU assignment data.
+ * \param[in] nrank Number of PP GPU ranks on the node.
+ * \param[in] rank Index of PP GPU rank on the node.
+ *
+ * This selects the GPUs we will use. This is an operation local to each physical node.
+ * If we have less MPI ranks than GPUs, we will waste some GPUs.
+ */
+static void assign_rank_gpu_ids(gmx_gpu_opt_t *gpu_opt, int nrank, int rank)
+{
+ GMX_RELEASE_ASSERT(gpu_opt, "Invalid gpu_opt pointer passed");
+ GMX_RELEASE_ASSERT(nrank >= 1,
+ gmx::formatString("Invalid limit (%d) for the number of GPUs (detected %d compatible GPUs)",
+ rank, gpu_opt->n_dev_compatible).c_str());
+
+ if (gpu_opt->n_dev_compatible == 0)
+ {
+ char host[HOSTNAMELEN];
+
+ gmx_gethostname(host, HOSTNAMELEN);
+ gmx_fatal(FARGS, "A GPU was requested on host %s, but no compatible GPUs were detected. All nodes with PP ranks need to have GPUs. If you intended to use GPU acceleration in a parallel run, you can either avoid using the nodes that don't have GPUs or place PME ranks on these nodes.", host);
+ }
+
+ int nshare;
+
+ nshare = 1;
+ if (nrank > gpu_opt->n_dev_compatible)
+ {
+ if (nrank % gpu_opt->n_dev_compatible == 0)
+ {
+ nshare = gmx_gpu_sharing_supported() ? nrank/gpu_opt->n_dev_compatible : 1;
+ }
+ else
+ {
+ if (rank == 0)
+ {
+ gmx_fatal(FARGS, "The number of MPI ranks (%d) in a physical node is not a multiple of the number of GPUs (%d). Select a different number of MPI ranks or use the -gpu_id option to manually specify the GPU to be used.",
+ nrank, gpu_opt->n_dev_compatible);
+ }
+
+#if GMX_MPI
+ /* We use a global barrier to prevent ranks from continuing with
+ * an invalid setup.
+ */
+ MPI_Barrier(MPI_COMM_WORLD);
+#endif
+ }
+ }
+
+ /* Here we will waste GPUs when nrank < gpu_opt->n_dev_compatible */
+ gpu_opt->n_dev_use = std::min(gpu_opt->n_dev_compatible*nshare, nrank);
+ if (!gmx_multiple_gpu_per_node_supported())
+ {
+ gpu_opt->n_dev_use = std::min(gpu_opt->n_dev_use, 1);
+ }
+ snew(gpu_opt->dev_use, gpu_opt->n_dev_use);
+ for (int i = 0; i != gpu_opt->n_dev_use; ++i)
+ {
+ /* TODO: improve this implementation: either sort GPUs or remove the weakest here */
+ gpu_opt->dev_use[i] = gpu_opt->dev_compatible[i/nshare];
+ }
+}
+
+void gmx_select_rank_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)
+{
+ int i;
+ char sbuf[STRLEN], stmp[STRLEN];
+
+ /* Bail if binary is not compiled with GPU acceleration, but this is either
+ * explicitly (-nb gpu) or implicitly (gpu ID passed) requested. */
+ if (bForceUseGPU && (GMX_GPU == GMX_GPU_NONE))
+ {
+ gmx_fatal(FARGS, "GPU acceleration requested, but %s was compiled without GPU support!",
+ gmx::getProgramContext().displayName());
+ }
+
+ if (!(cr->duty & DUTY_PP))
+ {
+ /* Our rank is not doing PP, we don't use a GPU */
+ return;
+ }
+
+ if (gpu_opt->bUserSet)
+ {
+ /* Check the GPU IDs passed by the user.
+ * (GPU IDs have been parsed by gmx_parse_gpu_ids before)
+ */
+ int *checkres;
+ int res;
+
+ snew(checkres, gpu_opt->n_dev_use);
+
+ res = check_selected_gpus(checkres, gpu_info, gpu_opt);
+
+ if (!res)
+ {
+ const bool canHaveHeterogeneousNodes = GMX_LIB_MPI && PAR(cr);
+ if (canHaveHeterogeneousNodes)
+ {
+ 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++)
+ {
+ if (checkres[i] != egpuCompatible)
+ {
+ sprintf(stmp, " GPU #%d: %s\n",
+ gpu_opt->dev_use[i],
+ gpu_detect_res_str[checkres[i]]);
+ strcat(sbuf, stmp);
+ }
+ }
+ gmx_fatal(FARGS, "%s", sbuf);
+ }
+
+ sfree(checkres);
+ }
+ else if (getenv("GMX_EMULATE_GPU") == NULL)
+ {
+ pick_compatible_gpus(gpu_info, gpu_opt);
+ assign_rank_gpu_ids(gpu_opt, cr->nrank_pp_intranode, cr->rank_pp_intranode);
+ }
+
+ /* If the user asked for a GPU, check whether we have a GPU */
+ if (bForceUseGPU && gpu_info->n_dev_compatible == 0)
+ {
+ gmx_fatal(FARGS, "GPU acceleration requested, but no compatible GPUs were detected.");
+ }
+}
/*
* 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
+#ifndef GMX_HARDWARE_HARDWAREASSIGN_H
+#define GMX_HARDWARE_HARDWAREASSIGN_H
-#include <cstdio>
+#include "gromacs/utility/basedefinitions.h"
+struct gmx_gpu_info_t;
+struct gmx_gpu_opt_t;
struct t_commrec;
-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.
- */
+namespace gmx
+{
+class MDLogger;
+}
-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.
- */
+void gmx_select_rank_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);
#endif
{
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
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)
*/
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
/*! \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
#include "gromacs/imd/imdsocket.h"
#include "gromacs/math/units.h"
#include "gromacs/math/vec.h"
+#include "gromacs/mdlib/broadcaststructs.h"
#include "gromacs/mdlib/groupcoord.h"
#include "gromacs/mdlib/mdrun.h"
#include "gromacs/mdlib/sighandler.h"
/*! \brief IMD Protocol Version. */
#define IMDVERSION 2
-/*! \brief Broadcast d to all nodes */
-#define block_bc(cr, d) gmx_bcast(sizeof(d), &(d), (cr))
-
-/*! \brief Broadcast nr elements of d to all nodes */
-#define nblock_bc(cr, nr, d) gmx_bcast((nr)*sizeof((d)[0]), (d), (cr))
-
/*! \internal
* \brief
{
IMDatoms = gmx_mtop_global_atoms(sys);
write_sto_conf_indexed(opt2fn("-imd", nfile, fnm), "IMDgroup", &IMDatoms,
- state->x, state->v, ir->ePBC, state->box, ir->imd->nat, ir->imd->ind);
+ as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), ir->ePBC, state->box, ir->imd->nat, ir->imd->ind);
}
}
F77_FUNC(dgemv, DGEMV) ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[8]],
&c__1, &c_b42, &workd[iwork[9]], &c__1);
}
- else if (*mode == 2)
+ else
{
F77_FUNC(dgemv, DGEMV) ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[10]
], &c__1, &c_b42, &workd[iwork[9]], &c__1);
F77_FUNC(sgemv, SGEMV) ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[8]],
&c__1, &c_b42, &workd[iwork[9]], &c__1);
}
- else if (*mode == 2)
+ else
{
F77_FUNC(sgemv, SGEMV) ("T", n, &iwork[12], &c_b18, &v[v_offset], ldv, &workd[iwork[10]
], &c__1, &c_b42, &workd[iwork[9]], &c__1);
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;
ulp = 2*GMX_DOUBLE_EPS;
rtoli = ulp * 2.;
nb = DSTEBZ_BLOCKSIZE;
+ // cppcheck-suppress knownConditionTrueFalse
if (nb <= 1) {
nb = 0;
}
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;
ulp = 2*GMX_FLOAT_EPS;
rtoli = ulp * 2.;
nb = DSTEBZ_BLOCKSIZE;
+ // cppcheck-suppress knownConditionTrueFalse
if (nb <= 1) {
nb = 0;
}
#
# 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.
gmx_install_headers(listed-forces.h)
if (BUILD_TESTING)
-# add_subdirectory(tests)
+ add_subdirectory(tests)
endif()
gmx_mtop_ilistloop_t iloop;
t_ilist *il;
gmx_mtop_atomloop_all_t aloop;
- t_atom *atom;
const gmx_multisim_t *ms;
od->nr = gmx_mtop_ftype_count(mtop, F_ORIRES);
mtot = 0.0;
j = 0;
aloop = gmx_mtop_atomloop_all_init(mtop);
+ const t_atom *atom;
while (gmx_mtop_atomloop_all_next(aloop, &i, &atom))
{
if (mtop->groups.grpnr[egcORFIT] == NULL ||
/*
* 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.
dvdl = 0;
v = posres(idef->il[F_POSRES].nr, idef->il[F_POSRES].iatoms,
idef->iparams_posres,
- x, fr->f_novirsum, fr->vir_diag_posres,
+ x, as_rvec_array(fr->f_novirsum->data()), fr->vir_diag_posres,
fr->ePBC == epbcNONE ? NULL : pbc,
lambda[efptRESTRAINT], &dvdl,
fr->rc_scaling, fr->ePBC, fr->posres_com, fr->posres_comB);
v = fbposres(idef->il[F_FBPOSRES].nr, idef->il[F_FBPOSRES].iatoms,
idef->iparams_fbposres,
- x, fr->f_novirsum, fr->vir_diag_posres,
+ x, as_rvec_array(fr->f_novirsum->data()), fr->vir_diag_posres,
fr->ePBC == epbcNONE ? NULL : pbc,
fr->rc_scaling, fr->ePBC, fr->posres_com);
enerd->term[F_FBPOSRES] += v;
--- /dev/null
+#
+# 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(ListedForcesTest listed-forces-test
+ bonded.cpp)
+
--- /dev/null
+/*
+ * 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 test of bonded force routines
+ *
+ * \author David van der Spoel <david.vanderspoel@icm.uu.se>
+ * \ingroup module_listed-forces
+ */
+#include "gmxpre.h"
+
+#include "gromacs/listed-forces/bonded.h"
+
+#include <cmath>
+
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/math/units.h"
+#include "gromacs/pbcutil/ishift.h"
+#include "gromacs/pbcutil/pbc.h"
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+#include "testutils/testfilemanager.h"
+
+namespace gmx
+{
+namespace
+{
+
+//! Number of atoms used in these tests.
+#define NATOMS 4
+
+class BondedTest : public ::testing::Test
+{
+ protected:
+ rvec x[NATOMS];
+ matrix box;
+ test::TestReferenceData refData_;
+ test::TestReferenceChecker checker_;
+ BondedTest( ) :
+ checker_(refData_.rootChecker())
+ {
+ test::FloatingPointTolerance tolerance(test::relativeToleranceAsFloatingPoint(1.0, 1e-6));
+ checker_.setDefaultTolerance(tolerance);
+ clear_rvecs(NATOMS, x);
+ x[1][2] = 1;
+ x[2][1] = x[2][2] = 1;
+ x[3][0] = x[3][1] = x[3][2] = 1;
+
+ clear_mat(box);
+ box[0][0] = box[1][1] = box[2][2] = 1.5;
+ }
+
+ void testBondAngle(int epbc)
+ {
+ rvec r_ij, r_kj;
+ real cosine_angle, angle;
+ int t1, t2;
+ t_pbc pbc;
+
+ set_pbc(&pbc, epbc, box);
+ angle = bond_angle(x[0], x[1], x[2], &pbc,
+ r_ij, r_kj, &cosine_angle,
+ &t1, &t2);
+ checker_.checkReal(angle, "angle");
+ checker_.checkReal(cosine_angle, "cosine_angle");
+ checker_.checkInteger(t1, "t1");
+ checker_.checkInteger(t2, "t2");
+ }
+
+ void testDihedralAngle(int epbc)
+ {
+ rvec r_ij, r_kj, r_kl, m, n;
+ real cosine_angle, angle;
+ int t1, t2, t3;
+ t_pbc pbc;
+
+ set_pbc(&pbc, epbc, box);
+ angle = dih_angle(x[0], x[1], x[2], x[3], &pbc,
+ r_ij, r_kj, r_kl, m, n, &cosine_angle,
+ &t1, &t2, &t3);
+
+ checker_.checkReal(angle, "angle");
+ checker_.checkReal(cosine_angle, "cosine_angle");
+ checker_.checkInteger(t1, "t1");
+ checker_.checkInteger(t2, "t2");
+ checker_.checkInteger(t3, "t3");
+ }
+
+ void testIfunc(int ftype,
+ const std::vector<t_iatom> &iatoms,
+ const t_iparams iparams[],
+ int epbc)
+ {
+ real lambda = 0;
+ real dvdlambda;
+ rvec4 f[NATOMS];
+ for (int i = 0; i < NATOMS; i++)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ f[i][j] = 0;
+ }
+ }
+ rvec fshift[N_IVEC];
+ clear_rvecs(N_IVEC, fshift);
+ t_pbc pbc;
+ set_pbc(&pbc, epbc, box);
+ int ddgatindex = 0;
+ real energy = interaction_function[ftype].ifunc(iatoms.size(),
+ iatoms.data(),
+ iparams,
+ x, f, fshift,
+ &pbc,
+ /* const struct t_graph *g */ NULL,
+ lambda, &dvdlambda,
+ /* const struct t_mdatoms *md */ NULL,
+ /* struct t_fcdata *fcd */ NULL,
+ &ddgatindex);
+ checker_.checkReal(energy, interaction_function[ftype].longname);
+ }
+
+};
+
+TEST_F (BondedTest, BondAnglePbcNone)
+{
+ testBondAngle(epbcNONE);
+}
+
+TEST_F (BondedTest, BondAnglePbcXy)
+{
+ testBondAngle(epbcXY);
+}
+
+TEST_F (BondedTest, BondAnglePbcXyz)
+{
+ testBondAngle(epbcXYZ);
+}
+
+TEST_F (BondedTest, DihedralAnglePbcNone)
+{
+ testDihedralAngle(epbcNONE);
+}
+
+TEST_F (BondedTest, DihedralAnglePbcXy)
+{
+ testDihedralAngle(epbcXY);
+}
+
+TEST_F (BondedTest, DihedarlAnglePbcXyz)
+{
+ testDihedralAngle(epbcXYZ);
+}
+
+TEST_F (BondedTest, IfuncBondsPbcNo)
+{
+ std::vector<t_iatom> iatoms = { 0, 0, 1, 0, 1, 2, 0, 2, 3 };
+ t_iparams iparams;
+ iparams.harmonic.rA = iparams.harmonic.rB = 0.8;
+ iparams.harmonic.krA = iparams.harmonic.krB = 50;
+ testIfunc(F_BONDS, iatoms, &iparams, epbcNONE);
+}
+
+TEST_F (BondedTest, IfuncBondsPbcXy)
+{
+ std::vector<t_iatom> iatoms = { 0, 0, 1, 0, 1, 2, 0, 2, 3 };
+ t_iparams iparams;
+ iparams.harmonic.rA = iparams.harmonic.rB = 0.8;
+ iparams.harmonic.krA = iparams.harmonic.krB = 50;
+ testIfunc(F_BONDS, iatoms, &iparams, epbcXY);
+}
+
+TEST_F (BondedTest, IfuncBondsPbcXyz)
+{
+ std::vector<t_iatom> iatoms = { 0, 0, 1, 0, 1, 2, 0, 2, 3 };
+ t_iparams iparams;
+ iparams.harmonic.rA = iparams.harmonic.rB = 0.8;
+ iparams.harmonic.krA = iparams.harmonic.krB = 50;
+ testIfunc(F_BONDS, iatoms, &iparams, epbcXYZ);
+}
+
+TEST_F (BondedTest, IfuncAnglesPbcNo)
+{
+ std::vector<t_iatom> iatoms = { 0, 0, 1, 2, 0, 1, 2, 3 };
+ t_iparams iparams;
+ real k = 50;
+ iparams.harmonic.rA = iparams.harmonic.rB = 100;
+ iparams.harmonic.krA = iparams.harmonic.krB = k;
+ testIfunc(F_ANGLES, iatoms, &iparams, epbcNONE);
+}
+
+TEST_F (BondedTest, IfuncAnglesPbcXy)
+{
+ std::vector<t_iatom> iatoms = { 0, 0, 1, 2, 0, 1, 2, 3 };
+ t_iparams iparams;
+ real k = 50;
+ iparams.harmonic.rA = iparams.harmonic.rB = 100;
+ iparams.harmonic.krA = iparams.harmonic.krB = k;
+ testIfunc(F_ANGLES, iatoms, &iparams, epbcXY);
+}
+
+TEST_F (BondedTest, IfuncAnglesPbcXYZ)
+{
+ std::vector<t_iatom> iatoms = { 0, 0, 1, 2, 0, 1, 2, 3 };
+ t_iparams iparams;
+ real k = 50;
+ iparams.harmonic.rA = iparams.harmonic.rB = 100;
+ iparams.harmonic.krA = iparams.harmonic.krB = k;
+ testIfunc(F_ANGLES, iatoms, &iparams, epbcXYZ);
+}
+
+TEST_F (BondedTest, IfuncProperDihedralsPbcNo)
+{
+ std::vector<t_iatom> iatoms = { 0, 0, 1, 2, 3 };
+ t_iparams iparams;
+ iparams.pdihs.phiA = iparams.pdihs.phiB = -100;
+ iparams.pdihs.cpA = iparams.pdihs.cpB = 10;
+ iparams.pdihs.mult = 1;
+ testIfunc(F_PDIHS, iatoms, &iparams, epbcNONE);
+}
+
+TEST_F (BondedTest, IfuncProperDihedralsPbcXy)
+{
+ std::vector<t_iatom> iatoms = { 0, 0, 1, 2, 3 };
+ t_iparams iparams;
+ iparams.pdihs.phiA = iparams.pdihs.phiB = -100;
+ iparams.pdihs.cpA = iparams.pdihs.cpB = 10;
+ iparams.pdihs.mult = 1;
+ testIfunc(F_PDIHS, iatoms, &iparams, epbcXY);
+}
+
+TEST_F (BondedTest, IfuncProperDihedralsPbcXyz)
+{
+ std::vector<t_iatom> iatoms = { 0, 0, 1, 2, 3 };
+ t_iparams iparams;
+ iparams.pdihs.phiA = iparams.pdihs.phiB = -100;
+ iparams.pdihs.cpA = iparams.pdihs.cpB = 10;
+ iparams.pdihs.mult = 1;
+ testIfunc(F_PDIHS, iatoms, &iparams, epbcXYZ);
+}
+
+}
+
+}
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="angle">1.5707964</Real>
+ <Real Name="cosine_angle">0</Real>
+ <Int Name="t1">22</Int>
+ <Int Name="t2">22</Int>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="angle">1.5707964</Real>
+ <Real Name="cosine_angle">0</Real>
+ <Int Name="t1">22</Int>
+ <Int Name="t2">17</Int>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="angle">1.5707964</Real>
+ <Real Name="cosine_angle">0</Real>
+ <Int Name="t1">37</Int>
+ <Int Name="t2">17</Int>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="angle">1.5707964</Real>
+ <Real Name="cosine_angle">1</Real>
+ <Int Name="t1">37</Int>
+ <Int Name="t2">17</Int>
+ <Int Name="t3">23</Int>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="angle">-1.5707964</Real>
+ <Real Name="cosine_angle">-1</Real>
+ <Int Name="t1">22</Int>
+ <Int Name="t2">22</Int>
+ <Int Name="t3">22</Int>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="angle">-1.5707964</Real>
+ <Real Name="cosine_angle">-1</Real>
+ <Int Name="t1">22</Int>
+ <Int Name="t2">17</Int>
+ <Int Name="t3">23</Int>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="Angle">1.5230865</Real>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="Angle">1.5230865</Real>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="Angle">1.5230865</Real>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="Bond">2.9999995</Real>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="Bond">5.5</Real>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="Bond">6.75</Real>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="Proper Dih.">19.848078</Real>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="Proper Dih.">19.848078</Real>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Real Name="Proper Dih.">0.1519227</Real>
+</ReferenceData>
#
# 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.
utilities.h
vec.h
vectypes.h
+ paddedvector.h
)
if (BUILD_TESTING)
--- /dev/null
+/*
+ * 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::PaddedRVecVector
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \inpublicapi
+ * \ingroup module_math
+ */
+#ifndef GMX_MATH_PADDEDVECTOR_H
+#define GMX_MATH_PADDEDVECTOR_H
+
+#include <vector>
+
+#include "gromacs/math/vectypes.h"
+
+namespace gmx
+{
+
+/*! \brief Temporary definition of a type usable for SIMD-style loads of RVec quantities.
+ *
+ * \todo This vector is not padded yet, padding will be added soon */
+using PaddedRVecVector = std::vector<gmx::RVec>;
+
+} // namespace gmx
+
+// TODO This is a hack to avoid littering gmx:: all over code that is
+// almost all destined to move into the gmx namespace at some point.
+// An alternative would be about 20 files with using statements.
+using gmx::PaddedRVecVector;
+
+#endif
/*
* 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.
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]);
{
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]);
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]);
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]);
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]);
--- /dev/null
+/*
+ * 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);
+ }
+}
* 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
*
* 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.
}
}
-void pr_rvec(FILE *fp, int indent, const char *title, const real vec[], int n, gmx_bool bShowNumbers)
+template <typename T>
+static void printRealVector(FILE *fp, int indent, const char *title, const T vec[], int n, gmx_bool bShowNumbers)
{
- int i;
-
if (available(fp, vec, indent, title))
{
indent = pr_title_n(fp, indent, title, n);
- for (i = 0; i < n; i++)
+ for (int i = 0; i < n; i++)
{
pr_indent(fp, indent);
fprintf(fp, "%s[%d]=%12.5e\n", title, bShowNumbers ? i : -1, vec[i]);
}
}
-void pr_dvec(FILE *fp, int indent, const char *title, const double vec[], int n, gmx_bool bShowNumbers)
+void pr_rvec(FILE *fp, int indent, const char *title, const real vec[], int n, gmx_bool bShowNumbers)
{
- int i;
+ printRealVector<real>(fp, indent, title, vec, n, bShowNumbers);
+}
- if (available(fp, vec, indent, title))
- {
- indent = pr_title_n(fp, indent, title, n);
- for (i = 0; i < n; i++)
- {
- pr_indent(fp, indent);
- fprintf(fp, "%s[%d]=%12.5e\n", title, bShowNumbers ? i : -1, vec[i]);
- }
- }
+void pr_fvec(FILE *fp, int indent, const char *title, const float vec[], int n, gmx_bool bShowNumbers)
+{
+ printRealVector<float>(fp, indent, title, vec, n, bShowNumbers);
+}
+
+void pr_dvec(FILE *fp, int indent, const char *title, const double vec[], int n, gmx_bool bShowNumbers)
+{
+ printRealVector<double>(fp, indent, title, vec, n, bShowNumbers);
}
*
* 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.
void pr_bvec(FILE *fp, int indent, const char *title, const gmx_bool vec[], int n, gmx_bool bShowNnumbers);
void pr_rvec(FILE *fp, int indent, const char *title, const real vec[], int n, gmx_bool bShowNumbers);
void pr_rvecs_of_dim(FILE *fp, int indent, const char *title, const rvec vec[], int n, int dim);
+void pr_fvec(FILE *fp, int indent, const char *title, const float vec[], int n, gmx_bool bShowNumbers);
void pr_dvec(FILE *fp, int indent, const char *title, const double vec[], int n, gmx_bool bShowNumbers);
void pr_rvecs(FILE *fp, int indent, const char *title, const rvec vec[], int n);
void pr_rvecs_len(FILE *fp, int indent, const char *title, const rvec vec[], int n);
*
* Copyright (c) 1991-2000, University of Groningen, The Netherlands.
* Copyright (c) 2001-2004, The GROMACS development team.
- * 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.
typedef int ivec[DIM];
-typedef int imatrix[DIM][DIM];
-
#ifdef __cplusplus
namespace gmx
/* This file is completely threadsafe - keep it that way! */
#include "gmxpre.h"
+#include "broadcaststructs.h"
+
#include <string.h>
#include "gromacs/gmxlib/network.h"
#include "gromacs/utility/fatalerror.h"
#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 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)); }
-
static void bc_cstring(const t_commrec *cr, char **s)
{
int size = 0;
}
}
+static void bcastPaddedRVecVector(const t_commrec *cr, PaddedRVecVector *v, unsigned int n)
+{
+ (*v).resize(n + 1);
+ nblock_bc(cr, n, as_rvec_array(v->data()));
+}
+
void bcast_state(const t_commrec *cr, t_state *state)
{
int i, nnht, nnhtp;
- gmx_bool bAlloc;
if (!PAR(cr) || (cr->nnodes - cr->npmenodes <= 1))
{
block_bc(cr, state->nnhpres);
block_bc(cr, state->nhchainlength);
block_bc(cr, state->flags);
- if (state->lambda == NULL)
- {
- snew_bc(cr, state->lambda, efptNR)
- }
+ state->lambda.resize(efptNR);
if (cr->dd)
{
nnht = (state->ngtc)*(state->nhchainlength);
nnhtp = (state->nnhpres)*(state->nhchainlength);
- /* We still need to allocate the arrays in state for non-master
- * ranks, which is done (implicitly via bAlloc) in the dirty,
- * dirty nblock_abc macro. */
- bAlloc = !MASTER(cr);
- if (bAlloc)
- {
- state->nalloc = state->natoms;
- }
for (i = 0; i < estNR; i++)
{
if (state->flags & (1<<i))
{
switch (i)
{
- case estLAMBDA: nblock_bc(cr, efptNR, state->lambda); break;
+ case estLAMBDA: nblock_bc(cr, efptNR, state->lambda.data()); break;
case estFEPSTATE: block_bc(cr, state->fep_state); break;
case estBOX: block_bc(cr, state->box); break;
case estBOX_REL: block_bc(cr, state->box_rel); break;
case estPRES_PREV: block_bc(cr, state->pres_prev); break;
case estSVIR_PREV: block_bc(cr, state->svir_prev); break;
case estFVIR_PREV: block_bc(cr, state->fvir_prev); break;
- case estNH_XI: nblock_abc(cr, nnht, state->nosehoover_xi); break;
- case estNH_VXI: nblock_abc(cr, nnht, state->nosehoover_vxi); break;
- case estNHPRES_XI: nblock_abc(cr, nnhtp, state->nhpres_xi); break;
- case estNHPRES_VXI: nblock_abc(cr, nnhtp, state->nhpres_vxi); break;
- case estTC_INT: nblock_abc(cr, state->ngtc, state->therm_integral); break;
+ case estNH_XI: nblock_abc(cr, nnht, &state->nosehoover_xi); break;
+ case estNH_VXI: nblock_abc(cr, nnht, &state->nosehoover_vxi); break;
+ case estNHPRES_XI: nblock_abc(cr, nnhtp, &state->nhpres_xi); break;
+ case estNHPRES_VXI: nblock_abc(cr, nnhtp, &state->nhpres_vxi); break;
+ case estTC_INT: nblock_abc(cr, state->ngtc, &state->therm_integral); break;
case estVETA: block_bc(cr, state->veta); break;
case estVOL0: block_bc(cr, state->vol0); break;
- case estX: nblock_abc(cr, state->natoms, state->x); break;
- case estV: nblock_abc(cr, state->natoms, state->v); break;
- case estCGP: nblock_abc(cr, state->natoms, state->cg_p); break;
+ case estX: bcastPaddedRVecVector(cr, &state->x, state->natoms);
+ case estV: bcastPaddedRVecVector(cr, &state->v, state->natoms);
+ case estCGP: bcastPaddedRVecVector(cr, &state->cg_p, state->natoms);
case estDISRE_INITF: block_bc(cr, state->hist.disre_initf); break;
case estDISRE_RM3TAV:
block_bc(cr, state->hist.ndisrepairs);
- nblock_abc(cr, state->hist.ndisrepairs, state->hist.disre_rm3tav);
+ nblock_abc(cr, state->hist.ndisrepairs, &state->hist.disre_rm3tav);
break;
case estORIRE_INITF: block_bc(cr, state->hist.orire_initf); break;
case estORIRE_DTAV:
block_bc(cr, state->hist.norire_Dtav);
- nblock_abc(cr, state->hist.norire_Dtav, state->hist.orire_Dtav);
+ nblock_abc(cr, state->hist.norire_Dtav, &state->hist.orire_Dtav);
break;
default:
gmx_fatal(FARGS,
}
}
-static void bc_cosines(const t_commrec *cr, t_cosines *cs)
-{
- block_bc(cr, cs->n);
- snew_bc(cr, cs->a, cs->n);
- snew_bc(cr, cs->phi, cs->n);
- if (cs->n > 0)
- {
- nblock_bc(cr, cs->n, cs->a);
- nblock_bc(cr, cs->n, cs->phi);
- }
-}
-
static void bc_pull_group(const t_commrec *cr, t_pull_group *pgrp)
{
block_bc(cr, *pgrp);
static void bc_inputrec(const t_commrec *cr, t_inputrec *inputrec)
{
- int i;
-
+ /* The statement below is dangerous. It overwrites all structures in inputrec.
+ * If something is added to inputrec, like efield it will need to be
+ * treated here.
+ */
+ gmx::IInputRecExtension *eptr = inputrec->efield;
block_bc(cr, *inputrec);
+ inputrec->efield = eptr;
bc_grpopts(cr, &(inputrec->opts));
snew_bc(cr, inputrec->imd, 1);
bc_imd(cr, inputrec->imd);
}
- for (i = 0; (i < DIM); i++)
- {
- bc_cosines(cr, &(inputrec->ex[i]));
- bc_cosines(cr, &(inputrec->et[i]));
- }
+ inputrec->efield->broadCast(cr);
if (inputrec->eSwapCoords != eswapNO)
{
snew_bc(cr, inputrec->swap, 1);
static void bc_molblock(const t_commrec *cr, gmx_molblock_t *molb)
{
- block_bc(cr, molb->type);
- block_bc(cr, molb->nmol);
- block_bc(cr, molb->natoms_mol);
- block_bc(cr, molb->nposres_xA);
+ block_bc(cr, *molb);
if (molb->nposres_xA > 0)
{
snew_bc(cr, molb->posres_xA, molb->nposres_xA);
nblock_bc(cr, molb->nposres_xA*DIM, molb->posres_xA[0]);
}
- block_bc(cr, molb->nposres_xB);
if (molb->nposres_xB > 0)
{
snew_bc(cr, molb->posres_xB, molb->nposres_xB);
--- /dev/null
+/*
+ * 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 Convenience wrappers for broadcasting structs.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ *
+ * \inlibraryapi
+ * \ingroup module_mdlib
+ */
+#ifndef GMX_MDLIB_BROADCASTSTRUCTS_H
+#define GMX_MDLIB_BROADCASTSTRUCTS_H
+
+#include <vector>
+
+#include "gromacs/gmxlib/network.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/utility/smalloc.h"
+
+//! Convenience wrapper for gmx_bcast of a single value.
+template <typename T>
+void block_bc(const t_commrec *cr, T &data)
+{
+ gmx_bcast(sizeof(T), static_cast<void *>(&data), cr);
+}
+//! Convenience wrapper for gmx_bcast of a C-style array.
+template <typename T>
+void nblock_bc(const t_commrec *cr, int numElements, T *data)
+{
+ gmx_bcast(numElements * sizeof(T), static_cast<void *>(data), cr);
+}
+//! Convenience wrapper for allocation with snew of vectors that need allocation on non-master ranks.
+template <typename T>
+void snew_bc(const t_commrec *cr, T * &data, int numElements)
+{
+ if (!MASTER(cr))
+ {
+ snew(data, numElements);
+ }
+}
+//! Convenience wrapper for gmx_bcast of a C-style array which needs allocation on non-master ranks.
+template <typename T>
+static void nblock_abc(const t_commrec *cr, int numElements, T **v)
+{
+ snew_bc(cr, v, numElements);
+ nblock_bc(cr, numElements, *v);
+}
+//! Convenience wrapper for gmx_bcast of a std::vector which needs resizing on non-master ranks.
+template <typename T>
+static void nblock_abc(const t_commrec *cr, int numElements, std::vector<T> *v)
+{
+ if (!MASTER(cr))
+ {
+ v->resize(numElements);
+ }
+ gmx_bcast(numElements*sizeof(T), v->data(), cr);
+}
+
+#endif
#include "gromacs/pulling/pull.h"
#include "gromacs/topology/block.h"
#include "gromacs/topology/invblock.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/mtop_util.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/fatalerror.h"
FILE *out;
int dd_ac0 = 0, dd_ac1 = 0, i, ii, resnr;
gmx_domdec_t *dd;
- char *anm, *resnm;
+ const char *anm, *resnm;
dd = NULL;
if (DOMAINDECOMP(cr))
fprintf(out, "TITLE %s\n", title);
gmx_write_pdb_box(out, -1, box);
+ int molb = 0;
for (i = start; i < start+homenr; i++)
{
if (dd != NULL)
{
ii = i;
}
- gmx_mtop_atominfo_global(mtop, ii, &anm, &resnr, &resnm);
+ mtopGetAtomAndResidueName(mtop, ii, &molb, &anm, &resnr, &resnm, nullptr);
gmx_fprintf_pdb_atomline(out, epdbATOM, ii+1, anm, ' ', resnm, ' ', resnr, ' ',
10*x[i][XX], 10*x[i][YY], 10*x[i][ZZ], 1.0, 0.0, "");
}
/* 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, as_rvec_array(state->x.data()), state->box, state->edsamstate);
}
constr->warn_mtop = mtop;
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);
}
void parrinellorahman_pcoupl(FILE *fplog, gmx_int64_t step,
- t_inputrec *ir, real dt, tensor pres,
+ const t_inputrec *ir, real dt, const tensor pres,
tensor box, tensor box_rel, tensor boxv,
tensor M, matrix mu, gmx_bool bFirstStep)
{
}
void berendsen_pcoupl(FILE *fplog, gmx_int64_t step,
- t_inputrec *ir, real dt, tensor pres, matrix box,
+ const t_inputrec *ir, real dt,
+ const tensor pres, const matrix box,
matrix mu)
{
int d, n;
}
}
-void berendsen_pscale(t_inputrec *ir, matrix mu,
+void berendsen_pscale(const t_inputrec *ir, const matrix mu,
matrix box, matrix box_rel,
int start, int nr_atoms,
- rvec x[], unsigned short cFREEZE[],
+ rvec x[], const unsigned short cFREEZE[],
t_nrnb *nrnb)
{
ivec *nFreeze = ir->opts.nFreeze;
}
}
-t_state *init_bufstate(const t_state *template_state)
-{
- t_state *state;
- int nc = template_state->nhchainlength;
- snew(state, 1);
- snew(state->nosehoover_xi, nc*template_state->ngtc);
- snew(state->nosehoover_vxi, nc*template_state->ngtc);
- snew(state->therm_integral, template_state->ngtc);
- snew(state->nhpres_xi, nc*template_state->nnhpres);
- snew(state->nhpres_vxi, nc*template_state->nnhpres);
-
- return state;
-}
-
-void destroy_bufstate(t_state *state)
-{
- sfree(state->x);
- sfree(state->v);
- sfree(state->nosehoover_xi);
- sfree(state->nosehoover_vxi);
- sfree(state->therm_integral);
- sfree(state->nhpres_xi);
- sfree(state->nhpres_vxi);
- sfree(state);
-}
-
void trotter_update(t_inputrec *ir, gmx_int64_t step, gmx_ekindata_t *ekind,
gmx_enerdata_t *enerd, t_state *state,
tensor vir, t_mdatoms *md,
break;
case etrtBARONHC:
case etrtBARONHC2:
- NHC_trotter(opts, state->nnhpres, ekind, dt, state->nhpres_xi,
- state->nhpres_vxi, NULL, &(state->veta), MassQ, FALSE);
+ NHC_trotter(opts, state->nnhpres, ekind, dt, state->nhpres_xi.data(),
+ state->nhpres_vxi.data(), NULL, &(state->veta), MassQ, FALSE);
break;
case etrtNHC:
case etrtNHC2:
- NHC_trotter(opts, opts->ngtc, ekind, dt, state->nosehoover_xi,
- state->nosehoover_vxi, scalefac, NULL, MassQ, (ir->eI == eiVV));
+ NHC_trotter(opts, opts->ngtc, ekind, dt, state->nosehoover_xi.data(),
+ state->nosehoover_vxi.data(), scalefac, NULL, MassQ, (ir->eI == eiVV));
/* need to rescale the kinetic energies and velocities here. Could
scale the velocities later, but we need them scaled in order to
produce the correct outputs, so we'll scale them here. */
return trotter_seq;
}
-real NPT_energy(t_inputrec *ir, t_state *state, t_extmass *MassQ)
+static real energyNoseHoover(const t_inputrec *ir, const t_state *state, const t_extmass *MassQ)
{
- int i, j;
- real nd, ndj;
- real ener_npt, reft, kT;
- double *ivxi, *ixi;
- double *iQinv;
- real vol;
- int nh = state->nhchainlength;
+ real energy = 0;
- ener_npt = 0;
+ int nh = state->nhchainlength;
- /* now we compute the contribution of the pressure to the conserved quantity*/
-
- if (ir->epc == epcMTTK)
+ for (int i = 0; i < ir->opts.ngtc; i++)
{
- /* find the volume, and the kinetic energy of the volume */
-
- switch (ir->epct)
- {
+ const double *ixi = &state->nosehoover_xi[i*nh];
+ const double *ivxi = &state->nosehoover_vxi[i*nh];
+ const double *iQinv = &(MassQ->Qinv[i*nh]);
- case epctISOTROPIC:
- /* contribution from the pressure momenenta */
- ener_npt += 0.5*gmx::square(state->veta)/MassQ->Winv;
+ int nd = ir->opts.nrdf[i];
+ real reft = std::max<real>(ir->opts.ref_t[i], 0);
+ real kT = BOLTZ * reft;
- /* contribution from the PV term */
- vol = det(state->box);
- ener_npt += vol*trace(ir->ref_p)/(DIM*PRESFAC);
+ if (nd > 0.0)
+ {
+ if (inputrecNvtTrotter(ir))
+ {
+ /* contribution from the thermal momenta of the NH chain */
+ for (int j = 0; j < nh; j++)
+ {
+ if (iQinv[j] > 0)
+ {
+ energy += 0.5*gmx::square(ivxi[j])/iQinv[j];
+ /* contribution from the thermal variable of the NH chain */
+ int ndj;
+ if (j == 0)
+ {
+ ndj = nd;
+ }
+ else
+ {
+ ndj = 1.0;
+ }
+ energy += ndj*ixi[j]*kT;
+ }
+ }
+ }
+ else /* Other non Trotter temperature NH control -- no chains yet. */
+ {
+ energy += 0.5*BOLTZ*nd*gmx::square(ivxi[0])/iQinv[0];
+ energy += nd*ixi[0]*kT;
+ }
+ }
+ }
- break;
- case epctANISOTROPIC:
+ return energy;
+}
- break;
+/* Returns the energy from the barostat thermostat chain */
+static real energyPressureMTTK(const t_inputrec *ir, const t_state *state, const t_extmass *MassQ)
+{
+ real energy = 0;
- case epctSURFACETENSION:
+ int nh = state->nhchainlength;
- break;
- case epctSEMIISOTROPIC:
+ for (int i = 0; i < state->nnhpres; i++)
+ {
+ /* note -- assumes only one degree of freedom that is thermostatted in barostat */
+ real reft = std::max<real>(ir->opts.ref_t[0], 0.0); /* using 'System' temperature */
+ real kT = BOLTZ * reft;
- break;
- default:
- break;
+ for (int j = 0; j < nh; j++)
+ {
+ double iQinv = MassQ->QPinv[i*nh + j];
+ if (iQinv > 0)
+ {
+ energy += 0.5*gmx::square(state->nhpres_vxi[i*nh + j]/iQinv);
+ /* contribution from the thermal variable of the NH chain */
+ energy += state->nhpres_xi[i*nh + j]*kT;
+ }
+ if (debug)
+ {
+ fprintf(debug, "P-T-group: %10d Chain %4d ThermV: %15.8f ThermX: %15.8f", i, j, state->nhpres_vxi[i*nh + j], state->nhpres_xi[i*nh + j]);
+ }
}
}
- if (inputrecNptTrotter(ir) || inputrecNphTrotter(ir))
+ return energy;
+}
+
+/* Returns the energy accumulated by the V-rescale or Berendsen thermostat */
+static real energyVrescale(const t_inputrec *ir, const t_state *state)
+{
+ real energy = 0;
+ for (int i = 0; i < ir->opts.ngtc; i++)
{
- /* add the energy from the barostat thermostat chain */
- for (i = 0; i < state->nnhpres; i++)
- {
+ energy += state->therm_integral[i];
+ }
- /* note -- assumes only one degree of freedom that is thermostatted in barostat */
- ivxi = &state->nhpres_vxi[i*nh];
- ixi = &state->nhpres_xi[i*nh];
- iQinv = &(MassQ->QPinv[i*nh]);
- reft = std::max<real>(ir->opts.ref_t[0], 0.0); /* using 'System' temperature */
- kT = BOLTZ * reft;
+ return energy;
+}
- for (j = 0; j < nh; j++)
- {
- if (iQinv[j] > 0)
- {
- ener_npt += 0.5*gmx::square(ivxi[j])/iQinv[j];
- /* contribution from the thermal variable of the NH chain */
- ener_npt += ixi[j]*kT;
- }
- if (debug)
- {
- fprintf(debug, "P-T-group: %10d Chain %4d ThermV: %15.8f ThermX: %15.8f", i, j, ivxi[j], ixi[j]);
- }
- }
- }
- }
+real NPT_energy(const t_inputrec *ir, const t_state *state, const t_extmass *MassQ)
+{
+ real energyNPT = 0;
- if (ir->etc)
+ if (ir->epc != epcNO)
{
- for (i = 0; i < ir->opts.ngtc; i++)
+ /* Compute the contribution of the pressure to the conserved quantity*/
+
+ real vol = det(state->box);
+
+ switch (ir->epc)
{
- ixi = &state->nosehoover_xi[i*nh];
- ivxi = &state->nosehoover_vxi[i*nh];
- iQinv = &(MassQ->Qinv[i*nh]);
+ case epcPARRINELLORAHMAN:
+ // TODO: Implement
+ break;
+ case epcMTTK:
+ /* contribution from the pressure momenta */
+ energyNPT += 0.5*gmx::square(state->veta)/MassQ->Winv;
- nd = ir->opts.nrdf[i];
- reft = std::max<real>(ir->opts.ref_t[i], 0);
- kT = BOLTZ * reft;
+ /* contribution from the PV term */
+ energyNPT += vol*trace(ir->ref_p)/(DIM*PRESFAC);
- if (nd > 0.0)
- {
- if (inputrecNvtTrotter(ir))
- {
- /* contribution from the thermal momenta of the NH chain */
- for (j = 0; j < nh; j++)
- {
- if (iQinv[j] > 0)
- {
- ener_npt += 0.5*gmx::square(ivxi[j])/iQinv[j];
- /* contribution from the thermal variable of the NH chain */
- if (j == 0)
- {
- ndj = nd;
- }
- else
- {
- ndj = 1.0;
- }
- ener_npt += ndj*ixi[j]*kT;
- }
- }
- }
- else /* Other non Trotter temperature NH control -- no chains yet. */
+ if (ir->epc == epcMTTK)
{
- ener_npt += 0.5*BOLTZ*nd*gmx::square(ivxi[0])/iQinv[0];
- ener_npt += nd*ixi[0]*kT;
+ /* contribution from the MTTK chain */
+ energyNPT += energyPressureMTTK(ir, state, MassQ);
}
- }
+ break;
+ case epcBERENDSEN:
+ // Not supported, excluded in integratorHasConservedEnergyQuantity()
+ // TODO: Implement
+ break;
+ default:
+ GMX_RELEASE_ASSERT(false, "Conserved energy quantity for pressure coupling is not handled. A case should be added with either the conserved quantity added or nothing added and an exclusion added to integratorHasConservedEnergyQuantity().");
}
}
- return ener_npt;
+
+ switch (ir->etc)
+ {
+ case etcNO:
+ break;
+ case etcVRESCALE:
+ case etcBERENDSEN:
+ energyNPT += energyVrescale(ir, state);
+ break;
+ case etcNOSEHOOVER:
+ energyNPT += energyNoseHoover(ir, state, MassQ);
+ break;
+ case etcANDERSEN:
+ case etcANDERSENMASSIVE:
+ // Not supported, excluded in integratorHasConservedEnergyQuantity()
+ break;
+ default:
+ GMX_RELEASE_ASSERT(false, "Conserved energy quantity for temperature coupling is not handled. A case should be added with either the conserved quantity added or nothing added and an exclusion added to integratorHasConservedEnergyQuantity().");
+ }
+
+ return energyNPT;
}
}
}
-real vrescale_energy(t_grpopts *opts, double therm_integral[])
-{
- int i;
- real ener;
-
- ener = 0;
- for (i = 0; i < opts->ngtc; i++)
- {
- ener += therm_integral[i];
- }
-
- return ener;
-}
-
void rescale_velocities(gmx_ekindata_t *ekind, t_mdatoms *mdatoms,
int start, int end, rvec v[])
{
} 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;
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)
{
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)
excl, x, bSB ? boxs : box, mu_tot,
ir->ewald_geometry,
ir->epsilon_surface,
- fr->f_novirsum, *vir_q, *vir_lj,
+ as_rvec_array(fr->f_novirsum->data()),
+ *vir_q, *vir_lj,
Vcorrt_q, Vcorrt_lj,
lambda[efptCOUL], lambda[efptVDW],
dvdlt_q, dvdlt_lj);
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;
wallcycle_start(wcycle, ewcPMEMESH);
status = gmx_pme_do(fr->pmedata,
0, md->homenr - fr->n_tpi,
- x, fr->f_novirsum,
+ x,
+ as_rvec_array(fr->f_novirsum->data()),
md->chargeA, md->chargeB,
md->sqrt_c6A, md->sqrt_c6B,
md->sigmaA, md->sigmaB,
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);
if (!EEL_PME(fr->eeltype) && EEL_PME_EWALD(fr->eeltype))
{
- Vlr_q = do_ewald(ir, x, fr->f_novirsum,
+ Vlr_q = do_ewald(ir, x, as_rvec_array(fr->f_novirsum->data()),
md->chargeA, md->chargeB,
box_size, cr, md->homenr,
fr->vir_el_recip, fr->ewaldcoeff_q,
}
}
-void sum_dhdl(gmx_enerdata_t *enerd, real *lambda, t_lambda *fepvals)
+void sum_dhdl(gmx_enerdata_t *enerd, const std::vector<real> *lambda, t_lambda *fepvals)
{
int i, j, index;
double dlam;
for (j = 0; j < efptNR; j++)
{
/* Note that this loop is over all dhdl components, not just the separated ones */
- dlam = (fepvals->all_lambda[j][i]-lambda[j]);
+ dlam = (fepvals->all_lambda[j][i] - (*lambda)[j]);
enerd->enerpart_lambda[i+1] += dlam*enerd->dvdl_lin[j];
if (debug)
{
*
* 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 "gromacs/mdlib/vsite.h"
#include "gromacs/mdtypes/fcdata.h"
#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/state.h"
#include "gromacs/timing/wallcycle.h"
struct gmx_edsam;
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 */
*/
-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.
void sum_epot(gmx_grppairener_t *grpp, real *epot);
/* Locally sum the non-bonded potential energy terms */
-void sum_dhdl(gmx_enerdata_t *enerd, real *lambda, t_lambda *fepvals);
+void sum_dhdl(gmx_enerdata_t *enerd, const std::vector<real> *lambda, t_lambda *fepvals);
/* Sum the free energy contributions */
/* Compute the average C6 and C12 params for LJ corrections */
gmx_int64_t step, struct t_nrnb *nrnb, gmx_wallcycle_t wcycle,
gmx_localtop_t *top,
gmx_groups_t *groups,
- matrix box, rvec x[], history_t *hist,
- rvec f[],
+ matrix box, PaddedRVecVector *coordinates, history_t *hist,
+ PaddedRVecVector *force,
tensor vir_force,
t_mdatoms *mdatoms,
gmx_enerdata_t *enerd, t_fcdata *fcd,
- real *lambda, struct t_graph *graph,
+ std::vector<real> *lambda, struct t_graph *graph,
t_forcerec *fr,
gmx_vsite_t *vsite, rvec mu_tot,
- double t, FILE *field, struct gmx_edsam *ed,
+ double t, struct gmx_edsam *ed,
gmx_bool bBornRadii,
int flags);
#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"
#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"
if (fr->bF_NoVirSum)
{
- fr->f_novirsum_n = natoms_f_novirsum;
- if (fr->f_novirsum_n > fr->f_novirsum_nalloc)
- {
- fr->f_novirsum_nalloc = over_alloc_dd(fr->f_novirsum_n);
- srenew(fr->f_novirsum_alloc, fr->f_novirsum_nalloc);
- }
- }
- else
- {
- fr->f_novirsum_n = 0;
+ /* TODO: remove this + 1 when padding is properly implemented */
+ fr->forceBufferNoVirialSummation->resize(natoms_f_novirsum + 1);
}
}
if (bPrintNote)
{
- if (MASTER(cr))
- {
- fprintf(stderr, "\n%s\n", note);
- }
if (fp != NULL)
{
fprintf(fp, "\n%s\n", note);
}
-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)
{
* (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;
}
};
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,
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)
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);
}
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,
{
/* 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
}
static void init_nb_verlet(FILE *fp,
+ const gmx::MDLogger &mdlog,
nonbonded_verlet_t **nb_verlet,
gmx_bool bFEP_NonBonded,
const t_inputrec *ir,
snew(nbv, 1);
- pick_nbnxn_resources(fp, cr, fr->hwinfo,
+ pick_nbnxn_resources(mdlog, cr, fr->hwinfo,
fr->bNonbonded,
&nbv->bUseGPU,
&bEmulateGPU,
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,
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,
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;
* 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... */
{
/* 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;
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!");
}
}
fr->bcoultab = FALSE;
}
+ /* This now calculates sum for q and C6 */
+ set_chargesum(fp, fr, mtop);
+
/* Tables are used for direct ewald sum */
if (fr->bEwald)
{
if (ir->ewald_geometry == eewg3DC)
{
+ bool haveNetCharge = (fabs(fr->qsum[0]) > 1e-4 ||
+ fabs(fr->qsum[1]) > 1e-4);
if (fp)
{
- fprintf(fp, "Using the Ewald3DC correction for systems with a slab geometry.\n");
+ fprintf(fp, "Using the Ewald3DC correction for systems with a slab geometry%s.\n",
+ haveNetCharge ? " and net charge" : "");
}
please_cite(fp, "In-Chul99a");
+ if (haveNetCharge)
+ {
+ please_cite(fp, "Ballenegger2009");
+ }
}
}
fr->ewaldcoeff_q = calc_ewaldcoeff_q(ir->rcoulomb, ir->ewald_rtol);
fr->bF_NoVirSum = (EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype) ||
gmx_mtop_ftype_count(mtop, F_POSRES) > 0 ||
- gmx_mtop_ftype_count(mtop, F_FBPOSRES) > 0 ||
- inputrecElecField(ir)
- );
+ gmx_mtop_ftype_count(mtop, F_FBPOSRES) > 0);
+
+ /* Initialization call after setting bF_NoVirSum,
+ * since it efield->initForcerec also sets this to true.
+ */
+ ir->efield->initForcerec(fr);
+
+ if (fr->bF_NoVirSum)
+ {
+ fr->forceBufferNoVirialSummation = new PaddedRVecVector;
+ }
if (fr->cutoff_scheme == ecutsGROUP &&
ncg_mtop(mtop) > fr->cg_nalloc && !DOMAINDECOMP(cr))
&fr->kappa, &fr->k_rf, &fr->c_rf);
}
- /*This now calculates sum for q and c6*/
- set_chargesum(fp, fr, mtop);
-
/* Construct tables for the group scheme. A little unnecessary to
* make both vdw and coul tables sometimes, but what the
* heck. Note that both cutoff schemes construct Ewald tables in
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)
struct t_fcdata;
struct t_filenm;
+namespace gmx
+{
+class MDLogger;
+}
+
/*! \brief Create a new forcerec structure */
t_forcerec *mk_forcerec(void);
*
* 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
* \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,
#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
* 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;
{
sscanf(env, "%d", &nth);
+ // cppcheck-suppress knownConditionTrueFalse
if (!bOMP)
{
gmx_warning("%s=%d is set, but %s is compiled without OpenMP!",
/* 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
/*! \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;
{
return;
}
+#else
+ GMX_UNUSED_VALUE(cr);
#endif
if (modth.initialized)
/* 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)
/*! \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";
{
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.
*
* \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];
#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,
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,
}
#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)
struct t_commrec;
+namespace gmx
+{
+class MDLogger;
+}
+
/** Enum values corresponding to multithreaded algorithmic modules. */
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,
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/real.h"
+class energyhistory_t;
struct gmx_mtop_t;
struct gmx_membed_t;
struct gmx_output_env_t;
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
* \param[in] top_global Molecular topology for the whole system
* \param[in] fcd Force and constraint data
* \param[in] state_global The state (x, v, f, box etc.) of the whole system
+ * \param[in] energyHistory The energy statistics history
* \param[in] mdatoms Structure containing atom information
* \param[in] nrnb Accounting for floating point operations
* \param[in] wcycle Wall cycle timing information
* \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,
t_inputrec *inputrec,
gmx_mtop_t *top_global, t_fcdata *fcd,
t_state *state_global,
+ energyhistory_t *energyHistory,
t_mdatoms *mdatoms,
t_nrnb *nrnb, gmx_wallcycle_t wcycle,
gmx_edsam_t ed,
#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"
#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"
return nmin;
}
-void copy_coupling_state(t_state *statea, t_state *stateb,
- gmx_ekindata_t *ekinda, gmx_ekindata_t *ekindb, t_grpopts* opts)
-{
-
- /* MRS note -- might be able to get rid of some of the arguments. Look over it when it's all debugged */
-
- int i, j, nc;
-
- /* Make sure we have enough space for x and v */
- if (statea->nalloc > stateb->nalloc)
- {
- stateb->nalloc = statea->nalloc;
- /* We need to allocate one element extra, since we might use
- * (unaligned) 4-wide SIMD loads to access rvec entries.
- */
- srenew(stateb->x, stateb->nalloc + 1);
- srenew(stateb->v, stateb->nalloc + 1);
- }
-
- stateb->natoms = statea->natoms;
- stateb->ngtc = statea->ngtc;
- stateb->nnhpres = statea->nnhpres;
- stateb->veta = statea->veta;
- if (ekinda)
- {
- copy_mat(ekinda->ekin, ekindb->ekin);
- for (i = 0; i < stateb->ngtc; i++)
- {
- ekindb->tcstat[i].T = ekinda->tcstat[i].T;
- ekindb->tcstat[i].Th = ekinda->tcstat[i].Th;
- copy_mat(ekinda->tcstat[i].ekinh, ekindb->tcstat[i].ekinh);
- copy_mat(ekinda->tcstat[i].ekinf, ekindb->tcstat[i].ekinf);
- ekindb->tcstat[i].ekinscalef_nhc = ekinda->tcstat[i].ekinscalef_nhc;
- ekindb->tcstat[i].ekinscaleh_nhc = ekinda->tcstat[i].ekinscaleh_nhc;
- ekindb->tcstat[i].vscale_nhc = ekinda->tcstat[i].vscale_nhc;
- }
- }
- copy_rvecn(statea->x, stateb->x, 0, stateb->natoms);
- copy_rvecn(statea->v, stateb->v, 0, stateb->natoms);
- copy_mat(statea->box, stateb->box);
- copy_mat(statea->box_rel, stateb->box_rel);
- copy_mat(statea->boxv, stateb->boxv);
-
- for (i = 0; i < stateb->ngtc; i++)
- {
- nc = i*opts->nhchainlength;
- for (j = 0; j < opts->nhchainlength; j++)
- {
- stateb->nosehoover_xi[nc+j] = statea->nosehoover_xi[nc+j];
- stateb->nosehoover_vxi[nc+j] = statea->nosehoover_vxi[nc+j];
- }
- }
- if (stateb->nhpres_xi != NULL)
- {
- for (i = 0; i < stateb->nnhpres; i++)
- {
- nc = i*opts->nhchainlength;
- for (j = 0; j < opts->nhchainlength; j++)
- {
- stateb->nhpres_xi[nc+j] = statea->nhpres_xi[nc+j];
- stateb->nhpres_vxi[nc+j] = statea->nhpres_vxi[nc+j];
- }
- }
- }
-}
-
-real compute_conserved_from_auxiliary(t_inputrec *ir, t_state *state, t_extmass *MassQ)
-{
- real quantity = 0;
- switch (ir->etc)
- {
- case etcNO:
- break;
- case etcBERENDSEN:
- break;
- case etcNOSEHOOVER:
- quantity = NPT_energy(ir, state, MassQ);
- break;
- case etcVRESCALE:
- quantity = vrescale_energy(&(ir->opts), state->therm_integral);
- break;
- default:
- break;
- }
- return quantity;
-}
-
/* TODO Specialize this routine into init-time and loop-time versions?
e.g. bReadEkin is only true when restoring from checkpoint */
void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_inputrec *ir,
if (bStopCM)
{
calc_vcm_grp(0, mdatoms->homenr, mdatoms,
- state->x, state->v, vcm);
+ as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), vcm);
}
if (bTemp || bStopCM || bPres || bEner || bConstrain)
{
correct_ekin(debug,
0, mdatoms->homenr,
- state->v, vcm->group_p[0],
+ as_rvec_array(state->v.data()), vcm->group_p[0],
mdatoms->massT, mdatoms->tmass, ekind->ekin);
}
{
check_cm_grp(fplog, vcm, ir, 1);
do_stopcm_grp(0, mdatoms->homenr, mdatoms->cVCM,
- state->x, state->v, vcm);
+ as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), vcm);
inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr);
}
}
}
-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);
}
}
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))
{
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;
}
state->flags |= (1<<estFEPSTATE);
}
state->flags |= (1<<estX);
- if (state->lambda == NULL)
- {
- snew(state->lambda, efptNR);
- }
- if (state->x == NULL)
- {
- /* We need to allocate one element extra, since we might use
- * (unaligned) 4-wide SIMD loads to access rvec entries.
- */
- snew(state->x, state->nalloc + 1);
- }
+ state->lambda.resize(efptNR);
+ GMX_RELEASE_ASSERT(state->x.size() >= static_cast<unsigned int>(state->natoms), "We should start a run with an initialized state->x");
if (EI_DYNAMICS(ir->eI))
{
state->flags |= (1<<estV);
- if (state->v == NULL)
- {
- snew(state->v, state->nalloc + 1);
- }
+ state->v.resize(state->natoms + 1);
}
if (ir->eI == eiCG)
{
state->flags |= (1<<estCGP);
- if (state->cg_p == NULL)
- {
- /* cg_p is not stored in the tpx file, so we need to allocate it */
- snew(state->cg_p, state->nalloc + 1);
- }
+ /* cg_p is not stored in the tpx file, so we need to allocate it */
+ state->cg_p.resize(state->natoms + 1);
}
state->nnhpres = 0;
if ((ir->epc == epcPARRINELLORAHMAN) || (ir->epc == epcMTTK))
{
state->flags |= (1<<estBOXV);
+ state->flags |= (1<<estPRES_PREV);
}
- if (ir->epc != epcNO)
+ if (inputrecNptTrotter(ir) || (inputrecNphTrotter(ir)))
{
- if (inputrecNptTrotter(ir) || (inputrecNphTrotter(ir)))
- {
- state->nnhpres = 1;
- state->flags |= (1<<estNHPRES_XI);
- state->flags |= (1<<estNHPRES_VXI);
- state->flags |= (1<<estSVIR_PREV);
- state->flags |= (1<<estFVIR_PREV);
- state->flags |= (1<<estVETA);
- state->flags |= (1<<estVOL0);
- }
- else
- {
- state->flags |= (1<<estPRES_PREV);
- }
+ state->nnhpres = 1;
+ state->flags |= (1<<estNHPRES_XI);
+ state->flags |= (1<<estNHPRES_VXI);
+ state->flags |= (1<<estSVIR_PREV);
+ state->flags |= (1<<estFVIR_PREV);
+ state->flags |= (1<<estVETA);
+ state->flags |= (1<<estVOL0);
}
}
init_gtc_state(state, state->ngtc, state->nnhpres, ir->opts.nhchainlength); /* allocate the space for nose-hoover chains */
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;
+ }
}
namespace gmx
{
-
+class MDLogger;
class SimulationSignaller;
-
}
/* Define a number of flags to better control the information
/*! \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
*
void rerun_parallel_comm(t_commrec *cr, t_trxframe *fr,
gmx_bool *bNotLastFrame);
-/* get the conserved energy associated with the ensemble type*/
-real compute_conserved_from_auxiliary(t_inputrec *ir, t_state *state,
- t_extmass *MassQ);
-
/* set the lambda values at each step of mdrun when they change */
void set_current_lambdas(gmx_int64_t step, t_lambda *fepvals, gmx_bool bRerunMD,
t_trxframe *rerun_fr, t_state *state_global, t_state *state, double lam0[]);
int multisim_min(const gmx_multisim_t *ms, int nmin, int n);
/* Set an appropriate value for n across the whole multi-simulation */
-void copy_coupling_state(t_state *statea, t_state *stateb,
- gmx_ekindata_t *ekinda, gmx_ekindata_t *ekindb, t_grpopts* opts);
-/* Copy stuff from state A to state B */
-
void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_inputrec *ir,
t_forcerec *fr, gmx_ekindata_t *ekind,
t_state *state, t_mdatoms *mdatoms,
#include "gromacs/mdlib/qmmm.h"
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/exceptions.h"
{
int a;
double tmA, tmB;
- t_atom *atom;
+ const t_atom *atom;
t_mdatoms *md;
gmx_mtop_atomloop_all_t aloop;
t_mdatoms *md)
{
gmx_bool bLJPME;
- gmx_mtop_atomlookup_t alook;
- int i;
const t_grpopts *opts;
const gmx_groups_t *groups;
int nthreads gmx_unused;
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)
}
srenew(md->massT, md->nalloc);
srenew(md->invmass, md->nalloc);
+ srenew(md->invMassPerDim, md->nalloc);
srenew(md->chargeA, md->nalloc);
srenew(md->typeA, md->nalloc);
if (md->nPerturbed)
}
}
- alook = gmx_mtop_atomlookup_init(mtop);
+ int molb = 0;
// cppcheck-suppress unreadVariable
nthreads = gmx_omp_nthreads_get(emntDefault);
-#pragma omp parallel for num_threads(nthreads) schedule(static)
- for (i = 0; i < md->nr; i++)
+#pragma omp parallel for num_threads(nthreads) schedule(static) firstprivate(molb)
+ for (int i = 0; i < md->nr; i++)
{
try
{
int g, ag;
real mA, mB, fac;
real c6, c12;
- t_atom *atom;
if (index == NULL)
{
}
else
{
- ag = index[i];
+ ag = index[i];
}
- gmx_mtop_atomnr_to_atom(alook, ag, &atom);
+ const t_atom &atom = mtopGetAtomParameters(mtop, ag, &molb);
if (md->cFREEZE)
{
{
/* The friction coefficient is mass/tau_t */
fac = ir->delta_t/opts->tau_t[md->cTC ? groups->grpnr[egcTC][ag] : 0];
- mA = 0.5*atom->m*fac;
- mB = 0.5*atom->mB*fac;
+ mA = 0.5*atom.m*fac;
+ mB = 0.5*atom.mB*fac;
}
}
else
{
- mA = atom->m;
- mB = atom->mB;
+ mA = atom.m;
+ mB = atom.mB;
}
if (md->nMassPerturbed)
{
md->massB[i] = mB;
}
md->massT[i] = mA;
+
if (mA == 0.0)
{
- md->invmass[i] = 0;
+ md->invmass[i] = 0;
+ md->invMassPerDim[i][XX] = 0;
+ md->invMassPerDim[i][YY] = 0;
+ md->invMassPerDim[i][ZZ] = 0;
}
else if (md->cFREEZE)
{
*/
md->invmass[i] = 1.0/mA;
}
+ for (int d = 0; d < DIM; d++)
+ {
+ md->invMassPerDim[i][d] = (opts->nFreeze[g][d] ? 0 : 1.0/mA);
+ }
}
else
{
- md->invmass[i] = 1.0/mA;
+ md->invmass[i] = 1.0/mA;
+ for (int d = 0; d < DIM; d++)
+ {
+ md->invMassPerDim[i][d] = 1.0/mA;
+ }
}
- md->chargeA[i] = atom->q;
- md->typeA[i] = atom->type;
+
+ md->chargeA[i] = atom.q;
+ md->typeA[i] = atom.type;
if (bLJPME)
{
- c6 = mtop->ffparams.iparams[atom->type*(mtop->ffparams.atnr+1)].lj.c6;
- c12 = mtop->ffparams.iparams[atom->type*(mtop->ffparams.atnr+1)].lj.c12;
+ c6 = mtop->ffparams.iparams[atom.type*(mtop->ffparams.atnr+1)].lj.c6;
+ c12 = mtop->ffparams.iparams[atom.type*(mtop->ffparams.atnr+1)].lj.c12;
md->sqrt_c6A[i] = sqrt(c6);
if (c6 == 0.0 || c12 == 0)
{
}
if (md->nPerturbed)
{
- md->bPerturbed[i] = PERTURBED(*atom);
- md->chargeB[i] = atom->qB;
- md->typeB[i] = atom->typeB;
+ md->bPerturbed[i] = PERTURBED(atom);
+ md->chargeB[i] = atom.qB;
+ md->typeB[i] = atom.typeB;
if (bLJPME)
{
- c6 = mtop->ffparams.iparams[atom->typeB*(mtop->ffparams.atnr+1)].lj.c6;
- c12 = mtop->ffparams.iparams[atom->typeB*(mtop->ffparams.atnr+1)].lj.c12;
+ c6 = mtop->ffparams.iparams[atom.typeB*(mtop->ffparams.atnr+1)].lj.c6;
+ c12 = mtop->ffparams.iparams[atom.typeB*(mtop->ffparams.atnr+1)].lj.c12;
md->sqrt_c6B[i] = sqrt(c6);
if (c6 == 0.0 || c12 == 0)
{
md->sigma3B[i] = 1/(md->sigmaB[i]*md->sigmaB[i]*md->sigmaB[i]);
}
}
- md->ptype[i] = atom->ptype;
+ md->ptype[i] = atom.ptype;
if (md->cTC)
{
md->cTC[i] = groups->grpnr[egcTC][ag];
GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
}
- gmx_mtop_atomlookup_destroy(alook);
-
md->homenr = homenr;
+ /* We set mass, invmass, invMassPerDim and tmass for lambda=0.
+ * For free-energy runs, these should be updated using update_mdatoms().
+ */
+ md->tmass = md->tmassA;
md->lambda = 0;
}
void update_mdatoms(t_mdatoms *md, real lambda)
{
- int al, end;
- real L1 = 1.0-lambda;
-
- end = md->nr;
-
- if (md->nMassPerturbed)
+ if (md->nMassPerturbed && lambda != md->lambda)
{
- for (al = 0; (al < end); al++)
+ real L1 = 1 - lambda;
+
+ /* Update masses of perturbed atoms for the change in lambda */
+ // cppcheck-suppress unreadVariable
+ int gmx_unused nthreads = gmx_omp_nthreads_get(emntDefault);
+#pragma omp parallel for num_threads(nthreads) schedule(static)
+ for (int i = 0; i < md->nr; i++)
{
- if (md->bPerturbed[al])
+ if (md->bPerturbed[i])
{
- md->massT[al] = L1*md->massA[al]+ lambda*md->massB[al];
- if (md->invmass[al] > 1.1*ALMOST_ZERO)
+ md->massT[i] = L1*md->massA[i] + lambda*md->massB[i];
+ /* Atoms with invmass 0 or ALMOST_ZERO are massless or frozen
+ * and their invmass does not depend on lambda.
+ */
+ if (md->invmass[i] > 1.1*ALMOST_ZERO)
{
- md->invmass[al] = 1.0/md->massT[al];
+ md->invmass[i] = 1.0/md->massT[i];
+ for (int d = 0; d < DIM; d++)
+ {
+ if (md->invMassPerDim[i][d] > 1.1*ALMOST_ZERO)
+ {
+ md->invMassPerDim[i][d] = md->invmass[i];
+ }
+ }
}
}
}
- md->tmass = L1*md->tmassA + lambda*md->tmassB;
- }
- else
- {
- md->tmass = md->tmassA;
+
+ /* Update the system mass for the change in lambda */
+ md->tmass = L1*md->tmassA + lambda*md->tmassB;
}
+
md->lambda = lambda;
}
*
* Copyright (c) 1991-2000, University of Groningen, The Netherlands.
* Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2010,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,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.
t_mdatoms *md);
/* This routine copies the atoms->atom struct into md.
* If index!=NULL only the indexed atoms are copied.
+ * For the masses the A-state (lambda=0) mass is used.
+ * Sets md->lambda = 0.
+ * In free-energy runs, update_mdatoms() should be called after atoms2md()
+ * to set the masses corresponding to the value of lambda at each step.
*/
void update_mdatoms(t_mdatoms *md, real lambda);
-/* (Re)set all the mass parameters */
+/* When necessary, sets all the mass parameters to values corresponding
+ * to the free-energy parameter lambda.
+ * Sets md->lambda = lambda.
+ */
#endif
*
* 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.
void update_energyhistory(energyhistory_t * enerhist, t_mdebin * mdebin)
{
- int i;
+ const t_ebin * const ebin = mdebin->ebin;
- enerhist->nsteps = mdebin->ebin->nsteps;
- enerhist->nsum = mdebin->ebin->nsum;
- enerhist->nsteps_sim = mdebin->ebin->nsteps_sim;
- enerhist->nsum_sim = mdebin->ebin->nsum_sim;
- enerhist->nener = mdebin->ebin->nener;
+ enerhist->nsteps = ebin->nsteps;
+ enerhist->nsum = ebin->nsum;
+ enerhist->nsteps_sim = ebin->nsteps_sim;
+ enerhist->nsum_sim = ebin->nsum_sim;
- if (mdebin->ebin->nsum > 0)
+ if (ebin->nsum > 0)
{
- /* Check if we need to allocate first */
- if (enerhist->ener_ave == NULL)
- {
- snew(enerhist->ener_ave, enerhist->nener);
- snew(enerhist->ener_sum, enerhist->nener);
- }
+ /* This will only actually resize the first time */
+ enerhist->ener_ave.resize(ebin->nener);
+ enerhist->ener_sum.resize(ebin->nener);
- for (i = 0; i < enerhist->nener; i++)
+ for (int i = 0; i < ebin->nener; i++)
{
- enerhist->ener_ave[i] = mdebin->ebin->e[i].eav;
- enerhist->ener_sum[i] = mdebin->ebin->e[i].esum;
+ enerhist->ener_ave[i] = ebin->e[i].eav;
+ enerhist->ener_sum[i] = ebin->e[i].esum;
}
}
- if (mdebin->ebin->nsum_sim > 0)
+ if (ebin->nsum_sim > 0)
{
- /* Check if we need to allocate first */
- if (enerhist->ener_sum_sim == NULL)
- {
- snew(enerhist->ener_sum_sim, enerhist->nener);
- }
+ /* This will only actually resize the first time */
+ enerhist->ener_sum_sim.resize(ebin->nener);
- for (i = 0; i < enerhist->nener; i++)
+ for (int i = 0; i < ebin->nener; i++)
{
- enerhist->ener_sum_sim[i] = mdebin->ebin->e_sim[i].esum;
+ enerhist->ener_sum_sim[i] = ebin->e_sim[i].esum;
}
}
if (mdebin->dhc)
void restore_energyhistory_from_state(t_mdebin * mdebin,
energyhistory_t * enerhist)
{
- int i;
+ unsigned int nener = static_cast<unsigned int>(mdebin->ebin->nener);
- if ((enerhist->nsum > 0 || enerhist->nsum_sim > 0) &&
- mdebin->ebin->nener != enerhist->nener)
+ if ((enerhist->nsum > 0 && nener != enerhist->ener_sum.size()) ||
+ (enerhist->nsum_sim > 0 && nener != enerhist->ener_sum_sim.size()))
{
- gmx_fatal(FARGS, "Mismatch between number of energies in run input (%d) and checkpoint file (%d).",
- mdebin->ebin->nener, enerhist->nener);
+ gmx_fatal(FARGS, "Mismatch between number of energies in run input (%d) and checkpoint file (%u or %u).",
+ nener, enerhist->ener_sum.size(), enerhist->ener_sum_sim.size());
}
mdebin->ebin->nsteps = enerhist->nsteps;
mdebin->ebin->nsteps_sim = enerhist->nsteps_sim;
mdebin->ebin->nsum_sim = enerhist->nsum_sim;
- for (i = 0; i < mdebin->ebin->nener; i++)
+ for (int i = 0; i < mdebin->ebin->nener; i++)
{
mdebin->ebin->e[i].eav =
(enerhist->nsum > 0 ? enerhist->ener_ave[i] : 0);
}
if (mdebin->dhc)
{
- mde_delta_h_coll_restore_energyhistory(mdebin->dhc, enerhist);
+ mde_delta_h_coll_restore_energyhistory(mdebin->dhc, enerhist->deltaHForeignLambdas.get());
}
}
*
* 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 "gromacs/mdtypes/forcerec.h"
#include "gromacs/mdtypes/state.h"
+class energyhistory_t;
struct gmx_constr;
struct gmx_ekindata_t;
struct gmx_mtop_t;
/* Between .edr writes, the averages are history dependent,
and that history needs to be retained in checkpoints.
- These functions set/read the energyhistory_t structure
+ These functions set/read the energyhistory_t class
that is written to checkpoints in checkpoint.c */
-/* Set the energyhistory_t data structure from a mdebin structure */
+/* Set the energyhistory_t data from a mdebin structure */
void update_energyhistory(energyhistory_t * enerhist, t_mdebin * mdebin);
-/* Read the energyhistory_t data structure to a mdebin structure*/
+/* Read the energyhistory_t data to a mdebin structure*/
void restore_energyhistory_from_state(t_mdebin * mdebin,
energyhistory_t * enerhist);
*
* 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 <math.h>
#include <string.h>
+#include <cassert>
+
#include "gromacs/fileio/enxio.h"
#include "gromacs/mdlib/mdebin.h"
#include "gromacs/mdtypes/energyhistory.h"
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/md_enums.h"
#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/smalloc.h"
/* reset the delta_h list to prepare it for new values */
dh->type = type;
dh->derivative = derivative;
- dh->lambda = lambda;
dh->nlambda = nlambda;
snew(dh->lambda, nlambda);
for (i = 0; i < nlambda; i++)
{
+ assert(lambda);
dh->lambda[i] = lambda[i];
}
}
/* set the energyhistory variables to save state */
-void mde_delta_h_coll_update_energyhistory(t_mde_delta_h_coll *dhc,
- energyhistory_t *enerhist)
+void mde_delta_h_coll_update_energyhistory(const t_mde_delta_h_coll *dhc,
+ energyhistory_t *enerhist)
{
- int i;
- if (!enerhist->dht)
+ if (enerhist->deltaHForeignLambdas == nullptr)
{
- snew(enerhist->dht, 1);
- snew(enerhist->dht->ndh, dhc->ndh);
- snew(enerhist->dht->dh, dhc->ndh);
- enerhist->dht->nndh = dhc->ndh;
+ enerhist->deltaHForeignLambdas.reset(new delta_h_history_t);
+ enerhist->deltaHForeignLambdas->dh.resize(dhc->ndh);
}
- else
- {
- if (enerhist->dht->nndh != dhc->ndh)
- {
- gmx_incons("energy history number of delta_h histograms != inputrec's number");
- }
- }
- for (i = 0; i < dhc->ndh; i++)
+
+ delta_h_history_t * const deltaH = enerhist->deltaHForeignLambdas.get();
+
+ GMX_RELEASE_ASSERT(deltaH->dh.size() == static_cast<size_t>(dhc->ndh), "energy history number of delta_h histograms should match inputrec's number");
+
+ for (int i = 0; i < dhc->ndh; i++)
{
- enerhist->dht->dh[i] = dhc->dh[i].dh;
- enerhist->dht->ndh[i] = dhc->dh[i].ndh;
+ std::vector<real> &dh = deltaH->dh[i];
+ dh.resize(dhc->dh[i].ndh);
+ std::copy(dh.begin(), dh.end(), dhc->dh[i].dh);
}
- enerhist->dht->start_time = dhc->start_time;
- enerhist->dht->start_lambda = dhc->start_lambda;
+ deltaH->start_time = dhc->start_time;
+ deltaH->start_lambda = dhc->start_lambda;
}
/* restore the variables from an energyhistory */
-void mde_delta_h_coll_restore_energyhistory(t_mde_delta_h_coll *dhc,
- energyhistory_t *enerhist)
+void mde_delta_h_coll_restore_energyhistory(t_mde_delta_h_coll *dhc,
+ const delta_h_history_t *deltaH)
{
- int i;
- unsigned int j;
-
- if (!dhc)
- {
- gmx_incons("No delta_h histograms found");
- }
- if (!enerhist->dht)
- {
- gmx_incons("No delta_h histograms found in energy history");
- }
- if (enerhist->dht->nndh != dhc->ndh)
- {
- gmx_incons("energy history number of delta_h histograms != inputrec's number");
- }
+ GMX_RELEASE_ASSERT(dhc, "Should have delta_h histograms");
+ GMX_RELEASE_ASSERT(deltaH, "Should have delta_h histograms in energy history");
+ GMX_RELEASE_ASSERT(deltaH->dh.size() == static_cast<size_t>(dhc->ndh), "energy history number of delta_h histograms should match inputrec's number");
- for (i = 0; i < enerhist->dht->nndh; i++)
+ for (unsigned int i = 0; i < deltaH->dh.size(); i++)
{
- dhc->dh[i].ndh = enerhist->dht->ndh[i];
- for (j = 0; j < dhc->dh[i].ndh; j++)
+ dhc->dh[i].ndh = deltaH->dh[i].size();
+ for (unsigned int j = 0; j < dhc->dh[i].ndh; j++)
{
- dhc->dh[i].dh[j] = enerhist->dht->dh[i][j];
+ dhc->dh[i].dh[j] = deltaH->dh[i][j];
}
}
- dhc->start_time = enerhist->dht->start_time;
- if (enerhist->dht->start_lambda_set)
+ dhc->start_time = deltaH->start_time;
+ if (deltaH->start_lambda_set)
{
- dhc->start_lambda = enerhist->dht->start_lambda;
+ dhc->start_lambda = deltaH->start_lambda;
}
if (dhc->dh[0].ndh > 0)
{
*
* 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 "gromacs/mdlib/mdebin.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
/* The functions & data structures here describe writing
energy differences (or their histogram )for use with g_bar */
+class delta_h_history_t;
+
/* Data for one foreign lambda, or derivative. */
typedef struct
{
/* set the energyhistory variables to save state */
-void mde_delta_h_coll_update_energyhistory(t_mde_delta_h_coll *dhc,
- energyhistory_t *enerhist);
+void mde_delta_h_coll_update_energyhistory(const t_mde_delta_h_coll *dhc,
+ energyhistory_t *enerhist);
/* restore the variables from an energyhistory */
-void mde_delta_h_coll_restore_energyhistory(t_mde_delta_h_coll *dhc,
- energyhistory_t *enerhist);
-
-
-#ifdef __cplusplus
-}
-#endif
+void mde_delta_h_coll_restore_energyhistory(t_mde_delta_h_coll *dhc,
+ const delta_h_history_t *enerhist);
#endif /* _mdebin_bar_h */
int elamstats;
int simulation_part;
FILE *fp_dhdl;
- FILE *fp_field;
int natoms_global;
int natoms_x_compressed;
gmx_groups_t *groups; /* for compressed position writing */
of->tng = NULL;
of->tng_low_prec = NULL;
of->fp_dhdl = NULL;
- of->fp_field = NULL;
of->eIntegrator = ir->eI;
of->bExpanded = ir->bExpanded;
}
}
- if (opt2bSet("-field", nfile, fnm) &&
- (ir->ex[XX].n || ir->ex[YY].n || ir->ex[ZZ].n))
- {
- if (bAppendFiles)
- {
- of->fp_field = gmx_fio_fopen(opt2fn("-field", nfile, fnm),
- filemode);
- }
- else
- {
- of->fp_field = xvgropen(opt2fn("-field", nfile, fnm),
- "Applied electric field", "Time (ps)",
- "E (V/nm)", oenv);
- }
- }
+ ir->efield->initOutput(fplog, nfile, fnm, bAppendFiles, oenv);
/* Set up atom counts so they can be passed to actual
trajectory-writing routines later. Also, XTC writing needs
return of;
}
-FILE *mdoutf_get_fp_field(gmx_mdoutf_t of)
-{
- return of->fp_field;
-}
-
ener_file_t mdoutf_get_fp_ene(gmx_mdoutf_t of)
{
return of->fp_ene;
gmx_mtop_t *top_global,
gmx_int64_t step, double t,
t_state *state_local, t_state *state_global,
- rvec *f_local)
+ energyhistory_t *energyHistory,
+ PaddedRVecVector *f_local)
{
- rvec *local_v;
- rvec *global_v;
rvec *f_global;
- /* MRS -- defining these variables is to manage the difference
- * between half step and full step velocities, but there must be a better way . . . */
-
- local_v = state_local->v;
- global_v = state_global->v;
-
if (DOMAINDECOMP(cr))
{
if (mdof_flags & MDOF_CPT)
{
if (mdof_flags & (MDOF_X | MDOF_X_COMPRESSED))
{
- dd_collect_vec(cr->dd, state_local, state_local->x,
- state_global->x);
+ dd_collect_vec(cr->dd, state_local, &state_local->x,
+ &state_global->x);
}
if (mdof_flags & MDOF_V)
{
- dd_collect_vec(cr->dd, state_local, local_v,
- global_v);
+ dd_collect_vec(cr->dd, state_local, &state_local->v,
+ &state_global->v);
}
}
f_global = of->f_global;
}
else
{
- if (mdof_flags & MDOF_CPT)
- {
- /* All pointers in state_local are equal to state_global,
- * but we need to copy the non-pointer entries.
- */
- state_global->lambda = state_local->lambda;
- state_global->veta = state_local->veta;
- state_global->vol0 = state_local->vol0;
- copy_mat(state_local->box, state_global->box);
- copy_mat(state_local->boxv, state_global->boxv);
- copy_mat(state_local->svir_prev, state_global->svir_prev);
- copy_mat(state_local->fvir_prev, state_global->fvir_prev);
- copy_mat(state_local->pres_prev, state_global->pres_prev);
- }
- f_global = f_local;
+ /* We have the whole state locally: copy the local state pointer */
+ state_global = state_local;
+
+ f_global = as_rvec_array(f_local->data());
}
if (MASTER(cr))
DOMAINDECOMP(cr) ? cr->dd->nc : one_ivec,
DOMAINDECOMP(cr) ? cr->dd->nnodes : cr->nnodes,
of->eIntegrator, of->simulation_part,
- of->bExpanded, of->elamstats, step, t, state_global);
+ of->bExpanded, of->elamstats, step, t,
+ state_global, energyHistory);
}
if (mdof_flags & (MDOF_X | MDOF_V | MDOF_F))
{
+ const rvec *x = (mdof_flags & MDOF_X) ? as_rvec_array(state_global->x.data()) : NULL;
+ const rvec *v = (mdof_flags & MDOF_V) ? as_rvec_array(state_global->v.data()) : NULL;
+ const rvec *f = (mdof_flags & MDOF_F) ? f_global : NULL;
+
if (of->fp_trn)
{
gmx_trr_write_frame(of->fp_trn, step, t, state_local->lambda[efptFEP],
state_local->box, top_global->natoms,
- (mdof_flags & MDOF_X) ? state_global->x : NULL,
- (mdof_flags & MDOF_V) ? global_v : NULL,
- (mdof_flags & MDOF_F) ? f_global : NULL);
+ x, v, f);
if (gmx_fio_flush(of->fp_trn) != 0)
{
gmx_file("Cannot write trajectory; maybe you are out of disk space?");
gmx_fwrite_tng(of->tng, FALSE, step, t, state_local->lambda[efptFEP],
state_local->box,
top_global->natoms,
- (mdof_flags & MDOF_X) ? state_global->x : NULL,
- (mdof_flags & MDOF_V) ? global_v : NULL,
- (mdof_flags & MDOF_F) ? f_global : NULL);
+ x, v, f);
}
/* If only a TNG file is open for compressed coordinate output (no uncompressed
coordinate output) also write forces and velocities to it. */
gmx_fwrite_tng(of->tng_low_prec, FALSE, step, t, state_local->lambda[efptFEP],
state_local->box,
top_global->natoms,
- (mdof_flags & MDOF_X) ? state_global->x : NULL,
- (mdof_flags & MDOF_V) ? global_v : NULL,
- (mdof_flags & MDOF_F) ? f_global : NULL);
+ x, v, f);
}
}
if (mdof_flags & MDOF_X_COMPRESSED)
{
/* We are writing the positions of all of the atoms to
the compressed output */
- xxtc = state_global->x;
+ xxtc = as_rvec_array(state_global->x.data());
}
else
{
}
}
-void done_mdoutf(gmx_mdoutf_t of)
+void done_mdoutf(gmx_mdoutf_t of, const t_inputrec *ir)
{
if (of->fp_ene != NULL)
{
{
gmx_fio_fclose(of->fp_dhdl);
}
- if (of->fp_field != NULL)
- {
- /* This is opened sometimes with xvgropen, sometimes with
- * gmx_fio_fopen, so we use the least common denominator for closing.
- */
- gmx_fio_fclose(of->fp_field);
- }
+ ir->efield->finishOutput();
if (of->f_global != NULL)
{
sfree(of->f_global);
/*
* 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.
#include "gromacs/timing/wallcycle.h"
#include "gromacs/utility/basedefinitions.h"
+class energyhistory_t;
struct gmx_mtop_t;
struct gmx_output_env_t;
struct t_commrec;
const gmx_output_env_t *oenv,
gmx_wallcycle_t wcycle);
-/*! \brief Getter for file pointer */
-FILE *mdoutf_get_fp_field(gmx_mdoutf_t of);
-
/*! \brief Getter for file pointer */
ener_file_t mdoutf_get_fp_ene(gmx_mdoutf_t of);
void mdoutf_tng_close(gmx_mdoutf_t of);
/*! \brief Close all open output files and free the of pointer */
-void done_mdoutf(gmx_mdoutf_t of);
+void done_mdoutf(gmx_mdoutf_t of, const t_inputrec *ir);
/*! \brief Routine that writes trajectory-like frames.
*
* Writes data to trn, xtc and/or checkpoint. What is written is
* determined by the mdof_flags defined below. Data is collected to
- * the master node only when necessary.
+ * the master node only when necessary. Without domain decomposition
+ * only data from state_local is used and state_global is ignored.
*/
void mdoutf_write_to_trajectory_files(FILE *fplog, t_commrec *cr,
gmx_mdoutf_t of,
gmx_mtop_t *top_global,
gmx_int64_t step, double t,
t_state *state_local, t_state *state_global,
- rvec *f_local);
+ energyhistory_t *energyHistory,
+ PaddedRVecVector *f_local);
#define MDOF_X (1<<0)
#define MDOF_V (1<<1)
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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
#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"
#include "gromacs/mdlib/mdatoms.h"
#include "gromacs/mdlib/mdebin.h"
#include "gromacs/mdlib/mdrun.h"
+#include "gromacs/mdlib/mdsetup.h"
#include "gromacs/mdlib/ns.h"
#include "gromacs/mdlib/shellfc.h"
#include "gromacs/mdlib/sim_util.h"
#include "gromacs/timing/wallcycle.h"
#include "gromacs/timing/walltime_accounting.h"
#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/topology.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/logger.h"
#include "gromacs/utility/smalloc.h"
//! Utility structure for manipulating states during EM
typedef struct {
//! Copy of the global state
- t_state s;
+ t_state s;
//! Force array
- rvec *f;
+ PaddedRVecVector f;
//! Potential energy
- real epot;
+ real epot;
//! Norm of the force
- real fnorm;
+ real fnorm;
//! Maximum force
- real fmax;
+ real fmax;
//! Direction
- int a_fmax;
+ int a_fmax;
} em_state_t;
-//! Initiate em_state_t structure and return pointer to it
-static em_state_t *init_em_state()
-{
- em_state_t *ems;
-
- snew(ems, 1);
-
- /* does this need to be here? Should the array be declared differently (staticaly)in the state definition? */
- snew(ems->s.lambda, efptNR);
-
- return ems;
-}
-
//! Print the EM starting conditions
static void print_em_start(FILE *fplog,
t_commrec *cr,
//! Print message about convergence of the EM
static void print_converged(FILE *fp, const char *alg, real ftol,
gmx_int64_t count, gmx_bool bDone, gmx_int64_t nsteps,
- real epot, real fmax, int nfmax, real fnorm)
+ const em_state_t *ems, double sqrtNumAtoms)
{
char buf[STEPSTRSIZE];
}
#if GMX_DOUBLE
- fprintf(fp, "Potential Energy = %21.14e\n", epot);
- fprintf(fp, "Maximum force = %21.14e on atom %d\n", fmax, nfmax+1);
- fprintf(fp, "Norm of force = %21.14e\n", fnorm);
+ fprintf(fp, "Potential Energy = %21.14e\n", ems->epot);
+ fprintf(fp, "Maximum force = %21.14e on atom %d\n", ems->fmax, ems->a_fmax + 1);
+ fprintf(fp, "Norm of force = %21.14e\n", ems->fnorm/sqrtNumAtoms);
#else
- fprintf(fp, "Potential Energy = %14.7e\n", epot);
- fprintf(fp, "Maximum force = %14.7e on atom %d\n", fmax, nfmax+1);
- fprintf(fp, "Norm of force = %14.7e\n", fnorm);
+ fprintf(fp, "Potential Energy = %14.7e\n", ems->epot);
+ fprintf(fp, "Maximum force = %14.7e on atom %d\n", ems->fmax, ems->a_fmax + 1);
+ fprintf(fp, "Norm of force = %14.7e\n", ems->fnorm/sqrtNumAtoms);
#endif
}
//! Compute the norm and max of the force array in parallel
static void get_f_norm_max(t_commrec *cr,
- t_grpopts *opts, t_mdatoms *mdatoms, rvec *f,
+ t_grpopts *opts, t_mdatoms *mdatoms, const rvec *f,
real *fnorm, real *fmax, int *a_fmax)
{
double fnorm2, *sum;
t_grpopts *opts, t_mdatoms *mdatoms,
em_state_t *ems)
{
- get_f_norm_max(cr, opts, mdatoms, ems->f, &ems->fnorm, &ems->fmax, &ems->a_fmax);
+ get_f_norm_max(cr, opts, mdatoms, as_rvec_array(ems->f.data()),
+ &ems->fnorm, &ems->fmax, &ems->a_fmax);
}
//! Initialize the energy minimization
t_commrec *cr, t_inputrec *ir,
t_state *state_global, gmx_mtop_t *top_global,
em_state_t *ems, gmx_localtop_t **top,
- rvec **f,
t_nrnb *nrnb, rvec mu_tot,
t_forcerec *fr, gmx_enerdata_t **enerd,
t_graph **graph, t_mdatoms *mdatoms, gmx_global_stat_t *gstat,
- gmx_vsite_t *vsite, gmx_constr_t constr,
+ gmx_vsite_t *vsite, gmx_constr_t constr, gmx_shellfc_t **shellfc,
int nfile, const t_filenm fnm[],
gmx_mdoutf_t *outf, t_mdebin **mdebin,
int imdport, unsigned long gmx_unused Flags,
gmx_wallcycle_t wcycle)
{
- int i;
real dvdl_constr;
if (fplog)
state_global->ngtc = 0;
/* Initialize lambda variables */
- initialize_lambdas(fplog, ir, &(state_global->fep_state), state_global->lambda, NULL);
+ initialize_lambdas(fplog, ir, &(state_global->fep_state), &state_global->lambda, NULL);
init_nrnb(nrnb);
/* Interactive molecular dynamics */
- init_IMD(ir, cr, top_global, fplog, 1, state_global->x,
+ init_IMD(ir, cr, top_global, fplog, 1, as_rvec_array(state_global->x.data()),
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);
dd_init_local_state(cr->dd, state_global, &ems->s);
- *f = NULL;
-
/* Distribute the charge groups over the nodes from the master node */
dd_partition_system(fplog, ir->init_step, cr, TRUE, 1,
state_global, top_global, ir,
}
else
{
- snew(*f, top_global->natoms);
-
/* Just copy the state */
ems->s = *state_global;
/* We need to allocate one element extra, since we might use
* (unaligned) 4-wide SIMD loads to access rvec entries.
*/
- snew(ems->s.x, ems->s.nalloc + 1);
- snew(ems->f, ems->s.nalloc+1);
- snew(ems->s.v, ems->s.nalloc+1);
- for (i = 0; i < state_global->natoms; i++)
- {
- copy_rvec(state_global->x[i], ems->s.x[i]);
- }
- copy_mat(state_global->box, ems->s.box);
+ ems->s.x.resize(ems->s.natoms + 1);
+ ems->f.resize(ems->s.natoms + 1);
- *top = gmx_mtop_generate_local_top(top_global, ir->efep != efepNO);
+ snew(*top, 1);
+ mdAlgorithmsSetupAtomData(cr, ir, top_global, *top, fr,
+ graph, mdatoms,
+ vsite, shellfc ? *shellfc : NULL);
- setup_bonded_threading(fr, &(*top)->idef);
-
- if (ir->ePBC != epbcNONE && !fr->bMolPBC)
- {
- *graph = mk_graph(fplog, &((*top)->idef), 0, top_global->natoms, FALSE, FALSE);
- }
- else
- {
- *graph = NULL;
- }
-
- atoms2md(top_global, ir, 0, NULL, top_global->natoms, mdatoms);
update_mdatoms(mdatoms, state_global->lambda[efptFEP]);
if (vsite)
dvdl_constr = 0;
constrain(PAR(cr) ? NULL : fplog, TRUE, TRUE, constr, &(*top)->idef,
ir, cr, -1, 0, 1.0, mdatoms,
- ems->s.x, ems->s.x, NULL, fr->bMolPBC, ems->s.box,
+ as_rvec_array(ems->s.x.data()),
+ as_rvec_array(ems->s.x.data()),
+ NULL,
+ fr->bMolPBC, ems->s.box,
ems->s.lambda[efptFEP], &dvdl_constr,
NULL, NULL, nrnb, econqCoord);
}
}
//! Finalize the minimization
-static void finish_em(t_commrec *cr, gmx_mdoutf_t outf,
+static void finish_em(t_commrec *cr, gmx_mdoutf_t outf, const t_inputrec *ir,
gmx_walltime_accounting_t walltime_accounting,
gmx_wallcycle_t wcycle)
{
gmx_pme_send_finish(cr);
}
- done_mdoutf(outf);
+ done_mdoutf(outf, ir);
em_time_end(walltime_accounting, wcycle);
}
//! Swap two different EM states during minimization
-static void swap_em_state(em_state_t *ems1, em_state_t *ems2)
+static void swap_em_state(em_state_t **ems1, em_state_t **ems2)
{
- em_state_t tmp;
+ em_state_t *tmp;
tmp = *ems1;
*ems1 = *ems2;
*ems2 = tmp;
}
-//! Copy coordinate from an EM state to a "normal" state structure
-static void copy_em_coords(em_state_t *ems, t_state *state)
-{
- int i;
-
- for (i = 0; (i < state->natoms); i++)
- {
- copy_rvec(ems->s.x[i], state->x[i]);
- }
-}
-
//! Save the EM trajectory
static void write_em_traj(FILE *fplog, t_commrec *cr,
gmx_mdoutf_t outf,
gmx_mtop_t *top_global,
t_inputrec *ir, gmx_int64_t step,
em_state_t *state,
- t_state *state_global)
+ t_state *state_global,
+ energyhistory_t *energyHistory)
{
- int mdof_flags;
- gmx_bool bIMDout = FALSE;
-
-
- /* Shall we do IMD output? */
- if (ir->bIMD)
- {
- bIMDout = do_per_step(step, IMD_get_step(ir->imd->setup));
- }
-
- if ((bX || bF || bIMDout || confout != NULL) && !DOMAINDECOMP(cr))
- {
- copy_em_coords(state, state_global);
- }
+ int mdof_flags = 0;
- mdof_flags = 0;
if (bX)
{
mdof_flags |= MDOF_X;
mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags,
top_global, step, (double)step,
- &state->s, state_global, state->f);
+ &state->s, state_global, energyHistory,
+ &state->f);
if (confout != NULL && MASTER(cr))
{
{
/* Make molecules whole only for confout writing */
do_pbc_mtop(fplog, ir->ePBC, state_global->box, top_global,
- state_global->x);
+ as_rvec_array(state_global->x.data()));
}
write_sto_conf_mtop(confout,
*top_global->name, top_global,
- state_global->x, NULL, ir->ePBC, state_global->box);
+ as_rvec_array(state_global->x.data()), NULL, ir->ePBC, state_global->box);
}
}
// \returns true when the step succeeded, false when a constraint error occurred
static bool do_em_step(t_commrec *cr, t_inputrec *ir, t_mdatoms *md,
gmx_bool bMolPBC,
- em_state_t *ems1, real a, rvec *f, em_state_t *ems2,
+ em_state_t *ems1, real a, const PaddedRVecVector *force,
+ em_state_t *ems2,
gmx_constr_t constr, gmx_localtop_t *top,
t_nrnb *nrnb, gmx_wallcycle_t wcycle,
gmx_int64_t count)
s2->flags = s1->flags;
- if (s2->nalloc != s1->nalloc)
+ if (s2->natoms != s1->natoms)
{
- s2->nalloc = s1->nalloc;
+ s2->natoms = s1->natoms;
/* We need to allocate one element extra, since we might use
* (unaligned) 4-wide SIMD loads to access rvec entries.
*/
- srenew(s2->x, s1->nalloc + 1);
- srenew(ems2->f, s1->nalloc);
+ s2->x.resize(s1->natoms + 1);
+ ems2->f.resize(s1->natoms + 1);
if (s2->flags & (1<<estCGP))
{
- srenew(s2->cg_p, s1->nalloc + 1);
+ s2->cg_p.resize(s1->natoms + 1);
}
}
+ if (DOMAINDECOMP(cr) && s2->cg_gl.size() != s1->cg_gl.size())
+ {
+ s2->cg_gl.resize(s1->cg_gl.size());
+ }
s2->natoms = s1->natoms;
copy_mat(s1->box, s2->box);
/* Copy free energy state */
- for (int i = 0; i < efptNR; i++)
- {
- s2->lambda[i] = s1->lambda[i];
- }
+ s2->lambda = s1->lambda;
copy_mat(s1->box, s2->box);
start = 0;
nthreads = gmx_omp_nthreads_get(emntUpdate);
#pragma omp parallel num_threads(nthreads)
{
- rvec *x1 = s1->x;
- rvec *x2 = s2->x;
+ const rvec *x1 = as_rvec_array(s1->x.data());
+ rvec *x2 = as_rvec_array(s2->x.data());
+ const rvec *f = as_rvec_array(force->data());
- int gf = 0;
+ int gf = 0;
#pragma omp for schedule(static) nowait
for (int i = start; i < end; i++)
{
if (s2->flags & (1<<estCGP))
{
/* Copy the CG p vector */
- rvec *p1 = s1->cg_p;
- rvec *p2 = s2->cg_p;
+ const rvec *p1 = as_rvec_array(s1->cg_p.data());
+ rvec *p2 = as_rvec_array(s2->cg_p.data());
#pragma omp for schedule(static) nowait
for (int i = start; i < end; i++)
{
if (DOMAINDECOMP(cr))
{
s2->ddp_count = s1->ddp_count;
- if (s2->cg_gl_nalloc < s1->cg_gl_nalloc)
- {
-#pragma omp barrier
- s2->cg_gl_nalloc = s1->cg_gl_nalloc;
- try
- {
- /* We need to allocate one element extra, since we might use
- * (unaligned) 4-wide SIMD loads to access rvec entries.
- */
- srenew(s2->cg_gl, s2->cg_gl_nalloc + 1);
- }
- GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
-#pragma omp barrier
- }
- s2->ncg_gl = s1->ncg_gl;
+
+ /* OpenMP does not supported unsigned loop variables */
#pragma omp for schedule(static) nowait
- for (int i = 0; i < s2->ncg_gl; i++)
+ for (int i = 0; i < static_cast<int>(s2->cg_gl.size()); i++)
{
s2->cg_gl[i] = s1->cg_gl[i];
}
validStep =
constrain(NULL, TRUE, TRUE, constr, &top->idef,
ir, cr, count, 0, 1.0, md,
- s1->x, s2->x, NULL, bMolPBC, s2->box,
+ as_rvec_array(s1->x.data()), as_rvec_array(s2->x.data()),
+ NULL, bMolPBC, s2->box,
s2->lambda[efptBONDED], &dvdl_constr,
NULL, NULL, nrnb, econqCoord);
wallcycle_stop(wcycle, ewcCONSTR);
if (vsite)
{
- construct_vsites(vsite, ems->s.x, 1, NULL,
+ construct_vsites(vsite, as_rvec_array(ems->s.x.data()), 1, NULL,
top->idef.iparams, top->idef.il,
fr->ePBC, fr->bMolPBC, cr, ems->s.box);
}
*/
do_force(fplog, cr, inputrec,
count, nrnb, wcycle, top, &top_global->groups,
- ems->s.box, ems->s.x, &ems->s.hist,
- ems->f, force_vir, mdatoms, enerd, fcd,
- ems->s.lambda, graph, fr, vsite, mu_tot, t, NULL, NULL, TRUE,
+ ems->s.box, &ems->s.x, &ems->s.hist,
+ &ems->f, force_vir, mdatoms, enerd, fcd,
+ &ems->s.lambda, graph, fr, vsite, mu_tot, t, NULL, TRUE,
GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES |
GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY |
(bNS ? GMX_FORCE_NS : 0));
/* Project out the constraint components of the force */
wallcycle_start(wcycle, ewcCONSTR);
dvdl_constr = 0;
+ rvec *f_rvec = as_rvec_array(ems->f.data());
constrain(NULL, FALSE, FALSE, constr, &top->idef,
inputrec, cr, count, 0, 1.0, mdatoms,
- ems->s.x, ems->f, ems->f, fr->bMolPBC, ems->s.box,
+ as_rvec_array(ems->s.x.data()), f_rvec, f_rvec,
+ fr->bMolPBC, ems->s.box,
ems->s.lambda[efptBONDED], &dvdl_constr,
NULL, &shake_vir, nrnb, econqForceDispl);
enerd->term[F_DVDL_CONSTR] += dvdl_constr;
enerd->term[F_PRES] =
calc_pres(fr->ePBC, inputrec->nwall, ems->s.box, ekin, vir, pres);
- sum_dhdl(enerd, ems->s.lambda, inputrec->fepvals);
+ sum_dhdl(enerd, &ems->s.lambda, inputrec->fepvals);
if (EI_ENERGY_MINIMIZATION(inputrec->eI))
{
gmx_mtop_t *top_global,
em_state_t *s_min, em_state_t *s_b)
{
- rvec *fm, *fb, *fmg;
t_block *cgs_gl;
int ncg, *cg_gl, *index, c, cg, i, a0, a1, a, gf, m;
double partsum;
fprintf(debug, "Doing reorder_partsum\n");
}
- fm = s_min->f;
- fb = s_b->f;
+ const rvec *fm = as_rvec_array(s_min->f.data());
+ const rvec *fb = as_rvec_array(s_b->f.data());
cgs_gl = dd_charge_groups_global(cr->dd);
index = cgs_gl->index;
* This conflicts with the spirit of domain decomposition,
* but to fully optimize this a much more complicated algorithm is required.
*/
+ rvec *fmg;
snew(fmg, top_global->natoms);
- ncg = s_min->s.ncg_gl;
- cg_gl = s_min->s.cg_gl;
+ ncg = s_min->s.cg_gl.size();
+ cg_gl = s_min->s.cg_gl.data();
i = 0;
for (c = 0; c < ncg; c++)
{
gmx_sum(top_global->natoms*3, fmg[0], cr);
/* Now we will determine the part of the sum for the cgs in state s_b */
- ncg = s_b->s.ncg_gl;
- cg_gl = s_b->s.cg_gl;
+ ncg = s_b->s.cg_gl.size();
+ cg_gl = s_b->s.cg_gl.data();
partsum = 0;
i = 0;
gf = 0;
gmx_mtop_t *top_global,
em_state_t *s_min, em_state_t *s_b)
{
- rvec *fm, *fb;
double sum;
- int gf, i, m;
/* This is just the classical Polak-Ribiere calculation of beta;
* it looks a bit complicated since we take freeze groups into account,
(s_min->s.ddp_count == cr->dd->ddp_count &&
s_b->s.ddp_count == cr->dd->ddp_count))
{
- fm = s_min->f;
- fb = s_b->f;
- sum = 0;
- gf = 0;
+ const rvec *fm = as_rvec_array(s_min->f.data());
+ const rvec *fb = as_rvec_array(s_b->f.data());
+ sum = 0;
+ int gf = 0;
/* This part of code can be incorrect with DD,
* since the atom ordering in s_b and s_min might differ.
*/
- for (i = 0; i < mdatoms->homenr; i++)
+ for (int i = 0; i < mdatoms->homenr; i++)
{
if (mdatoms->cFREEZE)
{
gf = mdatoms->cFREEZE[i];
}
- for (m = 0; m < DIM; m++)
+ for (int m = 0; m < DIM; m++)
{
if (!opts->nFreeze[gf][m])
{
{
/*! \brief Do conjugate gradients minimization
- \copydoc integrator_t (FILE *fplog, t_commrec *cr,
+ \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
int nfile, const t_filenm fnm[],
const gmx_output_env_t *oenv, gmx_bool bVerbose,
int nstglobalcomm,
unsigned long Flags,
gmx_walltime_accounting_t walltime_accounting)
*/
-double do_cg(FILE *fplog, t_commrec *cr,
+double do_cg(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog,
int nfile, const t_filenm fnm[],
const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
int gmx_unused nstglobalcomm,
t_inputrec *inputrec,
gmx_mtop_t *top_global, t_fcdata *fcd,
t_state *state_global,
+ energyhistory_t *energyHistory,
t_mdatoms *mdatoms,
t_nrnb *nrnb, gmx_wallcycle_t wcycle,
gmx_edsam_t gmx_unused ed,
{
const char *CG = "Polak-Ribiere Conjugate Gradients";
- em_state_t *s_min, *s_a, *s_b, *s_c;
gmx_localtop_t *top;
gmx_enerdata_t *enerd;
- rvec *f;
gmx_global_stat_t gstat;
t_graph *graph;
- rvec *p, *sf;
- double gpa, gpb, gpc, tmp, minstep;
- real fnormn;
+ double tmp, minstep;
real stepsize;
real a, b, c, beta = 0.0;
real epot_repl = 0;
tensor vir, pres;
int number_steps, neval = 0, nstcg = inputrec->nstcgsteep;
gmx_mdoutf_t outf;
- int i, m, gf, step, nminstep;
+ int m, step, nminstep;
step = 0;
- s_min = init_em_state();
- s_a = init_em_state();
- s_b = init_em_state();
- s_c = init_em_state();
+ /* Create 4 states on the stack and extract pointers that we will swap */
+ em_state_t s0 {}, s1 {}, s2 {}, s3 {};
+ em_state_t *s_min = &s0;
+ em_state_t *s_a = &s1;
+ em_state_t *s_b = &s2;
+ em_state_t *s_c = &s3;
/* Init em and store the local state in s_min */
init_em(fplog, CG, cr, inputrec,
- state_global, top_global, s_min, &top, &f,
- nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
+ state_global, top_global, s_min, &top,
+ nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
+ vsite, constr, NULL,
nfile, fnm, &outf, &mdebin, imdport, Flags, wcycle);
/* Print to log file */
*/
/* Calculate the new direction in p, and the gradient in this direction, gpa */
- p = s_min->s.cg_p;
- sf = s_min->f;
- gpa = 0;
- gf = 0;
- for (i = 0; i < mdatoms->homenr; i++)
+ rvec *pm = as_rvec_array(s_min->s.cg_p.data());
+ const rvec *sfm = as_rvec_array(s_min->f.data());
+ double gpa = 0;
+ int gf = 0;
+ for (int i = 0; i < mdatoms->homenr; i++)
{
if (mdatoms->cFREEZE)
{
{
if (!inputrec->opts.nFreeze[gf][m])
{
- p[i][m] = sf[i][m] + beta*p[i][m];
- gpa -= p[i][m]*sf[i][m];
+ pm[i][m] = sfm[i][m] + beta*pm[i][m];
+ gpa -= pm[i][m]*sfm[i][m];
/* f is negative gradient, thus the sign */
}
else
{
- p[i][m] = 0;
+ pm[i][m] = 0;
}
}
}
}
/* Calculate the norm of the search vector */
- get_f_norm_max(cr, &(inputrec->opts), mdatoms, p, &pnorm, NULL, NULL);
+ get_f_norm_max(cr, &(inputrec->opts), mdatoms, pm, &pnorm, NULL, NULL);
/* Just in case stepsize reaches zero due to numerical precision... */
if (stepsize <= 0)
* relative change in coordinate is smaller than precision
*/
minstep = 0;
- for (i = 0; i < mdatoms->homenr; i++)
+ for (int i = 0; i < mdatoms->homenr; i++)
{
for (m = 0; m < DIM; m++)
{
{
tmp = 1.0;
}
- tmp = p[i][m]/tmp;
+ tmp = pm[i][m]/tmp;
minstep += tmp*tmp;
}
}
write_em_traj(fplog, cr, outf, do_x, do_f, NULL,
top_global, inputrec, step,
- s_min, state_global);
+ s_min, state_global, energyHistory);
/* Take a step downhill.
* In theory, we should minimize the function along this direction.
}
/* Take a trial step (new coords in s_c) */
- do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, c, s_min->s.cg_p, s_c,
+ do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, c, &s_min->s.cg_p, s_c,
constr, top, nrnb, wcycle, -1);
neval++;
mu_tot, enerd, vir, pres, -1, FALSE);
/* Calc derivative along line */
- p = s_c->s.cg_p;
- sf = s_c->f;
- gpc = 0;
- for (i = 0; i < mdatoms->homenr; i++)
+ const rvec *pc = as_rvec_array(s_c->s.cg_p.data());
+ const rvec *sfc = as_rvec_array(s_c->f.data());
+ double gpc = 0;
+ for (int i = 0; i < mdatoms->homenr; i++)
{
for (m = 0; m < DIM; m++)
{
- gpc -= p[i][m]*sf[i][m]; /* f is negative gradient, thus the sign */
+ gpc -= pc[i][m]*sfc[i][m]; /* f is negative gradient, thus the sign */
}
}
/* Sum the gradient along the line across CPUs */
*
* If we already found a lower value we just skip this step and continue to the update.
*/
+ double gpb;
if (!foundlower)
{
nminstep = 0;
}
/* Take a trial step to this new point - new coords in s_b */
- do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, b, s_min->s.cg_p, s_b,
+ do_em_step(cr, inputrec, mdatoms, fr->bMolPBC, s_min, b, &s_min->s.cg_p, s_b,
constr, top, nrnb, wcycle, -1);
neval++;
/* p does not change within a step, but since the domain decomposition
* might change, we have to use cg_p of s_b here.
*/
- p = s_b->s.cg_p;
- sf = s_b->f;
- gpb = 0;
- for (i = 0; i < mdatoms->homenr; i++)
+ const rvec *pb = as_rvec_array(s_b->s.cg_p.data());
+ const rvec *sfb = as_rvec_array(s_b->f.data());
+ gpb = 0;
+ for (int i = 0; i < mdatoms->homenr; i++)
{
for (m = 0; m < DIM; m++)
{
- gpb -= p[i][m]*sf[i][m]; /* f is negative gradient, thus the sign */
+ gpb -= pb[i][m]*sfb[i][m]; /* f is negative gradient, thus the sign */
}
}
/* Sum the gradient along the line across CPUs */
if (gpb > 0)
{
/* Replace c endpoint with b */
- swap_em_state(s_b, s_c);
+ swap_em_state(&s_b, &s_c);
c = b;
gpc = gpb;
}
else
{
/* Replace a endpoint with b */
- swap_em_state(s_b, s_a);
+ swap_em_state(&s_b, &s_a);
a = b;
gpa = gpb;
}
fprintf(debug, "CGE: C (%f) is lower than A (%f), moving C to B\n",
s_c->epot, s_a->epot);
}
- swap_em_state(s_b, s_c);
+ swap_em_state(&s_b, &s_c);
gpb = gpc;
}
else
fprintf(debug, "CGE: A (%f) is lower than C (%f), moving A to B\n",
s_a->epot, s_c->epot);
}
- swap_em_state(s_b, s_a);
+ swap_em_state(&s_b, &s_a);
gpb = gpa;
}
fprintf(debug, "CGE: Found a lower energy %f, moving C to B\n",
s_c->epot);
}
- swap_em_state(s_b, s_c);
+ swap_em_state(&s_b, &s_c);
gpb = gpc;
}
/* update positions */
- swap_em_state(s_min, s_b);
+ swap_em_state(&s_min, &s_b);
gpa = gpb;
/* Print it if necessary */
}
/* Send energies and positions to the IMD client if bIMD is TRUE. */
- if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, state_global->x, inputrec, 0, wcycle) && MASTER(cr))
+ if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, as_rvec_array(state_global->x.data()), inputrec, 0, wcycle) && MASTER(cr))
{
IMD_send_positions(inputrec->imd);
}
write_em_traj(fplog, cr, outf, do_x, do_f, ftp2fn(efSTO, nfile, fnm),
top_global, inputrec, step,
- s_min, state_global);
+ s_min, state_global, energyHistory);
if (MASTER(cr))
{
double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
- fnormn = s_min->fnorm/sqrtNumAtoms;
print_converged(stderr, CG, inputrec->em_tol, step, converged, number_steps,
- s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
+ s_min, sqrtNumAtoms);
print_converged(fplog, CG, inputrec->em_tol, step, converged, number_steps,
- s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
+ s_min, sqrtNumAtoms);
fprintf(fplog, "\nPerformed %d energy evaluations in total.\n", neval);
}
- finish_em(cr, outf, walltime_accounting, wcycle);
+ finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
/* To print the actual number of steps we needed somewhere */
walltime_accounting_set_nsteps_done(walltime_accounting, step);
/*! \brief Do L-BFGS conjugate gradients minimization
- \copydoc integrator_t (FILE *fplog, t_commrec *cr,
- int nfile, const t_filenm fnm[],
- const gmx_output_env_t *oenv, gmx_bool bVerbose,
- int nstglobalcomm,
- gmx_vsite_t *vsite, gmx_constr_t constr,
- int stepout,
- t_inputrec *inputrec,
- gmx_mtop_t *top_global, t_fcdata *fcd,
- t_state *state_global,
- t_mdatoms *mdatoms,
- t_nrnb *nrnb, gmx_wallcycle_t wcycle,
- gmx_edsam_t ed,
- t_forcerec *fr,
- int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
- real cpt_period, real max_hours,
- int imdport,
- unsigned long Flags,
- gmx_walltime_accounting_t walltime_accounting)
+ \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
+ int nfile, const t_filenm fnm[],
+ const gmx_output_env_t *oenv, gmx_bool bVerbose,
+ int nstglobalcomm,
+ gmx_vsite_t *vsite, gmx_constr_t constr,
+ int stepout,
+ t_inputrec *inputrec,
+ gmx_mtop_t *top_global, t_fcdata *fcd,
+ t_state *state_global,
+ t_mdatoms *mdatoms,
+ t_nrnb *nrnb, gmx_wallcycle_t wcycle,
+ gmx_edsam_t ed,
+ t_forcerec *fr,
+ int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
+ real cpt_period, real max_hours,
+ int imdport,
+ unsigned long Flags,
+ gmx_walltime_accounting_t walltime_accounting)
*/
-double do_lbfgs(FILE *fplog, t_commrec *cr,
+double do_lbfgs(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog,
int nfile, const t_filenm fnm[],
const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
int gmx_unused nstglobalcomm,
t_inputrec *inputrec,
gmx_mtop_t *top_global, t_fcdata *fcd,
t_state *state_global,
+ energyhistory_t *energyHistory,
t_mdatoms *mdatoms,
t_nrnb *nrnb, gmx_wallcycle_t wcycle,
gmx_edsam_t gmx_unused ed,
em_state_t ems;
gmx_localtop_t *top;
gmx_enerdata_t *enerd;
- rvec *f;
gmx_global_stat_t gstat;
t_graph *graph;
int ncorr, nmaxcorr, point, cp, neval, nminstep;
double stepsize, step_taken, gpa, gpb, gpc, tmp, minstep;
- real *rho, *alpha, *ff, *xx, *p, *s, *lastx, *lastf, **dx, **dg;
- real *xa, *xb, *xc, *fa, *fb, *fc, *xtmp, *ftmp;
+ real *rho, *alpha, *p, *s, **dx, **dg;
real a, b, c, maxdelta, delta;
- real diag, Epot0, Epot, EpotA, EpotB, EpotC;
+ real diag, Epot0;
real dgdx, dgdg, sq, yr, beta;
t_mdebin *mdebin;
gmx_bool converged;
rvec mu_tot;
- real fnorm, fmax;
gmx_bool do_log, do_ene, do_x, do_f, foundlower, *frozen;
tensor vir, pres;
int start, end, number_steps;
gmx_mdoutf_t outf;
- int i, k, m, n, nfmax, gf, step;
+ int i, k, m, n, gf, step;
int mdof_flags;
if (PAR(cr))
n = 3*state_global->natoms;
nmaxcorr = inputrec->nbfgscorr;
- /* Allocate memory */
- /* Use pointers to real so we dont have to loop over both atoms and
- * dimensions all the time...
- * x/f are allocated as rvec *, so make new x0/f0 pointers-to-real
- * that point to the same memory.
- */
- snew(xa, n);
- snew(xb, n);
- snew(xc, n);
- snew(fa, n);
- snew(fb, n);
- snew(fc, n);
snew(frozen, n);
snew(p, n);
- snew(lastx, n);
- snew(lastf, n);
snew(rho, nmaxcorr);
snew(alpha, nmaxcorr);
/* Init em */
init_em(fplog, LBFGS, cr, inputrec,
- state_global, top_global, &ems, &top, &f,
- nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
+ state_global, top_global, &ems, &top,
+ nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
+ vsite, constr, 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.
- */
- sfree(ems.s.x);
- sfree(ems.f);
-
- xx = (real *)state_global->x;
- ff = (real *)f;
start = 0;
end = mdatoms->homenr;
+ /* We need 4 working states */
+ em_state_t s0 {}, s1 {}, s2 {}, s3 {};
+ em_state_t *sa = &s0;
+ em_state_t *sb = &s1;
+ em_state_t *sc = &s2;
+ em_state_t *last = &s3;
+ /* Initialize by copying the state from ems (we could skip x and f here) */
+ *sa = ems;
+ *sb = ems;
+ *sc = ems;
+
/* Print to log file */
print_em_start(fplog, cr, walltime_accounting, wcycle, LBFGS);
if (vsite)
{
- construct_vsites(vsite, state_global->x, 1, NULL,
+ construct_vsites(vsite, as_rvec_array(state_global->x.data()), 1, NULL,
top->idef.iparams, top->idef.il,
fr->ePBC, fr->bMolPBC, cr, state_global->box);
}
* We do not unshift, so molecules are always whole
*/
neval++;
- ems.s.x = state_global->x;
- ems.f = f;
evaluate_energy(fplog, cr,
top_global, &ems, top,
inputrec, nrnb, wcycle, gstat,
}
where();
- /* This is the starting energy */
- Epot = enerd->term[F_EPOT];
-
- fnorm = ems.fnorm;
- fmax = ems.fmax;
- nfmax = ems.a_fmax;
-
/* Set the initial step.
* since it will be multiplied by the non-normalized search direction
* vector (force vector the first time), we scale it by the
{
double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
fprintf(stderr, "Using %d BFGS correction steps.\n\n", nmaxcorr);
- fprintf(stderr, " F-max = %12.5e on atom %d\n", fmax, nfmax+1);
- fprintf(stderr, " F-Norm = %12.5e\n", fnorm/sqrtNumAtoms);
+ fprintf(stderr, " F-max = %12.5e on atom %d\n", ems.fmax, ems.a_fmax + 1);
+ fprintf(stderr, " F-Norm = %12.5e\n", ems.fnorm/sqrtNumAtoms);
fprintf(stderr, "\n");
/* and copy to the log file too... */
fprintf(fplog, "Using %d BFGS correction steps.\n\n", nmaxcorr);
- fprintf(fplog, " F-max = %12.5e on atom %d\n", fmax, nfmax+1);
- fprintf(fplog, " F-Norm = %12.5e\n", fnorm/sqrtNumAtoms);
+ fprintf(fplog, " F-max = %12.5e on atom %d\n", ems.fmax, ems.a_fmax + 1);
+ fprintf(fplog, " F-Norm = %12.5e\n", ems.fnorm/sqrtNumAtoms);
fprintf(fplog, "\n");
}
point = 0;
// Set initial search direction to the force (-gradient), or 0 for frozen particles.
+ real *fInit = static_cast<real *>(as_rvec_array(ems.f.data())[0]);
for (i = 0; i < n; i++)
{
if (!frozen[i])
{
- dx[point][i] = ff[i]; /* Initial search direction */
+ dx[point][i] = fInit[i]; /* Initial search direction */
}
else
{
// (the main efficiency in the algorithm comes from changing directions), but
// we still need an initial value, so estimate it as the inverse of the norm
// so we take small steps where the potential fluctuates a lot.
- stepsize = 1.0/fnorm;
+ stepsize = 1.0/ems.fnorm;
/* Start the loop over BFGS steps.
* Each successful step is counted, and we continue until
}
mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags,
- top_global, step, (real)step, state_global, state_global, f);
+ top_global, step, (real)step, &ems.s, state_global, energyHistory, &ems.f);
/* Do the linesearching in the direction dx[point][0..(n-1)] */
/* make s a pointer to current search direction - point=0 first time we get here */
s = dx[point];
+ real *xx = static_cast<real *>(as_rvec_array(ems.s.x.data())[0]);
+ real *ff = static_cast<real *>(as_rvec_array(ems.f.data())[0]);
+
// calculate line gradient in position A
for (gpa = 0, i = 0; i < n; i++)
{
}
// Before taking any steps along the line, store the old position
- for (i = 0; i < n; i++)
- {
- lastx[i] = xx[i];
- lastf[i] = ff[i];
- }
- Epot0 = Epot;
+ *last = ems;
+ real *lastx = static_cast<real *>(as_rvec_array(last->s.x.data())[0]);
+ real *lastf = static_cast<real *>(as_rvec_array(last->f.data())[0]);
+ Epot0 = ems.epot;
- for (i = 0; i < n; i++)
- {
- xa[i] = xx[i];
- }
+ *sa = ems;
/* Take a step downhill.
* In theory, we should find the actual minimum of the function in this
// State "A" is the first position along the line.
// reference position along line is initially zero
- EpotA = Epot0;
a = 0.0;
// Check stepsize first. We do not allow displacements
while (maxdelta > inputrec->em_stepsize);
// Take a trial step and move the coordinate array xc[] to position C
+ real *xc = static_cast<real *>(as_rvec_array(sc->s.x.data())[0]);
for (i = 0; i < n; i++)
{
xc[i] = lastx[i] + c*s[i];
neval++;
// Calculate energy for the trial step in position C
- ems.s.x = (rvec *)xc;
- ems.f = (rvec *)fc;
evaluate_energy(fplog, cr,
- top_global, &ems, top,
+ top_global, sc, top,
inputrec, nrnb, wcycle, gstat,
vsite, constr, fcd, graph, mdatoms, fr,
mu_tot, enerd, vir, pres, step, FALSE);
- EpotC = ems.epot;
// Calc line gradient in position C
+ real *fc = static_cast<real *>(as_rvec_array(sc->f.data())[0]);
for (gpc = 0, i = 0; i < n; i++)
{
gpc -= s[i]*fc[i]; /* f is negative gradient, thus the sign */
// This is the max amount of increase in energy we tolerate.
// By allowing VERY small changes (close to numerical precision) we
// frequently find even better (lower) final energies.
- tmp = sqrt(GMX_REAL_EPS)*fabs(EpotA);
+ tmp = sqrt(GMX_REAL_EPS)*fabs(sa->epot);
// Accept the step if the energy is lower in the new position C (compared to A),
// or if it is not significantly higher and the line derivative is still negative.
- if (EpotC < EpotA || (gpc < 0 && EpotC < (EpotA+tmp)))
+ if (sc->epot < sa->epot || (gpc < 0 && sc->epot < (sa->epot + tmp)))
{
// Great, we found a better energy. We no longer try to alter the
// stepsize, but simply accept this new better position. The we select a new
// to take smaller steps along a line. Set fnorm based on the new C position,
// which will be used to update the stepsize to 1/fnorm further down.
foundlower = TRUE;
- fnorm = ems.fnorm;
}
else
{
// I also have a safeguard for potentially really pathological functions so we never
// take more than 20 steps before we give up.
// If we already found a lower value we just skip this step and continue to the update.
- nminstep = 0;
+ real fnorm = 0;
+ nminstep = 0;
do
{
// Select a new trial point B in the interval [A,C].
}
// Take a trial step to point B
+ real *xb = static_cast<real *>(as_rvec_array(sb->s.x.data())[0]);
for (i = 0; i < n; i++)
{
xb[i] = lastx[i] + b*s[i];
neval++;
// Calculate energy for the trial step in point B
- ems.s.x = (rvec *)xb;
- ems.f = (rvec *)fb;
evaluate_energy(fplog, cr,
- top_global, &ems, top,
+ top_global, sb, top,
inputrec, nrnb, wcycle, gstat,
vsite, constr, fcd, graph, mdatoms, fr,
mu_tot, enerd, vir, pres, step, FALSE);
- EpotB = ems.epot;
- fnorm = ems.fnorm;
+ fnorm = sb->fnorm;
// Calculate gradient in point B
+ real *fb = static_cast<real *>(as_rvec_array(sb->f.data())[0]);
for (gpb = 0, i = 0; i < n; i++)
{
gpb -= s[i]*fb[i]; /* f is negative gradient, thus the sign */
if (gpb > 0)
{
/* Replace c endpoint with b */
- EpotC = EpotB;
- c = b;
- gpc = gpb;
- /* swap coord pointers b/c */
- xtmp = xb;
- ftmp = fb;
- xb = xc;
- fb = fc;
- xc = xtmp;
- fc = ftmp;
+ c = b;
+ /* swap states b and c */
+ swap_em_state(&sb, &sc);
}
else
{
/* Replace a endpoint with b */
- EpotA = EpotB;
- a = b;
- gpa = gpb;
- /* swap coord pointers a/b */
- xtmp = xb;
- ftmp = fb;
- xb = xa;
- fb = fa;
- xa = xtmp;
- fa = ftmp;
+ a = b;
+ /* swap states a and b */
+ swap_em_state(&sa, &sb);
}
/*
*/
nminstep++;
}
- while ((EpotB > EpotA || EpotB > EpotC) && (nminstep < 20));
+ while ((sb->epot > sa->epot || sb->epot > sc->epot) && (nminstep < 20));
- if (fabs(EpotB-Epot0) < GMX_REAL_EPS || nminstep >= 20)
+ if (fabs(sb->epot - Epot0) < GMX_REAL_EPS || nminstep >= 20)
{
/* OK. We couldn't find a significantly lower energy.
* If ncorr==0 this was steepest descent, and then we give up.
/* Select min energy state of A & C, put the best in xx/ff/Epot
*/
- if (EpotC < EpotA)
+ if (sc->epot < sa->epot)
{
- Epot = EpotC;
/* Use state C */
- for (i = 0; i < n; i++)
- {
- xx[i] = xc[i];
- ff[i] = fc[i];
- }
+ ems = *sc;
step_taken = c;
}
else
{
- Epot = EpotA;
/* Use state A */
- for (i = 0; i < n; i++)
- {
- xx[i] = xa[i];
- ff[i] = fa[i];
- }
+ ems = *sa;
step_taken = a;
}
else
{
/* found lower */
- Epot = EpotC;
/* Use state C */
- for (i = 0; i < n; i++)
- {
- xx[i] = xc[i];
- ff[i] = fc[i];
- }
+ ems = *sc;
step_taken = c;
}
}
}
- /* Test whether the convergence criterion is met */
- get_f_norm_max(cr, &(inputrec->opts), mdatoms, f, &fnorm, &fmax, &nfmax);
-
/* Print it if necessary */
if (MASTER(cr))
{
{
double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
fprintf(stderr, "\rStep %d, Epot=%12.6e, Fnorm=%9.3e, Fmax=%9.3e (atom %d)\n",
- step, Epot, fnorm/sqrtNumAtoms, fmax, nfmax+1);
+ step, ems.epot, ems.fnorm/sqrtNumAtoms, ems.fmax, ems.a_fmax + 1);
fflush(stderr);
}
/* Store the new (lower) energies */
}
/* Send x and E to IMD client, if bIMD is TRUE. */
- if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, state_global->x, inputrec, 0, wcycle) && MASTER(cr))
+ if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, as_rvec_array(state_global->x.data()), inputrec, 0, wcycle) && MASTER(cr))
{
IMD_send_positions(inputrec->imd);
}
// Reset stepsize in we are doing more iterations
- stepsize = 1.0/fnorm;
+ stepsize = 1.0/ems.fnorm;
/* Stop when the maximum force lies below tolerance.
* If we have reached machine precision, converged is already set to true.
*/
- converged = converged || (fmax < inputrec->em_tol);
+ converged = converged || (ems.fmax < inputrec->em_tol);
} /* End of the loop */
step--; /* we never took that last step in this case */
}
- if (fmax > inputrec->em_tol)
+ if (ems.fmax > inputrec->em_tol)
{
if (MASTER(cr))
{
do_f = !do_per_step(step, inputrec->nstfout);
write_em_traj(fplog, cr, outf, do_x, do_f, ftp2fn(efSTO, nfile, fnm),
top_global, inputrec, step,
- &ems, state_global);
+ &ems, state_global, energyHistory);
if (MASTER(cr))
{
double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
print_converged(stderr, LBFGS, inputrec->em_tol, step, converged,
- number_steps, Epot, fmax, nfmax, fnorm/sqrtNumAtoms);
+ number_steps, &ems, sqrtNumAtoms);
print_converged(fplog, LBFGS, inputrec->em_tol, step, converged,
- number_steps, Epot, fmax, nfmax, fnorm/sqrtNumAtoms);
+ number_steps, &ems, sqrtNumAtoms);
fprintf(fplog, "\nPerformed %d energy evaluations in total.\n", neval);
}
- finish_em(cr, outf, walltime_accounting, wcycle);
+ finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
/* To print the actual number of steps we needed somewhere */
walltime_accounting_set_nsteps_done(walltime_accounting, step);
} /* That's all folks */
/*! \brief Do steepest descents minimization
- \copydoc integrator_t (FILE *fplog, t_commrec *cr,
- int nfile, const t_filenm fnm[],
- const gmx_output_env_t *oenv, gmx_bool bVerbose,
- int nstglobalcomm,
- gmx_vsite_t *vsite, gmx_constr_t constr,
- int stepout,
- t_inputrec *inputrec,
- gmx_mtop_t *top_global, t_fcdata *fcd,
- t_state *state_global,
- t_mdatoms *mdatoms,
- t_nrnb *nrnb, gmx_wallcycle_t wcycle,
- gmx_edsam_t ed,
- t_forcerec *fr,
- int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
- real cpt_period, real max_hours,
- int imdport,
- unsigned long Flags,
- gmx_walltime_accounting_t walltime_accounting)
+ \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
+ int nfile, const t_filenm fnm[],
+ const gmx_output_env_t *oenv, gmx_bool bVerbose,
+ int nstglobalcomm,
+ gmx_vsite_t *vsite, gmx_constr_t constr,
+ int stepout,
+ t_inputrec *inputrec,
+ gmx_mtop_t *top_global, t_fcdata *fcd,
+ t_state *state_global,
+ t_mdatoms *mdatoms,
+ t_nrnb *nrnb, gmx_wallcycle_t wcycle,
+ gmx_edsam_t ed,
+ t_forcerec *fr,
+ int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
+ real cpt_period, real max_hours,
+ int imdport,
+ unsigned long Flags,
+ gmx_walltime_accounting_t walltime_accounting)
*/
-double do_steep(FILE *fplog, t_commrec *cr,
+double do_steep(FILE *fplog, t_commrec *cr, const gmx::MDLogger gmx_unused &mdlog,
int nfile, const t_filenm fnm[],
const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
int gmx_unused nstglobalcomm,
t_inputrec *inputrec,
gmx_mtop_t *top_global, t_fcdata *fcd,
t_state *state_global,
+ energyhistory_t *energyHistory,
t_mdatoms *mdatoms,
t_nrnb *nrnb, gmx_wallcycle_t wcycle,
gmx_edsam_t gmx_unused ed,
gmx_walltime_accounting_t walltime_accounting)
{
const char *SD = "Steepest Descents";
- em_state_t *s_min, *s_try;
gmx_localtop_t *top;
gmx_enerdata_t *enerd;
- rvec *f;
gmx_global_stat_t gstat;
t_graph *graph;
real stepsize;
- real ustep, fnormn;
+ real ustep;
gmx_mdoutf_t outf;
t_mdebin *mdebin;
gmx_bool bDone, bAbort, do_x, do_f;
int count = 0;
int steps_accepted = 0;
- s_min = init_em_state();
- s_try = init_em_state();
+ /* Create 2 states on the stack and extract pointers that we will swap */
+ em_state_t s0 {}, s1 {};
+ em_state_t *s_min = &s0;
+ em_state_t *s_try = &s1;
/* Init em and store the local state in s_try */
init_em(fplog, SD, cr, inputrec,
- state_global, top_global, s_try, &top, &f,
- nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
+ state_global, top_global, s_try, &top,
+ nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat,
+ vsite, constr, NULL,
nfile, fnm, &outf, &mdebin, imdport, Flags, wcycle);
/* Print to log file */
{
validStep =
do_em_step(cr, inputrec, mdatoms, fr->bMolPBC,
- s_min, stepsize, s_min->f, s_try,
+ s_min, stepsize, &s_min->f, s_try,
constr, top, nrnb, wcycle, count);
}
/* Copy the arrays for force, positions and energy */
/* The 'Min' array always holds the coords and forces of the minimal
sampled energy */
- swap_em_state(s_min, s_try);
+ swap_em_state(&s_min, &s_try);
if (count > 0)
{
ustep *= 1.2;
do_f = do_per_step(steps_accepted, inputrec->nstfout);
write_em_traj(fplog, cr, outf, do_x, do_f, NULL,
top_global, inputrec, count,
- s_min, state_global);
+ s_min, state_global, energyHistory);
}
else
{
}
/* Send IMD energies and positions, if bIMD is TRUE. */
- if (do_IMD(inputrec->bIMD, count, cr, TRUE, state_global->box, state_global->x, inputrec, 0, wcycle) && MASTER(cr))
+ if (do_IMD(inputrec->bIMD, count, cr, TRUE, state_global->box, as_rvec_array(state_global->x.data()), inputrec, 0, wcycle) && MASTER(cr))
{
IMD_send_positions(inputrec->imd);
}
}
write_em_traj(fplog, cr, outf, TRUE, inputrec->nstfout, ftp2fn(efSTO, nfile, fnm),
top_global, inputrec, count,
- s_min, state_global);
+ s_min, state_global, energyHistory);
if (MASTER(cr))
{
double sqrtNumAtoms = sqrt(static_cast<double>(state_global->natoms));
- fnormn = s_min->fnorm/sqrtNumAtoms;
print_converged(stderr, SD, inputrec->em_tol, count, bDone, nsteps,
- s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
+ s_min, sqrtNumAtoms);
print_converged(fplog, SD, inputrec->em_tol, count, bDone, nsteps,
- s_min->epot, s_min->fmax, s_min->a_fmax, fnormn);
+ s_min, sqrtNumAtoms);
}
- finish_em(cr, outf, walltime_accounting, wcycle);
+ finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
/* To print the actual number of steps we needed somewhere */
inputrec->nsteps = count;
} /* That's all folks */
/*! \brief Do normal modes analysis
- \copydoc integrator_t (FILE *fplog, t_commrec *cr,
- int nfile, const t_filenm fnm[],
- const gmx_output_env_t *oenv, gmx_bool bVerbose,
- int nstglobalcomm,
- gmx_vsite_t *vsite, gmx_constr_t constr,
- int stepout,
- t_inputrec *inputrec,
- gmx_mtop_t *top_global, t_fcdata *fcd,
- t_state *state_global,
- t_mdatoms *mdatoms,
- t_nrnb *nrnb, gmx_wallcycle_t wcycle,
- gmx_edsam_t ed,
- t_forcerec *fr,
- int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
- real cpt_period, real max_hours,
- int imdport,
- unsigned long Flags,
- gmx_walltime_accounting_t walltime_accounting)
+ \copydoc integrator_t(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
+ int nfile, const t_filenm fnm[],
+ const gmx_output_env_t *oenv, gmx_bool bVerbose,
+ int nstglobalcomm,
+ gmx_vsite_t *vsite, gmx_constr_t constr,
+ int stepout,
+ t_inputrec *inputrec,
+ gmx_mtop_t *top_global, t_fcdata *fcd,
+ t_state *state_global,
+ t_mdatoms *mdatoms,
+ t_nrnb *nrnb, gmx_wallcycle_t wcycle,
+ gmx_edsam_t ed,
+ t_forcerec *fr,
+ int repl_ex_nst, int repl_ex_nex, int repl_ex_seed,
+ real cpt_period, real max_hours,
+ int imdport,
+ unsigned long Flags,
+ gmx_walltime_accounting_t walltime_accounting)
*/
-double do_nm(FILE *fplog, t_commrec *cr,
+double do_nm(FILE *fplog, t_commrec *cr, const gmx::MDLogger &mdlog,
int nfile, const t_filenm fnm[],
const gmx_output_env_t gmx_unused *oenv, gmx_bool bVerbose,
int gmx_unused nstglobalcomm,
t_inputrec *inputrec,
gmx_mtop_t *top_global, t_fcdata *fcd,
t_state *state_global,
+ energyhistory_t gmx_unused *energyHistory,
t_mdatoms *mdatoms,
t_nrnb *nrnb, gmx_wallcycle_t wcycle,
gmx_edsam_t gmx_unused ed,
int nnodes, node;
gmx_localtop_t *top;
gmx_enerdata_t *enerd;
- rvec *f;
gmx_global_stat_t gstat;
t_graph *graph;
tensor vir, pres;
size_t sz;
gmx_sparsematrix_t * sparse_matrix = NULL;
real * full_matrix = NULL;
- em_state_t * state_work;
/* added with respect to mdrun */
int row, col;
gmx_fatal(FARGS, "Constraints present with Normal Mode Analysis, this combination is not supported");
}
- state_work = init_em_state();
+ gmx_shellfc_t *shellfc;
+
+ em_state_t state_work {};
/* Init em and store the local state in state_minimum */
init_em(fplog, NM, cr, inputrec,
- state_global, top_global, state_work, &top,
- &f,
- nrnb, mu_tot, fr, &enerd, &graph, mdatoms, &gstat, vsite, constr,
+ state_global, top_global, &state_work, &top,
+ 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());
*/
if (EEL_FULL(fr->eeltype) || fr->rlist == 0.0)
{
- md_print_info(cr, fplog, "Non-cutoff electrostatics used, forcing full Hessian format.\n");
+ GMX_LOG(mdlog.warning).appendText("Non-cutoff electrostatics used, forcing full Hessian format.");
bSparse = FALSE;
}
else if (atom_index.size() < 1000)
{
- md_print_info(cr, fplog, "Small system size (N=%d), using full Hessian format.\n", atom_index.size());
+ GMX_LOG(mdlog.warning).appendTextFormatted("Small system size (N=%d), using full Hessian format.",
+ atom_index.size());
bSparse = FALSE;
}
else
{
- md_print_info(cr, fplog, "Using compressed symmetric sparse Hessian format.\n");
+ GMX_LOG(mdlog.warning).appendText("Using compressed symmetric sparse Hessian format.");
bSparse = TRUE;
}
/* Make evaluate_energy do a single node force calculation */
cr->nnodes = 1;
evaluate_energy(fplog, cr,
- top_global, state_work, top,
+ top_global, &state_work, top,
inputrec, nrnb, wcycle, gstat,
vsite, constr, fcd, graph, mdatoms, fr,
mu_tot, enerd, vir, pres, -1, TRUE);
cr->nnodes = nnodes;
/* if forces are not small, warn user */
- get_state_f_norm_max(cr, &(inputrec->opts), mdatoms, state_work);
+ get_state_f_norm_max(cr, &(inputrec->opts), mdatoms, &state_work);
- md_print_info(cr, fplog, "Maximum force:%12.5e\n", state_work->fmax);
- if (state_work->fmax > 1.0e-3)
+ GMX_LOG(mdlog.warning).appendTextFormatted("Maximum force:%12.5e", state_work.fmax);
+ if (state_work.fmax > 1.0e-3)
{
- md_print_info(cr, fplog,
- "The force is probably not small enough to "
- "ensure that you are at a minimum.\n"
- "Be aware that negative eigenvalues may occur\n"
- "when the resulting matrix is diagonalized.\n\n");
+ GMX_LOG(mdlog.warning).appendText(
+ "The force is probably not small enough to "
+ "ensure that you are at a minimum.\n"
+ "Be aware that negative eigenvalues may occur\n"
+ "when the resulting matrix is diagonalized.");
}
/***********************************************************
int force_flags = GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES;
double t = 0;
- x_min = state_work->s.x[atom][d];
+ x_min = state_work.s.x[atom][d];
for (unsigned int dx = 0; (dx < 2); dx++)
{
if (dx == 0)
{
- state_work->s.x[atom][d] = x_min - der_range;
+ state_work.s.x[atom][d] = x_min - der_range;
}
else
{
- state_work->s.x[atom][d] = x_min + der_range;
+ state_work.s.x[atom][d] = x_min + der_range;
}
/* Make evaluate_energy do a single node force calculation */
inputrec, bNS, force_flags,
top,
constr, enerd, fcd,
- &state_work->s, state_work->f, vir, mdatoms,
+ &state_work.s, &state_work.f, vir, mdatoms,
nrnb, wcycle, graph, &top_global->groups,
shellfc, fr, bBornRadii, t, mu_tot,
- vsite, NULL);
+ vsite);
bNS = false;
step++;
}
else
{
evaluate_energy(fplog, cr,
- top_global, state_work, top,
+ top_global, &state_work, top,
inputrec, nrnb, wcycle, gstat,
vsite, constr, fcd, graph, mdatoms, fr,
mu_tot, enerd, vir, pres, atom*2+dx, FALSE);
{
for (size_t i = 0; i < atom_index.size(); i++)
{
- copy_rvec(state_work->f[atom_index[i]], fneg[i]);
+ copy_rvec(state_work.f[atom_index[i]], fneg[i]);
}
}
}
/* x is restored to original */
- state_work->s.x[atom][d] = x_min;
+ state_work.s.x[atom][d] = x_min;
for (size_t j = 0; j < atom_index.size(); j++)
{
for (size_t k = 0; (k < DIM); k++)
{
dfdx[j][k] =
- -(state_work->f[atom_index[j]][k] - fneg[j][k])/(2*der_range);
+ -(state_work.f[atom_index[j]][k] - fneg[j][k])/(2*der_range);
}
}
gmx_mtxio_write(ftp2fn(efMTX, nfile, fnm), sz, sz, full_matrix, sparse_matrix);
}
- finish_em(cr, outf, walltime_accounting, wcycle);
+ finish_em(cr, outf, inputrec, walltime_accounting, wcycle);
walltime_accounting_set_nsteps_done(walltime_accounting, atom_index.size()*2);
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,
{
real skipmask_rvdw;
- skipmask_rvdw = (rsq < rvdw2);
+ skipmask_rvdw = (rsq < rvdw2) ? 1.0 : 0.0;
frLJ *= skipmask_rvdw;
#ifdef CALC_ENERGIES
VLJ *= skipmask_rvdw;
#include "gromacs/mdtypes/nblist.h"
#include "gromacs/pbcutil/ishift.h"
#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/fatalerror.h"
{
/* fills the t_QMrec struct of QM group grpnr
*/
- int i;
- gmx_mtop_atomlookup_t alook;
- t_atom *atom;
-
qm->nrQMatoms = nr;
snew(qm->xQM, nr);
snew(qm->indexQM, nr);
snew(qm->shiftQM, nr); /* the shifts */
- for (i = 0; i < nr; i++)
+ for (int i = 0; i < nr; i++)
{
qm->indexQM[i] = atomarray[i];
}
- alook = gmx_mtop_atomlookup_init(mtop);
-
snew(qm->atomicnumberQM, nr);
- for (i = 0; i < qm->nrQMatoms; i++)
+ int molb = 0;
+ for (int i = 0; i < qm->nrQMatoms; i++)
{
- gmx_mtop_atomnr_to_atom(alook, qm->indexQM[i], &atom);
- qm->nelectrons += mtop->atomtypes.atomnumber[atom->type];
- qm->atomicnumberQM[i] = mtop->atomtypes.atomnumber[atom->type];
+ const t_atom &atom = mtopGetAtomParameters(mtop, qm->indexQM[i], &molb);
+ qm->nelectrons += mtop->atomtypes.atomnumber[atom.type];
+ qm->atomicnumberQM[i] = mtop->atomtypes.atomnumber[atom.type];
}
- gmx_mtop_atomlookup_destroy(alook);
-
qm->QMcharge = ir->opts.QMcharge[grpnr];
qm->multiplicity = ir->opts.QMmult[grpnr];
qm->nelectrons -= ir->opts.QMcharge[grpnr];
t_iatom *iatoms;
real c12au, c6au;
gmx_mtop_atomloop_all_t aloop;
- t_atom *atom;
gmx_mtop_ilistloop_all_t iloop;
int a_offset;
t_ilist *ilist_mol;
- gmx_mtop_atomlookup_t alook;
if (ir->cutoff_scheme != ecutsGROUP)
{
{
/* new layer */
aloop = gmx_mtop_atomloop_all_init(mtop);
+ const t_atom *atom;
while (gmx_mtop_atomloop_all_next(aloop, &i, &atom))
{
if (qm_nr >= qm_max)
/* standard QMMM, all layers are merged together so there is one QM
* subsystem and one MM subsystem.
- * Also we set the charges to zero in the md->charge arrays to prevent
- * the innerloops from doubly counting the electostatic QM MM interaction
+ * Also we set the charges to zero in mtop to prevent the innerloops
+ * from doubly counting the electostatic QM MM interaction
+ * TODO: Consider doing this in grompp instead.
*/
- alook = gmx_mtop_atomlookup_init(mtop);
-
+ int molb = 0;
for (k = 0; k < qm_nr; k++)
{
- gmx_mtop_atomnr_to_atom(alook, qm_arr[k], &atom);
+ int indexInMolecule;
+ mtopGetMolblockIndex(mtop, qm_arr[k], &molb, NULL, &indexInMolecule);
+ t_atom *atom = &mtop->moltype[mtop->molblock[molb].type].atoms.atom[indexInMolecule];
atom->q = 0.0;
atom->qB = 0.0;
}
{
for (i = 0; i < qm_nr; i++)
{
- gmx_mtop_atomnr_to_atom(alook, qm_arr[i], &atom);
+ const t_atom &atom = mtopGetAtomParameters(mtop, qm_arr[i], &molb);
/* nbfp now includes the 6.0/12.0 derivative prefactors */
- qr->qm[0]->c6[i] = C6(fr->nbfp, mtop->ffparams.atnr, atom->type, atom->type)/c6au/6.0;
- qr->qm[0]->c12[i] = C12(fr->nbfp, mtop->ffparams.atnr, atom->type, atom->type)/c12au/12.0;
+ qr->qm[0]->c6[i] = C6(fr->nbfp, mtop->ffparams.atnr, atom.type, atom.type)/c6au/6.0;
+ qr->qm[0]->c12[i] = C12(fr->nbfp, mtop->ffparams.atnr, atom.type, atom.type)/c12au/12.0;
}
}
*/
for (i = 0; i < qm_nr; i++)
{
- gmx_mtop_atomnr_to_ilist(alook, qm_arr[i], &ilist_mol, &a_offset);
- nrvsite2 = ilist_mol[F_VSITE2].nr;
- iatoms = ilist_mol[F_VSITE2].iatoms;
+ mtopGetMolblockIndex(mtop, qm_arr[i], &molb, NULL, &a_offset);
+ ilist_mol = mtop->moltype[mtop->molblock[molb].type].ilist;
+ nrvsite2 = ilist_mol[F_VSITE2].nr;
+ iatoms = ilist_mol[F_VSITE2].iatoms;
for (k = 0; k < nrvsite2; k += 4)
{
}
}
- gmx_mtop_atomlookup_destroy(alook);
-
/* MM rec creation */
mm = mk_MMrec();
mm->scalefactor = ir->scalefactor;
#include "gromacs/mdtypes/md_enums.h"
#include "gromacs/pbcutil/mshift.h"
#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/mtop_util.h"
#include "gromacs/utility/arraysize.h"
#include "gromacs/utility/cstringutil.h"
} t_shell;
struct gmx_shellfc_t {
+ /* Shell counts, indices, parameters and working data */
int nshell_gl; /* The number of shells in the system */
t_shell *shell_gl; /* All the shells (for DD only) */
int *shell_index_gl; /* Global shell index (for DD only) */
gmx_bool bPredict; /* Predict shell positions */
gmx_bool bRequireInit; /* Require initialization of shell positions */
int nflexcon; /* The number of flexible constraints */
- rvec *x[2]; /* Array for iterative minimization */
- rvec *f[2]; /* Array for iterative minimization */
- int x_nalloc; /* The allocation size of x and f */
+
+ /* Temporary arrays, should be fixed size 2 when fully converted to C++ */
+ PaddedRVecVector *x; /* Array for iterative minimization */
+ PaddedRVecVector *f; /* Array for iterative minimization */
+
+ /* Flexible constraint working data */
rvec *acc_dir; /* Acceleration direction for flexcon */
rvec *x_old; /* Old coordinates for flexcon */
int flex_nalloc; /* The allocation size of acc_dir and x_old */
int i, m, s1, n1, n2, n3;
real dt_1, fudge, tm, m1, m2, m3;
rvec *ptr;
- gmx_mtop_atomlookup_t alook = NULL;
- t_atom *atom;
-
- if (mass == NULL)
- {
- alook = gmx_mtop_atomlookup_init(mtop);
- }
/* We introduce a fudge factor for performance reasons: with this choice
* the initial force on the shells is about a factor of two lower than
dt_1 = fudge*dt;
}
+ int molb = 0;
for (i = 0; (i < ns); i++)
{
s1 = s[i].shell;
else
{
/* Not the correct masses with FE, but it is just a prediction... */
- gmx_mtop_atomnr_to_atom(alook, n1, &atom);
- m1 = atom->m;
- gmx_mtop_atomnr_to_atom(alook, n2, &atom);
- m2 = atom->m;
+ m1 = mtopGetAtomMass(mtop, n1, &molb);
+ m2 = mtopGetAtomMass(mtop, n2, &molb);
}
tm = dt_1/(m1+m2);
for (m = 0; (m < DIM); m++)
else
{
/* Not the correct masses with FE, but it is just a prediction... */
- gmx_mtop_atomnr_to_atom(alook, n1, &atom);
- m1 = atom->m;
- gmx_mtop_atomnr_to_atom(alook, n2, &atom);
- m2 = atom->m;
- gmx_mtop_atomnr_to_atom(alook, n3, &atom);
- m3 = atom->m;
+ m1 = mtopGetAtomMass(mtop, n1, &molb);
+ m2 = mtopGetAtomMass(mtop, n2, &molb);
+ m3 = mtopGetAtomMass(mtop, n3, &molb);
}
tm = dt_1/(m1+m2+m3);
for (m = 0; (m < DIM); m++)
gmx_fatal(FARGS, "Shell %d has %d nuclei!", i, s[i].nnucl);
}
}
-
- if (mass == NULL)
- {
- gmx_mtop_atomlookup_destroy(alook);
- }
}
/*! \brief Count the different particle types in a system
gmx_mtop_atomloop_block_t aloopb = gmx_mtop_atomloop_block_init(mtop);
int nmol;
- t_atom *atom;
+ const t_atom *atom;
while (gmx_mtop_atomloop_block_next(aloopb, &atom, &nmol))
{
switch (atom->ptype)
gmx_shellfc_t *shfc;
t_shell *shell;
int *shell_index = NULL, *at2cg;
- t_atom *atom;
+ const t_atom *atom;
int ns, nshell, nsi;
int i, j, type, mb, a_offset, cg, mol, ftype, nra;
}
snew(shfc, 1);
+ shfc->x = new PaddedRVecVector[2] {};
+ shfc->f = new PaddedRVecVector[2] {};
shfc->nflexcon = nflexcon;
if (nshell == 0)
shfc->shell = shell;
}
-static void do_1pos(rvec xnew, rvec xold, rvec f, real step)
+static void do_1pos(rvec xnew, const rvec xold, const rvec f, real step)
{
real xo, yo, zo;
real dx, dy, dz;
xnew[ZZ] = zo+dz;
}
-static void do_1pos3(rvec xnew, rvec xold, rvec f, rvec step)
+static void do_1pos3(rvec xnew, const rvec xold, const rvec f, const rvec step)
{
real xo, yo, zo;
real dx, dy, dz;
xnew[ZZ] = zo+dz;
}
-static void directional_sd(rvec xold[], rvec xnew[], rvec acc_dir[],
- int start, int homenr, real step)
+static void directional_sd(const PaddedRVecVector *xold, PaddedRVecVector *xnew, const rvec acc_dir[],
+ int homenr, real step)
{
- int i;
+ const rvec *xo = as_rvec_array(xold->data());
+ rvec *xn = as_rvec_array(xnew->data());
- for (i = start; i < homenr; i++)
+ for (int i = 0; i < homenr; i++)
{
- do_1pos(xnew[i], xold[i], acc_dir[i], step);
+ do_1pos(xn[i], xo[i], acc_dir[i], step);
}
}
-static void shell_pos_sd(rvec xcur[], rvec xnew[], rvec f[],
+static void shell_pos_sd(const PaddedRVecVector * gmx_restrict xcur,
+ PaddedRVecVector * gmx_restrict xnew,
+ const PaddedRVecVector *f,
int ns, t_shell s[], int count)
{
const real step_scale_min = 0.8,
{
for (d = 0; d < DIM; d++)
{
- dx = xcur[shell][d] - s[i].xold[d];
- df = f[shell][d] - s[i].fold[d];
+ dx = (*xcur)[shell][d] - s[i].xold[d];
+ df = (*f)[shell][d] - s[i].fold[d];
/* -dx/df gets used to generate an interpolated value, but would
* cause a NaN if df were binary-equal to zero. Values close to
* zero won't cause problems (because of the min() and max()), so
#endif
}
}
- copy_rvec(xcur[shell], s[i].xold);
- copy_rvec(f[shell], s[i].fold);
+ copy_rvec((*xcur)[shell], s[i].xold);
+ copy_rvec((*f)[shell], s[i].fold);
- do_1pos3(xnew[shell], xcur[shell], f[shell], s[i].step);
+ do_1pos3((*xnew)[shell], (*xcur)[shell], (*f)[shell], s[i].step);
if (gmx_debug_at)
{
fprintf(debug, "shell[%d] = %d\n", i, shell);
- pr_rvec(debug, 0, "fshell", f[shell], DIM, TRUE);
- pr_rvec(debug, 0, "xold", xcur[shell], DIM, TRUE);
+ pr_rvec(debug, 0, "fshell", (*f)[shell], DIM, TRUE);
+ pr_rvec(debug, 0, "xold", (*xcur)[shell], DIM, TRUE);
pr_rvec(debug, 0, "step", s[i].step, DIM, TRUE);
- pr_rvec(debug, 0, "xnew", xnew[shell], DIM, TRUE);
+ pr_rvec(debug, 0, "xnew", (*xnew)[shell], DIM, TRUE);
}
}
#ifdef PRINT_STEP
}
-static real rms_force(t_commrec *cr, rvec f[], int ns, t_shell s[],
+static real rms_force(t_commrec *cr, const PaddedRVecVector *force, int ns, t_shell s[],
int ndir, real *sf_dir, real *Epot)
{
- int i, shell, ntot;
- double buf[4];
+ double buf[4];
+ const rvec *f = as_rvec_array(force->data());
buf[0] = *sf_dir;
- for (i = 0; i < ns; i++)
+ for (int i = 0; i < ns; i++)
{
- shell = s[i].shell;
- buf[0] += norm2(f[shell]);
+ int shell = s[i].shell;
+ buf[0] += norm2(f[shell]);
}
- ntot = ns;
+ int ntot = ns;
if (PAR(cr))
{
return (ntot ? std::sqrt(buf[0]/ntot) : 0);
}
-static void check_pbc(FILE *fp, rvec x[], int shell)
+static void check_pbc(FILE *fp, PaddedRVecVector x, int shell)
{
int m, now;
{
if (fabs(x[shell][m]-x[now][m]) > 0.3)
{
- pr_rvecs(fp, 0, "SHELL-X", x+now, 5);
+ pr_rvecs(fp, 0, "SHELL-X", as_rvec_array(x.data())+now, 5);
break;
}
}
}
-static void dump_shells(FILE *fp, rvec x[], rvec f[], real ftol, int ns, t_shell s[])
+static void dump_shells(FILE *fp, PaddedRVecVector x, PaddedRVecVector f, real ftol, int ns, t_shell s[])
{
int i, shell;
real ft2, ff2;
static void init_adir(FILE *log, gmx_shellfc_t *shfc,
gmx_constr_t constr, t_idef *idef, t_inputrec *ir,
t_commrec *cr, int dd_ac1,
- gmx_int64_t step, t_mdatoms *md, int start, int end,
+ gmx_int64_t step, t_mdatoms *md, int end,
rvec *x_old, rvec *x_init, rvec *x,
rvec *f, rvec *acc_dir,
gmx_bool bMolPBC, matrix box,
- real *lambda, real *dvdlambda, t_nrnb *nrnb)
+ const std::vector<real> *lambda, real *dvdlambda,
+ t_nrnb *nrnb)
{
rvec *xnold, *xnew;
double dt, w_dt;
}
else
{
- n = end - start;
+ n = end;
}
if (n > shfc->adir_nalloc)
{
dt = ir->delta_t;
/* Does NOT work with freeze or acceleration groups (yet) */
- for (n = start; n < end; n++)
+ for (n = 0; n < end; n++)
{
w_dt = md->invmass[n]*dt;
{
if ((ptype[n] != eptVSite) && (ptype[n] != eptShell))
{
- xnold[n-start][d] = x[n][d] - (x_init[n][d] - x_old[n][d]);
- xnew[n-start][d] = 2*x[n][d] - x_old[n][d] + f[n][d]*w_dt*dt;
+ xnold[n][d] = x[n][d] - (x_init[n][d] - x_old[n][d]);
+ xnew[n][d] = 2*x[n][d] - x_old[n][d] + f[n][d]*w_dt*dt;
}
else
{
- xnold[n-start][d] = x[n][d];
- xnew[n-start][d] = x[n][d];
+ xnold[n][d] = x[n][d];
+ xnew[n][d] = x[n][d];
}
}
}
constrain(log, FALSE, FALSE, constr, idef, ir, cr, step, 0, 1.0, md,
- x, xnold-start, NULL, bMolPBC, box,
- lambda[efptBONDED], &(dvdlambda[efptBONDED]),
+ x, xnold, NULL, bMolPBC, box,
+ (*lambda)[efptBONDED], &(dvdlambda[efptBONDED]),
NULL, NULL, nrnb, econqCoord);
constrain(log, FALSE, FALSE, constr, idef, ir, cr, step, 0, 1.0, md,
- x, xnew-start, NULL, bMolPBC, box,
- lambda[efptBONDED], &(dvdlambda[efptBONDED]),
+ x, xnew, NULL, bMolPBC, box,
+ (*lambda)[efptBONDED], &(dvdlambda[efptBONDED]),
NULL, NULL, nrnb, econqCoord);
- for (n = start; n < end; n++)
+ for (n = 0; n < end; n++)
{
for (d = 0; d < DIM; d++)
{
- xnew[n-start][d] =
- -(2*x[n][d]-xnold[n-start][d]-xnew[n-start][d])/gmx::square(dt)
+ xnew[n][d] =
+ -(2*x[n][d]-xnold[n][d]-xnew[n][d])/gmx::square(dt)
- f[n][d]*md->invmass[n];
}
clear_rvec(acc_dir[n]);
/* Project the acceleration on the old bond directions */
constrain(log, FALSE, FALSE, constr, idef, ir, cr, step, 0, 1.0, md,
- x_old, xnew-start, acc_dir, bMolPBC, box,
- lambda[efptBONDED], &(dvdlambda[efptBONDED]),
+ x_old, xnew, acc_dir, bMolPBC, box,
+ (*lambda)[efptBONDED], &(dvdlambda[efptBONDED]),
NULL, NULL, nrnb, econqDeriv_FlexCon);
}
gmx_localtop_t *top,
gmx_constr_t constr,
gmx_enerdata_t *enerd, t_fcdata *fcd,
- t_state *state, rvec f[],
+ t_state *state, PaddedRVecVector *f,
tensor force_vir,
t_mdatoms *md,
t_nrnb *nrnb, gmx_wallcycle_t wcycle,
t_forcerec *fr,
gmx_bool bBornRadii,
double t, rvec mu_tot,
- gmx_vsite_t *vsite,
- FILE *fp_field)
+ gmx_vsite_t *vsite)
{
int nshell;
t_shell *shell;
t_idef *idef;
- rvec *pos[2], *force[2], *acc_dir = NULL, *x_old = NULL;
+ rvec *acc_dir = NULL, *x_old = NULL;
real Epot[2], df[2];
real sf_dir, invdt;
real ftol, dum = 0;
char sbuf[22];
gmx_bool bCont, bInit, bConverged;
int nat, dd_ac0, dd_ac1 = 0, i;
- int start = 0, homenr = md->homenr, end = start+homenr, cg0, cg1;
+ int homenr = md->homenr, end = homenr, cg0, cg1;
int nflexcon, number_steps, d, Min = 0, count = 0;
#define Try (1-Min) /* At start Try = 1 */
nat = state->natoms;
}
- if (nat > shfc->x_nalloc)
+ for (i = 0; (i < 2); i++)
{
- /* Allocate local arrays */
- shfc->x_nalloc = over_alloc_dd(nat);
- for (i = 0; (i < 2); i++)
- {
- srenew(shfc->x[i], shfc->x_nalloc);
- srenew(shfc->f[i], shfc->x_nalloc);
- }
+ shfc->x[i].resize(nat + 1);
+ shfc->f[i].resize(nat + 1);
}
+
+ /* Create pointer that we can swap */
+ PaddedRVecVector *pos[2];
+ PaddedRVecVector *force[2];
for (i = 0; (i < 2); i++)
{
- pos[i] = shfc->x[i];
- force[i] = shfc->f[i];
+ pos[i] = &shfc->x[i];
+ force[i] = &shfc->f[i];
}
if (bDoNS && inputrec->ePBC != epbcNONE && !DOMAINDECOMP(cr))
*/
if (inputrec->cutoff_scheme == ecutsVERLET)
{
- put_atoms_in_box_omp(fr->ePBC, state->box, md->homenr, state->x);
+ put_atoms_in_box_omp(fr->ePBC, state->box, md->homenr, as_rvec_array(state->x.data()));
}
else
{
cg0 = 0;
cg1 = top->cgs.nr;
put_charge_groups_in_box(fplog, cg0, cg1, fr->ePBC, state->box,
- &(top->cgs), state->x, fr->cg_cm);
+ &(top->cgs), as_rvec_array(state->x.data()), fr->cg_cm);
}
if (graph)
{
- mk_mshift(fplog, graph, fr->ePBC, state->box, state->x);
+ mk_mshift(fplog, graph, fr->ePBC, state->box, as_rvec_array(state->x.data()));
}
}
/* After this all coordinate arrays will contain whole charge groups */
if (graph)
{
- shift_self(graph, state->box, state->x);
+ shift_self(graph, state->box, as_rvec_array(state->x.data()));
}
if (nflexcon)
for (d = 0; d < DIM; d++)
{
shfc->x_old[i][d] =
- state->x[start+i][d] - state->v[start+i][d]*inputrec->delta_t;
+ state->x[i][d] - state->v[i][d]*inputrec->delta_t;
}
}
}
/* Do a prediction of the shell positions */
if (shfc->bPredict && !bCont)
{
- predict_shells(fplog, state->x, state->v, inputrec->delta_t, nshell, shell,
+ predict_shells(fplog, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), inputrec->delta_t, nshell, shell,
md->massT, NULL, bInit);
}
/* do_force expected the charge groups to be in the box */
if (graph)
{
- unshift_self(graph, state->box, state->x);
+ unshift_self(graph, state->box, as_rvec_array(state->x.data()));
}
/* Calculate the forces first time around */
if (gmx_debug_at)
{
- pr_rvecs(debug, 0, "x b4 do_force", state->x + start, homenr);
+ pr_rvecs(debug, 0, "x b4 do_force", as_rvec_array(state->x.data()), homenr);
}
do_force(fplog, cr, inputrec, mdstep, nrnb, wcycle, top, groups,
- state->box, state->x, &state->hist,
+ state->box, &state->x, &state->hist,
force[Min], force_vir, md, enerd, fcd,
- state->lambda, graph,
- fr, vsite, mu_tot, t, fp_field, NULL, bBornRadii,
+ &state->lambda, graph,
+ fr, vsite, mu_tot, t, NULL, bBornRadii,
(bDoNS ? GMX_FORCE_NS : 0) | force_flags);
sf_dir = 0;
if (nflexcon)
{
init_adir(fplog, shfc,
- constr, idef, inputrec, cr, dd_ac1, mdstep, md, start, end,
- shfc->x_old-start, state->x, state->x, force[Min],
- shfc->acc_dir-start,
- fr->bMolPBC, state->box, state->lambda, &dum, nrnb);
+ constr, idef, inputrec, cr, dd_ac1, mdstep, md, end,
+ shfc->x_old, as_rvec_array(state->x.data()), as_rvec_array(state->x.data()), as_rvec_array(force[Min]->data()),
+ shfc->acc_dir,
+ fr->bMolPBC, state->box, &state->lambda, &dum, nrnb);
- for (i = start; i < end; i++)
+ for (i = 0; i < end; i++)
{
- sf_dir += md->massT[i]*norm2(shfc->acc_dir[i-start]);
+ sf_dir += md->massT[i]*norm2(shfc->acc_dir[i]);
}
}
Epot[Min] = enerd->term[F_EPOT];
- df[Min] = rms_force(cr, shfc->f[Min], nshell, shell, nflexcon, &sf_dir, &Epot[Min]);
+ df[Min] = rms_force(cr, &shfc->f[Min], nshell, shell, nflexcon, &sf_dir, &Epot[Min]);
df[Try] = 0;
if (debug)
{
if (gmx_debug_at)
{
- pr_rvecs(debug, 0, "force0", force[Min], md->nr);
+ pr_rvecs(debug, 0, "force0", as_rvec_array(force[Min]->data()), md->nr);
}
if (nshell+nflexcon > 0)
* shell positions are updated, therefore the other particles must
* be set here.
*/
- memcpy(pos[Min], state->x, nat*sizeof(state->x[0]));
- memcpy(pos[Try], state->x, nat*sizeof(state->x[0]));
+ *pos[Min] = state->x;
+ *pos[Try] = state->x;
}
if (bVerbose && MASTER(cr))
{
if (vsite)
{
- construct_vsites(vsite, pos[Min], inputrec->delta_t, state->v,
+ construct_vsites(vsite, as_rvec_array(pos[Min]->data()),
+ inputrec->delta_t, as_rvec_array(state->v.data()),
idef->iparams, idef->il,
fr->ePBC, fr->bMolPBC, cr, state->box);
}
if (nflexcon)
{
init_adir(fplog, shfc,
- constr, idef, inputrec, cr, dd_ac1, mdstep, md, start, end,
- x_old-start, state->x, pos[Min], force[Min], acc_dir-start,
- fr->bMolPBC, state->box, state->lambda, &dum, nrnb);
+ constr, idef, inputrec, cr, dd_ac1, mdstep, md, end,
+ x_old, as_rvec_array(state->x.data()), as_rvec_array(pos[Min]->data()), as_rvec_array(force[Min]->data()), acc_dir,
+ fr->bMolPBC, state->box, &state->lambda, &dum, nrnb);
- directional_sd(pos[Min], pos[Try], acc_dir-start, start, end,
- fr->fc_stepsize);
+ directional_sd(pos[Min], pos[Try], acc_dir, end, fr->fc_stepsize);
}
/* New positions, Steepest descent */
/* do_force expected the charge groups to be in the box */
if (graph)
{
- unshift_self(graph, state->box, pos[Try]);
+ unshift_self(graph, state->box, as_rvec_array(pos[Try]->data()));
}
if (gmx_debug_at)
{
- pr_rvecs(debug, 0, "RELAX: pos[Min] ", pos[Min] + start, homenr);
- pr_rvecs(debug, 0, "RELAX: pos[Try] ", pos[Try] + start, homenr);
+ pr_rvecs(debug, 0, "RELAX: pos[Min] ", as_rvec_array(pos[Min]->data()), homenr);
+ pr_rvecs(debug, 0, "RELAX: pos[Try] ", as_rvec_array(pos[Try]->data()), homenr);
}
/* Try the new positions */
do_force(fplog, cr, inputrec, 1, nrnb, wcycle,
top, groups, state->box, pos[Try], &state->hist,
force[Try], force_vir,
- md, enerd, fcd, state->lambda, graph,
- fr, vsite, mu_tot, t, fp_field, NULL, bBornRadii,
+ md, enerd, fcd, &state->lambda, graph,
+ fr, vsite, mu_tot, t, NULL, bBornRadii,
force_flags);
if (gmx_debug_at)
{
- pr_rvecs(debug, 0, "RELAX: force[Min]", force[Min] + start, homenr);
- pr_rvecs(debug, 0, "RELAX: force[Try]", force[Try] + start, homenr);
+ pr_rvecs(debug, 0, "RELAX: force[Min]", as_rvec_array(force[Min]->data()), homenr);
+ pr_rvecs(debug, 0, "RELAX: force[Try]", as_rvec_array(force[Try]->data()), homenr);
}
sf_dir = 0;
if (nflexcon)
{
init_adir(fplog, shfc,
- constr, idef, inputrec, cr, dd_ac1, mdstep, md, start, end,
- x_old-start, state->x, pos[Try], force[Try], acc_dir-start,
- fr->bMolPBC, state->box, state->lambda, &dum, nrnb);
+ constr, idef, inputrec, cr, dd_ac1, mdstep, md, end,
+ x_old, as_rvec_array(state->x.data()), as_rvec_array(pos[Try]->data()), as_rvec_array(force[Try]->data()), acc_dir,
+ fr->bMolPBC, state->box, &state->lambda, &dum, nrnb);
- for (i = start; i < end; i++)
+ for (i = 0; i < end; i++)
{
- sf_dir += md->massT[i]*norm2(acc_dir[i-start]);
+ sf_dir += md->massT[i]*norm2(acc_dir[i]);
}
}
{
if (gmx_debug_at)
{
- pr_rvecs(debug, 0, "F na do_force", force[Try] + start, homenr);
+ pr_rvecs(debug, 0, "F na do_force", as_rvec_array(force[Try]->data()), homenr);
}
if (gmx_debug_at)
{
fprintf(debug, "SHELL ITER %d\n", count);
- dump_shells(debug, pos[Try], force[Try], ftol, nshell, shell);
+ dump_shells(debug, *pos[Try], *force[Try], ftol, nshell, shell);
}
}
{
/* Correct the velocities for the flexible constraints */
invdt = 1/inputrec->delta_t;
- for (i = start; i < end; i++)
+ for (i = 0; i < end; i++)
{
for (d = 0; d < DIM; d++)
{
}
/* Copy back the coordinates and the forces */
- memcpy(state->x, pos[Min], nat*sizeof(state->x[0]));
- memcpy(f, force[Min], nat*sizeof(f[0]));
+ state->x = *pos[Min];
+ *f = *force[Min];
}
void done_shellfc(FILE *fplog, gmx_shellfc_t *shfc, gmx_int64_t numSteps)
#include <cstdio>
#include "gromacs/mdlib/vsite.h"
+#include "gromacs/mdtypes/state.h"
#include "gromacs/timing/wallcycle.h"
struct gmx_constr;
gmx_localtop_t *top,
gmx_constr *constr,
gmx_enerdata_t *enerd, t_fcdata *fcd,
- t_state *state, rvec f[],
+ t_state *state, PaddedRVecVector *f,
tensor force_vir,
t_mdatoms *md,
t_nrnb *nrnb, gmx_wallcycle_t wcycle,
t_forcerec *fr,
gmx_bool bBornRadii,
double t, rvec mu_tot,
- gmx_vsite_t *vsite,
- FILE *fp_field);
+ gmx_vsite_t *vsite);
/* Print some final output */
void done_shellfc(FILE *fplog, gmx_shellfc_t *shellfc, gmx_int64_t numSteps);
walltime_accounting_get_start_time_stamp(walltime_accounting));
}
-static void sum_forces(int start, int end, rvec f[], rvec flr[])
+static void sum_forces(rvec f[], const PaddedRVecVector *forceToAdd)
{
- int i;
+ /* TODO: remove this - 1 when padding is properly implemented */
+ int end = forceToAdd->size() - 1;
+ const rvec *fAdd = as_rvec_array(forceToAdd->data());
- if (gmx_debug_at)
- {
- pr_rvecs(debug, 0, "fsr", f+start, end-start);
- pr_rvecs(debug, 0, "flr", flr+start, end-start);
- }
// cppcheck-suppress unreadVariable
int gmx_unused nt = gmx_omp_nthreads_get(emntDefault);
#pragma omp parallel for num_threads(nt) schedule(static)
- for (i = start; i < end; i++)
+ for (int i = 0; i < end; i++)
{
- rvec_inc(f[i], flr[i]);
- }
-}
-
-/*
- * calc_f_el calculates forces due to an electric field.
- *
- * force is kJ mol^-1 nm^-1 = e * kJ mol^-1 nm^-1 / e
- *
- * Et[] contains the parameters for the time dependent
- * part of the field.
- * Ex[] contains the parameters for
- * the spatial dependent part of the field.
- * The function should return the energy due to the electric field
- * (if any) but for now returns 0.
- *
- * WARNING:
- * There can be problems with the virial.
- * Since the field is not self-consistent this is unavoidable.
- * For neutral molecules the virial is correct within this approximation.
- * For neutral systems with many charged molecules the error is small.
- * But for systems with a net charge or a few charged molecules
- * the error can be significant when the field is high.
- * Solution: implement a self-consistent electric field into PME.
- */
-static void calc_f_el(FILE *fp, int start, int homenr,
- real charge[], rvec f[],
- t_cosines Ex[], t_cosines Et[], double t)
-{
- rvec Ext;
- real t0;
- int i, m;
-
- for (m = 0; (m < DIM); m++)
- {
- if (Et[m].n > 0)
- {
- if (Et[m].n == 3)
- {
- t0 = Et[m].a[1];
- Ext[m] = std::cos(Et[m].a[0]*(t-t0))*std::exp(-gmx::square(t-t0)/(2.0*gmx::square(Et[m].a[2])));
- }
- else
- {
- Ext[m] = std::cos(Et[m].a[0]*t);
- }
- }
- else
- {
- Ext[m] = 1.0;
- }
- if (Ex[m].n > 0)
- {
- /* Convert the field strength from V/nm to MD-units */
- Ext[m] *= Ex[m].a[0]*FIELDFAC;
- for (i = start; (i < start+homenr); i++)
- {
- f[i][m] += charge[i]*Ext[m];
- }
- }
- else
- {
- Ext[m] = 0;
- }
- }
- if (fp != NULL)
- {
- fprintf(fp, "%10g %10g %10g %10g #FIELD\n", t,
- Ext[XX]/FIELDFAC, Ext[YY]/FIELDFAC, Ext[ZZ]/FIELDFAC);
+ rvec_inc(f[i], fAdd[i]);
}
}
wallcycle_start(wcycle, ewcPP_PMEWAITRECVF);
dvdl_q = 0;
dvdl_lj = 0;
- gmx_pme_receive_f(cr, fr->f_novirsum, fr->vir_el_recip, &e_q,
+ gmx_pme_receive_f(cr, as_rvec_array(fr->f_novirsum->data()), fr->vir_el_recip, &e_q,
fr->vir_lj_recip, &e_lj, &dvdl_q, &dvdl_lj,
&cycles_seppme);
enerd->term[F_COUL_RECIP] += e_q;
* if the constructing atoms aren't local.
*/
wallcycle_start(wcycle, ewcVSITESPREAD);
- spread_vsite_f(vsite, x, fr->f_novirsum, NULL,
+ spread_vsite_f(vsite, x, as_rvec_array(fr->f_novirsum->data()), NULL,
(flags & GMX_FORCE_VIRIAL), fr->vir_el_recip,
nrnb,
&top->idef, fr->ePBC, fr->bMolPBC, graph, box, cr);
if (flags & GMX_FORCE_VIRIAL)
{
/* Now add the forces, this is local */
- if (fr->bDomDec)
- {
- sum_forces(0, fr->f_novirsum_n, f, fr->f_novirsum);
- }
- else
- {
- sum_forces(0, mdatoms->homenr,
- f, fr->f_novirsum);
- }
+ sum_forces(f, fr->f_novirsum);
+
if (EEL_FULL(fr->eeltype))
{
/* Add the mesh contribution to the virial */
gmx_localtop_t *top,
gmx_groups_t gmx_unused *groups,
matrix box, rvec x[], history_t *hist,
- rvec f[],
+ PaddedRVecVector *force,
tensor vir_force,
t_mdatoms *mdatoms,
gmx_enerdata_t *enerd, t_fcdata *fcd,
real *lambda, t_graph *graph,
t_forcerec *fr, interaction_const_t *ic,
gmx_vsite_t *vsite, rvec mu_tot,
- double t, FILE *field, gmx_edsam_t ed,
+ double t, gmx_edsam_t ed,
gmx_bool bBornRadii,
int flags)
{
int cg1, i, j;
- int start, homenr;
double mu[2*DIM];
gmx_bool bStateChanged, bNS, bFillGrid, bCalcCGCM;
gmx_bool bDoForces, bUseGPU, bUseOrEmulGPU;
cycles_wait_gpu = 0;
nbv = fr->nbv;
- start = 0;
- homenr = mdatoms->homenr;
+ const int start = 0;
+ const int homenr = mdatoms->homenr;
clear_mat(vir_force);
* we do not need to worry about shifting.
*/
- int pme_flags = 0;
-
wallcycle_start(wcycle, ewcPP_PMESENDX);
bBS = (inputrec->nwall == 2);
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);
}
wallcycle_stop(wcycle, ewcROT);
}
+ /* Temporary solution until all routines take PaddedRVecVector */
+ rvec *f = as_rvec_array(force->data());
+
/* Start the force cycle counter.
* This counter is stopped after do_force_lowlevel.
* No parallel communication should occur while this counter is running,
{
if (flags & GMX_FORCE_VIRIAL)
{
- fr->f_novirsum = fr->f_novirsum_alloc;
+ fr->f_novirsum = fr->forceBufferNoVirialSummation;
}
else
{
* a separate array for forces that do not contribute
* to the pressure.
*/
- fr->f_novirsum = f;
+ fr->f_novirsum = force;
}
}
{
if (flags & GMX_FORCE_VIRIAL)
{
- if (fr->bDomDec)
- {
- clear_rvecs_omp(fr->f_novirsum_n, fr->f_novirsum);
- }
- else
- {
- clear_rvecs_omp(homenr, fr->f_novirsum+start);
- }
+ /* TODO: remove this - 1 when padding is properly implemented */
+ clear_rvecs_omp(fr->f_novirsum->size() - 1,
+ as_rvec_array(fr->f_novirsum->data()));
}
}
/* Clear the short- and long-range forces */
if (bDoForces)
{
- if (inputrecElecField(inputrec))
+ /* Compute forces due to electric field */
+ if (fr->efield != nullptr)
{
- /* Compute forces due to electric field */
- calc_f_el(MASTER(cr) ? field : NULL,
- start, homenr, mdatoms->chargeA, fr->f_novirsum,
- inputrec->ex, inputrec->et, t);
+ fr->efield->calculateForces(cr, mdatoms, fr->f_novirsum, t);
}
/* If we have NoVirSum forces, but we do not calculate the virial,
gmx_localtop_t *top,
gmx_groups_t *groups,
matrix box, rvec x[], history_t *hist,
- rvec f[],
+ PaddedRVecVector *force,
tensor vir_force,
t_mdatoms *mdatoms,
gmx_enerdata_t *enerd, t_fcdata *fcd,
real *lambda, t_graph *graph,
t_forcerec *fr, gmx_vsite_t *vsite, rvec mu_tot,
- double t, FILE *field, gmx_edsam_t ed,
+ double t, gmx_edsam_t ed,
gmx_bool bBornRadii,
int flags)
{
int cg0, cg1, i, j;
- int start, homenr;
double mu[2*DIM];
gmx_bool bStateChanged, bNS, bFillGrid, bCalcCGCM;
gmx_bool bDoForces;
float cycles_pme, cycles_force;
- start = 0;
- homenr = mdatoms->homenr;
+ const int start = 0;
+ const int homenr = mdatoms->homenr;
clear_mat(vir_force);
* we do not need to worry about shifting.
*/
- int pme_flags = 0;
-
wallcycle_start(wcycle, ewcPP_PMESENDX);
bBS = (inputrec->nwall == 2);
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);
}
wallcycle_stop(wcycle, ewcROT);
}
+ /* Temporary solution until all routines take PaddedRVecVector */
+ rvec *f = as_rvec_array(force->data());
+
/* Start the force cycle counter.
* This counter is stopped after do_force_lowlevel.
* No parallel communication should occur while this counter is running,
{
if (flags & GMX_FORCE_VIRIAL)
{
- fr->f_novirsum = fr->f_novirsum_alloc;
- if (fr->bDomDec)
- {
- clear_rvecs(fr->f_novirsum_n, fr->f_novirsum);
- }
- else
- {
- clear_rvecs(homenr, fr->f_novirsum+start);
- }
+ fr->f_novirsum = fr->forceBufferNoVirialSummation;
+ /* TODO: remove this - 1 when padding is properly implemented */
+ clear_rvecs(fr->f_novirsum->size() - 1,
+ as_rvec_array(fr->f_novirsum->data()));
}
else
{
* a separate array for forces that do not contribute
* to the pressure.
*/
- fr->f_novirsum = f;
+ fr->f_novirsum = force;
}
}
if (bDoForces)
{
- if (inputrecElecField(inputrec))
+ /* Compute forces due to electric field */
+ if (fr->efield != nullptr)
{
- /* Compute forces due to electric field */
- calc_f_el(MASTER(cr) ? field : NULL,
- start, homenr, mdatoms->chargeA, fr->f_novirsum,
- inputrec->ex, inputrec->et, t);
+ fr->efield->calculateForces(cr, mdatoms, fr->f_novirsum, t);
}
/* Communicate the forces */
if (EEL_FULL(fr->eeltype) && cr->dd->n_intercg_excl &&
(flags & GMX_FORCE_VIRIAL))
{
- dd_move_f(cr->dd, fr->f_novirsum, NULL);
+ dd_move_f(cr->dd, as_rvec_array(fr->f_novirsum->data()), NULL);
}
wallcycle_stop(wcycle, ewcMOVEF);
}
gmx_int64_t step, t_nrnb *nrnb, gmx_wallcycle_t wcycle,
gmx_localtop_t *top,
gmx_groups_t *groups,
- matrix box, rvec x[], history_t *hist,
- rvec f[],
+ matrix box, PaddedRVecVector *coordinates, history_t *hist,
+ PaddedRVecVector *force,
tensor vir_force,
t_mdatoms *mdatoms,
gmx_enerdata_t *enerd, t_fcdata *fcd,
- real *lambda, t_graph *graph,
+ std::vector<real> *lambda, t_graph *graph,
t_forcerec *fr,
gmx_vsite_t *vsite, rvec mu_tot,
- double t, FILE *field, gmx_edsam_t ed,
+ double t, gmx_edsam_t ed,
gmx_bool bBornRadii,
int flags)
{
flags &= ~GMX_FORCE_NONBONDED;
}
+ GMX_ASSERT(coordinates->size() >= static_cast<unsigned int>(fr->natoms_force + 1), "We might need 1 element extra for SIMD");
+ GMX_ASSERT(force->size() >= static_cast<unsigned int>(fr->natoms_force + 1), "We might need 1 element extra for SIMD");
+
+ rvec *x = as_rvec_array(coordinates->data());
+
switch (inputrec->cutoff_scheme)
{
case ecutsVERLET:
top,
groups,
box, x, hist,
- f, vir_force,
+ force, vir_force,
mdatoms,
enerd, fcd,
- lambda, graph,
+ lambda->data(), graph,
fr, fr->ic,
vsite, mu_tot,
- t, field, ed,
+ t, ed,
bBornRadii,
flags);
break;
top,
groups,
box, x, hist,
- f, vir_force,
+ force, vir_force,
mdatoms,
enerd, fcd,
- lambda, graph,
+ lambda->data(), graph,
fr, vsite, mu_tot,
- t, field, ed,
+ t, ed,
bBornRadii,
flags);
break;
/* constrain the current position */
constrain(NULL, TRUE, FALSE, constr, &(top->idef),
ir, cr, step, 0, 1.0, md,
- state->x, state->x, NULL,
+ as_rvec_array(state->x.data()), as_rvec_array(state->x.data()), NULL,
fr->bMolPBC, state->box,
state->lambda[efptBONDED], &dvdl_dum,
NULL, NULL, nrnb, econqCoord);
/* also may be useful if we need the ekin from the halfstep for velocity verlet */
constrain(NULL, TRUE, FALSE, constr, &(top->idef),
ir, cr, step, 0, 1.0, md,
- state->x, state->v, state->v,
+ as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), as_rvec_array(state->v.data()),
fr->bMolPBC, state->box,
state->lambda[efptBONDED], &dvdl_dum,
NULL, NULL, nrnb, econqVeloc);
dvdl_dum = 0;
constrain(NULL, TRUE, FALSE, constr, &(top->idef),
ir, cr, step, -1, 1.0, md,
- state->x, savex, NULL,
+ as_rvec_array(state->x.data()), savex, NULL,
fr->bMolPBC, state->box,
state->lambda[efptBONDED], &dvdl_dum,
- state->v, NULL, nrnb, econqCoord);
+ as_rvec_array(state->v.data()), NULL, nrnb, econqCoord);
for (i = start; i < end; i++)
{
}
// 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,
{
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);
}
}
-extern void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, real *lambda, double *lam0)
+extern void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, std::vector<real> *lambda, double *lam0)
{
/* this function works, but could probably use a logic rewrite to keep all the different
types of efep straight. */
- int i;
+ if ((ir->efep == efepNO) && (ir->bSimTemp == FALSE))
+ {
+ return;
+ }
+
t_lambda *fep = ir->fepvals;
+ *fep_state = fep->init_fep_state; /* this might overwrite the checkpoint
+ if checkpoint is set -- a kludge is in for now
+ to prevent this.*/
- if ((ir->efep == efepNO) && (ir->bSimTemp == FALSE))
+ lambda->resize(efptNR);
+
+ for (int i = 0; i < efptNR; i++)
{
- for (i = 0; i < efptNR; i++)
+ /* overwrite lambda state with init_lambda for now for backwards compatibility */
+ if (fep->init_lambda >= 0) /* if it's -1, it was never initializd */
{
- lambda[i] = 0.0;
+ (*lambda)[i] = fep->init_lambda;
if (lam0)
{
- lam0[i] = 0.0;
+ lam0[i] = (*lambda)[i];
}
}
- return;
- }
- else
- {
- *fep_state = fep->init_fep_state; /* this might overwrite the checkpoint
- if checkpoint is set -- a kludge is in for now
- to prevent this.*/
- for (i = 0; i < efptNR; i++)
+ else
{
- /* overwrite lambda state with init_lambda for now for backwards compatibility */
- if (fep->init_lambda >= 0) /* if it's -1, it was never initializd */
- {
- lambda[i] = fep->init_lambda;
- if (lam0)
- {
- lam0[i] = lambda[i];
- }
- }
- else
+ (*lambda)[i] = fep->all_lambda[i][*fep_state];
+ if (lam0)
{
- lambda[i] = fep->all_lambda[i][*fep_state];
- if (lam0)
- {
- lam0[i] = lambda[i];
- }
+ lam0[i] = (*lambda)[i];
}
}
- if (ir->bSimTemp)
+ }
+ if (ir->bSimTemp)
+ {
+ /* need to rescale control temperatures to match current state */
+ for (int i = 0; i < ir->opts.ngtc; i++)
{
- /* need to rescale control temperatures to match current state */
- for (i = 0; i < ir->opts.ngtc; i++)
+ if (ir->opts.ref_t[i] > 0)
{
- if (ir->opts.ref_t[i] > 0)
- {
- ir->opts.ref_t[i] = ir->simtempvals->temperatures[*fep_state];
- }
+ ir->opts.ref_t[i] = ir->simtempvals->temperatures[*fep_state];
}
}
}
if (fplog != NULL)
{
fprintf(fplog, "Initial vector of lambda components:[ ");
- for (i = 0; i < efptNR; i++)
+ for (int i = 0; i < efptNR; i++)
{
- fprintf(fplog, "%10.4f ", lambda[i]);
+ fprintf(fplog, "%10.4f ", (*lambda)[i]);
}
fprintf(fplog, "]\n");
}
void init_md(FILE *fplog,
t_commrec *cr, t_inputrec *ir, const gmx_output_env_t *oenv,
double *t, double *t0,
- real *lambda, int *fep_state, double *lam0,
+ std::vector<real> *lambda, int *fep_state, double *lam0,
t_nrnb *nrnb, gmx_mtop_t *mtop,
gmx_update_t **upd,
int nfile, const t_filenm fnm[],
please_cite(fplog, "Goga2012");
}
}
- if ((ir->et[XX].n > 0) || (ir->et[YY].n > 0) || (ir->et[ZZ].n > 0))
- {
- please_cite(fplog, "Caleman2008a");
- }
init_nrnb(nrnb);
if (nfile != -1)
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,
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,
matrix box, real lambda, tensor pres, tensor virial,
real *prescorr, real *enercorr, real *dvdlcorr);
-void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, real *lambda, double *lam0);
+void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, std::vector<real> *lambda, double *lam0);
void do_constrain_first(FILE *log, gmx_constr *constr,
t_inputrec *inputrec, t_mdatoms *md,
void init_md(FILE *fplog,
t_commrec *cr, t_inputrec *ir, const gmx_output_env_t *oenv,
double *t, double *t0,
- real *lambda, int *fep_state, double *lam0,
+ std::vector<real> *lambda, int *fep_state, double *lam0,
t_nrnb *nrnb, gmx_mtop_t *mtop,
gmx_update_t **upd,
int nfile, const t_filenm fnm[],
* 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
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
}
}
-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
gmx_groups_t *groups;
gmx_mtop_atomloop_all_t aloop;
int i, grp;
- t_atom *atom;
+ const t_atom *atom;
if (ngacc > 0)
{
{
/*! \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,
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,
t_inputrec *inputrec,
gmx_mtop_t *top_global, t_fcdata *fcd,
t_state *state_global,
+ energyhistory_t gmx_unused *energyHistory,
t_mdatoms *mdatoms,
t_nrnb *nrnb, gmx_wallcycle_t wcycle,
gmx_edsam_t gmx_unused ed,
unsigned long gmx_unused Flags,
gmx_walltime_accounting_t walltime_accounting)
{
- gmx_localtop_t *top;
- gmx_groups_t *groups;
- gmx_enerdata_t *enerd;
- rvec *f;
- real lambda, t, temp, beta, drmax, epot;
- double embU, sum_embU, *sum_UgembU, V, V_all, VembU_all;
- t_trxstatus *status;
- t_trxframe rerun_fr;
- gmx_bool bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS;
- tensor force_vir, shake_vir, vir, pres;
- int cg_tp, a_tp0, a_tp1, ngid, gid_tp, nener, e;
- rvec *x_mol;
- rvec mu_tot, x_init, dx, x_tp;
- int nnodes, frame;
- gmx_int64_t frame_step_prev, frame_step;
- gmx_int64_t nsteps, stepblocksize = 0, step;
- gmx_int64_t seed;
- int i;
- FILE *fp_tpi = NULL;
- char *ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN];
- double dbl, dump_ener;
- gmx_bool bCavity;
- int nat_cavity = 0, d;
- real *mass_cavity = NULL, mass_tot;
- int nbin;
- double invbinw, *bin, refvolshift, logV, bUlogV;
- real prescorr, enercorr, dvdlcorr;
- gmx_bool bEnergyOutOfBounds;
- const char *tpid_leg[2] = {"direct", "reweighted"};
+ gmx_localtop_t *top;
+ gmx_groups_t *groups;
+ gmx_enerdata_t *enerd;
+ PaddedRVecVector f {};
+ real lambda, t, temp, beta, drmax, epot;
+ double embU, sum_embU, *sum_UgembU, V, V_all, VembU_all;
+ t_trxstatus *status;
+ t_trxframe rerun_fr;
+ gmx_bool bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS;
+ tensor force_vir, shake_vir, vir, pres;
+ int cg_tp, a_tp0, a_tp1, ngid, gid_tp, nener, e;
+ rvec *x_mol;
+ rvec mu_tot, x_init, dx, x_tp;
+ int nnodes, frame;
+ gmx_int64_t frame_step_prev, frame_step;
+ gmx_int64_t nsteps, stepblocksize = 0, step;
+ gmx_int64_t seed;
+ int i;
+ FILE *fp_tpi = NULL;
+ char *ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN];
+ double dbl, dump_ener;
+ gmx_bool bCavity;
+ int nat_cavity = 0, d;
+ real *mass_cavity = NULL, mass_tot;
+ int nbin;
+ double invbinw, *bin, refvolshift, logV, bUlogV;
+ real prescorr, enercorr, dvdlcorr;
+ gmx_bool bEnergyOutOfBounds;
+ const char *tpid_leg[2] = {"direct", "reweighted"};
/* Since there is no upper limit to the insertion energies,
* we need to set an upper limit for the distribution output.
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);
init_enerdata(groups->grps[egcENER].nr, inputrec->fepvals->n_lambda, enerd);
- snew(f, top_global->natoms);
+ f.resize(top_global->natoms + 1);
/* Print to log file */
walltime_accounting_start(walltime_accounting);
}
bRFExcl = (bCharge && EEL_RF(fr->eeltype));
- calc_cgcm(fplog, cg_tp, cg_tp+1, &(top->cgs), state_global->x, fr->cg_cm);
+ calc_cgcm(fplog, cg_tp, cg_tp+1, &(top->cgs), as_rvec_array(state_global->x.data()), fr->cg_cm);
if (bCavity)
{
if (norm(fr->cg_cm[cg_tp]) > 0.5*inputrec->rlist && fplog)
copy_rvec(x_mol[i-a_tp0], state_global->x[i]);
}
/* Rotate the molecule randomly */
- rotate_conf(a_tp1-a_tp0, state_global->x+a_tp0, NULL,
+ rotate_conf(a_tp1-a_tp0, as_rvec_array(state_global->x.data())+a_tp0, NULL,
2*M_PI*dist(rng),
2*M_PI*dist(rng),
2*M_PI*dist(rng));
cr->nnodes = 1;
do_force(fplog, cr, inputrec,
step, nrnb, wcycle, top, &top_global->groups,
- state_global->box, state_global->x, &state_global->hist,
- f, force_vir, mdatoms, enerd, fcd,
- state_global->lambda,
- NULL, fr, NULL, mu_tot, t, NULL, NULL, FALSE,
+ state_global->box, &state_global->x, &state_global->hist,
+ &f, force_vir, mdatoms, enerd, fcd,
+ &state_global->lambda,
+ NULL, fr, NULL, mu_tot, t, NULL, FALSE,
GMX_FORCE_NONBONDED | GMX_FORCE_ENERGY |
(bNS ? GMX_FORCE_DYNAMICBOX | GMX_FORCE_NS : 0) |
(bStateChanged ? GMX_FORCE_STATECHANGED : 0));
{
sprintf(str, "t%g_step%d.pdb", t, (int)step);
sprintf(str2, "t: %f step %d ener: %f", t, (int)step, epot);
- write_sto_conf_mtop(str, str2, top_global, state_global->x, state_global->v,
+ write_sto_conf_mtop(str, str2, top_global, as_rvec_array(state_global->x.data()), as_rvec_array(state_global->v.data()),
inputrec->ePBC, state_global->box);
}
#include "gromacs/utility/smalloc.h"
void
-do_md_trajectory_writing(FILE *fplog,
- t_commrec *cr,
- int nfile,
- const t_filenm fnm[],
- gmx_int64_t step,
- gmx_int64_t step_rel,
- double t,
- t_inputrec *ir,
- t_state *state,
- t_state *state_global,
- gmx_mtop_t *top_global,
- t_forcerec *fr,
- gmx_mdoutf_t outf,
- t_mdebin *mdebin,
- gmx_ekindata_t *ekind,
- rvec *f,
- int *nchkpt,
- gmx_bool bCPT,
- gmx_bool bRerunMD,
- gmx_bool bLastStep,
- gmx_bool bDoConfOut,
- gmx_bool bSumEkinhOld
+do_md_trajectory_writing(FILE *fplog,
+ t_commrec *cr,
+ int nfile,
+ const t_filenm fnm[],
+ gmx_int64_t step,
+ gmx_int64_t step_rel,
+ double t,
+ t_inputrec *ir,
+ t_state *state,
+ t_state *state_global,
+ energyhistory_t *energyHistory,
+ gmx_mtop_t *top_global,
+ t_forcerec *fr,
+ gmx_mdoutf_t outf,
+ t_mdebin *mdebin,
+ gmx_ekindata_t *ekind,
+ PaddedRVecVector *f,
+ int *nchkpt,
+ gmx_bool bCPT,
+ gmx_bool bRerunMD,
+ gmx_bool bLastStep,
+ gmx_bool bDoConfOut,
+ gmx_bool bSumEkinhOld
)
{
int mdof_flags;
update_ekinstate(&state_global->ekinstate, ekind);
state_global->ekinstate.bUpToDate = TRUE;
}
- update_energyhistory(state_global->enerhist, mdebin);
+ update_energyhistory(energyHistory, mdebin);
}
}
mdoutf_write_to_trajectory_files(fplog, cr, outf, mdof_flags, top_global,
- step, t, state, state_global, f);
+ step, t, state, state_global, energyHistory, f);
if (bCPT)
{
(*nchkpt)++;
bDoConfOut && MASTER(cr) &&
!bRerunMD)
{
- if (fr->bMolPBC && state->x == state_global->x)
+ if (fr->bMolPBC && state == state_global)
{
/* This (single-rank) run needs to allocate a
temporary array of size natoms so that any
identical, and makes .edr restarts binary
identical. */
snew(x_for_confout, state_global->natoms);
- copy_rvecn(state_global->x, x_for_confout, 0, state_global->natoms);
+ copy_rvecn(as_rvec_array(state_global->x.data()), x_for_confout, 0, state_global->natoms);
}
else
{
/* With DD, or no bMolPBC, it doesn't matter if
- we change state_global->x */
- x_for_confout = state_global->x;
+ we change as_rvec_array(state_global->x.data()) */
+ x_for_confout = as_rvec_array(state_global->x.data());
}
/* x and v have been collected in mdoutf_write_to_trajectory_files,
}
write_sto_conf_mtop(ftp2fn(efSTO, nfile, fnm),
*top_global->name, top_global,
- x_for_confout, state_global->v,
+ x_for_confout, as_rvec_array(state_global->v.data()),
ir->ePBC, state->box);
- if (fr->bMolPBC && state->x == state_global->x)
+ if (fr->bMolPBC && state == state_global)
{
sfree(x_for_confout);
}
*
* 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.
t_inputrec *ir,
t_state *state,
t_state *state_global,
+ energyhistory_t *energyHistory,
struct gmx_mtop_t *top_global,
t_forcerec *fr,
gmx_mdoutf_t outf,
t_mdebin *mdebin,
struct gmx_ekindata_t *ekind,
- rvec *f,
+ PaddedRVecVector *f,
int *nchkpt,
gmx_bool bCPT,
gmx_bool bRerunMD,
struct gmx_update_t
{
- gmx_stochd_t *sd;
+ gmx_stochd_t *sd;
/* xprime for constraint algorithms */
- rvec *xp;
- int xp_nalloc;
+ PaddedRVecVector xp;
/* Variables for the deform algorithm */
- gmx_int64_t deformref_step;
- matrix deformref_box;
+ gmx_int64_t deformref_step;
+ matrix deformref_box;
};
+static bool isTemperatureCouplingStep(gmx_int64_t step, const t_inputrec *ir)
+{
+ /* We should only couple after a step where energies were determined (for leapfrog versions)
+ or the step energies are determined, for velocity verlet versions */
+ int offset;
+ if (EI_VV(ir->eI))
+ {
+ offset = 0;
+ }
+ else
+ {
+ offset = 1;
+ }
+ return ir->etc != etcNO &&
+ (ir->nsttcouple == 1 ||
+ do_per_step(step + ir->nsttcouple - offset, ir->nsttcouple));
+}
-static void do_update_md(int start, int nrend,
- double dt, int nstpcouple,
- t_grp_tcstat *tcstat,
- double nh_vxi[],
- gmx_bool bNEMD, t_grp_acc *gstat, rvec accel[],
- ivec nFreeze[],
- real invmass[],
- unsigned short ptype[], unsigned short cFREEZE[],
- unsigned short cACC[], unsigned short cTC[],
- rvec x[], rvec xprime[], rvec v[],
- rvec f[], matrix M,
- gmx_bool bNH, gmx_bool bPR)
+static bool isPressureCouplingStep(gmx_int64_t step, const t_inputrec *ir)
{
- double imass, w_dt;
- int gf = 0, ga = 0, gt = 0;
- rvec vrel;
- real vn, vv, va, vb, vnrel;
- real lg, vxi = 0, u;
- int n, d;
+ GMX_ASSERT(ir->epc != epcMTTK, "MTTK pressure coupling is not handled here");
- if (bNH || bPR)
+ int offset;
+ if (ir->epc == epcBERENDSEN)
{
- /* Update with coupling to extended ensembles, used for
- * Nose-Hoover and Parrinello-Rahman coupling
- * Nose-Hoover uses the reversible leap-frog integrator from
- * Holian et al. Phys Rev E 52(3) : 2338, 1995
- */
- for (n = start; n < nrend; n++)
+ offset = 0;
+ }
+ else
+ {
+ offset = 1;
+ }
+ /* We should only couple after a step where pressures were determined */
+ return ir->epc != etcNO &&
+ (ir->nstpcouple == 1 ||
+ do_per_step(step + ir->nstpcouple - offset, ir->nstpcouple));
+}
+
+/*! \brief Sets the number of different temperature coupling values */
+enum class NumTempScaleValues
+{
+ single, //!< Single T-scaling value (either one group or all values =1)
+ multiple //!< Multiple T-scaling values, need to use T-group indices
+};
+
+/*! \brief Sets if to apply no or diagonal Parrinello-Rahman pressure scaling
+ *
+ * Note that this enum is only used in updateMdLeapfrogSimple(), which does
+ * not handle fully anistropic Parrinello-Rahman scaling, so we only have
+ * options \p no and \p diagonal here and no anistropic option.
+ */
+enum class ApplyParrinelloRahmanVScaling
+{
+ no, //!< Do not apply velocity scaling (not a PR-coupling run or step)
+ diagonal //!< Apply velocity scaling using a diagonal matrix
+};
+
+/*! \brief Integrate using leap-frog with T-scaling and optionally diagonal Parrinello-Rahman p-coupling
+ *
+ * \tparam numTempScaleValues The number of different T-couple values
+ * \tparam applyPRVScaling Apply Parrinello-Rahman velocity scaling
+ * \param[in] start Index of first atom to update
+ * \param[in] nrend Last atom to update: \p nrend - 1
+ * \param[in] dt The time step
+ * \param[in] dtPressureCouple Time step for pressure coupling
+ * \param[in] invMassPerDim 1/mass per atom and dimension
+ * \param[in] tcstat Temperature coupling information
+ * \param[in] cTC T-coupling group index per atom
+ * \param[in] pRVScaleMatrixDiagonal Parrinello-Rahman v-scale matrix diagonal
+ * \param[in] x Input coordinates
+ * \param[out] xprime Updated coordinates
+ * \param[inout] v Velocities
+ * \param[in] f Forces
+ *
+ * We expect this template to get good SIMD acceleration by most compilers,
+ * unlike the more complex general template.
+ * Note that we might get even better SIMD acceleration when we introduce
+ * aligned (and padded) memory, possibly with some hints for the compilers.
+ */
+template<NumTempScaleValues numTempScaleValues,
+ ApplyParrinelloRahmanVScaling applyPRVScaling>
+static void
+updateMdLeapfrogSimple(int start,
+ int nrend,
+ real dt,
+ real dtPressureCouple,
+ const rvec * gmx_restrict invMassPerDim,
+ const t_grp_tcstat * tcstat,
+ const unsigned short * cTC,
+ const rvec pRVScaleMatrixDiagonal,
+ const rvec * gmx_restrict x,
+ rvec * gmx_restrict xprime,
+ rvec * gmx_restrict v,
+ const rvec * gmx_restrict f)
+{
+ real lambdaGroup;
+
+ if (numTempScaleValues == NumTempScaleValues::single)
+ {
+ lambdaGroup = tcstat[0].lambda;
+ }
+
+ for (int a = start; a < nrend; a++)
+ {
+ if (numTempScaleValues == NumTempScaleValues::multiple)
{
- imass = invmass[n];
- if (cFREEZE)
- {
- gf = cFREEZE[n];
- }
- if (cACC)
- {
- ga = cACC[n];
- }
- if (cTC)
- {
- gt = cTC[n];
- }
- lg = tcstat[gt].lambda;
- if (bNH)
+ lambdaGroup = tcstat[cTC[a]].lambda;
+ }
+
+ for (int d = 0; d < DIM; d++)
+ {
+ /* Note that using rvec invMassPerDim results in more efficient
+ * SIMD code, but this increases the cache pressure.
+ * For large systems with PME on the CPU this slows down the
+ * (then already slow) update by 20%. If all data remains in cache,
+ * using rvec is much faster.
+ */
+ real vNew = lambdaGroup*v[a][d] + f[a][d]*invMassPerDim[a][d]*dt;
+
+ if (applyPRVScaling == ApplyParrinelloRahmanVScaling::diagonal)
{
- vxi = nh_vxi[gt];
+ vNew -= dtPressureCouple*pRVScaleMatrixDiagonal[d]*v[a][d];
}
- rvec_sub(v[n], gstat[ga].u, vrel);
+ v[a][d] = vNew;
+ xprime[a][d] = x[a][d] + vNew*dt;
+ }
+ }
+}
- for (d = 0; d < DIM; d++)
- {
- if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
- {
- vnrel = (lg*vrel[d] + dt*(imass*f[n][d] - 0.5*vxi*vrel[d]
- - nstpcouple*iprod(M[d], vrel)))/(1 + 0.5*vxi*dt);
- /* do not scale the mean velocities u */
- vn = gstat[ga].u[d] + accel[ga][d]*dt + vnrel;
- v[n][d] = vn;
- xprime[n][d] = x[n][d]+vn*dt;
- }
- else
+/*! \brief Sets the NEMD acceleration type */
+enum class AccelerationType
+{
+ none, group, cosine
+};
+
+/*! \brief Integrate using leap-frog with support for everything
+ *
+ * \tparam accelerationType Type of NEMD acceleration
+ * \param[in] start Index of first atom to update
+ * \param[in] nrend Last atom to update: \p nrend - 1
+ * \param[in] doNoseHoover If to apply Nose-Hoover T-coupling
+ * \param[in] dt The time step
+ * \param[in] dtPressureCouple Time step for pressure coupling, is 0 when no pressure coupling should be applied at this step
+ * \param[in] ir The input parameter record
+ * \param[in] md Atom properties
+ * \param[in] ekind Kinetic energy data
+ * \param[in] box The box dimensions
+ * \param[in] x Input coordinates
+ * \param[out] xprime Updated coordinates
+ * \param[inout] v Velocities
+ * \param[in] f Forces
+ * \param[in] nh_vxi Nose-Hoover velocity scaling factors
+ * \param[in] M Parrinello-Rahman scaling matrix
+ */
+template<AccelerationType accelerationType>
+static void
+updateMdLeapfrogGeneral(int start,
+ int nrend,
+ bool doNoseHoover,
+ real dt,
+ real dtPressureCouple,
+ const t_inputrec * ir,
+ const t_mdatoms * md,
+ const gmx_ekindata_t * ekind,
+ const matrix box,
+ const rvec * gmx_restrict x,
+ rvec * gmx_restrict xprime,
+ rvec * gmx_restrict v,
+ const rvec * gmx_restrict f,
+ const double * gmx_restrict nh_vxi,
+ const matrix M)
+{
+ /* This is a version of the leap-frog integrator that supports
+ * all combinations of T-coupling, P-coupling and NEMD.
+ * Nose-Hoover uses the reversible leap-frog integrator from
+ * Holian et al. Phys Rev E 52(3) : 2338, 1995
+ */
+
+ const unsigned short * cTC = md->cTC;
+ const t_grp_tcstat * tcstat = ekind->tcstat;
+
+ const unsigned short * cACC = md->cACC;
+ const rvec * accel = ir->opts.acc;
+ const t_grp_acc * grpstat = ekind->grpstat;
+
+ const rvec * gmx_restrict invMassPerDim = md->invMassPerDim;
+
+ /* Initialize group values, changed later when multiple groups are used */
+ int ga = 0;
+ int gt = 0;
+ real factorNH = 0;
+
+ for (int n = start; n < nrend; n++)
+ {
+ if (cTC)
+ {
+ gt = cTC[n];
+ }
+ real lg = tcstat[gt].lambda;
+
+ rvec vRel;
+ real cosineZ, vCosine;
+#ifdef __INTEL_COMPILER
+#pragma warning( disable : 280 )
+#endif
+ switch (accelerationType)
+ {
+ case AccelerationType::none:
+ copy_rvec(v[n], vRel);
+ break;
+ case AccelerationType::group:
+ if (cACC)
{
- v[n][d] = 0.0;
- xprime[n][d] = x[n][d];
+ ga = cACC[n];
}
+ /* Avoid scaling the group velocity */
+ rvec_sub(v[n], grpstat[ga].u, vRel);
+ break;
+ case AccelerationType::cosine:
+ cosineZ = std::cos(x[n][ZZ]*static_cast<real>(M_PI)/box[ZZ][ZZ]);
+ vCosine = cosineZ*ekind->cosacc.vcos;
+ /* Avoid scaling the cosine profile velocity */
+ copy_rvec(v[n], vRel);
+ vRel[XX] -= vCosine;
+ break;
+ }
+
+ if (doNoseHoover)
+ {
+ /* Here we account for multiple time stepping, by increasing
+ * the Nose-Hoover correction by nsttcouple
+ */
+ factorNH = 0.5*ir->nsttcouple*dt*nh_vxi[gt];
+ }
+
+ for (int d = 0; d < DIM; d++)
+ {
+ real vNew =
+ (lg*vRel[d] + (f[n][d]*invMassPerDim[n][d]*dt - factorNH*vRel[d]
+ - dtPressureCouple*iprod(M[d], vRel)))/(1 + factorNH);
+ switch (accelerationType)
+ {
+ case AccelerationType::none:
+ break;
+ case AccelerationType::group:
+ /* Add back the mean velocity and apply acceleration */
+ vNew += grpstat[ga].u[d] + accel[ga][d]*dt;
+ break;
+ case AccelerationType::cosine:
+ if (d == XX)
+ {
+ /* Add back the mean velocity and apply acceleration */
+ vNew += vCosine + cosineZ*ekind->cosacc.cos_accel*dt;
+ }
+ break;
}
+ v[n][d] = vNew;
+ xprime[n][d] = x[n][d] + vNew*dt;
+ }
+ }
+}
+
+/*! \brief Handles the Leap-frog MD x and v integration */
+static void do_update_md(int start,
+ int nrend,
+ gmx_int64_t step,
+ real dt,
+ const t_inputrec * ir,
+ const t_mdatoms * md,
+ const gmx_ekindata_t * ekind,
+ const matrix box,
+ const rvec * gmx_restrict x,
+ rvec * gmx_restrict xprime,
+ rvec * gmx_restrict v,
+ const rvec * gmx_restrict f,
+ const double * gmx_restrict nh_vxi,
+ const matrix M)
+{
+ GMX_ASSERT(nrend == start || xprime != x, "For SIMD optimization certain compilers need to have xprime != x");
+
+ /* Note: Berendsen pressure scaling is handled after do_update_md() */
+ bool doTempCouple = isTemperatureCouplingStep(step, ir);
+ bool doNoseHoover = (ir->etc == etcNOSEHOOVER && doTempCouple);
+ bool doParrinelloRahman = (ir->epc == epcPARRINELLORAHMAN && isPressureCouplingStep(step, ir));
+ bool doPROffDiagonal = (doParrinelloRahman && (M[YY][XX] != 0 || M[ZZ][XX] != 0 || M[ZZ][YY] != 0));
+
+ real dtPressureCouple = (doParrinelloRahman ? ir->nstpcouple*dt : 0);
+
+ /* NEMD (also cosine) acceleration is applied in updateMdLeapFrogGeneral */
+ bool doAcceleration = (ekind->bNEMD || ekind->cosacc.cos_accel != 0);
+
+ if (doNoseHoover || doPROffDiagonal || doAcceleration)
+ {
+ if (!doAcceleration)
+ {
+ updateMdLeapfrogGeneral<AccelerationType::none>
+ (start, nrend, doNoseHoover, dt, dtPressureCouple,
+ ir, md, ekind, box, x, xprime, v, f, nh_vxi, M);
+ }
+ else if (ekind->bNEMD)
+ {
+ updateMdLeapfrogGeneral<AccelerationType::group>
+ (start, nrend, doNoseHoover, dt, dtPressureCouple,
+ ir, md, ekind, box, x, xprime, v, f, nh_vxi, M);
+ }
+ else
+ {
+ updateMdLeapfrogGeneral<AccelerationType::cosine>
+ (start, nrend, doNoseHoover, dt, dtPressureCouple,
+ ir, md, ekind, box, x, xprime, v, f, nh_vxi, M);
}
}
- else if (cFREEZE != NULL ||
- nFreeze[0][XX] || nFreeze[0][YY] || nFreeze[0][ZZ] ||
- bNEMD)
+ else
{
- /* Update with Berendsen/v-rescale coupling and freeze or NEMD */
- for (n = start; n < nrend; n++)
+ /* We determine if we have a single T-coupling lambda value for all
+ * atoms. That allows for better SIMD acceleration in the template.
+ * If we do not do temperature coupling (in the run or this step),
+ * all scaling values are 1, so we effectively have a single value.
+ */
+ bool haveSingleTempScaleValue = (!doTempCouple || ekind->ngtc == 1);
+
+ /* Extract some pointers needed by all cases */
+ const unsigned short *cTC = md->cTC;
+ const t_grp_tcstat *tcstat = ekind->tcstat;
+ const rvec *invMassPerDim = md->invMassPerDim;
+
+ if (doParrinelloRahman)
{
- w_dt = invmass[n]*dt;
- if (cFREEZE)
- {
- gf = cFREEZE[n];
- }
- if (cACC)
+ GMX_ASSERT(!doPROffDiagonal, "updateMdLeapfrogSimple only support diagonal Parrinello-Rahman scaling matrices");
+
+ rvec diagM;
+ for (int d = 0; d < DIM; d++)
{
- ga = cACC[n];
+ diagM[d] = M[d][d];
}
- if (cTC)
+
+ if (haveSingleTempScaleValue)
{
- gt = cTC[n];
+ updateMdLeapfrogSimple
+ <NumTempScaleValues::single,
+ ApplyParrinelloRahmanVScaling::diagonal>
+ (start, nrend, dt, dtPressureCouple,
+ invMassPerDim, tcstat, cTC, diagM, x, xprime, v, f);
}
- lg = tcstat[gt].lambda;
-
- for (d = 0; d < DIM; d++)
+ else
{
- vn = v[n][d];
- if ((ptype[n] != eptVSite) && (ptype[n] != eptShell) && !nFreeze[gf][d])
- {
- vv = lg*vn + f[n][d]*w_dt;
-
- /* do not scale the mean velocities u */
- u = gstat[ga].u[d];
- va = vv + accel[ga][d]*dt;
- vb = va + (1.0-lg)*u;
- v[n][d] = vb;
- xprime[n][d] = x[n][d]+vb*dt;
- }
- else
- {
- v[n][d] = 0.0;
- xprime[n][d] = x[n][d];
- }
+ updateMdLeapfrogSimple
+ <NumTempScaleValues::multiple,
+ ApplyParrinelloRahmanVScaling::diagonal>
+ (start, nrend, dt, dtPressureCouple,
+ invMassPerDim, tcstat, cTC, diagM, x, xprime, v, f);
}
}
- }
- else
- {
- /* Plain update with Berendsen/v-rescale coupling */
- for (n = start; n < nrend; n++)
+ else
{
- if ((ptype[n] != eptVSite) && (ptype[n] != eptShell))
+ if (haveSingleTempScaleValue)
{
- w_dt = invmass[n]*dt;
- if (cTC)
- {
- gt = cTC[n];
- }
- lg = tcstat[gt].lambda;
-
- for (d = 0; d < DIM; d++)
- {
- vn = lg*v[n][d] + f[n][d]*w_dt;
- v[n][d] = vn;
- xprime[n][d] = x[n][d] + vn*dt;
- }
+ updateMdLeapfrogSimple
+ <NumTempScaleValues::single,
+ ApplyParrinelloRahmanVScaling::no>
+ (start, nrend, dt, dtPressureCouple,
+ invMassPerDim, tcstat, cTC, NULL, x, xprime, v, f);
}
else
{
- for (d = 0; d < DIM; d++)
- {
- v[n][d] = 0.0;
- xprime[n][d] = x[n][d];
- }
+ updateMdLeapfrogSimple
+ <NumTempScaleValues::multiple,
+ ApplyParrinelloRahmanVScaling::no>
+ (start, nrend, dt, dtPressureCouple,
+ invMassPerDim, tcstat, cTC, NULL, x, xprime, v, f);
}
}
}
}
-static void do_update_vv_vel(int start, int nrend, double dt,
+static void do_update_vv_vel(int start, int nrend, real dt,
rvec accel[], ivec nFreeze[], real invmass[],
unsigned short ptype[], unsigned short cFREEZE[],
- unsigned short cACC[], rvec v[], rvec f[],
+ unsigned short cACC[], rvec v[], const rvec f[],
gmx_bool bExtended, real veta, real alpha)
{
- double w_dt;
int gf = 0, ga = 0;
int n, d;
- double g, mv1, mv2;
+ real g, mv1, mv2;
if (bExtended)
{
g = 0.25*dt*veta*alpha;
- mv1 = exp(-g);
+ mv1 = std::exp(-g);
mv2 = gmx::series_sinhx(g);
}
else
}
for (n = start; n < nrend; n++)
{
- w_dt = invmass[n]*dt;
+ real w_dt = invmass[n]*dt;
if (cFREEZE)
{
gf = cFREEZE[n];
}
} /* do_update_vv_vel */
-static void do_update_vv_pos(int start, int nrend, double dt,
+static void do_update_vv_pos(int start, int nrend, real dt,
ivec nFreeze[],
unsigned short ptype[], unsigned short cFREEZE[],
- rvec x[], rvec xprime[], rvec v[],
+ const rvec x[], rvec xprime[], rvec v[],
gmx_bool bExtended, real veta)
{
int gf = 0;
int n, d;
- double g, mr1, mr2;
+ real g, mr1, mr2;
/* Would it make more sense if Parrinello-Rahman was put here? */
if (bExtended)
{
g = 0.5*dt*veta;
- mr1 = exp(g);
+ mr1 = std::exp(g);
mr2 = gmx::series_sinhx(g);
}
else
}
} /* do_update_vv_pos */
-static void do_update_visc(int start, int nrend,
- double dt, int nstpcouple,
- t_grp_tcstat *tcstat,
- double nh_vxi[],
- real invmass[],
- unsigned short ptype[], unsigned short cTC[],
- rvec x[], rvec xprime[], rvec v[],
- rvec f[], matrix M, matrix box, real
- cos_accel, real vcos,
- gmx_bool bNH, gmx_bool bPR)
-{
- double imass, w_dt;
- int gt = 0;
- real vn, vc;
- real lg, vxi = 0, vv;
- real fac, cosz;
- rvec vrel;
- int n, d;
-
- fac = 2*M_PI/(box[ZZ][ZZ]);
-
- if (bNH || bPR)
- {
- /* Update with coupling to extended ensembles, used for
- * Nose-Hoover and Parrinello-Rahman coupling
- */
- for (n = start; n < nrend; n++)
- {
- imass = invmass[n];
- if (cTC)
- {
- gt = cTC[n];
- }
- lg = tcstat[gt].lambda;
- cosz = cos(fac*x[n][ZZ]);
-
- copy_rvec(v[n], vrel);
-
- vc = cosz*vcos;
- vrel[XX] -= vc;
- if (bNH)
- {
- vxi = nh_vxi[gt];
- }
- for (d = 0; d < DIM; d++)
- {
- if ((ptype[n] != eptVSite) && (ptype[n] != eptShell))
- {
- vn = (lg*vrel[d] + dt*(imass*f[n][d] - 0.5*vxi*vrel[d]
- - nstpcouple*iprod(M[d], vrel)))/(1 + 0.5*vxi*dt);
- if (d == XX)
- {
- vn += vc + dt*cosz*cos_accel;
- }
- v[n][d] = vn;
- xprime[n][d] = x[n][d]+vn*dt;
- }
- else
- {
- xprime[n][d] = x[n][d];
- }
- }
- }
- }
- else
- {
- /* Classic version of update, used with berendsen coupling */
- for (n = start; n < nrend; n++)
- {
- w_dt = invmass[n]*dt;
- if (cTC)
- {
- gt = cTC[n];
- }
- lg = tcstat[gt].lambda;
- cosz = cos(fac*x[n][ZZ]);
-
- for (d = 0; d < DIM; d++)
- {
- vn = v[n][d];
-
- if ((ptype[n] != eptVSite) && (ptype[n] != eptShell))
- {
- if (d == XX)
- {
- vc = cosz*vcos;
- /* Do not scale the cosine velocity profile */
- vv = vc + lg*(vn - vc + f[n][d]*w_dt);
- /* Add the cosine accelaration profile */
- vv += dt*cosz*cos_accel;
- }
- else
- {
- vv = lg*(vn + f[n][d]*w_dt);
- }
- v[n][d] = vv;
- xprime[n][d] = x[n][d]+vv*dt;
- }
- else
- {
- v[n][d] = 0.0;
- xprime[n][d] = x[n][d];
- }
- }
- }
- }
-}
-
static gmx_stochd_t *init_stochd(const t_inputrec *ir)
{
gmx_stochd_t *sd;
{
if (opts->tau_t[gt] > 0)
{
- sdc[gt].em = exp(-ir->delta_t/opts->tau_t[gt]);
+ sdc[gt].em = std::exp(-ir->delta_t/opts->tau_t[gt]);
}
else
{
gmx_update_t *init_update(const t_inputrec *ir)
{
- gmx_update_t *upd;
-
- snew(upd, 1);
+ gmx_update_t *upd = new(gmx_update_t);
if (ir->eI == eiBD || EI_SD(ir->eI) || ir->etc == etcVRESCALE || ETC_ANDERSEN(ir->etc))
{
update_temperature_constants(upd, ir);
- upd->xp = NULL;
- upd->xp_nalloc = 0;
+ upd->xp.resize(0);
return upd;
}
-void update_realloc(gmx_update_t *upd, int state_nalloc)
+void update_realloc(gmx_update_t *upd, int natoms)
{
GMX_ASSERT(upd, "upd must be allocated before its fields can be reallocated");
- if (state_nalloc > upd->xp_nalloc)
- {
- upd->xp_nalloc = state_nalloc;
- /* We need to allocate one element extra, since we might use
- * (unaligned) 4-wide SIMD loads to access rvec entries. */
- srenew(upd->xp, upd->xp_nalloc + 1);
- }
+
+ /* We need to allocate one element extra, since we might use
+ * (unaligned) 4-wide SIMD loads to access rvec entries. */
+ upd->xp.resize(natoms + 1);
}
static void do_update_sd1(gmx_stochd_t *sd,
- int start, int nrend, double dt,
+ int start, int nrend, real dt,
rvec accel[], ivec nFreeze[],
real invmass[], unsigned short ptype[],
unsigned short cFREEZE[], unsigned short cACC[],
unsigned short cTC[],
- rvec x[], rvec xprime[], rvec v[], rvec f[],
+ const rvec x[], rvec xprime[], rvec v[], const rvec f[],
gmx_bool bDoConstr,
gmx_bool bFirstHalfConstr,
gmx_int64_t step, int seed, int* gatindex)
}
}
-static void do_update_bd(int start, int nrend, double dt,
+static void do_update_bd(int start, int nrend, real dt,
ivec nFreeze[],
real invmass[], unsigned short ptype[],
unsigned short cFREEZE[], unsigned short cTC[],
- rvec x[], rvec xprime[], rvec v[],
- rvec f[], real friction_coefficient,
+ const rvec x[], rvec xprime[], rvec v[],
+ const rvec f[], real friction_coefficient,
real *rf, gmx_int64_t step, int seed,
int* gatindex)
{
}
static void dump_it_all(FILE gmx_unused *fp, const char gmx_unused *title,
- int gmx_unused natoms, rvec gmx_unused x[], rvec gmx_unused xp[],
- rvec gmx_unused v[], rvec gmx_unused f[])
+ int gmx_unused natoms,
+ const gmx_unused PaddedRVecVector *x,
+ const gmx_unused PaddedRVecVector *xp,
+ const gmx_unused PaddedRVecVector *v,
+ const gmx_unused PaddedRVecVector *f)
{
#ifdef DEBUG
if (fp)
{
fprintf(fp, "%s\n", title);
- pr_rvecs(fp, 0, "x", x, natoms);
- pr_rvecs(fp, 0, "xp", xp, natoms);
- pr_rvecs(fp, 0, "v", v, natoms);
- pr_rvecs(fp, 0, "f", f, natoms);
+ pr_rvecs(fp, 0, "x", as_rvec_array(x->data()), natoms);
+ pr_rvecs(fp, 0, "xp", as_rvec_array(xp->data()), natoms);
+ pr_rvecs(fp, 0, "v", as_rvec_array(v->data()), natoms);
+ if (f != NULL)
+ {
+ pr_rvecs(fp, 0, "f", as_rvec_array(f->data()), natoms);
+ }
}
#endif
}
{
if (ekind->cosacc.cos_accel == 0)
{
- calc_ke_part_normal(state->v, opts, md, ekind, nrnb, bEkinAveVel);
+ calc_ke_part_normal(as_rvec_array(state->v.data()), opts, md, ekind, nrnb, bEkinAveVel);
}
else
{
- calc_ke_part_visc(state->box, state->x, state->v, opts, md, ekind, nrnb, bEkinAveVel);
+ calc_ke_part_visc(state->box, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), opts, md, ekind, nrnb, bEkinAveVel);
}
}
snew(ekinstate->ekinh, ekinstate->ekin_n);
snew(ekinstate->ekinf, ekinstate->ekin_n);
snew(ekinstate->ekinh_old, ekinstate->ekin_n);
- snew(ekinstate->ekinscalef_nhc, ekinstate->ekin_n);
- snew(ekinstate->ekinscaleh_nhc, ekinstate->ekin_n);
- snew(ekinstate->vscale_nhc, ekinstate->ekin_n);
+ ekinstate->ekinscalef_nhc.resize(ekinstate->ekin_n);
+ ekinstate->ekinscaleh_nhc.resize(ekinstate->ekin_n);
+ ekinstate->vscale_nhc.resize(ekinstate->ekin_n);
ekinstate->dekindl = 0;
ekinstate->mvcos = 0;
}
t_mdatoms *md)
{
- gmx_bool bTCouple = FALSE;
- real dttc;
- int i, offset;
+ bool doTemperatureCoupling = false;
/* if using vv with trotter decomposition methods, we do this elsewhere in the code */
- if (inputrec->etc != etcNO &&
- !(inputrecNvtTrotter(inputrec) || inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec)))
+ if (!(EI_VV(inputrec->eI) &&
+ (inputrecNvtTrotter(inputrec) || inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec))))
{
- /* We should only couple after a step where energies were determined (for leapfrog versions)
- or the step energies are determined, for velocity verlet versions */
-
- if (EI_VV(inputrec->eI))
- {
- offset = 0;
- }
- else
- {
- offset = 1;
- }
- bTCouple = (inputrec->nsttcouple == 1 ||
- do_per_step(step+inputrec->nsttcouple-offset,
- inputrec->nsttcouple));
+ doTemperatureCoupling = isTemperatureCouplingStep(step, inputrec);
}
- if (bTCouple)
+ if (doTemperatureCoupling)
{
- dttc = inputrec->nsttcouple*inputrec->delta_t;
+ real dttc = inputrec->nsttcouple*inputrec->delta_t;
switch (inputrec->etc)
{
break;
case etcNOSEHOOVER:
nosehoover_tcoupl(&(inputrec->opts), ekind, dttc,
- state->nosehoover_xi, state->nosehoover_vxi, MassQ);
+ state->nosehoover_xi.data(), state->nosehoover_vxi.data(), MassQ);
break;
case etcVRESCALE:
vrescale_tcoupl(inputrec, step, ekind, dttc,
- state->therm_integral);
+ state->therm_integral.data());
break;
}
/* rescale in place here */
if (EI_VV(inputrec->eI))
{
- rescale_velocities(ekind, md, 0, md->homenr, state->v);
+ rescale_velocities(ekind, md, 0, md->homenr, as_rvec_array(state->v.data()));
}
}
else
{
/* Set the T scaling lambda to 1 to have no scaling */
- for (i = 0; (i < inputrec->opts.ngtc); i++)
+ for (int i = 0; (i < inputrec->opts.ngtc); i++)
{
ekind->tcstat[i].lambda = 1.0;
}
}
}
-void update_pcouple(FILE *fplog,
- gmx_int64_t step,
- t_inputrec *inputrec,
- t_state *state,
- matrix pcoupl_mu,
- matrix M,
- gmx_bool bInitStep)
+void update_pcouple_before_coordinates(FILE *fplog,
+ gmx_int64_t step,
+ const t_inputrec *inputrec,
+ t_state *state,
+ matrix parrinellorahmanMu,
+ matrix M,
+ gmx_bool bInitStep)
{
- gmx_bool bPCouple = FALSE;
- real dtpc = 0;
- int i;
-
- /* if using Trotter pressure, we do this in coupling.c, so we leave it false. */
- if (inputrec->epc != epcNO && (!(inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec))))
- {
- /* We should only couple after a step where energies were determined */
- bPCouple = (inputrec->nstpcouple == 1 ||
- do_per_step(step+inputrec->nstpcouple-1,
- inputrec->nstpcouple));
- }
-
- clear_mat(pcoupl_mu);
- for (i = 0; i < DIM; i++)
- {
- pcoupl_mu[i][i] = 1.0;
- }
-
- clear_mat(M);
-
- if (bPCouple)
+ /* Berendsen P-coupling is completely handled after the coordinate update.
+ * Trotter P-coupling is handled by separate calls to trotter_update().
+ */
+ if (inputrec->epc == epcPARRINELLORAHMAN &&
+ isPressureCouplingStep(step, inputrec))
{
- dtpc = inputrec->nstpcouple*inputrec->delta_t;
+ real dtpc = inputrec->nstpcouple*inputrec->delta_t;
- switch (inputrec->epc)
- {
- /* We can always pcoupl, even if we did not sum the energies
- * the previous step, since state->pres_prev is only updated
- * when the energies have been summed.
- */
- case (epcNO):
- break;
- case (epcBERENDSEN):
- if (!bInitStep)
- {
- berendsen_pcoupl(fplog, step, inputrec, dtpc, state->pres_prev, state->box,
- pcoupl_mu);
- }
- break;
- case (epcPARRINELLORAHMAN):
- parrinellorahman_pcoupl(fplog, step, inputrec, dtpc, state->pres_prev,
- state->box, state->box_rel, state->boxv,
- M, pcoupl_mu, bInitStep);
- break;
- default:
- break;
- }
+ parrinellorahman_pcoupl(fplog, step, inputrec, dtpc, state->pres_prev,
+ state->box, state->box_rel, state->boxv,
+ M, parrinellorahmanMu, bInitStep);
}
}
t_state *state,
gmx_bool bMolPBC,
t_graph *graph,
- rvec force[], /* forces on home particles */
+ PaddedRVecVector *force, /* forces on home particles */
t_idef *idef,
tensor vir_part,
t_commrec *cr,
gmx_bool bCalcVir)
{
gmx_bool bLastStep, bLog = FALSE, bEner = FALSE, bDoConstr = FALSE;
- double dt;
- int start, homenr, nrend, i;
tensor vir_con;
int nth, th;
/* for now, SD update is here -- though it really seems like it
should be reformulated as a velocity verlet method, since it has two parts */
- start = 0;
- homenr = md->homenr;
- nrend = start+homenr;
+ int start = 0;
+ int homenr = md->homenr;
+ int nrend = start+homenr;
- dt = inputrec->delta_t;
+ /* Cast delta_t from double to real to make the integrators faster.
+ * The only reason for having delta_t double is to get accurate values
+ * for t=delta_t*step when step is larger than float precision.
+ * For integration dt the accuracy of real suffices, since with
+ * integral += dt*integrand the increment is nearly always (much) smaller
+ * than the integral (and the integrand has real precision).
+ */
+ real dt = inputrec->delta_t;
/*
* Steps (7C, 8C)
{
constrain(NULL, bLog, bEner, constr, idef,
inputrec, cr, step, 1, 1.0, md,
- state->x, state->v, state->v,
+ as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), as_rvec_array(state->v.data()),
bMolPBC, state->box,
state->lambda[efptBONDED], dvdlambda,
NULL, bCalcVir ? &vir_con : NULL, nrnb, econqVeloc);
{
constrain(NULL, bLog, bEner, constr, idef,
inputrec, cr, step, 1, 1.0, md,
- state->x, upd->xp, NULL,
+ as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()), NULL,
bMolPBC, state->box,
state->lambda[efptBONDED], dvdlambda,
- state->v, bCalcVir ? &vir_con : NULL, nrnb, econqCoord);
+ as_rvec_array(state->v.data()), bCalcVir ? &vir_con : NULL, nrnb, econqCoord);
}
wallcycle_stop(wcycle, ewcCONSTR);
where();
dump_it_all(fplog, "After Shake",
- state->natoms, state->x, upd->xp, state->v, force);
+ state->natoms, &state->x, &upd->xp, &state->v, force);
if (bCalcVir)
{
inputrec->opts.acc, inputrec->opts.nFreeze,
md->invmass, md->ptype,
md->cFREEZE, md->cACC, md->cTC,
- state->x, upd->xp, state->v, force,
+ as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()), as_rvec_array(state->v.data()), as_rvec_array(force->data()),
bDoConstr, FALSE,
step, inputrec->ld_seed,
DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL);
constrain(NULL, bLog, bEner, constr, idef,
inputrec, cr, step, 1, 0.5, md,
- state->x, upd->xp, NULL,
+ as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()), NULL,
bMolPBC, state->box,
state->lambda[efptBONDED], dvdlambda,
- state->v, NULL, nrnb, econqCoord);
+ as_rvec_array(state->v.data()), NULL, nrnb, econqCoord);
wallcycle_stop(wcycle, ewcCONSTR);
}
if (graph && (graph->nnodes > 0))
{
- unshift_x(graph, state->box, state->x, upd->xp);
+ unshift_x(graph, state->box, as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()));
if (TRICLINIC(state->box))
{
inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes);
}
else
{
+ /* The copy is performance sensitive, so use a bare pointer */
+ rvec *xp = as_rvec_array(upd->xp.data());
#ifndef __clang_analyzer__
// cppcheck-suppress unreadVariable
nth = gmx_omp_nthreads_get(emntUpdate);
#endif
#pragma omp parallel for num_threads(nth) schedule(static)
- for (i = start; i < nrend; i++)
+ for (int i = start; i < nrend; i++)
{
// Trivial statement, does not throw
- copy_rvec(upd->xp[i], state->x[i]);
+ copy_rvec(xp[i], state->x[i]);
}
}
wallcycle_stop(wcycle, ewcUPDATE);
dump_it_all(fplog, "After unshift",
- state->natoms, state->x, upd->xp, state->v, force);
+ state->natoms, &state->x, &upd->xp, &state->v, force);
}
/* ############# END the update of velocities and positions ######### */
}
-void update_box(FILE *fplog,
- gmx_int64_t step,
- t_inputrec *inputrec, /* input record and box stuff */
- t_mdatoms *md,
- t_state *state,
- rvec force[], /* forces on home particles */
- matrix pcoupl_mu,
- t_nrnb *nrnb,
- gmx_update_t *upd)
+void update_pcouple_after_coordinates(FILE *fplog,
+ gmx_int64_t step,
+ const t_inputrec *inputrec,
+ const t_mdatoms *md,
+ const matrix pressure,
+ const matrix parrinellorahmanMu,
+ t_state *state,
+ t_nrnb *nrnb,
+ gmx_update_t *upd)
{
- double dt;
- int start, homenr, i, n, m;
+ int start = 0;
+ int homenr = md->homenr;
- start = 0;
- homenr = md->homenr;
-
- dt = inputrec->delta_t;
+ /* Cast to real for faster code, no loss in precision (see comment above) */
+ real dt = inputrec->delta_t;
where();
case (epcNO):
break;
case (epcBERENDSEN):
- /* We should only scale after a step where the pressure (kinetic
- * energy and virial) was calculated. This happens after the
- * coordinate update, whereas the current routine is called before
- * that, so we scale when step % nstpcouple = 1 instead of 0.
- */
- if (inputrec->nstpcouple == 1 || (step % inputrec->nstpcouple == 1))
+ if (isPressureCouplingStep(step, inputrec))
{
- berendsen_pscale(inputrec, pcoupl_mu, state->box, state->box_rel,
- start, homenr, state->x, md->cFREEZE, nrnb);
+ real dtpc = inputrec->nstpcouple*dt;
+ matrix mu;
+ berendsen_pcoupl(fplog, step, inputrec, dtpc, pressure, state->box,
+ mu);
+ berendsen_pscale(inputrec, mu, state->box, state->box_rel,
+ start, homenr, as_rvec_array(state->x.data()),
+ md->cFREEZE, nrnb);
}
break;
case (epcPARRINELLORAHMAN):
- /* The box velocities were updated in do_pr_pcoupl in the update
- * iteration, but we dont change the box vectors until we get here
- * since we need to be able to shift/unshift above.
- */
- for (i = 0; i < DIM; i++)
+ if (isPressureCouplingStep(step, inputrec))
{
- for (m = 0; m <= i; m++)
+ /* The box velocities were updated in do_pr_pcoupl,
+ * but we dont change the box vectors until we get here
+ * since we need to be able to shift/unshift above.
+ */
+ real dtpc = inputrec->nstpcouple*dt;
+ for (int i = 0; i < DIM; i++)
{
- state->box[i][m] += dt*state->boxv[i][m];
+ for (int m = 0; m <= i; m++)
+ {
+ state->box[i][m] += dtpc*state->boxv[i][m];
+ }
}
- }
- preserve_box_shape(inputrec, state->box_rel, state->box);
+ preserve_box_shape(inputrec, state->box_rel, state->box);
- /* Scale the coordinates */
- for (n = start; (n < start+homenr); n++)
- {
- tmvmul_ur0(pcoupl_mu, state->x[n], state->x[n]);
+ /* Scale the coordinates */
+ for (int n = start; n < start + homenr; n++)
+ {
+ tmvmul_ur0(parrinellorahmanMu, state->x[n], state->x[n]);
+ }
}
break;
case (epcMTTK):
ln V_new = ln V_old + 3*dt*veta => V_new = V_old*exp(3*dt*veta) =>
Side length scales as exp(veta*dt) */
- msmul(state->box, exp(state->veta*dt), state->box);
+ msmul(state->box, std::exp(state->veta*dt), state->box);
/* Relate veta to boxv. veta = d(eta)/dT = (1/DIM)*1/V dV/dT.
o If we assume isotropic scaling, and box length scaling
if (inputrecDeform(inputrec))
{
- deform(upd, start, homenr, state->x, state->box, inputrec, step);
+ deform(upd, start, homenr, as_rvec_array(state->x.data()), state->box, inputrec, step);
}
where();
dump_it_all(fplog, "After update",
- state->natoms, state->x, upd->xp, state->v, force);
+ state->natoms, &state->x, &upd->xp, &state->v, NULL);
}
void update_coords(FILE *fplog,
t_inputrec *inputrec, /* input record and box stuff */
t_mdatoms *md,
t_state *state,
- rvec *f, /* forces on home particles */
+ PaddedRVecVector *f, /* forces on home particles */
t_fcdata *fcd,
gmx_ekindata_t *ekind,
matrix M,
t_commrec *cr, /* these shouldn't be here -- need to think about it */
gmx_constr_t constr)
{
- gmx_bool bNH, bPR, bDoConstr = FALSE;
- double dt, alpha;
- int start, homenr, nrend;
- int nth, th;
-
- bDoConstr = (NULL != constr);
+ gmx_bool bDoConstr = (NULL != constr);
/* Running the velocity half does nothing except for velocity verlet */
if ((UpdatePart == etrtVELOCITY1 || UpdatePart == etrtVELOCITY2) &&
gmx_incons("update_coords called for velocity without VV integrator");
}
- start = 0;
- homenr = md->homenr;
- nrend = start+homenr;
+ int start = 0;
+ int homenr = md->homenr;
+ int nrend = start+homenr;
- dt = inputrec->delta_t;
+ /* Cast to real for faster code, no loss in precision (see comment above) */
+ real dt = inputrec->delta_t;
/* We need to update the NMR restraint history when time averaging is used */
if (state->flags & (1<<estDISRE_RM3TAV))
update_orires_history(fcd, &state->hist);
}
-
- bNH = inputrec->etc == etcNOSEHOOVER;
- bPR = ((inputrec->epc == epcPARRINELLORAHMAN) || (inputrec->epc == epcMTTK));
-
/* ############# START The update of velocities and positions ######### */
where();
dump_it_all(fplog, "Before update",
- state->natoms, state->x, upd->xp, state->v, f);
+ state->natoms, &state->x, &upd->xp, &state->v, f);
- nth = gmx_omp_nthreads_get(emntUpdate);
+ int nth = gmx_omp_nthreads_get(emntUpdate);
-#pragma omp parallel for num_threads(nth) schedule(static) private(alpha)
- for (th = 0; th < nth; th++)
+#pragma omp parallel for num_threads(nth) schedule(static)
+ for (int th = 0; th < nth; th++)
{
try
{
start_th = start + ((nrend-start)* th )/nth;
end_th = start + ((nrend-start)*(th+1))/nth;
+ const rvec *x_rvec = as_rvec_array(state->x.data());
+ rvec *xp_rvec = as_rvec_array(upd->xp.data());
+ rvec *v_rvec = as_rvec_array(state->v.data());
+ const rvec *f_rvec = as_rvec_array(f->data());
+
switch (inputrec->eI)
{
case (eiMD):
- if (ekind->cosacc.cos_accel == 0)
- {
- do_update_md(start_th, end_th,
- dt, inputrec->nstpcouple,
- ekind->tcstat, state->nosehoover_vxi,
- ekind->bNEMD, ekind->grpstat, inputrec->opts.acc,
- inputrec->opts.nFreeze,
- md->invmass, md->ptype,
- md->cFREEZE, md->cACC, md->cTC,
- state->x, upd->xp, state->v, f, M,
- bNH, bPR);
- }
- else
- {
- do_update_visc(start_th, end_th,
- dt, inputrec->nstpcouple,
- ekind->tcstat, state->nosehoover_vxi,
- md->invmass, md->ptype,
- md->cTC, state->x, upd->xp, state->v, f, M,
- state->box,
- ekind->cosacc.cos_accel,
- ekind->cosacc.vcos,
- bNH, bPR);
- }
+ do_update_md(start_th, end_th, step, dt,
+ inputrec, md, ekind, state->box,
+ x_rvec, xp_rvec, v_rvec, f_rvec,
+ state->nosehoover_vxi.data(), M);
break;
case (eiSD1):
/* With constraints, the SD1 update is done in 2 parts */
inputrec->opts.acc, inputrec->opts.nFreeze,
md->invmass, md->ptype,
md->cFREEZE, md->cACC, md->cTC,
- state->x, upd->xp, state->v, f,
+ x_rvec, xp_rvec, v_rvec, f_rvec,
bDoConstr, TRUE,
step, inputrec->ld_seed, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL);
break;
do_update_bd(start_th, end_th, dt,
inputrec->opts.nFreeze, md->invmass, md->ptype,
md->cFREEZE, md->cTC,
- state->x, upd->xp, state->v, f,
+ x_rvec, xp_rvec, v_rvec, f_rvec,
inputrec->bd_fric,
upd->sd->bd_rf,
step, inputrec->ld_seed, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL);
break;
case (eiVV):
case (eiVVAK):
- alpha = 1.0 + DIM/((double)inputrec->opts.nrdf[0]); /* assuming barostat coupled to group 0. */
+ {
+ gmx_bool bExtended = (inputrec->etc == etcNOSEHOOVER ||
+ inputrec->epc == epcPARRINELLORAHMAN ||
+ inputrec->epc == epcMTTK);
+
+ /* assuming barostat coupled to group 0 */
+ real alpha = 1.0 + DIM/static_cast<real>(inputrec->opts.nrdf[0]);
switch (UpdatePart)
{
case etrtVELOCITY1:
inputrec->opts.acc, inputrec->opts.nFreeze,
md->invmass, md->ptype,
md->cFREEZE, md->cACC,
- state->v, f,
- (bNH || bPR), state->veta, alpha);
+ v_rvec, f_rvec,
+ bExtended, state->veta, alpha);
break;
case etrtPOSITION:
do_update_vv_pos(start_th, end_th, dt,
inputrec->opts.nFreeze,
md->ptype, md->cFREEZE,
- state->x, upd->xp, state->v,
- (bNH || bPR), state->veta);
+ x_rvec, xp_rvec, v_rvec,
+ bExtended, state->veta);
break;
}
break;
+ }
default:
gmx_fatal(FARGS, "Don't know how to update coordinates");
break;
#define GMX_MDLIB_UPDATE_H
#include "gromacs/math/vectypes.h"
+#include "gromacs/mdtypes/state.h"
#include "gromacs/timing/wallcycle.h"
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/real.h"
/* Update the size of per-atom arrays (e.g. after DD re-partitioning,
which might increase the number of home atoms). */
-void update_realloc(gmx_update_t *upd, int state_nalloc);
+void update_realloc(gmx_update_t *upd, int natoms);
/* Store the box at step step
* as a reference state for simulations with box deformation.
t_mdatoms *md
);
-void update_pcouple(FILE *fplog,
- gmx_int64_t step,
- t_inputrec *inputrec,
- t_state *state,
- matrix pcoupl_mu,
- matrix M,
- gmx_bool bInitStep);
+/* Update Parrinello-Rahman, to be called before the coordinate update */
+void update_pcouple_before_coordinates(FILE *fplog,
+ gmx_int64_t step,
+ const t_inputrec *inputrec,
+ t_state *state,
+ matrix parrinellorahmanMu,
+ matrix M,
+ gmx_bool bInitStep);
+
+/* Update the box, to be called after the coordinate update.
+ * For Berendsen P-coupling, also calculates the scaling factor
+ * and scales the coordinates.
+ * When the deform option is used, scales coordinates and box here.
+ */
+void update_pcouple_after_coordinates(FILE *fplog,
+ gmx_int64_t step,
+ const t_inputrec *inputrec,
+ const t_mdatoms *md,
+ const matrix pressure,
+ const matrix parrinellorahmanMu,
+ t_state *state,
+ t_nrnb *nrnb,
+ gmx_update_t *upd);
void update_coords(FILE *fplog,
gmx_int64_t step,
t_inputrec *inputrec, /* input record and box stuff */
t_mdatoms *md,
t_state *state,
- rvec *f, /* forces on home particles */
+ PaddedRVecVector *f, /* forces on home particles */
t_fcdata *fcd,
gmx_ekindata_t *ekind,
matrix M,
t_state *state,
gmx_bool bMolPBC,
t_graph *graph,
- rvec force[], /* forces on home particles */
+ PaddedRVecVector *force, /* forces on home particles */
t_idef *idef,
tensor vir_part,
t_commrec *cr,
/* Return TRUE if OK, FALSE in case of Shake Error */
-void update_box(FILE *fplog,
- gmx_int64_t step,
- t_inputrec *inputrec, /* input record and box stuff */
- t_mdatoms *md,
- t_state *state,
- rvec force[], /* forces on home particles */
- matrix pcoupl_mu,
- t_nrnb *nrnb,
- gmx_update_t *upd);
-/* Return TRUE if OK, FALSE in case of Shake Error */
-
void calc_ke_part(t_state *state, t_grpopts *opts, t_mdatoms *md,
gmx_ekindata_t *ekind, t_nrnb *nrnb, gmx_bool bEkinAveVel);
/*
void nosehoover_tcoupl(t_grpopts *opts, gmx_ekindata_t *ekind, real dt,
double xi[], double vxi[], t_extmass *MassQ);
-t_state *init_bufstate(const t_state *template_state);
-
-void destroy_bufstate(t_state *state);
-
void trotter_update(t_inputrec *ir, gmx_int64_t step, gmx_ekindata_t *ekind,
gmx_enerdata_t *enerd, t_state *state, tensor vir, t_mdatoms *md,
t_extmass *MassQ, int **trotter_seqlist, int trotter_seqno);
int **init_npt_vars(t_inputrec *ir, t_state *state, t_extmass *Mass, gmx_bool bTrotter);
-real NPT_energy(t_inputrec *ir, t_state *state, t_extmass *MassQ);
+real NPT_energy(const t_inputrec *ir, const t_state *state, const t_extmass *MassQ);
/* computes all the pressure/tempertature control energy terms to get a conserved energy */
void NBaroT_trotter(t_grpopts *opts, real dt,
double therm_integral[]);
/* Compute temperature scaling. For V-rescale it is done in update. */
-real vrescale_energy(t_grpopts *opts, double therm_integral[]);
-/* Returns the V-rescale contribution to the conserved energy */
-
void rescale_velocities(gmx_ekindata_t *ekind, t_mdatoms *mdatoms,
int start, int end, rvec v[]);
/* Rescale the velocities with the scaling factor in ekind */
*/
void parrinellorahman_pcoupl(FILE *fplog, gmx_int64_t step,
- t_inputrec *ir, real dt, tensor pres,
+ const t_inputrec *ir, real dt, const tensor pres,
tensor box, tensor box_rel, tensor boxv,
tensor M, matrix mu,
gmx_bool bFirstStep);
void berendsen_pcoupl(FILE *fplog, gmx_int64_t step,
- t_inputrec *ir, real dt, tensor pres, matrix box,
+ const t_inputrec *ir, real dt,
+ const tensor pres, const matrix box,
matrix mu);
-void berendsen_pscale(t_inputrec *ir, matrix mu,
+void berendsen_pscale(const t_inputrec *ir, const matrix mu,
matrix box, matrix box_rel,
int start, int nr_atoms,
- rvec x[], unsigned short cFREEZE[],
+ rvec x[], const unsigned short cFREEZE[],
t_nrnb *nrnb);
void correct_ekin(FILE *log, int start, int end, rvec v[],
#
# 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()
--- /dev/null
+/*
+ * 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/applied-forces/electricfield.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)
+ {
+ field_ = createElectricFieldModule();
+ snew(ir_, 1);
+ snew(ir_->fepvals, 1);
+ snew(ir_->expandedvals, 1);
+ snew(ir_->simtempvals, 1);
+ ir_->efield = field_.get();
+ }
+ }
+
+ std::unique_ptr<IInputRecExtension> field_;
+ t_inputrec *ir_;
+};
+
+MDModules::MDModules() : impl_(new Impl)
+{
+}
+
+MDModules::~MDModules()
+{
+}
+
+t_inputrec *MDModules::inputrec()
+{
+ impl_->ensureInputrecInitialized();
+ return impl_->ir_;
+}
+
+} // namespace gmx
--- /dev/null
+/*
+ * 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. This class owns all such
+ * modules, and needs to remain in existence as long as the returned data
+ * structures are in use. Ideally, it is also the only place that creates
+ * instances of these modules (outside test code).
+ *
+ * The general idea is that each module takes care of its own data rather than
+ * mdrun having to know about all the details of each type of force calculation.
+ * Initially this is applied for simple things like electric field calculations
+ * but later more complex forces will be supported too.
+ *
+ * The current approach uses t_inputrec and IInputRecExtension to pass
+ * references to the modules to other code to avoid changing many function
+ * signatures. Also, the current usage means that nearly every use of
+ * t_inputrec (in particular, reading it from mdp or tpr files) needs to be
+ * initialized through MDModules for correct functionality. For the future, a
+ * better approach would be to pass around a reference to MDModules instead and
+ * call it directly for cases that are not related to t_inputrec functionality.
+ * This (and other refactoring) would allow simplifying IInputRecExtension.
+ * IForceProvider is the other interface currently used to interact with these
+ * modules. Also, all the places where these interfaces are used should become
+ * loops over a container of these interfaces, instead of the current single
+ * pointer.
+ *
+ * \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
--- /dev/null
+#
+# 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>)
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
#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)
{
}
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,
bool haveTopology;
bool invalidValue;
- const gmx::HardwareTopology &hwTop = *hwinfo->hardwareTopology;
-
haveTopology = (hwTop.supportLevel() >= gmx::HardwareTopology::SupportLevel::Basic);
if (pin_offset < 0)
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
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;
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;
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;
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;
}
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;
}
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
{
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;
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;
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)
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;
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);
if (validLayout)
{
allAffinitiesSet = set_affinity(cr, nthread_local, thread0_id_node,
- offset, core_pinning_stride, localityOrder);
+ offset, core_pinning_stride, localityOrder,
+ affinityAccess);
}
else
{
}
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.");
}
}
* 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");
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;
}
{
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;
}
/* 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());
}
}
/*
* 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,
* 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);
/*
* 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.
*/
+
+/*! \libinternal \file
+ *
+ *
+ * \brief
+ * This file contains datatypes for energy statistics history.
+ *
+ * \author Berk Hess
+ *
+ * \inlibraryapi
+ * \ingroup module_mdtypes
+ */
+
#ifndef GMX_MDLIB_ENERGYHISTORY_H
#define GMX_MDLIB_ENERGYHISTORY_H
+#include <memory>
+#include <vector>
+
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/real.h"
-/* energy history for delta_h histograms */
-typedef struct delta_h_history_t
-{
- int nndh; /* the number of energy difference lists */
- int *ndh; /* the number in each energy difference list */
- real **dh; /* the energy difference lists */
+//! \cond INTERNAL
- double start_time; /* the start time of these energy diff blocks */
- double start_lambda; /* lambda at start time */
+//! \brief Energy history for delta_h histograms in between energy file frames
+class delta_h_history_t
+{
+ public:
+ //! Vector (size number of intermediate data points) of vector of Hamiltonian differences for each foreign lambda
+ std::vector<std::vector<real> > dh;
+ //! The start time of these energy diff blocks
+ double start_time;
+ //! Lambda at start time
+ double start_lambda;
+ //! Whether the lambda value is set. Here for backward-compatibility.
+ gmx_bool start_lambda_set;
- gmx_bool start_lambda_set; /* whether the lambda value is set. Here
- For backward-compatibility. */
-} delta_h_history_t;
+ //! Constructor
+ delta_h_history_t() : dh(),
+ start_time(0),
+ start_lambda(0),
+ start_lambda_set(false)
+ {
+ }
+};
-typedef struct energyhistory_t
+//! \brief Energy statistics history, only used for output and reporting
+class energyhistory_t
{
- gmx_int64_t nsteps; /* The number of steps in the history */
- gmx_int64_t nsum; /* The nr. of steps in the ener_ave and ener_sum */
- double * ener_ave; /* Energy term history sum to get fluctuations */
- double * ener_sum; /* Energy term history sum to get fluctuations */
- int nener; /* Number of energy terms in two previous arrays */
- gmx_int64_t nsteps_sim; /* The number of steps in ener_sum_sim */
- gmx_int64_t nsum_sim; /* The number of frames in ener_sum_sim */
- double * ener_sum_sim; /* Energy term history sum of the whole sim */
+ public:
+ gmx_int64_t nsteps; //! The number of steps in the history
+ gmx_int64_t nsum; //! Nr. of steps in the ener_ave and ener_sum
+ std::vector<double> ener_ave; //! Energy terms difference^2 sum to get fluctuations
+ std::vector<double> ener_sum; //! Energy terms sum
+ gmx_int64_t nsteps_sim; //! The number of steps in ener_sum_sim
+ gmx_int64_t nsum_sim; //! The number of frames in ener_sum_sim
+ std::vector<double> ener_sum_sim; //! Energy term history sum of the whole sim
- delta_h_history_t *dht; /* The BAR energy differences */
-}
-energyhistory_t;
+ //! History for energy difference for foreign lambdas (useful for BAR)
+ std::unique_ptr<delta_h_history_t> deltaHForeignLambdas;
-/* \brief Initialize an energy history structure
- */
-void init_energyhistory(energyhistory_t * enerhist);
+ //! Constructor
+ energyhistory_t() : nsteps(0),
+ nsum(0),
+ ener_ave(),
+ ener_sum(),
+ nsteps_sim(0),
+ nsum_sim(0),
+ ener_sum_sim(0)
+ {
+ }
+};
-/* \brief Destroy an energy history structure
- */
-void done_energyhistory(energyhistory_t * enerhist);
+//! \endcond
#endif
#define GMX_MDTYPES_TYPES_FORCEREC_H
#include "gromacs/math/vectypes.h"
+#ifdef __cplusplus
+#include "gromacs/math/paddedvector.h"
+#endif
#include "gromacs/mdtypes/interaction_const.h"
#include "gromacs/mdtypes/md_enums.h"
#include "gromacs/topology/idef.h"
#include "gromacs/utility/real.h"
#ifdef __cplusplus
+
extern "C" {
-#endif
-#if 0
-} /* fixes auto-indentation problems */
+
+struct t_mdatoms;
+struct t_commrec;
+
+/*! \libinternal \brief
+ * Interface for a component that provides forces during MD.
+ *
+ * This is typically part of a larger structure/class managing its own
+ * data, such that it has the information on what to do stored locally.
+ * \todo Implement returning of energy and dH/dlambda.
+ * \inlibraryapi
+ */
+struct IForceProvider
+{
+ public:
+ /*! \brief Compute forces
+ *
+ * \todo This is specific for electric fields and needs to be generalized.
+ * \param[in] cr Communication record for parallel operations
+ * \param[in] mdatoms Atom information
+ * \param[inout] force The forces
+ * \param[in] t The actual time in the simulation (ps)
+ */
+ virtual void calculateForces(const t_commrec *cr,
+ const t_mdatoms *mdatoms,
+ PaddedRVecVector *force,
+ double t) = 0;
+
+ protected:
+ ~IForceProvider() {}
+};
#endif
/* Abstract type for PME that is defined only in the routine that use them. */
/* Forces that should not enter into the virial summation:
* PPPM/PME/Ewald/posres
+ * If such forces are present in the system, bF_NoVirSum=TRUE.
*/
- gmx_bool bF_NoVirSum;
- int f_novirsum_n;
- int f_novirsum_nalloc;
- rvec *f_novirsum_alloc;
- /* Pointer that points to f_novirsum_alloc when pressure is calcaluted,
- * points to the normal force vectors wen pressure is not requested.
+ gmx_bool bF_NoVirSum;
+#ifdef __cplusplus
+ /* TODO: Replace the pointer by an object once we got rid of C */
+ PaddedRVecVector *forceBufferNoVirialSummation;
+#else
+ void *forceBufferNoVirialSummation_dummy;
+#endif
+ /* Pointer that points to forceNoVirialSummation when virial is calcaluted,
+ * points to the normal force vector when the virial is not requested
+ * or when bF_NoVirSum == FALSE.
*/
- rvec *f_novirsum;
+#ifdef __cplusplus
+ PaddedRVecVector *f_novirsum;
+#else
+ void *f_novirsum_xdummy;
+#endif
/* Long-range forces and virial for PPPM/PME/Ewald */
struct gmx_pme_t *pmedata;
struct bonded_threading_t *bonded_threading;
/* Ewald correction thread local virial and energy data */
- int nthread_ewc;
- ewald_corr_thread_t *ewc_t;
+ int nthread_ewc;
+ ewald_corr_thread_t *ewc_t;
+
+ struct IForceProvider *efield;
} t_forcerec;
/* Important: Starting with Gromacs-4.6, the values of c6 and c12 in the nbfp array have
#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"
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)
void done_inputrec(t_inputrec *ir)
{
- int m;
-
- for (m = 0; (m < DIM); m++)
- {
- if (ir->ex[m].a)
- {
- sfree(ir->ex[m].a);
- }
- if (ir->ex[m].phi)
- {
- sfree(ir->ex[m].phi);
- }
- if (ir->et[m].a)
- {
- sfree(ir->et[m].a);
- }
- if (ir->et[m].phi)
- {
- sfree(ir->et[m].phi);
- }
- }
-
sfree(ir->opts.nrdf);
sfree(ir->opts.ref_t);
sfree(ir->opts.annealing);
sfree(ir->opts.SAsteps);
sfree(ir->opts.bOPT);
sfree(ir->opts.bTS);
+ sfree(ir->fepvals);
+ sfree(ir->expandedvals);
+ sfree(ir->simtempvals);
if (ir->pull)
{
}
}
-static void pr_cosine(FILE *fp, int indent, const char *title, const t_cosines *cos,
- gmx_bool bMDPformat)
-{
- int j;
-
- if (bMDPformat)
- {
- fprintf(fp, "%s = %d\n", title, cos->n);
- }
- else
- {
- indent = pr_title(fp, indent, title);
- pr_indent(fp, indent);
- fprintf(fp, "n = %d\n", cos->n);
- if (cos->n > 0)
- {
- pr_indent(fp, indent+2);
- fprintf(fp, "a =");
- for (j = 0; (j < cos->n); j++)
- {
- fprintf(fp, " %e", cos->a[j]);
- }
- fprintf(fp, "\n");
- pr_indent(fp, indent+2);
- fprintf(fp, "phi =");
- for (j = 0; (j < cos->n); j++)
- {
- fprintf(fp, " %e", cos->phi[j]);
- }
- fprintf(fp, "\n");
- }
- }
-}
-
#define PS(t, s) pr_str(fp, indent, t, s)
#define PI(t, s) pr_int(fp, indent, t, s)
#define PSTEP(t, s) pr_int64(fp, indent, t, s)
}
/* ELECTRIC FIELDS */
- pr_cosine(fp, indent, "E-x", &(ir->ex[XX]), bMDPformat);
- pr_cosine(fp, indent, "E-xt", &(ir->et[XX]), bMDPformat);
- pr_cosine(fp, indent, "E-y", &(ir->ex[YY]), bMDPformat);
- pr_cosine(fp, indent, "E-yt", &(ir->et[YY]), bMDPformat);
- pr_cosine(fp, indent, "E-z", &(ir->ex[ZZ]), bMDPformat);
- pr_cosine(fp, indent, "E-zt", &(ir->et[ZZ]), bMDPformat);
+ ir->efield->printParameters(fp, indent);
/* ION/WATER SWAPPING FOR COMPUTATIONAL ELECTROPHYSIOLOGY */
PS("swapcoords", ESWAPTYPE(ir->eSwapCoords));
#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_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);
+ ir1->efield->compare(fp, ir2->efield, 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 ||
(ir->ewald_geometry == eewg3DC || ir->epsilon_surface != 0));
}
-gmx_bool inputrecElecField(const t_inputrec *ir)
-{
- return (ir->ex[XX].n > 0 || ir->ex[YY].n > 0 || ir->ex[ZZ].n > 0);
-}
-
gmx_bool inputrecExclForces(const t_inputrec *ir)
{
return (EEL_FULL(ir->coulombtype) || (EEL_RF(ir->coulombtype)) ||
*
* 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 "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/real.h"
-typedef struct {
- //! Number of terms
- int n;
- //! Coeffients (V / nm)
- real *a;
- //! Phase angles
- real *phi;
-} t_cosines;
-
-typedef struct {
- real E0; /* Field strength (V/nm) */
- real omega; /* Frequency (1/ps) */
- real t0; /* Centre of the Gaussian pulse (ps) */
- real sigma; /* Width of the Gaussian pulse (FWHM) (ps) */
-} t_efield;
-
#define EGP_EXCL (1<<0)
#define EGP_TABLE (1<<1)
+struct gmx_output_env_t;
+struct pull_params_t;
+struct t_commrec;
+struct t_fileio;
+struct t_filenm;
+struct t_forcerec;
+struct t_inpfile;
+struct warninp;
+
+namespace gmx
+{
+
+class IKeyValueTreeTransformRules;
+class IOptionsContainerWithSections;
+
+/*! \libinternal \brief
+ * Inputrec extension interface for a mdrun module.
+ *
+ * This interface provides a mechanism for additional modules to contribute
+ * data that traditionally has been kept in t_inputrec. This is essentially
+ * parameters read from an mdp file and subsequently stored in a tpr file.
+ * The functionality to broadcast, compare, and print these parameters
+ * currently needs to be provided separately, but this should simplify
+ * significantly if/when we move to a more structured file format (both for mdp
+ * and tpr) that allows a generic representation for code that does not need to
+ * know the interpretation of the values.
+ *
+ * For now, this interface also includes some unrelated methods (initOutput(),
+ * finishOutput(), initForcerec()), because t_inputrec is used as a container
+ * to pass references to the modules around.
+ * See MDModules for more information on the general approach and future
+ * considerations.
+ */
+class IInputRecExtension
+{
+ public:
+ virtual ~IInputRecExtension() {}
+
+ /*! \brief Read or write tpr file
+ *
+ * Read or write the necessary data from a tpr file. The routine is responsible
+ * for consistency, such that all data belonging to this module is read or written.
+ * \param[inout] fio Gromacs file descriptor
+ * \param[in] bRead boolean determines whether we are reading or writing
+ */
+ virtual void doTpxIO(t_fileio *fio, bool bRead) = 0;
+
+ /*! \brief
+ * Initializes a transform from mdp values to sectioned options.
+ *
+ * The transform is specified from a flat KeyValueTreeObject that
+ * contains each mdp value as a property, to a structure which is then
+ * assigned to the options defined with initMdpOptions().
+ */
+ virtual void initMdpTransform(IKeyValueTreeTransformRules *transform) = 0;
+ /*! \brief
+ * Defines input (mdp) parameters for this extension.
+ */
+ virtual void initMdpOptions(IOptionsContainerWithSections *options) = 0;
+
+ /*! \brief Broadcast input parameters to all ranks
+ *
+ * \param[in] cr Communication record, gromacs structure
+ */
+ virtual void broadCast(const t_commrec *cr) = 0;
+
+ /*! \brief compare a section of two input record structures
+ *
+ * Routine is used in gmx check.
+ * \param[in] fp File pointer
+ * \param[inout] field2 Electric field
+ * \param[in] reltol Relative tolerance
+ * \param[in] abstol Absolute tolerance
+ */
+ virtual void compare(FILE *fp,
+ const gmx::IInputRecExtension *field2,
+ real reltol,
+ real abstol) = 0;
+
+ /*! \brief Print parameters belonging to this class to a file
+ *
+ * \param[in] fp File pointer
+ * \param[in] indent Initial indentation level for printing
+ */
+ virtual void printParameters(FILE *fp, int indent) = 0;
+
+ /*! \brief Initiate output parameters
+ *
+ * \param[in] fplog File pointer for log messages
+ * \param[in] nfile Number of files
+ * \param[in] fnm Array of filenames and properties
+ * \param[in] bAppendFiles Whether or not we should append to files
+ * \param[in] oenv The output environment for xvg files
+ */
+ virtual void initOutput(FILE *fplog, int nfile, const t_filenm fnm[],
+ bool bAppendFiles, const gmx_output_env_t *oenv) = 0;
+
+ //! Finalize output
+ virtual void finishOutput() = 0;
+
+ /*! \brief Set/initiate relevant options in the forcerec structure
+ *
+ * \param[inout] fr The forcerec structure
+ */
+ virtual void initForcerec(t_forcerec *fr) = 0;
+};
+
+} // namespace gmx
+
typedef struct t_grpopts {
int ngtc; /* # T-Coupl groups */
int nhchainlength; /* # of nose-hoover chains per group */
* 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 */
struct pull_t *pull_work; /* The COM pull force calculation data structure; TODO this pointer should live somewhere else */
/* Enforced rotation data */
- gmx_bool bRot; /* Calculate enforced rotation potential(s)? */
- t_rot *rot; /* The data for enforced rotation potentials */
-
- int eSwapCoords; /* Do ion/water position exchanges (CompEL)? */
- t_swapcoords *swap;
-
- gmx_bool bIMD; /* Allow interactive MD sessions for this .tpr? */
- t_IMD *imd; /* Interactive molecular dynamics */
-
- real cos_accel; /* Acceleration for viscosity calculation */
- tensor deform; /* Triclinic deformation velocities (nm/ps) */
- int userint1; /* User determined parameters */
- int userint2;
- int userint3;
- int userint4;
- real userreal1;
- real userreal2;
- real userreal3;
- real userreal4;
- t_grpopts opts; /* Group options */
- t_cosines ex[DIM]; /* Electric field stuff (spatial part) */
- t_cosines et[DIM]; /* Electric field stuff (time part) */
- gmx_bool bQMMM; /* QM/MM calculation */
- int QMconstraints; /* constraints on QM bonds */
- int QMMMscheme; /* Scheme: ONIOM or normal */
- real scalefactor; /* factor for scaling the MM charges in QM calc.*/
+ gmx_bool bRot; /* Calculate enforced rotation potential(s)? */
+ t_rot *rot; /* The data for enforced rotation potentials */
+
+ int eSwapCoords; /* Do ion/water position exchanges (CompEL)? */
+ t_swapcoords *swap;
+
+ gmx_bool bIMD; /* Allow interactive MD sessions for this .tpr? */
+ t_IMD *imd; /* Interactive molecular dynamics */
+
+ real cos_accel; /* Acceleration for viscosity calculation */
+ tensor deform; /* Triclinic deformation velocities (nm/ps) */
+ int userint1; /* User determined parameters */
+ int userint2;
+ int userint3;
+ int userint4;
+ real userreal1;
+ real userreal2;
+ real userreal3;
+ real userreal4;
+ t_grpopts opts; /* Group options */
+ gmx::IInputRecExtension *efield; /* Applied electric field */
+ gmx_bool bQMMM; /* QM/MM calculation */
+ int QMconstraints; /* constraints on QM bonds */
+ int QMMMscheme; /* Scheme: ONIOM or normal */
+ real scalefactor; /* factor for scaling the MM charges in QM calc.*/
/* 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);
*/
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.
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);
gmx_bool inputrecTwinRange(const t_inputrec *ir);
-gmx_bool inputrecElecField(const t_inputrec *ir);
-
gmx_bool inputrecExclForces(const t_inputrec *ir);
gmx_bool inputrecNptTrotter(const t_inputrec *ir);
*
* Copyright (c) 1991-2000, University of Groningen, The Netherlands.
* Copyright (c) 2001-2004, The GROMACS development team.
- * 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.
#ifndef GMX_MDTYPES_MDATOM_H
#define GMX_MDTYPES_MDATOM_H
+#include "gromacs/math/vectypes.h"
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/real.h"
real *massB;
//! Atomic mass in present state
real *massT;
- //! Inverse atomic mass
+ //! Inverse atomic mass per atom, 0 for vsites and shells
real *invmass;
+ //! Inverse atomic mass per atom and dimension, 0 for vsites, shells and frozen dimensions
+ rvec *invMassPerDim;
//! Atomic charge in A state
real *chargeA;
//! Atomic charge in B state
*
* 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/gmxassert.h"
#include "gromacs/utility/smalloc.h"
/* The source code in this file should be thread-safe.
eks->ekinh = NULL;
eks->ekinf = NULL;
eks->ekinh_old = NULL;
- eks->ekinscalef_nhc = NULL;
- eks->ekinscaleh_nhc = NULL;
- eks->vscale_nhc = NULL;
+ eks->ekinscalef_nhc.resize(0);
+ eks->ekinscaleh_nhc.resize(0);
+ eks->vscale_nhc.resize(0);
eks->dekindl = 0;
eks->mvcos = 0;
}
void init_gtc_state(t_state *state, int ngtc, int nnhpres, int nhchainlength)
{
- int i, j;
-
state->ngtc = ngtc;
state->nnhpres = nnhpres;
state->nhchainlength = nhchainlength;
- if (state->ngtc > 0)
- {
- snew(state->nosehoover_xi, state->nhchainlength*state->ngtc);
- snew(state->nosehoover_vxi, state->nhchainlength*state->ngtc);
- snew(state->therm_integral, state->ngtc);
- for (i = 0; i < state->ngtc; i++)
- {
- for (j = 0; j < state->nhchainlength; j++)
- {
- state->nosehoover_xi[i*state->nhchainlength + j] = 0.0;
- state->nosehoover_vxi[i*state->nhchainlength + j] = 0.0;
- }
- }
- for (i = 0; i < state->ngtc; i++)
- {
- state->therm_integral[i] = 0.0;
- }
- }
- else
- {
- state->nosehoover_xi = NULL;
- state->nosehoover_vxi = NULL;
- state->therm_integral = NULL;
- }
-
- if (state->nnhpres > 0)
- {
- snew(state->nhpres_xi, state->nhchainlength*nnhpres);
- snew(state->nhpres_vxi, state->nhchainlength*nnhpres);
- for (i = 0; i < nnhpres; i++)
- {
- for (j = 0; j < state->nhchainlength; j++)
- {
- state->nhpres_xi[i*nhchainlength + j] = 0.0;
- state->nhpres_vxi[i*nhchainlength + j] = 0.0;
- }
- }
- }
- else
- {
- state->nhpres_xi = NULL;
- state->nhpres_vxi = NULL;
- }
+ state->nosehoover_xi.resize(state->nhchainlength*state->ngtc, 0);
+ state->nosehoover_vxi.resize(state->nhchainlength*state->ngtc, 0);
+ state->therm_integral.resize(state->ngtc, 0);
+ state->nhpres_xi.resize(state->nhchainlength*nnhpres, 0);
+ state->nhpres_vxi.resize(state->nhchainlength*nnhpres, 0);
}
-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;
-
state->natoms = natoms;
state->flags = 0;
state->fep_state = 0;
- state->lambda = 0;
- snew(state->lambda, efptNR);
- for (i = 0; i < efptNR; i++)
- {
- state->lambda[i] = 0;
- }
+ state->lambda.resize(efptNR, 0);
state->veta = 0;
clear_mat(state->box);
clear_mat(state->box_rel);
clear_mat(state->svir_prev);
clear_mat(state->fvir_prev);
init_gtc_state(state, ngtc, nnhpres, nhchainlength);
- state->nalloc = state->natoms;
- if (state->nalloc > 0)
+ if (state->natoms > 0)
{
/* We need to allocate one element extra, since we might use
* (unaligned) 4-wide SIMD loads to access rvec entries.
*/
- snew(state->x, state->nalloc + 1);
- snew(state->v, state->nalloc + 1);
+ state->x.resize(state->natoms + 1);
+ state->v.resize(state->natoms + 1);
}
else
{
- state->x = NULL;
- state->v = NULL;
+ state->x.resize(0);
+ state->v.resize(0);
}
- state->cg_p = NULL;
+ state->cg_p.resize(0);
zero_history(&state->hist);
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;
- state->cg_gl_nalloc = 0;
+ state->cg_gl.resize(0);
}
-void done_state(t_state *state)
+void comp_state(const t_state *st1, const t_state *st2,
+ gmx_bool bRMSD, real ftol, real abstol)
{
- if (state->x)
+ 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))
{
- sfree(state->x);
+ fprintf(stdout, "comparing shake vir_prev\n");
+ cmp_rvecs(stdout, "svir_prev", DIM, st1->svir_prev, st2->svir_prev, FALSE, ftol, abstol);
}
- if (state->v)
+ if (st1->flags & (1<<estFVIR_PREV))
{
- sfree(state->v);
+ fprintf(stdout, "comparing force vir_prev\n");
+ cmp_rvecs(stdout, "fvir_prev", DIM, st1->fvir_prev, st2->fvir_prev, FALSE, ftol, abstol);
}
- if (state->cg_p)
+ if (st1->flags & (1<<estPRES_PREV))
{
- sfree(state->cg_p);
+ fprintf(stdout, "comparing prev_pres\n");
+ cmp_rvecs(stdout, "pres_prev", DIM, st1->pres_prev, st2->pres_prev, FALSE, ftol, abstol);
}
- state->nalloc = 0;
- if (state->cg_gl)
+ 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)
{
- sfree(state->cg_gl);
+ 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);
+ }
+ }
}
- state->cg_gl_nalloc = 0;
- if (state->lambda)
+ cmp_int(stdout, "nnhpres", -1, st1->nnhpres, st2->nnhpres);
+ if (st1->nnhpres == st2->nnhpres && st1->nhchainlength == st2->nhchainlength)
{
- sfree(state->lambda);
+ 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);
+ }
+ }
}
- if (state->ngtc > 0)
+
+ cmp_int(stdout, "natoms", -1, st1->natoms, st2->natoms);
+ if (st1->natoms == st2->natoms)
{
- sfree(state->nosehoover_xi);
- sfree(state->nosehoover_vxi);
- sfree(state->therm_integral);
+ if ((st1->flags & (1<<estX)) && (st2->flags & (1<<estX)))
+ {
+ fprintf(stdout, "comparing x\n");
+ cmp_rvecs(stdout, "x", st1->natoms, as_rvec_array(st1->x.data()), as_rvec_array(st2->x.data()), bRMSD, ftol, abstol);
+ }
+ if ((st1->flags & (1<<estV)) && (st2->flags & (1<<estV)))
+ {
+ fprintf(stdout, "comparing v\n");
+ cmp_rvecs(stdout, "v", st1->natoms, as_rvec_array(st1->v.data()), as_rvec_array(st2->v.data()), bRMSD, ftol, abstol);
+ }
}
}
-t_state *serial_init_local_state(t_state *state_global)
+rvec *getRvecArrayFromPaddedRVecVector(const PaddedRVecVector *v,
+ unsigned int n)
{
- int i;
- t_state *state_local;
+ GMX_ASSERT(v->size() >= n, "We can't copy more elements than the vector size");
+
+ rvec *dest;
- snew(state_local, 1);
+ snew(dest, n);
- /* Copy all the contents */
- *state_local = *state_global;
- snew(state_local->lambda, efptNR);
- /* local storage for lambda */
- for (i = 0; i < efptNR; i++)
+ const rvec *vPtr = as_rvec_array(v->data());
+ for (unsigned int i = 0; i < n; i++)
{
- state_local->lambda[i] = state_global->lambda[i];
+ copy_rvec(vPtr[i], dest[i]);
}
- return state_local;
+ return dest;
}
*
* 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.
#ifndef GMX_MDTYPES_STATE_H
#define GMX_MDTYPES_STATE_H
+#include <vector>
+
+#include "gromacs/math/paddedvector.h"
#include "gromacs/math/vectypes.h"
#include "gromacs/mdtypes/md_enums.h"
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/real.h"
-struct energyhistory_t;
-
/*
* The t_state struct should contain all the (possibly) non-static
* information required to define the state of the system.
*/
typedef struct ekinstate_t
{
- gmx_bool bUpToDate;
- int ekin_n;
- tensor *ekinh;
- tensor *ekinf;
- tensor *ekinh_old;
- tensor ekin_total;
- double *ekinscalef_nhc;
- double *ekinscaleh_nhc;
- double *vscale_nhc;
- real dekindl;
- real mvcos;
+ gmx_bool bUpToDate;
+ int ekin_n;
+ tensor *ekinh;
+ tensor *ekinf;
+ tensor *ekinh_old;
+ tensor ekin_total;
+ std::vector<double> ekinscalef_nhc;
+ std::vector<double> ekinscaleh_nhc;
+ std::vector<double> vscale_nhc;
+ real dekindl;
+ real mvcos;
} ekinstate_t;
typedef struct df_history_t
int nhchainlength; /* number of nose-hoover chains */
int flags; /* Flags telling which entries are present */
int fep_state; /* indicates which of the alchemical states we are in */
- real *lambda; /* lambda vector */
+ std::vector<real> lambda; /* lambda vector */
matrix box; /* box vector coordinates */
matrix box_rel; /* Relitaive box vectors to preserve shape */
matrix boxv; /* box velocitites for Parrinello-Rahman pcoupl */
matrix pres_prev; /* Pressure of the previous step for pcoupl */
matrix svir_prev; /* Shake virial for previous step for pcoupl */
matrix fvir_prev; /* Force virial of the previous step for pcoupl */
- double *nosehoover_xi; /* for Nose-Hoover tcoupl (ngtc) */
- double *nosehoover_vxi; /* for N-H tcoupl (ngtc) */
- double *nhpres_xi; /* for Nose-Hoover pcoupl for barostat */
- double *nhpres_vxi; /* for Nose-Hoover pcoupl for barostat */
- double *therm_integral; /* for N-H/V-rescale tcoupl (ngtc) */
+ std::vector<double> nosehoover_xi; /* for Nose-Hoover tcoupl (ngtc) */
+ std::vector<double> nosehoover_vxi; /* for N-H tcoupl (ngtc) */
+ std::vector<double> nhpres_xi; /* for Nose-Hoover pcoupl for barostat */
+ std::vector<double> nhpres_vxi; /* for Nose-Hoover pcoupl for barostat */
+ std::vector<double> therm_integral; /* for N-H/V-rescale tcoupl (ngtc) */
real veta; /* trotter based isotropic P-coupling */
real vol0; /* initial volume,required for computing NPT conserverd quantity */
- int nalloc; /* Allocation size for x and v when !=NULL*/
- rvec *x; /* the coordinates (natoms) */
- rvec *v; /* the velocities (natoms) */
- rvec *cg_p; /* p vector for conjugate gradient minimization */
-
- history_t hist; /* Time history for restraints */
+ PaddedRVecVector x; /* the coordinates (natoms) */
+ PaddedRVecVector v; /* the velocities (natoms) */
+ PaddedRVecVector cg_p; /* p vector for conjugate gradient minimization */
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 */
+ /* History for special algorithms, should be moved to a history struct */
+ history_t hist; /* Time history for restraints */
+ 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 */
- int ncg_gl; /* The number of local charge groups */
- int *cg_gl; /* The global cg number of the local cgs */
- int cg_gl_nalloc; /* Allocation size of cg_gl; */
+ std::vector<int> cg_gl; /* The global cg number of the local cgs */
} t_state;
typedef struct t_extmass
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 comp_state(const t_state *st1, const t_state *st2, gmx_bool bRMSD, real ftol, real abstol);
-void done_state(t_state *state);
+/*! \brief Allocate an rvec pointer and copy the contents of v to it */
+rvec *getRvecArrayFromPaddedRVecVector(const PaddedRVecVector *v,
+ unsigned int n);
#endif
/*
* 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.
{
impl_->bPrintHeader_ = true;
}
- impl_->columns_.push_back(Impl::ColumnData(title, width, bWrap));
+ impl_->columns_.emplace_back(title, width, bWrap);
}
void TextTableFormatter::setFirstColumnIndent(int indent)
{
if (overflow > columnWidth && column->bWrap_)
{
- columnLines.push_back(std::string());
+ columnLines.emplace_back();
continue;
}
columnWidth -= overflow;
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);
}
/********************************************************************
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.
#
# 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
#
# 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)
/*
* 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 "gromacs/options/optionflags.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/variant.h"
#include "basicoptionstorage.h"
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;
return description;
}
-std::string OptionInfo::formatDefaultValueIfSet() const
+std::vector<Variant> OptionInfo::defaultValues() const
{
- return option().formatDefaultValueIfSet();
+ return option().defaultValues();
}
-int OptionInfo::valueCount() const
+std::vector<std::string> OptionInfo::defaultValuesAsStrings() const
{
- return option().valueCount();
+ return option().defaultValuesAsStrings();
}
-std::string OptionInfo::formatValue(int i) const
+std::vector<Variant> OptionInfo::normalizeValues(const std::vector<Variant> &values) const
{
- return option().formatValue(i);
+ return option().normalizeValues(values);
}
} // namespace gmx
/*
* 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.
class AbstractOptionStorage;
template <typename T> class OptionStorageTemplate;
class OptionManagerContainer;
+class Variant;
namespace internal
{
-class OptionsImpl;
+class OptionSectionImpl;
}
/*! \brief
*/
friend class AbstractOptionStorage;
//! Needed to be able to call createStorage().
- friend class internal::OptionsImpl;
+ friend class internal::OptionSectionImpl;
};
/*! \brief
std::string type() const;
//! Returns the description of the option.
std::string formatDescription() const;
+
/*! \brief
- * Returns the default value if set for the option as a string.
+ * Returns the default value(s) of the option.
+ *
+ * The returned values should all be of the same type, but returning
+ * each as a separate variant is currently simpler.
*
- * \see OptionTemplate::defaultValueIfSet()
+ * Currently, this can only be called before option values have been
+ * assigned.
*/
- std::string formatDefaultValueIfSet() const;
-
- //! Returns the number of values given for the option.
- int valueCount() const;
- //! Returns the i'th value of the option as a string.
- std::string formatValue(int i) const;
+ std::vector<Variant> defaultValues() const;
+ /*! \brief
+ * Returns the default value(s) of the option as strings.
+ *
+ * If there is no default value, but defaultValueIfSet() is set, that
+ * is returned instead.
+ *
+ * Currently, this can only be called before option values have been
+ * assigned.
+ */
+ std::vector<std::string> defaultValuesAsStrings() const;
+ /*! \brief
+ * Converts given values to native representation for this option.
+ *
+ * For example, strings are parsed to the type that is actually used to
+ * store the options.
+ *
+ * The return value only depends on the option type, not on the current
+ * value of the option, and the current value in the option is not
+ * changed.
+ */
+ std::vector<Variant> normalizeValues(const std::vector<Variant> &values) const;
protected:
/*! \cond libapi */
/*
* 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.
#define GMX_OPTIONS_ABSTRACTOPTIONSTORAGE_H
#include <string>
+#include <vector>
#include "gromacs/options/optionflags.h"
#include "gromacs/utility/classhelpers.h"
class AbstractOption;
class OptionInfo;
class Options;
+class Variant;
/*! \libinternal \brief
* Abstract base class for converting, validating, and storing option values.
* Returns the number of option values added so far.
*/
virtual int valueCount() const = 0;
- /*! \brief
- * Returns the i'th value formatted as a string.
- *
- * If \p i is DefaultValueIfSetIndex, should format the default value
- * if set (see OptionTemplate::defaultValueIfSet()).
- */
- virtual std::string formatValue(int i) const = 0;
- //! \copydoc OptionInfo::formatDefaultValueIfSet()
- std::string formatDefaultValueIfSet() const
- { return formatValue(DefaultValueIfSetIndex); }
+ //! \copydoc OptionInfo::defaultValues()
+ virtual std::vector<Variant> defaultValues() const = 0;
+ //! \copydoc OptionInfo::defaultValuesAsStrings()
+ virtual std::vector<std::string> defaultValuesAsStrings() const = 0;
+ //! \copydoc OptionInfo::normalizeValues()
+ virtual std::vector<Variant> normalizeValues(const std::vector<Variant> &values) const = 0;
/*! \brief
* Starts adding values from a new source for the option.
*/
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.
void finish();
protected:
- //! Index used with formatValue() for formatting default value if set.
- static const int DefaultValueIfSetIndex = -1;
-
/*! \brief
* Initializes the storage object from the settings object.
*
*/
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.
*
*
* \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.
--- /dev/null
+/*
+ * 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
+{
+
+/********************************************************************
+ * AbstractOptionSectionHandle
+ */
+
+// static
+IOptionSectionStorage *
+AbstractOptionSectionHandle::getStorage(internal::OptionSectionImpl *section)
+{
+ return section->storage_.get();
+}
+
+IOptionsContainer &AbstractOptionSectionHandle::addGroup()
+{
+ return section_->addGroup();
+}
+
+internal::OptionSectionImpl *
+AbstractOptionSectionHandle::addSectionImpl(const AbstractOptionSection §ion)
+{
+ return section_->addSectionImpl(section);
+}
+
+OptionInfo *AbstractOptionSectionHandle::addOptionImpl(const AbstractOption &settings)
+{
+ return section_->addOptionImpl(settings);
+}
+
+/********************************************************************
+ * AbstractOptionSectionInfo
+ */
+
+const std::string &AbstractOptionSectionInfo::name() const
+{
+ return section_.name_;
+}
+
+} // namespace gmx
--- /dev/null
+/*
+ * 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 §ion);
+ // 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 name of the section.
+ const std::string &name() const;
+
+ //! Returns the wrapped section storage object.
+ internal::OptionSectionImpl §ion() { return section_; }
+ //! Returns the wrapped section storage object.
+ const internal::OptionSectionImpl §ion() const { return section_; }
+
+ private:
+ internal::OptionSectionImpl §ion_;
+
+ GMX_DISALLOW_COPY_AND_ASSIGN(AbstractOptionSectionInfo);
+};
+
+} // namespace gmx
+
+#endif
/*
* 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 "gromacs/utility/cstringutil.h"
#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/strconvert.h"
#include "gromacs/utility/stringutil.h"
#include "basicoptionstorage.h"
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>);
}
/********************************************************************
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)
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>);
}
/********************************************************************
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>);
+ converter->addCastConversion<float>();
+}
+
+double DoubleOptionStorage::processValue(const double &value) const
+{
+ // TODO: Consider testing for overflow when scaling with factor_.
+ return value * factor_;
}
void DoubleOptionStorage::processSetValues(ValueList *values)
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;
}
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>);
+ converter->addCastConversion<double>();
+}
+
+float FloatOptionStorage::processValue(const float &value) const
+{
+ // TODO: Consider testing for overflow when scaling with factor_.
+ return value * factor_;
}
void FloatOptionStorage::processSetValues(ValueList *values)
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;
}
{
GMX_THROW(APIError("Enumeration value cannot be NULL"));
}
- allowed_.push_back(settings.enumValues_[i]);
+ allowed_.emplace_back(settings.enumValues_[i]);
}
if (settings.defaultEnumIndex_ >= 0)
{
{
GMX_THROW(APIError("Conflicting default values"));
}
- clear();
- addValue(allowed_[settings.defaultEnumIndex_]);
- commitValues();
+ setDefaultValue(allowed_[settings.defaultEnumIndex_]);
}
}
}
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) const
+{
+ if (allowed_.size() > 0)
{
- ValueList::const_iterator match = findEnumValue(allowed_, value);
- addValue(*match);
+ return *findEnumValue(this->allowed_, value);
}
+ return value;
}
/********************************************************************
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)
{
{
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");
{
setDefaultValueIfSet(defaultValueIfSet);
}
-
- if (values().empty())
- {
- values() = store_->initialValues();
- }
- refreshEnumIndexStore();
}
std::string EnumOptionStorage::formatExtraDescription() 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();
+ });
}
/********************************************************************
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));
}
/*
* 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/ivaluestore.h"
+#include "gromacs/utility/arrayref.h"
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/gmxassert.h"
/*! \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_;
};
createEnumOptionStorage(const AbstractOption &option,
const char *const *enumValues, int count,
int defaultValue, int defaultValueIfSet,
- EnumIndexStoreInterface *store);
+ IOptionValueStore<int> *store);
//! \endcond
} // namespace internal
/*
* 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.
/*! \internal \brief
* Converts, validates, and stores boolean values.
*/
-class BooleanOptionStorage : public OptionStorageTemplate<bool>
+class BooleanOptionStorage : public OptionStorageTemplateSimple<bool>
{
public:
/*! \brief
bool defaultValue() const { return valueCount() > 0 && values()[0]; }
private:
- virtual void convertValue(const std::string &value);
+ virtual void initConverter(ConverterType *converter);
BooleanOptionInfo info_;
};
/*! \internal \brief
* Converts, validates, and stores integer values.
*/
-class IntegerOptionStorage : public OptionStorageTemplate<int>
+class IntegerOptionStorage : public OptionStorageTemplateSimple<int>
{
public:
//! \copydoc BooleanOptionStorage::BooleanOptionStorage()
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_;
/*! \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()
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_;
};
/*! \internal \brief
* Converts, validates, and stores floating-point (double) values.
*/
-class DoubleOptionStorage : public OptionStorageTemplate<double>
+class DoubleOptionStorage : public OptionStorageTemplateSimple<double>
{
public:
//! \copydoc IntegerOptionStorage::IntegerOptionStorage()
void setScaleFactor(double factor);
private:
- virtual void convertValue(const std::string &value);
+ virtual void initConverter(ConverterType *converter);
+ virtual double processValue(const double &value) const;
virtual void processSetValues(ValueList *values);
DoubleOptionInfo info_;
/*! \internal \brief
* Converts, validates, and stores floating-point (float) values.
*/
-class FloatOptionStorage : public OptionStorageTemplate<float>
+class FloatOptionStorage : public OptionStorageTemplateSimple<float>
{
public:
//! \copydoc IntegerOptionStorage::IntegerOptionStorage()
void setScaleFactor(double factor);
private:
- virtual void convertValue(const std::string &value);
+ virtual void initConverter(ConverterType *converter);
+ virtual float processValue(const float &value) const;
virtual void processSetValues(ValueList *values);
FloatOptionInfo info_;
/*! \internal \brief
* Converts, validates, and stores string values.
*/
-class StringOptionStorage : public OptionStorageTemplate<std::string>
+class StringOptionStorage : public OptionStorageTemplateSimple<std::string>
{
public:
//! \copydoc DoubleOptionStorage::DoubleOptionStorage()
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) const;
StringOptionInfo info_;
ValueList allowed_;
/*! \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.
*
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"; }
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_;
};
/*!\}*/
/*
* 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.
return value;
}
-void FileNameOptionStorage::convertValue(const std::string &value)
+void FileNameOptionStorage::initConverter(ConverterType * /*converter*/)
+{
+}
+
+std::string FileNameOptionStorage::processValue(const std::string &value) const
{
if (manager_ != NULL)
{
"Manager returned an invalid file name");
}
}
- addValue(processedValue);
- return;
+ return processedValue;
}
}
// Currently, directory options are simple, and don't need any
// 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)
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())
GMX_ASSERT(isValidType(fn2ftp(newValue.c_str())),
"Manager returned an invalid default value");
valueList[0] = newValue;
- refreshValues();
}
}
}
/*
* 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.
/*! \internal \brief
* Converts, validates, and stores file names.
*/
-class FileNameOptionStorage : public OptionStorageTemplate<std::string>
+class FileNameOptionStorage : public OptionStorageTemplateSimple<std::string>
{
public:
/*! \brief
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) const;
virtual void processAll();
FileNameOptionInfo info_;
* 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.
*
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>();
// (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);
};
--- /dev/null
+/*
+ * 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 §ion)
+ {
+ 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 §ion) = 0;
+
+ GMX_DEFAULT_CONSTRUCTORS(IOptionsContainerWithSections);
+};
+
+} // namespace
+
+#endif
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
/*
* 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
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 §ion);
+
+ // 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.
*
* Does not throw.
*/
- Options *findSubSection(const char *name) const;
+ OptionSectionImpl *findSection(const char *name) const;
/*! \brief
* Finds an option by name.
*
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
/*
* 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 "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"
{
}
+/********************************************************************
+ * IOptionsContainerWithSections
+ */
+
+IOptionsContainerWithSections::~IOptionsContainerWithSections()
+{
+}
+
+/********************************************************************
+ * IOptionSectionStorage
+ */
+
+IOptionSectionStorage::~IOptionSectionStorage()
+{
+}
+
/********************************************************************
* OptionsImpl
*/
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 §ion)
+{
+ 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 §ion : 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 §ion = **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);
* Options
*/
-Options::Options(const char *name, const char *title)
- : impl_(new OptionsImpl(name, title))
+Options::Options()
+ : impl_(new OptionsImpl)
{
}
{
}
-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 §ion)
{
- // 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 §ion = **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
/*
* 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
{
* 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.
* \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.
*
* 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.
void finish();
private:
+ // From IOptionsContainerWithSections
+ virtual internal::OptionSectionImpl *
+ addSectionImpl(const AbstractOptionSection §ion);
+ // 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
/*
* 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 "gromacs/options/options.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/variant.h"
#include "options-impl.h"
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 ¤tSection() const { return *sectionStack_.back(); }
+ Section ¤tSection() const { return *sectionStack_.back(); }
/*! \brief
* Finds an option by the given name.
*
*
* 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
: options_(*options), bAcceptBooleanNoPrefix_(false),
currentOption_(NULL), currentValueCount_(0), reverseBoolean_(false)
{
- sectionStack_.push_back(&options_);
+ sectionStack_.push_back(&options_.impl_->rootSection_);
}
AbstractOptionStorage *
{
GMX_RELEASE_ASSERT(currentOption_ == NULL,
"Cannot search for another option while processing one");
- const Options §ion = currentSection();
- AbstractOptionStorage *option = section.impl_->findOption(name);
+ const Section §ion = 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;
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)
}
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");
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_)
{
}
}
-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
/*
* 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.
{
class Options;
+class Variant;
/*! \libinternal \brief
* Decorator class for assigning values to 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();
*
* Strong exception safety guarantee.
*/
- void startSubSection(const char *name);
+ void startSection(const char *name);
/*! \brief
* Starts assigning values for an option.
*
/*! \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.
*
* 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.
*
* Does not throw.
*/
- void finishSubSection();
+ void finishSection();
/*! \brief
* Finish assigning options through the object.
*
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
#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 "gromacs/utility/variant.h"
+
+#include "valueconverter.h"
namespace gmx
{
*
* \tparam T Assignable type that stores a single option value.
*
- * 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.
- * This leaves typeString(), formatValue(), and convertValue() to be
- * implemented in derived classes. processSetValues() and processAll() can
- * also be implemented if necessary.
+ * Provides an implementation of the clearSet(), valueCount(), processSet(),
+ * and defaultValuesAsStrings() methods of AbstractOptionStorage, as well as a
+ * basic no-action implementation of processAll(). Two new virtual methods are
+ * added: processSetValues() and formatSingleValue().
+ * This leaves typeString(), convertValue() and formatStringValue() to be
+ * implemented in derived classes.
+ * processSetValues() and processAll() can also be implemented if necessary.
*
* Implements transaction support for adding values within a set: all calls to
* addValue() add the value to a temporary storage, processSetValues() operates
//! 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()); }
- /*! \copydoc gmx::AbstractOptionStorage::formatValue()
+ virtual int valueCount() const { return store_->valueCount(); }
+ //! \copydoc gmx::AbstractOptionStorage::defaultValues()
+ virtual std::vector<Variant> defaultValues() const;
+ /*! \copydoc gmx::AbstractOptionStorage::defaultValuesAsStrings()
*
- * OptionStorageTemplate implements handling of DefaultValueIfSetIndex
- * in this method, as well as checking that \p i is a valid index.
+ * OptionStorageTemplate implements handling of defaultValueIfSet()
+ * cases and composing the vector.
* Derived classes must implement formatSingleValue() to provide the
* actual formatting for a value of type \p T.
*/
- virtual std::string formatValue(int i) const;
+ virtual std::vector<std::string> defaultValuesAsStrings() const;
protected:
+ //! Smart pointer for managing the final storage interface.
+ typedef std::unique_ptr<IOptionValueStore<T> > StorePointer;
+
/*! \brief
* Initializes the storage from option settings.
*
* 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();
* 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.
*
* \returns \p value formatted as a string.
*
* The derived class must provide this method to format values a
- * strings. Called by formatValue() to do the actual formatting.
+ * strings. Called by defaultValuesAsStrings() to do the actual
+ * formatting.
*/
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.
*
* 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.
* 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)
+ {
+ }
+
+ virtual std::vector<Variant>
+ normalizeValues(const std::vector<Variant> &values) const
+ {
+ const_cast<MyBase *>(this)->ensureConverterInitialized();
+ std::vector<Variant> result;
+ for (const auto &value : values)
+ {
+ result.push_back(
+ Variant::create<T>(
+ processValue(converter_.convert(value))));
+ }
+ return result;
+ }
+
/*! \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.
+ *
+ * \param[in] value Value after conversion.
+ * \returns Value to store for the option.
*
- * Primarily, modifications to values are done only to this storage,
- * and other storage locations are updated only when refreshValues() is
- * called.
+ * 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) const
+ {
+ return value;
+ }
- // Copy and assign disallowed by base.
+ private:
+ virtual void convertValue(const Variant &variant)
+ {
+ ensureConverterInitialized();
+ this->addValue(processValue(converter_.convert(variant)));
+ }
+ void ensureConverterInitialized()
+ {
+ if (!initialized_)
+ {
+ initConverter(&converter_);
+ initialized_ = true;
+ }
+ }
+
+ 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);
{
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_);
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>());
}
template <typename T>
-std::string OptionStorageTemplate<T>::formatValue(int i) const
+std::vector<Variant> OptionStorageTemplate<T>::defaultValues() const
{
- GMX_RELEASE_ASSERT(i == DefaultValueIfSetIndex || (i >= 0 && i < valueCount()),
- "Invalid value index");
- if (i == DefaultValueIfSetIndex)
+ std::vector<Variant> result;
+ if (hasFlag(efOption_NoDefaultValue))
{
+ return result;
+ }
+ GMX_RELEASE_ASSERT(hasFlag(efOption_HasDefaultValue),
+ "Current option implementation can only provide default values before assignment");
+ for (const auto &value : values())
+ {
+ result.push_back(Variant::create<T>(value));
+ }
+ return result;
+}
+
+
+template <typename T>
+std::vector<std::string> OptionStorageTemplate<T>::defaultValuesAsStrings() const
+{
+ std::vector<std::string> result;
+ if (hasFlag(efOption_NoDefaultValue))
+ {
+ return result;
+ }
+ GMX_RELEASE_ASSERT(hasFlag(efOption_HasDefaultValue),
+ "Current option implementation can only provide default values before assignment");
+ for (const auto &value : values())
+ {
+ result.push_back(formatSingleValue(value));
+ }
+ if (result.empty() || (result.size() == 1 && result[0].empty()))
+ {
+ result.clear();
if (defaultValueIfSet_.get() != NULL)
{
- return formatSingleValue(*defaultValueIfSet_);
+ result.push_back(formatSingleValue(*defaultValueIfSet_));
}
- return std::string();
}
- return formatSingleValue(values()[i]);
+ return result;
}
{
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];
- }
- }
}
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);
}
}
/*
* 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.
#include "gromacs/options/abstractoptionstorage.h"
#include "gromacs/options/options.h"
+#include "gromacs/options/optionsection.h"
#include "options-impl.h"
//! 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);
}
}
*/
OptionsIterator::OptionsIterator(const Options &options)
- : options_(options)
+ : section_(options.rootSection().section())
{
}
-void OptionsIterator::acceptSubSections(OptionsVisitor *visitor) const
+OptionsIterator::OptionsIterator(const OptionSectionInfo §ion)
+ : 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 §ion : section_.subsections_)
{
- visitor->visitSubSection(*(*i));
+ visitor->visitSection(section->info());
}
}
void OptionsIterator::acceptOptions(OptionsVisitor *visitor) const
{
- acceptOptionsGroup(options_.impl_->rootGroup_, visitor);
+ acceptOptionsGroup(section_.rootGroup_, visitor);
}
/********************************************************************
*/
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 §ion : section_.subsections_)
{
- visitor->visitSubSection(*i);
+ visitor->visitSection(§ion->info());
}
}
void OptionsModifyingIterator::acceptOptions(OptionsModifyingVisitor *visitor) const
{
- acceptOptionsGroup(options_.impl_->rootGroup_, visitor);
+ acceptOptionsGroup(section_.rootGroup_, visitor);
}
} // namespace gmx
/*
* 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.
{
class Options;
+class OptionSectionInfo;
+
+namespace internal
+{
+class OptionSectionImpl;
+}
/*! \libinternal \brief
* Pure interface for visiting options in a Options object.
public:
virtual ~OptionsVisitor() {}
- /*! \brief
- * Called for each subsection in Options.
- */
- virtual void visitSubSection(const Options §ion) = 0;
- /*! \brief
- * Called for each option in Options.
- */
+ //! Called for each section.
+ virtual void visitSection(const OptionSectionInfo §ion) = 0;
+ //! Called for each option.
virtual void visitOption(const OptionInfo &option) = 0;
};
public:
virtual ~OptionsTypeVisitor() {}
- virtual void visitSubSection(const Options §ion) = 0;
+ virtual void visitSection(const OptionSectionInfo §ion) = 0;
/*! \brief
* Called for each option of type \p InfoType.
*/
/*! \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
class Visitor : public gmx::OptionsVisitor
{
public:
- void visitSubSection(const Options §ion)
+ void visitSection(const Options §ion)
{
OptionsIterator iterator(section);
- iterator.acceptSubSections(this);
+ iterator.acceptSections(this);
iterator.acceptOptions(this);
}
}
}
- Visitor().visitSubSection(options);
+ Visitor().visitSection(options);
* \endcode
*
* \inlibraryapi
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 §ion);
- /*! \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 §ion_;
GMX_DISALLOW_COPY_AND_ASSIGN(OptionsIterator);
};
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;
};
public:
virtual ~OptionsModifyingTypeVisitor() {}
- virtual void visitSubSection(Options *section) = 0;
+ virtual void visitSection(OptionSectionInfo *section) = 0;
/*! \brief
* Called for each option of type \p InfoType.
*/
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 §ion_;
GMX_DISALLOW_COPY_AND_ASSIGN(OptionsModifyingIterator);
};
--- /dev/null
+/*
+ * 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> §ion)
+ : 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
#
# 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.
filenameoptionmanager.cpp
option.cpp
optionsassigner.cpp
- timeunitmanager.cpp)
+ repeatingsection.cpp
+ timeunitmanager.cpp
+ treesupport.cpp
+ )
/*
* 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.
*
* \param[in] settings Storage settings.
*/
- MockOptionStorage(const MockOption &settings);
+ explicit MockOptionStorage(const MockOption &settings);
/*! \brief
* Calls addValue("dummy") in the base class.
{
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.
{
return "";
}
+ virtual std::vector<gmx::Variant>
+ normalizeValues(const std::vector<gmx::Variant> &values) const
+ {
+ return values;
+ }
+
+ 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));
*/
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));
*/
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());
*/
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());
*/
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));
*/
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));
/*
* 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.
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()
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()
TEST(FileNameOptionTest, HandlesOptionalUnsetOption)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::string value;
ASSERT_NO_THROW_GMX(options.addOption(
FileNameOption("f").store(&value)
TEST(FileNameOptionTest, HandlesOptionalDefaultValueWithoutExtension)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::string value;
ASSERT_NO_THROW_GMX(options.addOption(
FileNameOption("f").store(&value)
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()
TEST(FileNameOptionTest, HandlesOptionalCustomDefaultExtension)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::string value;
ASSERT_NO_THROW_GMX(options.addOption(
FileNameOption("f").store(&value)
TEST(FileNameOptionTest, GivesErrorOnUnknownFileSuffix)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::string value;
ASSERT_NO_THROW_GMX(options.addOption(
FileNameOption("f").store(&value)
TEST(FileNameOptionTest, GivesErrorOnInvalidFileSuffix)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::string value;
ASSERT_NO_THROW_GMX(options.addOption(
FileNameOption("f").store(&value)
/*
* 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.
{
public:
FileNameOptionManagerTest()
- : options_(NULL, NULL)
{
manager_.setInputRedirector(&redirector_);
options_.addManager(&manager_);
/*
* 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.
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)
/*
* 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 "gromacs/options/basicoptions.h"
#include "gromacs/options/options.h"
+#include "gromacs/options/optionsection.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/variant.h"
#include "testutils/testasserts.h"
TEST(OptionsAssignerTest, HandlesMissingRequiredParameter)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
int value = 0;
using gmx::IntegerOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerTest, HandlesRequiredParameterWithDefaultValue)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
int value = 0;
using gmx::IntegerOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerTest, HandlesInvalidMultipleParameter)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::vector<int> values;
bool bIsSet = false;
using gmx::IntegerOption;
TEST(OptionsAssignerTest, HandlesMultipleParameter)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::vector<int> values;
bool bIsSet = false;
using gmx::IntegerOption;
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)));
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)));
TEST(OptionsAssignerTest, HandlesGroups)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
gmx::IOptionsContainer &group1 = options.addGroup();
gmx::IOptionsContainer &group2 = options.addGroup();
int value = 3;
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());
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)));
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)));
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)));
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)));
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)));
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)));
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)));
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)));
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)));
TEST(OptionsAssignerIntegerTest, StoresDefaultValue)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
int value = -1;
using gmx::IntegerOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerIntegerTest, StoresDefaultValueIfSet)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
int value = -1;
using gmx::IntegerOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerIntegerTest, HandlesDefaultValueIfSetWhenNotSet)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
int value = -1;
using gmx::IntegerOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerIntegerTest, HandlesBothDefaultValues)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
int value = -1;
using gmx::IntegerOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerIntegerTest, StoresToVector)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::vector<int> values;
using gmx::IntegerOption;
ASSERT_NO_THROW(options.addOption(
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()));
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()));
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()));
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());
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]);
}
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)));
EXPECT_DOUBLE_EQ(2.7, value);
}
+TEST(OptionsAssignerDoubleTest, StoresValueFromFloat)
+{
+ gmx::Options options;
+ double value = 0.0;
+ using gmx::DoubleOption;
+ ASSERT_NO_THROW(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(gmx::Variant::create<float>(2.7)));
+ EXPECT_NO_THROW(assigner.finishOption());
+ EXPECT_NO_THROW(assigner.finish());
+ EXPECT_NO_THROW(options.finish());
+
+ EXPECT_FLOAT_EQ(2.7, value);
+}
+
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)));
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
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)));
TEST(OptionsAssignerStringTest, HandlesEnumValue)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::string value;
using gmx::StringOption;
ASSERT_NO_THROW(options.addOption(
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;
TEST(OptionsAssignerStringTest, HandlesIncorrectEnumValue)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::string value;
using gmx::StringOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerStringTest, CompletesEnumValue)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::string value;
using gmx::StringOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerStringTest, HandlesEnumWithNoValue)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::string value;
using gmx::StringOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerStringTest, HandlesEnumDefaultValue)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::string value;
using gmx::StringOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerStringTest, HandlesEnumDefaultValueFromVariable)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::string value("test");
using gmx::StringOption;
ASSERT_NO_THROW(options.addOption(
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)
TEST(OptionsAssignerEnumTest, StoresSingleValue)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
TestEnum value = etestNone;
using gmx::EnumOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerEnumTest, StoresVectorValues)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::vector<TestEnum> values;
using gmx::EnumOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerEnumTest, HandlesInitialValueOutOfRange)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
TestEnum value = etestNR;
using gmx::EnumOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValue)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
TestEnum value = etestNone;
using gmx::EnumOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValueFromVariable)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
TestEnum value = etestTest;
using gmx::EnumOption;
ASSERT_NO_THROW(options.addOption(
TEST(OptionsAssignerEnumTest, HandlesEnumDefaultValueFromVector)
{
- gmx::Options options(NULL, NULL);
+ gmx::Options options;
std::vector<TestEnum> value;
value.push_back(etestNone);
value.push_back(etestTest);
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input"></Object>
+ <Object Name="Output">
+ <Int Name="a">3</Int>
+ <Object Name="s">
+ <Int Name="a">1</Int>
+ </Object>
+ <Object Name="r">
+ <Int Name="a">2</Int>
+ </Object>
+ </Object>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input"></Object>
+ <Object Name="Output">
+ <Int Name="a">2</Int>
+ </Object>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input"></Object>
+ <Object Name="Output">
+ <Sequence Name="a">
+ <Int Name="Length">3</Int>
+ <Int>1</Int>
+ <Int>2</Int>
+ <Int>3</Int>
+ </Sequence>
+ </Object>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input">
+ <Int Name="b">1</Int>
+ </Object>
+ <Object Name="Output">
+ <Int Name="a">2</Int>
+ <Int Name="b">1</Int>
+ </Object>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input">
+ <String Name="a">2</String>
+ </Object>
+ <Object Name="Output">
+ <Int Name="a">2</Int>
+ </Object>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input">
+ <Int Name="a">1</Int>
+ <Int Name="c">1</Int>
+ <Int Name="b">1</Int>
+ </Object>
+ <Object Name="Output">
+ <Int Name="b">1</Int>
+ <Int Name="a">1</Int>
+ <Int Name="c">1</Int>
+ </Object>
+</ReferenceData>
--- /dev/null
+/*
+ * 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
/*
* 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.
{
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()));
{
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()));
{
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()));
{
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()));
--- /dev/null
+/*
+ * 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/exceptions.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+
+namespace
+{
+
+/********************************************************************
+ * Tests for assignOptionsFromKeyValueTree()
+ */
+
+TEST(TreeValueSupportAssignTest, 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, nullptr));
+ EXPECT_NO_THROW_GMX(options.finish());
+
+ EXPECT_EQ(2, a0);
+ EXPECT_EQ(1, a1);
+ EXPECT_EQ("foo", b1);
+}
+
+struct SectionData
+{
+ int a;
+};
+
+TEST(TreeValueSupportAssignTest, 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, nullptr));
+ 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);
+}
+
+TEST(TreeValueSupportAssignErrorTest, HandlesInvalidValue)
+{
+ int a1 = 0;
+
+ gmx::Options options;
+ auto sec = options.addSection(gmx::OptionSection("s"));
+ sec.addOption(gmx::IntegerOption("a").store(&a1));
+
+ gmx::KeyValueTreeBuilder builder;
+ auto obj = builder.rootObject().addObject("s");
+ obj.addValue<std::string>("a", "foo");
+ gmx::KeyValueTreeObject tree = builder.build();
+
+ EXPECT_THROW_GMX(gmx::assignOptionsFromKeyValueTree(&options, tree, nullptr),
+ gmx::InvalidInputError);
+}
+
+/********************************************************************
+ * Tests for adjustKeyValueTreeFromOptions()
+ */
+
+class TreeValueSupportAdjustTest : public ::testing::Test
+{
+ public:
+ void runTest()
+ {
+ gmx::test::TestReferenceData refdata;
+ gmx::test::TestReferenceChecker checker(refdata.rootChecker());
+ gmx::KeyValueTreeObject tree(builder_.build());
+ checker.checkKeyValueTreeObject(tree, "Input");
+ ASSERT_NO_THROW_GMX(tree = gmx::adjustKeyValueTreeFromOptions(tree, options_));
+ checker.checkKeyValueTreeObject(tree, "Output");
+ }
+
+ gmx::Options options_;
+ gmx::KeyValueTreeBuilder builder_;
+};
+
+TEST_F(TreeValueSupportAdjustTest, FillsDefaultValues)
+{
+ options_.addOption(gmx::IntegerOption("a").defaultValue(2));
+ runTest();
+}
+
+TEST_F(TreeValueSupportAdjustTest, FillsDefaultVectorValues)
+{
+ int v[3] = {1, 2, 3};
+ options_.addOption(gmx::IntegerOption("a").store(v).vector());
+ runTest();
+}
+
+TEST_F(TreeValueSupportAdjustTest, FillsDefaultObjectValues)
+{
+ auto sec1 = options_.addSection(gmx::OptionSection("s"));
+ sec1.addOption(gmx::IntegerOption("a").defaultValue(1));
+ auto sec2 = options_.addSection(gmx::OptionSection("r"));
+ sec2.addOption(gmx::IntegerOption("a").defaultValue(2));
+ options_.addOption(gmx::IntegerOption("a").defaultValue(3));
+ runTest();
+}
+
+TEST_F(TreeValueSupportAdjustTest, NormalizesValues)
+{
+ options_.addOption(gmx::IntegerOption("a"));
+ builder_.rootObject().addValue<std::string>("a", "2");
+ runTest();
+}
+
+TEST_F(TreeValueSupportAdjustTest, MergesDefaultValues)
+{
+ builder_.rootObject().addValue<int>("b", 1);
+ options_.addOption(gmx::IntegerOption("a").defaultValue(2));
+ options_.addOption(gmx::IntegerOption("b").defaultValue(3));
+ runTest();
+}
+
+TEST_F(TreeValueSupportAdjustTest, OrdersValues)
+{
+ builder_.rootObject().addValue<int>("a", 1);
+ builder_.rootObject().addValue<int>("c", 1);
+ builder_.rootObject().addValue<int>("b", 1);
+ options_.addOption(gmx::IntegerOption("b").defaultValue(2));
+ options_.addOption(gmx::IntegerOption("a").defaultValue(1));
+ options_.addOption(gmx::IntegerOption("c").defaultValue(3));
+ // TODO: This does not actually test the correct ordering, since the
+ // reference data is not currently order-sensitive, but the order can be
+ // checked manually from the reference data.
+ runTest();
+}
+
+} // namespace
/*
* 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.
//! 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);
}
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_);
--- /dev/null
+/*
+ * 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/options.h"
+#include "gromacs/options/optionsassigner.h"
+#include "gromacs/options/optionsection.h"
+#include "gromacs/options/optionsvisitor.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/ikeyvaluetreeerror.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+class TreeAssignHelper
+{
+ public:
+ TreeAssignHelper(Options *options, IKeyValueTreeErrorHandler *errorHandler)
+ : assigner_(options), errorHandler_(errorHandler)
+ {
+ if (errorHandler_ == nullptr)
+ {
+ errorHandler_ = defaultKeyValueTreeErrorHandler();
+ }
+ }
+
+ void assignAll(const KeyValueTreeObject &root)
+ {
+ assigner_.start();
+ assignSubTree(root);
+ assigner_.finish();
+ }
+
+ private:
+ void assignSubTree(const KeyValueTreeObject &tree)
+ {
+ // TODO: Use the error handler also in other case.
+ for (const KeyValueTreeProperty &prop : tree.properties())
+ {
+ context_.append(prop.key());
+ if (prop.value().isArray())
+ {
+ assignArray(prop.key(), prop.value().asArray());
+ }
+ else if (prop.value().isObject())
+ {
+ assigner_.startSection(prop.key().c_str());
+ assignSubTree(prop.value().asObject());
+ assigner_.finishSection();
+ }
+ else
+ {
+ assigner_.startOption(prop.key().c_str());
+ try
+ {
+ assigner_.appendValue(prop.value().asVariant());
+ }
+ catch (UserInputError &ex)
+ {
+ if (!errorHandler_->onError(&ex, context_))
+ {
+ throw;
+ }
+ }
+ assigner_.finishOption();
+ }
+ context_.pop_back();
+ }
+ }
+
+ void assignArray(const std::string &key,
+ const KeyValueTreeArray &array)
+ {
+ if (array.isObjectArray())
+ {
+ for (const KeyValueTreeValue &value : array.values())
+ {
+ assigner_.startSection(key.c_str());
+ assignSubTree(value.asObject());
+ assigner_.finishSection();
+ }
+ }
+ else
+ {
+ assigner_.startOption(key.c_str());
+ for (const KeyValueTreeValue &value : array.values())
+ {
+ assigner_.appendValue(value.asVariant());
+ }
+ assigner_.finishOption();
+ }
+ }
+
+ OptionsAssigner assigner_;
+ IKeyValueTreeErrorHandler *errorHandler_;
+ KeyValueTreePath context_;
+};
+
+class TreeIterationHelper : private OptionsVisitor
+{
+ public:
+ TreeIterationHelper(const KeyValueTreeObject &root,
+ KeyValueTreeBuilder *builder)
+ : currentSourceObject_(&root),
+ currentObjectBuilder_(builder->rootObject())
+ {
+ }
+
+ void processOptionSection(const OptionSectionInfo §ion)
+ {
+ OptionsIterator iterator(section);
+ iterator.acceptOptions(this);
+ iterator.acceptSections(this);
+ }
+
+ private:
+ virtual void visitSection(const OptionSectionInfo §ion)
+ {
+ const std::string &name = section.name();
+ auto parentBuilder = currentObjectBuilder_;
+ auto parentObject = currentSourceObject_;
+ currentObjectBuilder_ = currentObjectBuilder_.addObject(name);
+ currentSourceObject_ =
+ (currentSourceObject_ != nullptr && currentSourceObject_->keyExists(name)
+ ? &(*currentSourceObject_)[name].asObject()
+ : nullptr);
+ processOptionSection(section);
+ currentSourceObject_ = parentObject;
+ currentObjectBuilder_ = parentBuilder;
+ }
+ virtual void visitOption(const OptionInfo &option)
+ {
+ const std::string &name = option.name();
+ if (currentSourceObject_ == nullptr || !currentSourceObject_->keyExists(name))
+ {
+ std::vector<Variant> values = option.defaultValues();
+ if (values.size() == 1)
+ {
+ currentObjectBuilder_.addRawValue(name, std::move(values[0]));
+ }
+ else if (values.size() > 1)
+ {
+ auto arrayBuilder = currentObjectBuilder_.addArray(name);
+ for (Variant &value : values)
+ {
+ arrayBuilder.addRawValue(std::move(value));
+ }
+ }
+ }
+ else
+ {
+ const KeyValueTreeValue &value = (*currentSourceObject_)[name];
+ GMX_RELEASE_ASSERT(!value.isObject(), "Value objects not supported in this context");
+ std::vector<Variant> values;
+ if (value.isArray())
+ {
+ for (const auto &arrayValue : value.asArray().values())
+ {
+ GMX_RELEASE_ASSERT(!value.isObject() && !value.isArray(),
+ "Complex values not supported in this context");
+ values.push_back(arrayValue.asVariant());
+ }
+ }
+ else
+ {
+ values.push_back(value.asVariant());
+ }
+ values = option.normalizeValues(values);
+ if (values.empty())
+ {
+ }
+ else if (values.size() == 1)
+ {
+ currentObjectBuilder_.addRawValue(name, std::move(values[0]));
+ }
+ else
+ {
+ auto array = currentObjectBuilder_.addArray(name);
+ for (auto &arrayValue : values)
+ {
+ array.addRawValue(std::move(arrayValue));
+ }
+ }
+ }
+ }
+
+ const KeyValueTreeObject *currentSourceObject_;
+ KeyValueTreeObjectBuilder currentObjectBuilder_;
+};
+
+} // namespace
+
+//! \cond libapi
+
+void assignOptionsFromKeyValueTree(Options *options,
+ const KeyValueTreeObject &tree,
+ IKeyValueTreeErrorHandler *errorHandler)
+{
+ TreeAssignHelper helper(options, errorHandler);
+ helper.assignAll(tree);
+}
+
+KeyValueTreeObject
+adjustKeyValueTreeFromOptions(const KeyValueTreeObject &tree,
+ const Options &options)
+{
+ KeyValueTreeBuilder builder;
+ TreeIterationHelper helper(tree, &builder);
+ helper.processOptionSection(options.rootSection());
+ return builder.build();
+}
+
+//! \endcond
+
+} // namespace gmx
--- /dev/null
+/*
+ * 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 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
+
+namespace gmx
+{
+
+class IKeyValueTreeErrorHandler;
+class KeyValueTreeObject;
+class Options;
+
+//! \cond libapi
+
+/*! \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,
+ IKeyValueTreeErrorHandler *errorHandler);
+/*! \libinternal \brief
+ * Adjusts a KeyValueTreeObject to the structure of given Options.
+ *
+ * Assumes that all values in the input KeyValueTreeObject are valid values for
+ * the options. The output has all the values in the input, but in the order
+ * they are in the options. Values are also converted to the native type for
+ * the underlying option (e.g., strings are parsed to integers if the option
+ * accepts those). For any option that does not have a corresponding value in
+ * the input, the output has it with a default value (if one exists for the
+ * option).
+ *
+ * Does not currently work for option sections in an array.
+ *
+ * \ingroup module_options
+ */
+KeyValueTreeObject
+adjustKeyValueTreeFromOptions(const KeyValueTreeObject &tree,
+ const Options &options);
+
+//! \endcond
+
+} // namespace gmx
+
+#endif
--- /dev/null
+/*
+ * 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>());
+ };
+ }
+ /*! \brief
+ * Adds a supported conversion from a type that can be directly cast.
+ *
+ * \tparam InType Type to convert from with a simple cast.
+ */
+ template <typename InType>
+ void addCastConversion()
+ {
+ converters_[std::type_index(typeid(InType))] =
+ [] (const Variant &value)
+ {
+ return static_cast<OutType>(value.cast<InType>());
+ };
+ }
+
+ private:
+ typedef std::function<OutType(const Variant &value)> ConversionFunction;
+
+ std::map<std::type_index, ConversionFunction> converters_;
+};
+
+} // namespace gmx
+
+#endif
--- /dev/null
+/*
+ * 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 <>
+// cppcheck-suppress noConstructor
+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
/*
* 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.
*
* Change box components to box[XX][XX]*box_rel to preserve the relative box shape
*/
-static void do_box_rel(t_inputrec *ir, matrix box_rel, matrix b, gmx_bool bInit)
+static void do_box_rel(const t_inputrec *ir, matrix box_rel,
+ matrix b, gmx_bool bInit)
{
int d, d2;
}
}
-void preserve_box_shape(t_inputrec *ir, matrix box_rel, matrix b)
+void preserve_box_shape(const t_inputrec *ir, matrix box_rel, matrix b)
{
if (inputrecPreserveShape(ir))
{
}
}
-void set_box_rel(t_inputrec *ir, t_state *state)
+void set_box_rel(const t_inputrec *ir, t_state *state)
{
/* Make sure the box obeys the restrictions before we fix the ratios */
correct_box(NULL, 0, state->box, NULL);
/*
* 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.
* \param[in] box_rel Relative box
* \param[out] b The corrected box
*/
-void preserve_box_shape(t_inputrec *ir, matrix box_rel, matrix b);
+void preserve_box_shape(const t_inputrec *ir, matrix box_rel, matrix b);
/*! \brief Determine the relative box components
*
* \param[in] ir Input record
* \param[inout] state Structure containing the box
*/
-void set_box_rel(struct t_inputrec *ir, t_state *state);
+void set_box_rel(const t_inputrec *ir, t_state *state);
#endif
}
}
-//! Compute the box image corresponding to input vectors
-gmx_bool image_rect(ivec xi, ivec xj, ivec box_size, real rlong2, int *shift, real *r2)
-{
- int m, t;
- int dx, b, b_2;
- real dxr, rij2;
-
- rij2 = 0.0;
- t = 0;
- for (m = 0; (m < DIM); m++)
- {
- dx = xi[m]-xj[m];
- t *= DIM;
- b = box_size[m];
- b_2 = b/2;
- if (dx < -b_2)
- {
- t += 2;
- dx += b;
- }
- else if (dx > b_2)
- {
- dx -= b;
- }
- else
- {
- t += 1;
- }
- dxr = dx;
- rij2 += dxr*dxr;
- if (rij2 >= rlong2)
- {
- return FALSE;
- }
- }
-
- *shift = t;
- *r2 = rij2;
- return TRUE;
-}
-
-gmx_bool image_cylindric(ivec xi, ivec xj, ivec box_size, real rlong2,
- int *shift, real *r2)
-{
- int m, t;
- int dx, b, b_2;
- real dxr, rij2;
-
- rij2 = 0.0;
- t = 0;
- for (m = 0; (m < DIM); m++)
- {
- dx = xi[m]-xj[m];
- t *= DIM;
- b = box_size[m];
- b_2 = b/2;
- if (dx < -b_2)
- {
- t += 2;
- dx += b;
- }
- else if (dx > b_2)
- {
- dx -= b;
- }
- else
- {
- t += 1;
- }
-
- dxr = dx;
- rij2 += dxr*dxr;
- if (m < ZZ)
- {
- if (rij2 >= rlong2)
- {
- return FALSE;
- }
- }
- }
-
- *shift = t;
- *r2 = rij2;
- return TRUE;
-}
-
void calc_shifts(const matrix box, rvec shift_vec[])
{
int k, l, m, d, n, test;
*
* 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) 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.
*/
void pbc_dx_d(const t_pbc *pbc, const dvec x1, const dvec x2, dvec dx);
-/*! \brief Calculate the distance between xi and xj for a rectangular box.
- *
- * It is assumed that rlong2 is scaled the same way as the ivecs xi and xj.
- * \param[in] xi Box index
- * \param[in] xj Box index
- * \param[in] box The box of grid cells
- * \param[in] rlong2 Cutoff squared
- * \param[out] shift The shift code
- * \param[out] r2 The distance (squared???)
- * \return TRUE when the distance is SMALLER than rlong2
- */
-gmx_bool image_rect(ivec xi, ivec xj, imatrix box,
- real rlong2, int *shift, real *r2);
-
-/*! \brief Calculate the distance between xi and xj for a triclinic box.
- *
- * It is assumed that rlong2 is scaled the same way as the ivecs xi and xj.
- * \param[in] xi Box index
- * \param[in] xj Box index
- * \param[in] box Matrix of box grid cells
- * \param[in] rlong2 Cutoff squared
- * \param[out] shift The shift code
- * \param[out] r2 The distance (squared???)
- * \return TRUE when the distance is SMALLER than rlong2
- */
-gmx_bool image_tri(const ivec xi, const ivec xj, const imatrix box,
- real rlong2, int *shift, real *r2);
-
-/*! \brief Compute distance vector when using cylindrical cutoff
- *
- * Calculate the distance between xi and xj for a rectangular box
- * using a cylindric cutoff for long-range only.
- * It is assumed that rlong2 is scaled the same way as the ivecs xi and xj.
- * \param[in] xi Box index
- * \param[in] xj Box index
- * \param[in] box_size Number of box grid cells
- * \param[in] rlong2 Cutoff squared
- * \param[out] shift The shift code
- * \param[out] r2 The distance (squared???)
- * \return TRUE when the distance is SMALLER than rlong2 (in X and Y dir)
- */
-gmx_bool image_cylindric(const ivec xi, const ivec xj, const ivec box_size,
- real rlong2, int *shift, real *r2);
-
/*! \brief Computes shift vectors
*
* This routine calculates ths shift vectors necessary to use the
#include "gromacs/mdtypes/mdatom.h"
#include "gromacs/pbcutil/pbc.h"
#include "gromacs/pulling/pull_internal.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/exceptions.h"
const gmx_mtop_t *mtop,
const t_inputrec *ir, real lambda)
{
- int i, ii, d, nfrozen, ndim;
- real m, w, mbd;
- double tmass, wmass, wwmass;
- const gmx_groups_t *groups;
- gmx_mtop_atomlookup_t alook;
- t_atom *atom;
-
if (EI_ENERGY_MINIMIZATION(ir->eI) || ir->eI == eiBD)
{
/* There are no masses in the integrator.
}
}
- groups = &mtop->groups;
-
- alook = gmx_mtop_atomlookup_init(mtop);
+ const gmx_groups_t *groups = &mtop->groups;
- nfrozen = 0;
- tmass = 0;
- wmass = 0;
- wwmass = 0;
- for (i = 0; i < pg->params.nat; i++)
+ /* Count frozen dimensions and (weighted) mass */
+ int nfrozen = 0;
+ double tmass = 0;
+ double wmass = 0;
+ double wwmass = 0;
+ int molb = 0;
+ for (int i = 0; i < pg->params.nat; i++)
{
- ii = pg->params.ind[i];
- gmx_mtop_atomnr_to_atom(alook, ii, &atom);
+ int ii = pg->params.ind[i];
if (bConstraint && ir->opts.nFreeze)
{
- for (d = 0; d < DIM; d++)
+ for (int d = 0; d < DIM; d++)
{
if (pulldim_con[d] == 1 &&
ir->opts.nFreeze[ggrpnr(groups, egcFREEZE, ii)][d])
}
}
}
+ const t_atom &atom = mtopGetAtomParameters(mtop, ii, &molb);
+ real m;
if (ir->efep == efepNO)
{
- m = atom->m;
+ m = atom.m;
}
else
{
- m = (1 - lambda)*atom->m + lambda*atom->mB;
+ m = (1 - lambda)*atom.m + lambda*atom.mB;
}
+ real w;
if (pg->params.nweight > 0)
{
w = pg->params.weight[i];
}
else if (ir->eI == eiBD)
{
+ real mbd;
if (ir->bd_fric)
{
mbd = ir->bd_fric*ir->delta_t;
wwmass += m*w*w;
}
- gmx_mtop_atomlookup_destroy(alook);
-
if (wmass == 0)
{
/* We can have single atom groups with zero mass with potential pulling
}
else
{
- ndim = 0;
- for (d = 0; d < DIM; d++)
+ int ndim = 0;
+ for (int d = 0; d < DIM; d++)
{
ndim += pulldim_con[d]*pg->params.nat;
}
#include "gromacs/pbcutil/pbc.h"
#include "gromacs/timing/cyclecounter.h"
#include "gromacs/timing/wallcycle.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/pleasecite.h"
#include "gromacs/utility/qsort_threadsafe.h"
int i, ii;
rvec coord, xref, *xdum;
gmx_bool bFlex, bColl;
- t_atom *atom;
gmx_enfrotgrp_t erg; /* Pointer to enforced rotation group data */
int ref_firstindex, ref_lastindex;
- gmx_mtop_atomlookup_t alook = NULL;
real mass, totalmass;
real start = 0.0;
double t_start;
/* Copy the masses so that the center can be determined. For all types of
* enforced rotation, we store the masses in the erg->mc array. */
- if (rotg->bMassW)
- {
- alook = gmx_mtop_atomlookup_init(mtop);
- }
snew(erg->mc, rotg->nat);
if (bFlex)
{
snew(erg->m_loc, rotg->nat);
}
totalmass = 0.0;
+ int molb = 0;
for (i = 0; i < rotg->nat; i++)
{
if (rotg->bMassW)
{
- gmx_mtop_atomnr_to_atom(alook, rotg->ind[i], &atom);
- mass = atom->m;
+ mass = mtopGetAtomMass(mtop, rotg->ind[i], &molb);
}
else
{
}
erg->invmass = 1.0/totalmass;
- if (rotg->bMassW)
- {
- gmx_mtop_atomlookup_destroy(alook);
- }
-
/* Set xc_ref_center for any rotation potential */
if ((rotg->eType == erotgISO) || (rotg->eType == erotgPM) || (rotg->eType == erotgRM) || (rotg->eType == erotgRM2))
{
* 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
/*
* 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.
#include "gromacs/math/vec.h"
#include "gromacs/pbcutil/pbc.h"
#include "gromacs/topology/block.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/gmxassert.h"
void
-gmx_calc_cog(const t_topology * /* top */, rvec x[], int nrefat, const int index[], rvec xout)
+gmx_calc_cog(const gmx_mtop_t * /* top */, rvec x[], int nrefat, const int index[], rvec xout)
{
int m, ai;
* mass are calculated, and hence a topology with masses is required.
*/
void
-gmx_calc_com(const t_topology *top, rvec x[], int nrefat, const int index[], rvec xout)
+gmx_calc_com(const gmx_mtop_t *top, rvec x[], int nrefat, const int index[], rvec xout)
{
- int m, j, ai;
- real mass, mtot;
-
- GMX_RELEASE_ASSERT(top != nullptr,
+ GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top),
"No masses available while mass weighting was requested");
clear_rvec(xout);
- mtot = 0;
- for (m = 0; m < nrefat; ++m)
+ real mtot = 0;
+ int molb = 0;
+ for (int m = 0; m < nrefat; ++m)
{
- ai = index[m];
- mass = top->atoms.atom[ai].m;
- for (j = 0; j < DIM; ++j)
+ const int ai = index[m];
+ const real mass = mtopGetAtomMass(top, ai, &molb);
+ for (int j = 0; j < DIM; ++j)
{
xout[j] += mass * x[ai][j];
}
* \param[out] fout Force on the COG position for the indexed atoms.
*/
void
-gmx_calc_cog_f(const t_topology *top, rvec f[], int nrefat, const int index[], rvec fout)
+gmx_calc_cog_f(const gmx_mtop_t *top, rvec f[], int nrefat, const int index[], rvec fout)
{
- int m, j, ai;
- real mass, mtot;
-
- GMX_RELEASE_ASSERT(top != nullptr,
+ GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top),
"No masses available while mass weighting was requested");
clear_rvec(fout);
- mtot = 0;
- for (m = 0; m < nrefat; ++m)
+ real mtot = 0;
+ int molb = 0;
+ for (int m = 0; m < nrefat; ++m)
{
- ai = index[m];
- mass = top->atoms.atom[ai].m;
- for (j = 0; j < DIM; ++j)
+ const int ai = index[m];
+ const real mass = mtopGetAtomMass(top, ai, &molb);
+ for (int j = 0; j < DIM; ++j)
{
fout[j] += f[ai][j] / mass;
}
}
void
-gmx_calc_com_f(const t_topology * /* top */, rvec f[], int nrefat, const int index[], rvec fout)
+gmx_calc_com_f(const gmx_mtop_t * /* top */, rvec f[], int nrefat, const int index[], rvec fout)
{
clear_rvec(fout);
for (int m = 0; m < nrefat; ++m)
* Other parameters are passed unmodified to these functions.
*/
void
-gmx_calc_comg(const t_topology *top, rvec x[], int nrefat, const int index[],
+gmx_calc_comg(const gmx_mtop_t *top, rvec x[], int nrefat, const int index[],
bool bMass, rvec xout)
{
if (bMass)
* Other parameters are passed unmodified to these functions.
*/
void
-gmx_calc_comg_f(const t_topology *top, rvec f[], int nrefat, const int index[],
+gmx_calc_comg_f(const gmx_mtop_t *top, rvec f[], int nrefat, const int index[],
bool bMass, rvec fout)
{
if (bMass)
* Works exactly as gmx_calc_com_pbc(), but calculates the center of geometry.
*/
void
-gmx_calc_cog_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_cog_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
int nrefat, const int index[], rvec xout)
{
const real tol = 1e-4;
* Modified from src/tools/gmx_sorient.c in Gromacs distribution.
*/
void
-gmx_calc_com_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_com_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
int nrefat, const int index[], rvec xout)
{
- const real tol = 1e-4;
- bool bChanged;
- int m, j, ai, iter;
- real mass, mtot;
- rvec dx, xtest;
-
- GMX_RELEASE_ASSERT(top != nullptr,
+ GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top),
"No masses available while mass weighting was requested");
/* First simple calculation */
clear_rvec(xout);
- mtot = 0;
- for (m = 0; m < nrefat; ++m)
+ real mtot = 0;
+ int molb = 0;
+ for (int m = 0; m < nrefat; ++m)
{
- ai = index[m];
- mass = top->atoms.atom[ai].m;
- for (j = 0; j < DIM; ++j)
+ const int ai = index[m];
+ const real mass = mtopGetAtomMass(top, ai, &molb);
+ for (int j = 0; j < DIM; ++j)
{
xout[j] += mass * x[ai][j];
}
/* Now check if any atom is more than half the box from the COM */
if (pbc)
{
- iter = 0;
+ const real tol = 1e-4;
+ bool bChanged;
do
{
bChanged = false;
- for (m = 0; m < nrefat; ++m)
+ molb = 0;
+ for (int m = 0; m < nrefat; ++m)
{
- ai = index[m];
- mass = top->atoms.atom[ai].m / mtot;
+ rvec dx, xtest;
+ const int ai = index[m];
+ const real mass = mtopGetAtomMass(top, ai, &molb) / mtot;
pbc_dx(pbc, x[ai], xout, dx);
rvec_add(xout, dx, xtest);
- for (j = 0; j < DIM; ++j)
+ for (int j = 0; j < DIM; ++j)
{
if (fabs(xtest[j] - x[ai][j]) > tol)
{
}
}
}
- iter++;
}
while (bChanged);
}
* Other parameters are passed unmodified to these functions.
*/
void
-gmx_calc_comg_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_comg_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
int nrefat, const int index[], bool bMass, rvec xout)
{
if (bMass)
void
-gmx_calc_cog_block(const t_topology * /* top */, rvec x[], const t_block *block, const int index[],
+gmx_calc_cog_block(const gmx_mtop_t * /* top */, rvec x[], const t_block *block, const int index[],
rvec xout[])
{
int b, i, ai;
* mass are calculated, and hence a topology with masses is required.
*/
void
-gmx_calc_com_block(const t_topology *top, rvec x[], const t_block *block, const int index[],
+gmx_calc_com_block(const gmx_mtop_t *top, rvec x[], const t_block *block, const int index[],
rvec xout[])
{
- int b, i, ai, d;
- rvec xb;
- real mass, mtot;
-
- GMX_RELEASE_ASSERT(top != nullptr,
+ GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top),
"No masses available while mass weighting was requested");
- for (b = 0; b < block->nr; ++b)
+ int molb = 0;
+ for (int b = 0; b < block->nr; ++b)
{
+ rvec xb;
clear_rvec(xb);
- mtot = 0;
- for (i = block->index[b]; i < block->index[b+1]; ++i)
+ real mtot = 0;
+ for (int i = block->index[b]; i < block->index[b+1]; ++i)
{
- ai = index[i];
- mass = top->atoms.atom[ai].m;
- for (d = 0; d < DIM; ++d)
+ const int ai = index[i];
+ const real mass = mtopGetAtomMass(top, ai, &molb);
+ for (int d = 0; d < DIM; ++d)
{
xb[d] += mass * x[ai][d];
}
* \param[out] fout \p block->nr Forces on COG positions.
*/
void
-gmx_calc_cog_f_block(const t_topology *top, rvec f[], const t_block *block, const int index[],
+gmx_calc_cog_f_block(const gmx_mtop_t *top, rvec f[], const t_block *block, const int index[],
rvec fout[])
{
- int b, i, ai, d;
- rvec fb;
- real mass, mtot;
-
- GMX_RELEASE_ASSERT(top != nullptr,
+ GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top),
"No masses available while mass weighting was requested");
- for (b = 0; b < block->nr; ++b)
+ int molb = 0;
+ for (int b = 0; b < block->nr; ++b)
{
+ rvec fb;
clear_rvec(fb);
- mtot = 0;
- for (i = block->index[b]; i < block->index[b+1]; ++i)
+ real mtot = 0;
+ for (int i = block->index[b]; i < block->index[b+1]; ++i)
{
- ai = index[i];
- mass = top->atoms.atom[ai].m;
- for (d = 0; d < DIM; ++d)
+ const int ai = index[i];
+ const real mass = mtopGetAtomMass(top, ai, &molb);
+ for (int d = 0; d < DIM; ++d)
{
fb[d] += f[ai][d] / mass;
}
}
void
-gmx_calc_com_f_block(const t_topology * /* top */, rvec f[], const t_block *block, const int index[],
+gmx_calc_com_f_block(const gmx_mtop_t * /* top */, rvec f[], const t_block *block, const int index[],
rvec fout[])
{
for (int b = 0; b < block->nr; ++b)
* Other parameters are passed unmodified to these functions.
*/
void
-gmx_calc_comg_block(const t_topology *top, rvec x[], const t_block *block, const int index[],
+gmx_calc_comg_block(const gmx_mtop_t *top, rvec x[], const t_block *block, const int index[],
bool bMass, rvec xout[])
{
if (bMass)
* Other parameters are passed unmodified to these functions.
*/
void
-gmx_calc_comg_f_block(const t_topology *top, rvec f[], const t_block *block, const int index[],
+gmx_calc_comg_f_block(const gmx_mtop_t *top, rvec f[], const t_block *block, const int index[],
bool bMass, rvec fout[])
{
if (bMass)
* crashes.
*/
void
-gmx_calc_comg_blocka(const t_topology *top, rvec x[], const t_blocka *block,
+gmx_calc_comg_blocka(const gmx_mtop_t *top, rvec x[], const t_blocka *block,
bool bMass, rvec xout[])
{
/* TODO: It would probably be better to do this without the type cast */
- gmx_calc_comg_block(top, x, (t_block *)block, block->a, bMass, xout);
+ gmx_calc_comg_block(top, x, reinterpret_cast<const t_block *>(block), block->a, bMass, xout);
}
/*!
* crashes.
*/
void
-gmx_calc_comg_f_blocka(const t_topology *top, rvec f[], const t_blocka *block,
+gmx_calc_comg_f_blocka(const gmx_mtop_t *top, rvec f[], const t_blocka *block,
bool bMass, rvec fout[])
{
/* TODO: It would probably be better to do this without the type cast */
- gmx_calc_comg_f_block(top, f, (t_block *)block, block->a, bMass, fout);
+ gmx_calc_comg_f_block(top, f, reinterpret_cast<const t_block *>(block), block->a, bMass, fout);
}
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2009,2010,2011,2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2009,2010,2011,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/math/vectypes.h"
+struct gmx_mtop_t;
struct t_block;
struct t_blocka;
struct t_pbc;
-struct t_topology;
/*! \brief
* Calculate a single center of geometry.
* \param[out] xout COG position for the indexed atoms.
*/
void
-gmx_calc_cog(const t_topology *top, rvec x[], int nrefat, const int index[], rvec xout);
+gmx_calc_cog(const gmx_mtop_t *top, rvec x[], int nrefat, const int index[], rvec xout);
/** Calculate a single center of mass. */
void
-gmx_calc_com(const t_topology *top, rvec x[], int nrefat, const int index[], rvec xout);
+gmx_calc_com(const gmx_mtop_t *top, rvec x[], int nrefat, const int index[], rvec xout);
/** Calculate force on a single center of geometry. */
void
-gmx_calc_cog_f(const t_topology *top, rvec f[], int nrefat, const int index[], rvec fout);
+gmx_calc_cog_f(const gmx_mtop_t *top, rvec f[], int nrefat, const int index[], rvec fout);
/*! \brief
* Calculate force on a single center of mass.
*
* \param[out] fout Force on the COM position for the indexed atoms.
*/
void
-gmx_calc_com_f(const t_topology *top, rvec f[], int nrefat, const int index[], rvec fout);
+gmx_calc_com_f(const gmx_mtop_t *top, rvec f[], int nrefat, const int index[], rvec fout);
/** Calculate a single center of mass/geometry. */
void
-gmx_calc_comg(const t_topology *top, rvec x[], int nrefat, const int index[],
+gmx_calc_comg(const gmx_mtop_t *top, rvec x[], int nrefat, const int index[],
bool bMass, rvec xout);
/** Calculate force on a single center of mass/geometry. */
void
-gmx_calc_comg_f(const t_topology *top, rvec f[], int nrefat, const int index[],
+gmx_calc_comg_f(const gmx_mtop_t *top, rvec f[], int nrefat, const int index[],
bool bMass, rvec fout);
/** Calculate a single center of geometry iteratively, taking PBC into account. */
void
-gmx_calc_cog_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_cog_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
int nrefat, const int index[], rvec xout);
/** Calculate a single center of mass iteratively, taking PBC into account. */
void
-gmx_calc_com_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_com_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
int nrefat, const int index[], rvec xout);
/** Calculate a single center of mass/geometry iteratively with PBC. */
void
-gmx_calc_comg_pbc(const t_topology *top, rvec x[], t_pbc *pbc,
+gmx_calc_comg_pbc(const gmx_mtop_t *top, rvec x[], const t_pbc *pbc,
int nrefat, const int index[], bool bMass, rvec xout);
/*! \brief
* \param[out] xout \p block->nr COG positions.
*/
void
-gmx_calc_cog_block(const t_topology *top, rvec x[], const t_block *block,
+gmx_calc_cog_block(const gmx_mtop_t *top, rvec x[], const t_block *block,
const int index[], rvec xout[]);
/** Calculate centers of mass for a blocked index. */
void
-gmx_calc_com_block(const t_topology *top, rvec x[], const t_block *block,
+gmx_calc_com_block(const gmx_mtop_t *top, rvec x[], const t_block *block,
const int index[], rvec xout[]);
/** Calculate forces on centers of geometry for a blocked index. */
void
-gmx_calc_cog_f_block(const t_topology *top, rvec f[], const t_block *block,
+gmx_calc_cog_f_block(const gmx_mtop_t *top, rvec f[], const t_block *block,
const int index[], rvec fout[]);
/*! \brief
* Calculate forces on centers of mass for a blocked index.
* \param[out] fout \p block->nr Forces on COM positions.
*/
void
-gmx_calc_com_f_block(const t_topology *top, rvec f[], const t_block *block,
+gmx_calc_com_f_block(const gmx_mtop_t *top, rvec f[], const t_block *block,
const int index[], rvec fout[]);
/** Calculate centers of mass/geometry for a blocked index. */
void
-gmx_calc_comg_block(const t_topology *top, rvec x[], const t_block *block,
+gmx_calc_comg_block(const gmx_mtop_t *top, rvec x[], const t_block *block,
const int index[], bool bMass, rvec xout[]);
/** Calculate forces on centers of mass/geometry for a blocked index. */
void
-gmx_calc_comg_f_block(const t_topology *top, rvec f[], const t_block *block,
+gmx_calc_comg_f_block(const gmx_mtop_t *top, rvec f[], const t_block *block,
const int index[], bool bMass, rvec fout[]);
/** Calculate centers of mass/geometry for a set of blocks; */
void
-gmx_calc_comg_blocka(const t_topology *top, rvec x[], const t_blocka *block,
+gmx_calc_comg_blocka(const gmx_mtop_t *top, rvec x[], const t_blocka *block,
bool bMass, rvec xout[]);
/** Calculate forces on centers of mass/geometry for a set of blocks; */
void
-gmx_calc_comg_f_blocka(const t_topology *top, rvec x[], const t_blocka *block,
+gmx_calc_comg_f_blocka(const gmx_mtop_t *top, rvec x[], const t_blocka *block,
bool bMass, rvec xout[]);
#endif
* is prevented by using \ref SEL_METHODINIT and \ref SEL_OUTINIT flags.
*/
static void
-init_method(const SelectionTreeElementPointer &sel, t_topology *top, int isize)
+init_method(const SelectionTreeElementPointer &sel, const gmx_mtop_t *top, int isize)
{
/* Find out whether there are any atom-valued parameters */
bool bAtomVal = false;
/*
* 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.
void
_gmx_sel_evaluate_init(gmx_sel_evaluate_t *data,
gmx_sel_mempool_t *mp, gmx_ana_index_t *gall,
- t_topology *top, t_trxframe *fr, t_pbc *pbc)
+ const gmx_mtop_t *top, t_trxframe *fr, t_pbc *pbc)
{
data->mp = mp;
data->gall = gall;
gmx_ana_index_t *g)
{
_gmx_sel_evaluate_method_params(data, sel, g);
+ gmx::SelMethodEvalContext context(data->top, data->fr, data->pbc);
if (sel->flags & SEL_INITFRAME)
{
sel->flags &= ~SEL_INITFRAME;
- sel->u.expr.method->init_frame(data->top, data->fr, data->pbc,
- sel->u.expr.mdata);
+ sel->u.expr.method->init_frame(context, sel->u.expr.mdata);
}
if (sel->u.expr.pc)
{
gmx_ana_poscalc_update(sel->u.expr.pc, sel->u.expr.pos, g,
data->fr, data->pbc);
- sel->u.expr.method->pupdate(data->top, data->fr, data->pbc,
- sel->u.expr.pos, &sel->v,
+ sel->u.expr.method->pupdate(context, sel->u.expr.pos, &sel->v,
sel->u.expr.mdata);
if ((sel->flags & SEL_ATOMVAL) && sel->v.nr < g->isize)
{
}
else
{
- sel->u.expr.method->update(data->top, data->fr, data->pbc, g,
- &sel->v, sel->u.expr.mdata);
+ sel->u.expr.method->update(context, g, &sel->v, sel->u.expr.mdata);
}
}
gmx_ana_index_t *g)
{
_gmx_sel_evaluate_method_params(data, sel, g);
+ gmx::SelMethodEvalContext context(data->top, data->fr, data->pbc);
if (sel->flags & SEL_INITFRAME)
{
sel->flags &= ~SEL_INITFRAME;
- sel->u.expr.method->init_frame(data->top, data->fr, data->pbc,
- sel->u.expr.mdata);
+ sel->u.expr.method->init_frame(context, sel->u.expr.mdata);
}
if (sel->child && sel->child->v.type != POS_VALUE)
{
GMX_THROW(gmx::NotImplementedError("Non-position valued modifiers not implemented"));
}
- sel->u.expr.method->pupdate(data->top, data->fr, data->pbc,
- NULL, &sel->v, sel->u.expr.mdata);
+ sel->u.expr.method->pupdate(context, NULL, &sel->v, sel->u.expr.mdata);
}
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2009,2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2009,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.
#include "selelem.h"
struct gmx_ana_index_t;
+struct gmx_mtop_t;
struct gmx_sel_mempool_t;
struct t_pbc;
-struct t_topology;
struct t_trxframe;
/*! \internal \brief
/** Index group that contains all the atoms. */
gmx_ana_index_t *gall;
/** Topology information. */
- t_topology *top;
+ const gmx_mtop_t *top;
/** Current frame. */
t_trxframe *fr;
/** PBC data. */
void
_gmx_sel_evaluate_init(gmx_sel_evaluate_t *data,
gmx_sel_mempool_t *mp, gmx_ana_index_t *gall,
- t_topology *top, t_trxframe *fr, t_pbc *pbc);
+ const gmx_mtop_t *top, t_trxframe *fr, t_pbc *pbc);
/** Evaluates the children of a general selection element. */
void
_gmx_sel_evaluate_children(gmx_sel_evaluate_t *data,
#include "gromacs/topology/block.h"
#include "gromacs/topology/index.h"
+#include "gromacs/topology/mtop_lookup.h"
+#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxassert.h"
* If both are null, the index group structure is initialized empty.
*/
void
-gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top,
+gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, gmx_mtop_t *top,
const char *fnm)
{
t_blocka *block = NULL;
else if (top)
{
block = new_blocka();
- analyse(&top->atoms, block, &names, FALSE, FALSE);
+ // TODO: Propagate mtop further.
+ t_atoms atoms = gmx_mtop_global_atoms(top);
+ analyse(&atoms, block, &names, FALSE, FALSE);
+ done_atom(&atoms);
}
else
{
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 (...)
* \ingroup module_selection
*/
static bool
-next_group_index(int atomIndex, t_topology *top, e_index_t type, int *id)
+next_group_index(int atomIndex, const gmx_mtop_t *top, e_index_t type, int *id)
{
int prev = *id;
switch (type)
*id = atomIndex;
break;
case INDEX_RES:
- *id = top->atoms.atom[atomIndex].resind;
+ {
+ int resind, molb = 0;
+ mtopGetAtomAndResidueName(top, atomIndex, &molb, nullptr, nullptr, nullptr, &resind);
+ *id = resind;
break;
+ }
case INDEX_MOL:
if (*id >= 0 && top->mols.index[*id] > atomIndex)
{
* \p g should be sorted.
*/
void
-gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
+gmx_ana_index_make_block(t_blocka *t, const gmx_mtop_t *top, gmx_ana_index_t *g,
e_index_t type, bool bComplete)
{
if (type == INDEX_UNKNOWN)
t->nra = 0;
/* We may allocate some extra memory here because we don't know in
* advance how much will be needed. */
- if (t->nalloc_a < top->atoms.nr)
+ if (t->nalloc_a < top->natoms)
{
- srenew(t->a, top->atoms.nr);
- t->nalloc_a = top->atoms.nr;
+ srenew(t->a, top->natoms);
+ t->nalloc_a = top->natoms;
}
}
else
}
/* Clear counters */
t->nr = 0;
- int j = 0; /* j is used by residue completion for the first atom not stored */
- int id = -1;
+ int id = -1;
+ int molb = 0;
for (int i = 0; i < g->isize; ++i)
{
+ const int ai = g->index[i];
/* Find the ID number of the atom/residue/molecule corresponding to
* the atom. */
- if (next_group_index(g->index[i], top, type, &id))
+ if (next_group_index(ai, top, type, &id))
{
/* If this is the first atom in a new block, initialize the block. */
if (bComplete)
switch (type)
{
case INDEX_RES:
- while (top->atoms.atom[j].resind != id)
+ {
+ int molnr, atnr_mol;
+ mtopGetMolblockIndex(top, ai, &molb, &molnr, &atnr_mol);
+ const t_atoms &mol_atoms = top->moltype[top->molblock[molb].type].atoms;
+ int last_atom = atnr_mol + 1;
+ while (last_atom < mol_atoms.nr
+ && mol_atoms.atom[last_atom].resind == id)
+ {
+ ++last_atom;
+ }
+ int first_atom = atnr_mol - 1;
+ while (first_atom >= 0
+ && mol_atoms.atom[first_atom].resind == id)
{
- ++j;
+ --first_atom;
}
- while (j < top->atoms.nr && top->atoms.atom[j].resind == id)
+ int first_mol_atom = top->molblock[molb].globalAtomStart;
+ first_mol_atom += molnr*top->molblock[molb].natoms_mol;
+ first_atom = first_mol_atom + first_atom + 1;
+ last_atom = first_mol_atom + last_atom - 1;
+ for (int j = first_atom; j <= last_atom; ++j)
{
t->a[t->nra++] = j;
- ++j;
}
break;
-
+ }
case INDEX_MOL:
- for (j = top->mols.index[id]; j < top->mols.index[id+1]; ++j)
+ for (int j = top->mols.index[id]; j < top->mols.index[id+1]; ++j)
{
t->a[t->nra++] = j;
}
* The atoms in \p g are assumed to be sorted.
*/
bool
-gmx_ana_index_has_full_blocks(gmx_ana_index_t *g, t_block *b)
+gmx_ana_index_has_full_blocks(const gmx_ana_index_t *g, const t_block *b)
{
int i, j, bi;
return true;
}
+/*!
+ * \brief Returns if an atom is at a residue boundary.
+ *
+ * \param[in] top Topology data.
+ * \param[in] a Atom index to check, should be -1 <= \p a < top->natoms.
+ * \param[in,out] molb The molecule block of atom a
+ * \returns true if atoms \p a and \p a + 1 are in different residues, false otherwise.
+ */
+static bool is_at_residue_boundary(const gmx_mtop_t *top, int a, int *molb)
+{
+ if (a == -1 || a + 1 == top->natoms)
+ {
+ return true;
+ }
+ int resindA;
+ mtopGetAtomAndResidueName(top, a, molb,
+ nullptr, nullptr, nullptr, &resindA);
+ int resindAPlusOne;
+ mtopGetAtomAndResidueName(top, a + 1, molb,
+ nullptr, nullptr, nullptr, &resindAPlusOne);
+ return resindAPlusOne != resindA;
+}
+
/*!
* \param[in] g Index group to check.
* \param[in] type Block data to check against.
*/
bool
gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type,
- t_topology *top)
+ const gmx_mtop_t *top)
{
+ if (g->isize == 0)
+ {
+ return true;
+ }
+
// TODO: Consider whether unsorted groups need to be supported better.
switch (type)
{
case INDEX_RES:
{
- int i, ai;
- int id, prev;
-
- prev = -1;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ int aPrev = -1;
+ for (int i = 0; i < g->isize; ++i)
{
- ai = g->index[i];
- id = top->atoms.atom[ai].resind;
- if (id != prev)
+ const int a = g->index[i];
+ // Check if a is consecutive or on a residue boundary
+ if (a != aPrev + 1)
{
- if (ai > 0 && top->atoms.atom[ai-1].resind == id)
+ if (!is_at_residue_boundary(top, aPrev, &molb))
{
return false;
}
- if (i > 0 && g->index[i-1] < top->atoms.nr - 1
- && top->atoms.atom[g->index[i-1]+1].resind == prev)
+ if (!is_at_residue_boundary(top, a - 1, &molb))
{
return false;
}
}
- prev = id;
+ aPrev = a;
}
- if (g->index[i-1] < top->atoms.nr - 1
- && top->atoms.atom[g->index[i-1]+1].resind == prev)
+ GMX_ASSERT(g->isize > 0, "We return above when isize=0");
+ const int a = g->index[g->isize - 1];
+ if (!is_at_residue_boundary(top, a, &molb))
{
return false;
}
*/
void
gmx_ana_indexmap_init(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
- t_topology *top, e_index_t type)
+ const gmx_mtop_t *top, e_index_t type)
{
m->type = type;
gmx_ana_index_make_block(&m->b, top, g, type, false);
}
int
-gmx_ana_indexmap_init_orgid_group(gmx_ana_indexmap_t *m, t_topology *top,
+gmx_ana_indexmap_init_orgid_group(gmx_ana_indexmap_t *m, const gmx_mtop_t *top,
e_index_t type)
{
GMX_RELEASE_ASSERT(m->bStatic,
class TextWriter;
}
-struct t_topology;
+struct gmx_mtop_t;
/** Stores a set of index groups. */
struct gmx_ana_indexgrps_t;
/*@{*/
/** Reads index groups from a file or constructs them from topology. */
void
-gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, t_topology *top,
+gmx_ana_indexgrps_init(gmx_ana_indexgrps_t **g, gmx_mtop_t *top,
const char *fnm);
/** Frees memory allocated for index groups. */
void
/*@{*/
/** Partition a group based on topology information. */
void
-gmx_ana_index_make_block(t_blocka *t, t_topology *top, gmx_ana_index_t *g,
+gmx_ana_index_make_block(t_blocka *t, const gmx_mtop_t *top, gmx_ana_index_t *g,
e_index_t type, bool bComplete);
/** Checks whether a group consists of full blocks. */
bool
-gmx_ana_index_has_full_blocks(gmx_ana_index_t *g, t_block *b);
+gmx_ana_index_has_full_blocks(const gmx_ana_index_t *g, const t_block *b);
/** Checks whether a group consists of full blocks. */
bool
gmx_ana_index_has_full_ablocks(gmx_ana_index_t *g, t_blocka *b);
/** Checks whether a group consists of full residues/molecules. */
bool
-gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type, t_topology *top);
+gmx_ana_index_has_complete_elems(gmx_ana_index_t *g, e_index_t type,
+ const gmx_mtop_t *top);
/** Initializes an empty index group mapping. */
void
/** Initializes an index group mapping. */
void
gmx_ana_indexmap_init(gmx_ana_indexmap_t *m, gmx_ana_index_t *g,
- t_topology *top, e_index_t type);
+ const gmx_mtop_t *top, e_index_t type);
/*! \brief
* Initializes `orgid` entries based on topology grouping.
*
* Strong exception safety guarantee.
*/
int
-gmx_ana_indexmap_init_orgid_group(gmx_ana_indexmap_t *m, t_topology *top,
+gmx_ana_indexmap_init_orgid_group(gmx_ana_indexmap_t *m, const gmx_mtop_t *top,
e_index_t type);
/** Sets an index group mapping to be static. */
void
-/* 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/>. */
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. */
#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"
#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.
*/
#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"
#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
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
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.
* 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;
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 };
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
#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
# 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
# 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
# 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
# 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
# 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
#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
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
for (yyi = 0; yyi < (Count); yyi++) \
(Dst)[yyi] = (Src)[yyi]; \
} \
- while (YYID (0))
+ while (0)
# endif
# endif
#endif /* !YYCOPY_NEEDED */
#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,
};
#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
"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",
"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,
};
# 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,
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,
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,
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,
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,
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,
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)
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].
#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; \
(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. */
/* 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;
}
#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);
}
| 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, ": ");
| 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++)
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. */
/* YYINITDEPTH -- initial size of the parser's stacks. */
-#ifndef YYINITDEPTH
+#ifndef YYINITDEPTH
# define YYINITDEPTH 200
#endif
# 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++)
# 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;
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: ;
}
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
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
}
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;
| 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
}
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. */
};
/* 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
| 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. */
#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
# 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 */
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));
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
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);
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;
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;
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;
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
*++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. */
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. */
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
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;
| 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);
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
if (yymsg != yymsgbuf)
YYSTACK_FREE (yymsg);
#endif
- /* Make sure YYID is used. */
- return YYID (yyresult);
+ return yyresult;
}
-
-
-/* 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.
* 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;
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 };
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 */
--- 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);
/*
* 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.
%define api.push-pull push
%locations
-%name-prefix="_gmx_sel_yy"
+%name-prefix "_gmx_sel_yy"
%parse-param { void *scanner }
%%
{
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;
}
;
* Can be NULL if none of the calculations require topology data or if
* setTopology() has not been called.
*/
- t_topology *top_;
+ const gmx_mtop_t *top_;
//! Pointer to the first data structure.
gmx_ana_poscalc_t *first_;
//! Pointer to the last data structure.
namespace gmx
{
+namespace
+{
+
+//! Helper function for determining required topology information.
+PositionCalculationCollection::RequiredTopologyInfo
+requiredTopologyInfo(e_poscalc_t type, int flags)
+{
+ if (type != POS_ATOM)
+ {
+ if ((flags & POS_MASS) || (flags & POS_FORCES))
+ {
+ return PositionCalculationCollection::RequiredTopologyInfo::TopologyAndMasses;
+ }
+ if (type == POS_RES || type == POS_MOL)
+ {
+ return PositionCalculationCollection::RequiredTopologyInfo::Topology;
+ }
+ }
+ return PositionCalculationCollection::RequiredTopologyInfo::None;
+}
+
+} // namespace
+
// static
void
PositionCalculationCollection::typeFromEnum(const char *post,
}
}
+// static
+PositionCalculationCollection::RequiredTopologyInfo
+PositionCalculationCollection::requiredTopologyInfoForType(const char *post,
+ bool forces)
+{
+ e_poscalc_t type;
+ int flags = (forces ? POS_FORCES : 0);
+ PositionCalculationCollection::typeFromEnum(post, &type, &flags);
+ return requiredTopologyInfo(type, flags);
+}
+
/********************************************************************
* PositionCalculationCollection::Impl
*/
}
void
-PositionCalculationCollection::setTopology(t_topology *top)
+PositionCalculationCollection::setTopology(const gmx_mtop_t *top)
{
impl_->top_ = top;
}
static void
set_poscalc_maxindex(gmx_ana_poscalc_t *pc, gmx_ana_index_t *g, bool bBase)
{
- t_topology *top = pc->coll->top_;
+ const gmx_mtop_t *top = pc->coll->top_;
gmx_ana_index_make_block(&pc->b, top, g, pc->itype, pc->flags & POS_COMPLWHOLE);
/* Set the type to POS_ATOM if the calculation in fact is such. */
if (pc->b.nr == pc->b.nra)
sfree(pc);
}
-/*!
- * \param[in] pc Position calculation data to query.
- * \returns true if \p pc requires topology for initialization and/or
- * evaluation, false otherwise.
- */
-bool
-gmx_ana_poscalc_requires_top(gmx_ana_poscalc_t *pc)
+gmx::PositionCalculationCollection::RequiredTopologyInfo
+gmx_ana_poscalc_required_topology_info(gmx_ana_poscalc_t *pc)
{
- if ((pc->flags & POS_MASS) || pc->type == POS_RES || pc->type == POS_MOL
- || ((pc->flags & POS_FORCES) && pc->type != POS_ATOM))
- {
- return true;
- }
- return false;
+ return gmx::requiredTopologyInfo(pc->type, pc->flags);
}
/*!
*/
void
gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc, gmx_ana_pos_t *p,
- gmx_ana_index_t *g, t_trxframe *fr, t_pbc *pbc)
+ gmx_ana_index_t *g, t_trxframe *fr, const t_pbc *pbc)
{
int i, bi, bj;
}
}
gmx::ConstArrayRef<int> index = pc->coll->getFrameIndices(pc->b.nra, pc->b.a);
- const t_topology *top = pc->coll->top_;
+ const gmx_mtop_t *top = pc->coll->top_;
const bool bMass = pc->flags & POS_MASS;
switch (pc->type)
{
struct gmx_ana_index_t;
struct gmx_ana_pos_t;
+struct gmx_mtop_t;
struct t_pbc;
-struct t_topology;
struct t_trxframe;
namespace gmx
class PositionCalculationCollection
{
public:
+ //! Describes what topology information is needed for position calculation.
+ enum class RequiredTopologyInfo
+ {
+ None, //!< No topology is needed.
+ Topology, //!< Topology is needed (residue/molecule info).
+ TopologyAndMasses //!< Masses are needed.
+ };
+
/*! \brief
* Array of strings acceptable for position calculation type enum.
*
* \see typeEnumValues
*/
static void typeFromEnum(const char *post, e_poscalc_t *type, int *flags);
+ /*! \brief
+ * Returns what information is needed for position evaluation.
+ *
+ * \param[in] post Position type (see typeFromEnum()).
+ * \param[in] forces Whether forces are needed.
+ * \returns What topology information is required for initializing
+ * and/or evaluating the positions.
+ */
+ static RequiredTopologyInfo requiredTopologyInfoForType(const char *post, bool forces);
/*! \brief
* Creates a new position calculation collection object.
*
* Does not throw.
*/
- void setTopology(t_topology *top);
+ void setTopology(const gmx_mtop_t *top);
/*! \brief
* Prints information about calculations.
*
/** Frees the memory allocated for position calculation. */
void
gmx_ana_poscalc_free(gmx_ana_poscalc_t *pc);
-/** Returns true if the position calculation requires topology information. */
-bool
-gmx_ana_poscalc_requires_top(gmx_ana_poscalc_t *pc);
+/*! \brief
+ * Returns true if the position calculation requires topology information.
+ *
+ * \param[in] pc Position calculation data to query.
+ * \returns Which topology information \p pc requires for initialization
+ * and/or evaluation.
+ */
+gmx::PositionCalculationCollection::RequiredTopologyInfo
+gmx_ana_poscalc_required_topology_info(gmx_ana_poscalc_t *pc);
/** Updates a single COM/COG structure for a frame. */
void
gmx_ana_poscalc_update(gmx_ana_poscalc_t *pc,
gmx_ana_pos_t *p, gmx_ana_index_t *g,
- t_trxframe *fr, t_pbc *pbc);
+ t_trxframe *fr, const t_pbc *pbc);
#endif
/*
* 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.
#include "gromacs/selection/nbsearch.h"
#include "gromacs/selection/position.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxassert.h"
*
* Does not throw if enough space has been reserved for the output vectors.
*/
-void computeMassesAndCharges(const t_topology *top, const gmx_ana_pos_t &pos,
+void computeMassesAndCharges(const gmx_mtop_t *top, const gmx_ana_pos_t &pos,
std::vector<real> *masses,
std::vector<real> *charges)
{
GMX_ASSERT(top != NULL, "Should not have been called with NULL topology");
masses->clear();
charges->clear();
+ int molb = 0;
for (int b = 0; b < pos.count(); ++b)
{
real mass = 0.0;
real charge = 0.0;
for (int i = pos.m.mapb.index[b]; i < pos.m.mapb.index[b+1]; ++i)
{
- const int index = pos.m.mapb.a[i];
- mass += top->atoms.atom[index].m;
- charge += top->atoms.atom[index].q;
+ const int index = pos.m.mapb.a[i];
+ const t_atom &atom = mtopGetAtomParameters(top, index, &molb);
+ mass += atom.m;
+ charge += atom.q;
}
masses->push_back(mass);
charges->push_back(charge);
}
void
-SelectionData::initializeMassesAndCharges(const t_topology *top)
+SelectionData::initializeMassesAndCharges(const gmx_mtop_t *top)
{
GMX_ASSERT(posMass_.empty() && posCharge_.empty(),
"Should not be called more than once");
void
-SelectionData::refreshMassesAndCharges(const t_topology *top)
+SelectionData::refreshMassesAndCharges(const gmx_mtop_t *top)
{
if (top != NULL && isDynamic() && !hasFlag(efSelection_DynamicMask))
{
void
-SelectionData::restoreOriginalPositions(const t_topology *top)
+SelectionData::restoreOriginalPositions(const gmx_mtop_t *top)
{
if (isDynamic())
{
int
-Selection::initOriginalIdsToGroup(t_topology *top, e_index_t type)
+Selection::initOriginalIdsToGroup(const gmx_mtop_t *top, e_index_t type)
{
try
{
/*
* 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.
#include "gromacs/utility/classhelpers.h"
#include "gromacs/utility/gmxassert.h"
-struct t_topology;
+struct gmx_mtop_t;
namespace gmx
{
*
* Strong exception safety guarantee.
*/
- void initializeMassesAndCharges(const t_topology *top);
+ void initializeMassesAndCharges(const gmx_mtop_t *top);
/*! \brief
* Updates masses and charges after dynamic selection has been
* evaluated.
*
* Called by SelectionEvaluator.
*/
- void refreshMassesAndCharges(const t_topology *top);
+ void refreshMassesAndCharges(const gmx_mtop_t *top);
/*! \brief
* Updates the covered fraction after a selection has been evaluated.
*
* \a rootElement_ object.
* Called by SelectionEvaluator::evaluateFinal().
*/
- void restoreOriginalPositions(const t_topology *top);
+ void restoreOriginalPositions(const gmx_mtop_t *top);
private:
//! Name of the selection.
* \see setOriginalId()
* \see SelectionPosition::mappedId()
*/
- int initOriginalIdsToGroup(t_topology *top, e_index_t type);
+ int initOriginalIdsToGroup(const gmx_mtop_t *top, e_index_t type);
/*! \brief
* Prints out one-line description of the selection.
#include "poscalc.h"
#include "selelem.h"
+struct gmx_mtop_t;
struct gmx_sel_mempool_t;
struct t_pbc;
-struct t_topology;
struct t_trxframe;
namespace gmx
typedef std::vector<SelectionDataPointer> SelectionDataList;
class SelectionParserSymbolTable;
+struct SelectionTopologyProperties;
} // namespace gmx
char **varstrs;
/** Topology for the collection. */
- t_topology *top;
+ const gmx_mtop_t *top;
/** Index group that contains all the atoms. */
gmx_ana_index_t gall;
/** Memory pool used for selection evaluation. */
void resolveExternalGroups(const gmx::SelectionTreeElementPointer &root,
ExceptionInitializer *errors);
+ //! Whether forces have been requested for some selection.
+ bool areForcesRequested() const;
+ /*! \brief
+ * Returns topology properties needed for a certain position type.
+ */
+ SelectionTopologyProperties
+ requiredTopologyPropertiesForPositionType(const std::string &post,
+ bool forces) const;
+
//! Internal data, used for interfacing with old C code.
gmx_ana_selcollection_t sc_;
//! Default reference position type for selections.
#include "gromacs/options/ioptionscontainer.h"
#include "gromacs/selection/selection.h"
#include "gromacs/selection/selhelp.h"
+#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
#include "gromacs/trajectory/trajectoryframe.h"
#include "gromacs/utility/exceptions.h"
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;
}
}
}
+//! Checks whether the given topology properties are available.
+void checkTopologyProperties(const gmx_mtop_t *top,
+ const SelectionTopologyProperties &props)
+{
+ if (top == NULL)
+ {
+ if (props.hasAny())
+ {
+ GMX_THROW(InconsistentInputError("Selection requires topology information, but none provided"));
+ }
+ return;
+ }
+ if (props.needsMasses && !gmx_mtop_has_masses(top))
+ {
+ GMX_THROW(InconsistentInputError("Selection requires mass information, but it is not available in the topology"));
+ }
+}
+
} // namespace
}
+bool SelectionCollection::Impl::areForcesRequested() const
+{
+ for (const auto &sel : sc_.sel)
+ {
+ if (sel->hasFlag(gmx::efSelection_EvaluateForces))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+SelectionTopologyProperties
+SelectionCollection::Impl::requiredTopologyPropertiesForPositionType(
+ const std::string &post, bool forces) const
+{
+ SelectionTopologyProperties props;
+ if (!post.empty())
+ {
+ switch (PositionCalculationCollection::requiredTopologyInfoForType(post.c_str(), forces))
+ {
+ case PositionCalculationCollection::RequiredTopologyInfo::None:
+ break;
+ case PositionCalculationCollection::RequiredTopologyInfo::Topology:
+ props.merge(SelectionTopologyProperties::topology());
+ break;
+ case PositionCalculationCollection::RequiredTopologyInfo::TopologyAndMasses:
+ props.merge(SelectionTopologyProperties::masses());
+ break;
+ }
+ }
+ return props;
+}
+
+
/********************************************************************
* SelectionCollection
*/
void
-SelectionCollection::setTopology(t_topology *top, int natoms)
+SelectionCollection::setTopology(gmx_mtop_t *top, int natoms)
{
GMX_RELEASE_ASSERT(natoms > 0 || top != NULL,
"The number of atoms must be given if there is no topology");
+ checkTopologyProperties(top, requiredTopologyProperties());
// Get the number of atoms from the topology if it is not given.
if (natoms <= 0)
{
- natoms = top->atoms.nr;
+ natoms = top->natoms;
}
if (impl_->bExternalGroupsSet_)
{
gmx_ana_selcollection_t *sc = &impl_->sc_;
// Do this first, as it allocates memory, while the others don't throw.
gmx_ana_index_init_simple(&sc->gall, natoms);
- sc->pcc.setTopology(top);
sc->top = top;
+ sc->pcc.setTopology(top);
}
}
}
-
-bool
-SelectionCollection::requiresTopology() const
+SelectionTopologyProperties
+SelectionCollection::requiredTopologyProperties() const
{
- e_poscalc_t type;
- int flags;
+ SelectionTopologyProperties props;
- if (!impl_->rpost_.empty())
- {
- flags = 0;
- // Should not throw, because has been checked earlier.
- PositionCalculationCollection::typeFromEnum(impl_->rpost_.c_str(),
- &type, &flags);
- if (type != POS_ATOM)
- {
- return true;
- }
- }
- if (!impl_->spost_.empty())
- {
- flags = 0;
- // Should not throw, because has been checked earlier.
- PositionCalculationCollection::typeFromEnum(impl_->spost_.c_str(),
- &type, &flags);
- if (type != POS_ATOM)
- {
- return true;
- }
- }
+ // These should not throw, because has been checked earlier.
+ props.merge(impl_->requiredTopologyPropertiesForPositionType(impl_->rpost_, false));
+ const bool forcesRequested = impl_->areForcesRequested();
+ props.merge(impl_->requiredTopologyPropertiesForPositionType(impl_->spost_,
+ forcesRequested));
SelectionTreeElementPointer sel = impl_->sc_.root;
- while (sel)
+ while (sel && !props.hasAll())
{
- if (_gmx_selelem_requires_top(*sel))
- {
- return true;
- }
+ props.merge(sel->requiredTopologyProperties());
sel = sel->next;
}
- return false;
+ return props;
}
void
SelectionCollection::compile()
{
- if (impl_->sc_.top == NULL && requiresTopology())
- {
- GMX_THROW(InconsistentInputError("Selection requires topology information, but none provided"));
- }
+ checkTopologyProperties(impl_->sc_.top, requiredTopologyProperties());
if (!impl_->bExternalGroupsSet_)
{
setIndexGroups(NULL);
}
}
}
+ impl_->rpost_.clear();
+ impl_->spost_.clear();
}
void
SelectionCollection::evaluate(t_trxframe *fr, t_pbc *pbc)
{
+ checkTopologyProperties(impl_->sc_.top, requiredTopologyProperties());
if (fr->bIndex)
{
gmx_ana_index_t g;
/*
* 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 "gromacs/utility/classhelpers.h"
struct gmx_ana_indexgrps_t;
+struct gmx_mtop_t;
struct t_pbc;
-struct t_topology;
struct t_trxframe;
namespace gmx
class SelectionEvaluator;
class TextInputStream;
class TextOutputStream;
+struct SelectionTopologyProperties;
/*! \brief
* Collection of selections.
void setDebugLevel(int debugLevel);
/*! \brief
- * Returns true if the collection requires topology information for
- * evaluation.
+ * Returns what topology information is required for evaluation.
*
- * \returns true if any selection in the collection requires topology
- * information.
+ * \returns What topology information is required for compiling and/or
+ * evaluating the selections in the collection.
*
* Before the parser functions have been called, the return value is
* based just on the position types set.
* After parser functions have been called, the return value also takes
* into account the selection keywords used.
+ * After the compiler has been called, the return value is final and
+ * also considers possible force evaluation requested for the
+ * selections.
*
* Does not throw.
*/
- bool requiresTopology() const;
+ SelectionTopologyProperties requiredTopologyProperties() const;
/*! \brief
* Returns true if the collection requires external index groups.
*
* Does not throw currently, but this is subject to change when more
* underlying code is converted to C++.
*/
- void setTopology(t_topology *top, int natoms);
+ void setTopology(gmx_mtop_t *top, int natoms);
/*! \brief
* Sets the external index groups to use for the selections.
*
/*
* 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.
typedef FlagsTemplate<SelectionFlag> SelectionFlags;
//! \endcond
+/*! \brief
+ * Describes topology properties required for selection evaluation.
+ *
+ * See SelectionCollection::requiredTopologyProperties().
+ *
+ * \inpublicapi
+ * \ingroup module_selection
+ */
+struct SelectionTopologyProperties
+{
+ //! Returns a property object that requires generic topology info.
+ static SelectionTopologyProperties topology()
+ {
+ return SelectionTopologyProperties(true, false);
+ }
+ //! Returns a property object that requires atom masses.
+ static SelectionTopologyProperties masses()
+ {
+ return SelectionTopologyProperties(true, true);
+ }
+
+ //! Initializes properties that does not require anything.
+ SelectionTopologyProperties()
+ : needsTopology(false), needsMasses(false)
+ {
+ }
+ //! Initializes properties with the given flags.
+ SelectionTopologyProperties(bool needsTopology, bool needsMasses)
+ : needsTopology(needsTopology), needsMasses(needsMasses)
+ {
+ }
+
+ //! Combines flags from another properties object to this.
+ void merge(const SelectionTopologyProperties &other)
+ {
+ needsTopology = needsTopology || other.needsTopology;
+ needsMasses = needsMasses || other.needsMasses;
+ }
+ //! Whether all flags are `true` (for short-ciruiting logic).
+ bool hasAll() const { return needsTopology && needsMasses; }
+ //! Whether any flag is `true`.
+ bool hasAny() const { return needsTopology || needsMasses; }
+
+ //! Whether topology information is needed for selection evaluation.
+ bool needsTopology;
+ //! Whether atom masses are needed for selection evaluation.
+ bool needsMasses;
+};
+
}
#endif
/*
* 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.
virtual OptionInfo &optionInfo() { return info_; }
virtual std::string typeString() const { return "file"; }
virtual int valueCount() const { return 0; }
- virtual std::string formatValue(int /*i*/) const { return ""; }
+ virtual std::vector<Variant> defaultValues() const { return {}; }
+ virtual std::vector<std::string> defaultValuesAsStrings() const { return {}; }
+ virtual std::vector<Variant>
+ normalizeValues(const std::vector<Variant> &values) const { return values; }
private:
virtual void clearSet();
- virtual void convertValue(const std::string &value);
+ virtual void convertValue(const Variant &value);
virtual void processSet();
virtual void processAll() {}
/*
* 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.
}
+std::vector<Variant>
+SelectionOptionStorage::normalizeValues(const std::vector<Variant> & /*values*/) const
+{
+ GMX_THROW(NotImplementedError("Selection options not supported in this context"));
+}
+
+
void SelectionOptionStorage::addSelections(
const SelectionList &selections,
bool bFullValue)
}
-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)
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() + "'");
}
}
selectionFlags_.set(flag, bSet);
- for (i = values().begin(); i != values().end(); ++i)
+ for (Selection &value : values())
{
- i->data().setFlags(selectionFlags_);
+ value.data().setFlags(selectionFlags_);
}
}
bValueParsed_ = false;
}
-void SelectionFileOptionStorage::convertValue(const std::string &value)
+void SelectionFileOptionStorage::convertValue(const Variant &value)
{
if (bValueParsed_)
{
}
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()
/*
* 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.
#include "gromacs/selection/selectioncollection.h"
#include "gromacs/selection/selectionfileoption.h"
#include "gromacs/selection/selectionoptionmanager.h"
+#include "gromacs/topology/atoms.h"
+#include "gromacs/topology/topology.h"
+#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/filestream.h"
namespace gmx
}
if (ndxfile_.empty())
{
- t_topology *top = topologyProvider_.getTopology(false);
+ gmx_mtop_t *top = topologyProvider_.getTopology(false);
gmx_ana_indexgrps_init(&grps_, top, NULL);
}
else
void compileSelections()
{
- t_topology *top = topologyProvider_.getTopology(selections_.requiresTopology());
- int natoms = -1;
+ const bool topRequired = selections_.requiredTopologyProperties().needsTopology;
+ gmx_mtop_t *top = topologyProvider_.getTopology(topRequired);
+ int natoms = -1;
if (top == NULL)
{
natoms = topologyProvider_.getAtomCount();
}
+ getMassesIfRequired(top);
selections_.setTopology(top, natoms);
selections_.compile();
+ // Situation may have changed after compilation.
+ getMassesIfRequired(top);
+ }
+
+ void getMassesIfRequired(gmx_mtop_t *top)
+ {
+ const bool massRequired = selections_.requiredTopologyProperties().needsMasses;
+ if (!massRequired)
+ {
+ return;
+ }
+ // TODO: There can be some corner cases that still hit this assert
+ // when the user has not provided the topology.
+ GMX_RELEASE_ASSERT(top != nullptr,
+ "Masses are required, but no topology is loaded");
+ for (int i = 0; i < top->nmoltype; ++i)
+ {
+ gmx_moltype_t &moltype = top->moltype[i];
+ if (!moltype.atoms.haveMass)
+ {
+ atomsSetMassesBasedOnNames(&moltype.atoms, TRUE);
+ if (!moltype.atoms.haveMass)
+ {
+ GMX_THROW(InconsistentInputError("Selections require mass information for evaluation, but it is not available in the input and could not be determined for all atoms based on atom names."));
+ }
+ }
+ }
}
SelectionCollection &selections_;
/*
* 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.
#include "gromacs/options/ioptionsbehavior.h"
#include "gromacs/utility/classhelpers.h"
-struct t_topology;
+struct gmx_mtop_t;
namespace gmx
{
* different values of \p required. Subsequent calls should just
* return the same topology that was loaded in the first call.
*/
- virtual t_topology *getTopology(bool required) = 0;
+ virtual gmx_mtop_t *getTopology(bool required) = 0;
/*! \brief
* Returns the number of atoms.
*
/*
* 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.
SelectionOptionStorage &storage = **i;
if (storage.isRequired() && !storage.isSet())
{
- requests_.push_back(SelectionRequest(&storage));
+ requests_.emplace_back(&storage);
}
}
}
SelectionOptionManager::requestOptionDelayedParsing(
SelectionOptionStorage *storage)
{
- impl_->requests_.push_back(Impl::SelectionRequest(storage));
+ impl_->requests_.emplace_back(storage);
}
bool
/*
* 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.
virtual OptionInfo &optionInfo() { return info_; }
virtual std::string typeString() const { return "selection"; }
virtual std::string formatSingleValue(const Selection &value) const;
+ virtual std::vector<Variant>
+ normalizeValues(const std::vector<Variant> &values) const;
/*! \brief
* Adds selections to the storage.
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();
/*
* 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.
#include "gromacs/selection/indexutil.h"
#include "gromacs/selection/position.h"
+#include "gromacs/selection/selectionenums.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxassert.h"
#include "gromacs/utility/smalloc.h"
const SelectionLocation &location)
: location_(location)
{
+ // cppcheck-suppress useInitializationList
this->type = type;
this->flags = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
if (type == SEL_BOOLEAN)
}
}
+SelectionTopologyProperties
+SelectionTreeElement::requiredTopologyProperties() const
+{
+ SelectionTopologyProperties props;
+ if (type == SEL_EXPRESSION || type == SEL_MODIFIER)
+ {
+ bool needsTop = false;
+ bool needsMasses = false;
+ if (u.expr.method != nullptr)
+ {
+ needsTop = (u.expr.method->flags & SMETH_REQTOP);
+ needsMasses = (u.expr.method->flags & SMETH_REQMASS);
+ }
+ if (u.expr.pc != nullptr)
+ {
+ auto requiredTopologyInfo = gmx_ana_poscalc_required_topology_info(u.expr.pc);
+ needsTop = needsTop
+ || (requiredTopologyInfo != PositionCalculationCollection::RequiredTopologyInfo::None);
+ needsMasses = needsMasses
+ || (requiredTopologyInfo == PositionCalculationCollection::RequiredTopologyInfo::TopologyAndMasses);
+ }
+ if (needsTop)
+ {
+ props.merge(SelectionTopologyProperties::topology());
+ }
+ if (needsMasses)
+ {
+ props.merge(SelectionTopologyProperties::masses());
+ }
+ }
+ SelectionTreeElementPointer child = this->child;
+ while (child && !props.hasAll())
+ {
+ props.merge(child->requiredTopologyProperties());
+ child = child->next;
+ }
+ return props;
+}
+
void SelectionTreeElement::checkUnsortedAtoms(
bool bUnsortedAllowed, ExceptionInitializer *errors) const
{
child = child->next;
}
}
-
-/*!
- * \param[in] root Root of the subtree to query.
- * \returns true if \p root or any any of its elements require topology
- * information, false otherwise.
- */
-bool
-_gmx_selelem_requires_top(const gmx::SelectionTreeElement &root)
-{
- if (root.type == SEL_EXPRESSION || root.type == SEL_MODIFIER)
- {
- if (root.u.expr.method && (root.u.expr.method->flags & SMETH_REQTOP))
- {
- return true;
- }
- if (root.u.expr.pc && gmx_ana_poscalc_requires_top(root.u.expr.pc))
- {
- return true;
- }
- }
- gmx::SelectionTreeElementPointer child = root.child;
- while (child)
- {
- if (_gmx_selelem_requires_top(*child))
- {
- return true;
- }
- child = child->next;
- }
- return false;
-}
/*
* 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.
namespace gmx
{
class SelectionTreeElement;
+struct SelectionTopologyProperties;
//! Smart pointer type for selection tree element pointers.
typedef std::shared_ptr<SelectionTreeElement> SelectionTreeElementPointer;
*/
void fillNameIfMissing(const char *selectionText);
+ /*! \brief
+ * Returns which topology properties the selection element subtree requires
+ * for evaluation.
+ *
+ * \returns List of topology properties required for evaluation.
+ */
+ SelectionTopologyProperties requiredTopologyProperties() const;
/*! \brief
* Checks that this element and its children do not contain unsupported
* elements with unsorted atoms.
_gmx_selelem_print_compiler_info(FILE *fp, const gmx::SelectionTreeElement &sel,
int level);
-/** Returns true if the selection element subtree requires topology information for evaluation. */
-bool
-_gmx_selelem_requires_top(const gmx::SelectionTreeElement &root);
-
/* In sm_insolidangle.c */
/** Returns true if the covered fraction of the selection can be calculated. */
bool
/*
* 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.
* and the \p top pointer passed to the callbacks is guaranteed to be
* non-NULL. Should be set if the method requires topology information
* for evaluation.
+ * - \ref SMETH_REQMASS : If set, masses of atoms is always loaded
+ * and the \p top pointer passed to the callbacks is guaranteed to be
+ * non-NULL and have meaningful masses. Should be set if the method requires
+ * atom masses for evaluation. Implies \ref SMETH_REQTOP.
* - \ref SMETH_DYNAMIC : If set, the method can only be evaluated dynamically,
* i.e., it requires data from the trajectory frame.
* - \ref SMETH_MODIFIER : If set, the method is a selection modifier and
#include "selparam.h"
#include "selvalue.h"
-namespace gmx
-{
-class PositionCalculationCollection;
-class SelectionParserSymbolTable;
-} // namespace gmx
-
struct gmx_ana_index_t;
struct gmx_ana_pos_t;
struct gmx_ana_selcollection_t;
+struct gmx_mtop_t;
struct t_pbc;
-struct t_topology;
struct t_trxframe;
+namespace gmx
+{
+class PositionCalculationCollection;
+class SelectionParserSymbolTable;
+
+/*! \internal
+ * \brief
+ * Evaluation context for selection methods.
+ *
+ * This structure encapsulates common parameters passed to selection method
+ * evaluation functions. The contained values describe the evaluation context,
+ * i.e., the topology and the current trajectory frame.
+ *
+ * \ingroup module_selection
+ */
+struct SelMethodEvalContext
+{
+ //! Initializes the context with given values.
+ SelMethodEvalContext(const gmx_mtop_t *top, t_trxframe *fr, const t_pbc *pbc)
+ : top(top), fr(fr), pbc(pbc)
+ {
+ }
+
+ /*! \brief
+ * Topology.
+ *
+ * Can be NULL if \ref SMETH_REQTOP or \ref SMETH_REQMASS is not set for
+ * the method.
+ */
+ const gmx_mtop_t *top;
+ /*! \brief
+ * Trajectory frame.
+ *
+ * For static methods that are evaluated based on topology information
+ * alone, this is `NULL`.
+ */
+ t_trxframe *fr;
+ /*! \brief
+ * Periodic boundary condition information.
+ *
+ * Can be `NULL`, in which case PBC should not be used.
+ */
+ const t_pbc *pbc;
+};
+
+} // namespace gmx
+
/*! \name Selection method flags
* \anchor selmethod_flags
*/
/*@{*/
-/*! \brief
- * If set, the method requires topology information.
- */
+//! If set, the method requires topology information.
#define SMETH_REQTOP 1
-/*! \brief
- * If set, the method can only be evaluated dynamically.
- */
-#define SMETH_DYNAMIC 2
+//! If set, the method requires atom masses.
+#define SMETH_REQMASS 2
+//! If set, the method can only be evaluated dynamically.
+#define SMETH_DYNAMIC 4
/*! \brief
* If set, the method evaluates to a single value.
*
* The default is that the method evaluates to a value for each input atom.
* Cannot be combined with \ref SMETH_VARNUMVAL.
*/
-#define SMETH_SINGLEVAL 4
+#define SMETH_SINGLEVAL 8
/*! \brief
* If set, the method evaluates to an arbitrary number of values.
*
* The default is that the method evaluates to a value for each input atom.
* Cannot be combined with \ref SMETH_SINGLEVAL or with \ref GROUP_VALUE.
*/
-#define SMETH_VARNUMVAL 8
+#define SMETH_VARNUMVAL 16
/*! \brief
* If set, the method evaluates to single-character strings.
*
* Does initialization based on topology and/or parameter values.
*
* \param[in] top Topology structure
- * (can be NULL if \ref SMETH_REQTOP is not set).
+ * (can be NULL if \ref SMETH_REQTOP or \ref SMETH_REQMASS is not set).
* \param[in] npar Number of parameters in \p param.
* \param[in] param Pointer to (an initialized copy of) the method's
* \c gmx_ana_selmethod_t::param.
* This function may be called multiple times for the same method if the
* method takes parameters with \ref SPAR_ATOMVAL set.
*/
-typedef void (*sel_initfunc)(t_topology *top, int npar,
+typedef void (*sel_initfunc)(const gmx_mtop_t *top, int npar,
gmx_ana_selparam_t *param, void *data);
/*! \brief
* Initializes output data structure.
*
* \param[in] top Topology structure
- * (can be NULL if \ref SMETH_REQTOP is not set).
+ * (can be NULL if \ref SMETH_REQTOP or \ref SMETH_REQMASS is not set).
* \param[in,out] out Output data structure.
* \param[in] data Internal data structure from sel_datafunc().
* \returns 0 on success, an error code on error.
* This function may be called multiple times for the same method if the
* method takes parameters with \ref SPAR_ATOMVAL set.
*/
-typedef void (*sel_outinitfunc)(t_topology *top, gmx_ana_selvalue_t *out,
+typedef void (*sel_outinitfunc)(const gmx_mtop_t *top, gmx_ana_selvalue_t *out,
void *data);
/*! \brief
* Frees the internal data.
/*! \brief
* Initializes the evaluation for a new frame.
*
- * \param[in] top Topology structure
- * (can be NULL if \ref SMETH_REQTOP is not set).
- * \param[in] fr Current frame.
- * \param[in] pbc Initialized periodic boundary condition structure,
- * or NULL if PBC should not be used.
+ * \param[in] context Evaluation context.
* \param data Internal data structure from sel_datafunc().
* \returns 0 on success, a non-zero error code on failure.
*
* For static methods, it is called once, with \p fr and \p pbc set to
* NULL.
*/
-typedef void (*sel_framefunc)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
- void *data);
+typedef void (*sel_framefunc)(const gmx::SelMethodEvalContext &context,
+ void *data);
/*! \brief
* Evaluates a selection method.
*
- * \param[in] top Topology structure
- * (can be NULL if \ref SMETH_REQTOP is not set).
- * \param[in] fr Current frame.
- * \param[in] pbc Initialized periodic boundary condition structure,
- * or NULL if PBC should not be used.
+ * \param[in] context Evaluation context.
* \param[in] g Index group for which the method should be evaluated.
* \param[out] out Output data structure.
* \param data Internal data structure from sel_datafunc().
* contains such an atom in case the \p fr has been loaded from a trajectory
* that only contains a subset of the system.
*/
-typedef void (*sel_updatefunc)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+typedef void (*sel_updatefunc)(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out,
void *data);
/*! \brief
* Evaluates a selection method using positions.
*
- * \param[in] top Topology structure
- * (can be NULL if \ref SMETH_REQTOP is not set).
- * \param[in] fr Current frame.
- * \param[in] pbc Initialized periodic boundary condition structure,
- * or NULL if PBC should not be used.
+ * \param[in] context Evaluation context.
* \param[in] pos Positions for which the method should be evaluated.
* \param[out] out Output data structure.
* \param data Internal data structure from sel_datafunc().
* contains such an atom in case the \p fr has been loaded from a trajectory
* that only contains a subset of the system.
*/
-typedef void (*sel_updatefunc_pos)(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+typedef void (*sel_updatefunc_pos)(const gmx::SelMethodEvalContext &context,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out,
void *data);
/*
* 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.
* \returns 0 if the input data is valid, -1 on error.
*/
static void
-init_compare(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_compare(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/** Frees the memory allocated for comparison expression evaluation. */
static void
free_data_compare(void *data);
-/** Evaluates comparison expressions. */
+/*! \brief
+ * Evaluates comparison expressions.
+ *
+ * \param[in] context Not used.
+ * \param[in] g Evaluation index group.
+ * \param[out] out Output data structure (\p out->u.g is used).
+ * \param[in] data Should point to a \c t_methoddata_compare.
+ */
static void
-evaluate_compare(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_compare(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Parameters for comparison expression evaluation. */
}
static void
-init_compare(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_compare(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
{
t_methoddata_compare *d = (t_methoddata_compare *)data;
int n1, n2;
/*! \brief
* Implementation for evaluate_compare() for integer values.
*
- * \param[in] top Not used.
- * \param[in] fr Not used.
- * \param[in] pbc Not used.
* \param[in] g Evaluation index group.
* \param[out] out Output data structure (\p out->u.g is used).
* \param[in] data Should point to a \c t_methoddata_compare.
*/
static void
-evaluate_compare_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
- gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+evaluate_compare_int(gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_compare *d = (t_methoddata_compare *)data;
int i, i1, i2, ig;
int a, b;
bool bAccept;
- GMX_UNUSED_VALUE(top);
- GMX_UNUSED_VALUE(fr);
- GMX_UNUSED_VALUE(pbc);
for (i = i1 = i2 = ig = 0; i < g->isize; ++i)
{
a = d->left.i[i1];
/*! \brief
* Implementation for evaluate_compare() if either value is non-integer.
*
- * \param[in] top Not used.
- * \param[in] fr Not used.
- * \param[in] pbc Not used.
* \param[in] g Evaluation index group.
* \param[out] out Output data structure (\p out->u.g is used).
* \param[in] data Should point to a \c t_methoddata_compare.
* This is ensured by the initialization method.
*/
static void
-evaluate_compare_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
- gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+evaluate_compare_real(gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_compare *d = (t_methoddata_compare *)data;
int i, i1, i2, ig;
real a, b;
bool bAccept;
- GMX_UNUSED_VALUE(top);
- GMX_UNUSED_VALUE(fr);
- GMX_UNUSED_VALUE(pbc);
for (i = i1 = i2 = ig = 0; i < g->isize; ++i)
{
a = d->left.r[i1];
out->u.g->isize = ig;
}
-/*!
- * \param[in] top Not used.
- * \param[in] fr Not used.
- * \param[in] pbc Not used.
- * \param[in] g Evaluation index group.
- * \param[out] out Output data structure (\p out->u.g is used).
- * \param[in] data Should point to a \c t_methoddata_compare.
- */
static void
-evaluate_compare(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_compare(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_compare *d = (t_methoddata_compare *)data;
if (!((d->left.flags | d->right.flags) & CMP_REALVAL))
{
- evaluate_compare_int(top, fr, pbc, g, out, data);
+ evaluate_compare_int(g, out, data);
}
else
{
- evaluate_compare_real(top, fr, pbc, g, out, data);
+ evaluate_compare_real(g, out, data);
}
}
/*
* 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.
* Also checks that the cutoff is valid.
*/
static void
-init_common(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_common(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/** Frees the data allocated for a distance-based selection method. */
static void
free_data_common(void *data);
* Initializes the evaluation of a distance-based within selection method for a
* frame.
*
- * \param[in] top Not used.
- * \param[in] fr Current frame.
- * \param[in] pbc PBC structure.
- * \param data Should point to a \c t_methoddata_distance.
+ * \param[in] context Evaluation context.
+ * \param data Should point to a \c t_methoddata_distance.
* \returns 0 on success, a non-zero error code on error.
*
* Initializes the neighborhood search for the current frame.
*/
static void
-init_frame_common(t_topology *top, t_trxframe * fr, t_pbc *pbc, void *data);
+init_frame_common(const gmx::SelMethodEvalContext &context, void *data);
/** Evaluates the \p distance selection method. */
static void
-evaluate_distance(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_distance(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p within selection method. */
static void
-evaluate_within(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_within(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
/** Parameters for the \p distance selection method. */
}
static void
-init_common(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_common(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
{
t_methoddata_distance *d = static_cast<t_methoddata_distance *>(data);
}
static void
-init_frame_common(t_topology * /* top */, t_trxframe * /* fr */, t_pbc *pbc, void *data)
+init_frame_common(const gmx::SelMethodEvalContext &context, void *data)
{
t_methoddata_distance *d = static_cast<t_methoddata_distance *>(data);
d->nbsearch.reset();
gmx::AnalysisNeighborhoodPositions pos(d->p.x, d->p.count());
- d->nbsearch = d->nb.initSearch(pbc, pos);
+ d->nbsearch = d->nb.initSearch(context.pbc, pos);
}
/*!
* and puts them in \p out->u.r.
*/
static void
-evaluate_distance(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_distance(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_distance *d = static_cast<t_methoddata_distance *>(data);
* \c t_methoddata_distance::xref and puts them in \p out.g.
*/
static void
-evaluate_within(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_within(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_distance *d = static_cast<t_methoddata_distance *>(data);
* and allocates memory for the bins used during the evaluation.
*/
static void
-init_insolidangle(t_topology * top, int npar, gmx_ana_selparam_t * param, void *data);
+init_insolidangle(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t * param, void *data);
/** Frees the data allocated for the \p insolidangle selection method. */
static void
free_data_insolidangle(void *data);
/*! \brief
* Initializes the evaluation of the \p insolidangle selection method for a frame.
*
- * \param[in] top Not used.
- * \param[in] fr Not used.
- * \param[in] pbc PBC structure.
- * \param data Should point to a \ref t_methoddata_insolidangle.
+ * \param[in] context Evaluation context.
+ * \param data Should point to a \ref t_methoddata_insolidangle.
*
* Creates a lookup structure that enables fast queries of whether a point
* is within the solid angle or not.
*/
static void
-init_frame_insolidangle(t_topology * top, t_trxframe * fr, t_pbc *pbc, void *data);
+init_frame_insolidangle(const gmx::SelMethodEvalContext &context, void *data);
/** Internal helper function for evaluate_insolidangle(). */
static bool
-accept_insolidangle(rvec x, t_pbc *pbc, void *data);
+accept_insolidangle(rvec x, const t_pbc *pbc, void *data);
/** Evaluates the \p insolidangle selection method. */
static void
-evaluate_insolidangle(t_topology * /* top */, t_trxframe * /* fr */, t_pbc *pbc,
+evaluate_insolidangle(const gmx::SelMethodEvalContext &context,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
/** Calculates the distance between unit vectors. */
}
static void
-init_insolidangle(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
+init_insolidangle(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
{
t_methoddata_insolidangle *surf = (t_methoddata_insolidangle *)data;
int i, c;
}
static void
-init_frame_insolidangle(t_topology * /* top */, t_trxframe * /* fr */, t_pbc *pbc, void *data)
+init_frame_insolidangle(const gmx::SelMethodEvalContext &context, void *data)
{
t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
rvec dx;
clear_surface_points(d);
for (i = 0; i < d->span.count(); ++i)
{
- if (pbc)
+ if (context.pbc)
{
- pbc_dx(pbc, d->span.x[i], d->center.x[0], dx);
+ pbc_dx(context.pbc, d->span.x[i], d->center.x[0], dx);
}
else
{
* \returns true if \p x is within the solid angle, false otherwise.
*/
static bool
-accept_insolidangle(rvec x, t_pbc *pbc, void *data)
+accept_insolidangle(rvec x, const t_pbc *pbc, void *data)
{
t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
rvec dx;
* \c t_methoddata_insolidangle::center, and stores the result in \p out->u.g.
*/
static void
-evaluate_insolidangle(t_topology * /* top */, t_trxframe * /* fr */, t_pbc *pbc,
+evaluate_insolidangle(const gmx::SelMethodEvalContext &context,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
{
out->u.g->isize = 0;
for (int b = 0; b < pos->count(); ++b)
{
- if (accept_insolidangle(pos->x[b], pbc, data))
+ if (accept_insolidangle(pos->x[b], context.pbc, data))
{
gmx_ana_pos_add_to_group(out->u.g, pos, b);
}
/*
* 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.
* \param[in] data Should point to \ref t_methoddata_kwint.
*/
static void
-init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_kwint(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/*! \brief
* Initializes data for real keyword evaluation.
*
* \returns 0 (the initialization always succeeds).
*/
static void
-init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_kwreal(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/*! \brief
* Initializes data for string keyword evaluation.
*
* \param[in] data Should point to t_methoddata_kwstr.
*/
static void
-init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_kwstr(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/** Frees the memory allocated for string keyword evaluation. */
static void
free_data_kwstr(void *data);
/** Evaluates integer selection keywords. */
static void
-evaluate_keyword_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_int(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates real selection keywords. */
static void
-evaluate_keyword_real(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_real(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates string selection keywords. */
static void
-evaluate_keyword_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_str(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/*! \internal \brief
* Calls the initialization method of the wrapped keyword.
*/
static void
-init_kweval(t_topology *top, int npar, gmx_ana_selparam_t * param, void *data);
+init_kweval(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t * param, void *data);
/*! \brief
* Initializes output for keyword evaluation in an arbitrary group.
*
* \returns 0 for success.
*/
static void
-init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+init_output_kweval(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data);
/** Frees the data allocated for keyword evaluation in an arbitrary group. */
static void
free_data_kweval(void *data);
/** Initializes frame evaluation for keyword evaluation in an arbitrary group. */
static void
-init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
+init_frame_kweval(const gmx::SelMethodEvalContext &context, void *data);
/*! \brief
* Evaluates keywords in an arbitrary group.
*
* evaluation group.
*/
static void
-evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t *g,
+evaluate_kweval(const gmx::SelMethodEvalContext &context, gmx_ana_index_t *g,
gmx_ana_selvalue_t *out, void *data);
/*! \brief
* Evaluates keywords in an arbitrary set of positions.
* evaluation positions.
*/
static void
-evaluate_kweval_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t *g,
+evaluate_kweval_pos(const gmx::SelMethodEvalContext &context, gmx_ana_index_t *g,
gmx_ana_selvalue_t *out, void *data);
/*! \internal \brief
}
static void
-init_kwint(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_kwint(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
{
t_methoddata_kwint *d = (t_methoddata_kwint *)data;
* Matching atoms are stored in \p out->u.g.
*/
static void
-evaluate_keyword_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_int(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_kwint *d = (t_methoddata_kwint *)data;
}
static void
-init_kwreal(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_kwreal(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
{
t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
* Matching atoms are stored in \p out->u.g.
*/
static void
-evaluate_keyword_real(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_real(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
}
static void
-init_kwstr(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_kwstr(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
{
t_methoddata_kwstr *d = static_cast<t_methoddata_kwstr *>(data);
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);
}
}
* Matching atoms are stored in \p out->u.g.
*/
static void
-evaluate_keyword_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_keyword_str(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_kwstr *d = static_cast<t_methoddata_kwstr *>(data);
********************************************************************/
static void
-init_kweval(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
+init_kweval(const gmx_mtop_t *top, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
{
t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
}
static void
-init_output_kweval(t_topology * /* top */, gmx_ana_selvalue_t *out, void *data)
+init_output_kweval(const gmx_mtop_t * /* top */, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
}
/*!
- * \param[in] top Topology.
- * \param[in] fr Current frame.
- * \param[in] pbc PBC structure.
+ * \param[in] context Evaluation context.
* \param data Should point to a \ref t_methoddata_kweval.
- * \returns 0 on success, a non-zero error code on error.
- *
- * Creates a lookup structure that enables fast queries of whether a point
- * is within the solid angle or not.
*/
static void
-init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
+init_frame_kweval(const gmx::SelMethodEvalContext &context, void *data)
{
t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
- d->kwmethod->init_frame(top, fr, pbc, d->kwmdata);
+ d->kwmethod->init_frame(context, d->kwmdata);
}
static void
-evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_kweval(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
- d->kwmethod->update(top, fr, pbc, &d->g, out, d->kwmdata);
+ d->kwmethod->update(context, &d->g, out, d->kwmdata);
}
static void
-evaluate_kweval_pos(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_kweval_pos(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_kweval *d = static_cast<t_methoddata_kweval *>(data);
- d->kwmethod->pupdate(top, fr, pbc, &d->p, out, d->kwmdata);
+ d->kwmethod->pupdate(context, &d->p, out, d->kwmdata);
}
/*! \brief
/*
* 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.
* \returns 0 if everything is successful, -1 on error.
*/
static void
-init_merge(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_merge(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/** Initializes output for the \p merge selection modifier. */
static void
-init_output_merge(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+init_output_merge(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data);
/** Initializes output for the \p plus selection modifier. */
static void
-init_output_plus(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+init_output_plus(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data);
/** Frees the memory allocated for the merging selection modifiers. */
static void
free_data_merge(void *data);
/*! \brief
* Evaluates the \p merge selection modifier.
*
- * \param[in] top Not used.
- * \param[in] fr Not used.
- * \param[in] pbc Not used.
+ * \param[in] context Not used.
* \param[in] p Positions to merge (should point to \p data->p1).
* \param[out] out Output data structure (\p out->u.p is used).
* \param[in] data Should point to a \p t_methoddata_merge.
*/
static void
-evaluate_merge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_merge(const gmx::SelMethodEvalContext &context,
gmx_ana_pos_t * p, gmx_ana_selvalue_t *out, void *data);
/*! \brief
* Evaluates the \p plus selection modifier.
*
- * \param[in] top Not used.
- * \param[in] fr Not used.
- * \param[in] pbc Not used.
+ * \param[in] context Not used.
* \param[in] p Positions to merge (should point to \p data->p1).
* \param[out] out Output data structure (\p out->u.p is used).
* \param[in] data Should point to a \p t_methoddata_merge.
*/
static void
-evaluate_plus(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_plus(const gmx::SelMethodEvalContext &context,
gmx_ana_pos_t * p, gmx_ana_selvalue_t *out, void *data);
/** Parameters for the merging selection modifiers. */
}
static void
-init_merge(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
+init_merge(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
{
t_methoddata_merge *d = (t_methoddata_merge *)data;
* \param[in,out] data Should point to \c t_methoddata_merge.
*/
static void
-init_output_common(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+init_output_common(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_merge *d = (t_methoddata_merge *)data;
* \param[in,out] data Should point to \c t_methoddata_merge.
*/
static void
-init_output_merge(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+init_output_merge(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_merge *d = (t_methoddata_merge *)data;
int i, j;
* \param[in,out] data Should point to \c t_methoddata_merge.
*/
static void
-init_output_plus(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+init_output_plus(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_merge *d = (t_methoddata_merge *)data;
int i;
}
static void
-evaluate_merge(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_merge(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_pos_t * /* p */, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_merge *d = (t_methoddata_merge *)data;
}
static void
-evaluate_plus(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_plus(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_pos_t * /* p */, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_merge *d = (t_methoddata_merge *)data;
/*
* 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.
* \returns 0 if the input permutation is valid, -1 on error.
*/
static void
-init_permute(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_permute(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/*! \brief
* Initializes output for the \p permute selection modifier.
*
* \param[in,out] data Should point to \c t_methoddata_permute.
*/
static void
-init_output_permute(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+init_output_permute(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data);
/** Frees the memory allocated for the \p permute selection modifier. */
static void
free_data_permute(void *data);
-static void
/*! \brief
* Evaluates the \p permute selection modifier.
*
- * \param[in] top Not used.
- * \param[in] fr Not used.
- * \param[in] pbc Not used.
+ * \param[in] context Not used.
* \param[in] p Positions to permute (should point to \p data->p).
* \param[out] out Output data structure (\p out->u.p is used).
* \param[in] data Should point to a \p t_methoddata_permute.
- * \returns 0 if \p p could be permuted, -1 on error.
*
- * Returns -1 if the size of \p p is not divisible by the number of
+ * Throws if the size of \p p is not divisible by the number of
* elements in the permutation.
*/
-evaluate_permute(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+static void
+evaluate_permute(const gmx::SelMethodEvalContext &context,
gmx_ana_pos_t *p, gmx_ana_selvalue_t *out, void *data);
/** Parameters for the \p permute selection modifier. */
}
static void
-init_permute(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_permute(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
{
t_methoddata_permute *d = (t_methoddata_permute *)data;
int i;
}
static void
-init_output_permute(t_topology * /* top */, gmx_ana_selvalue_t *out, void *data)
+init_output_permute(const gmx_mtop_t * /* top */, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_permute *d = (t_methoddata_permute *)data;
int i, j, b;
}
static void
-evaluate_permute(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_permute(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_pos_t * /*p*/, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_permute *d = (t_methoddata_permute *)data;
/*
* 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.
* externally using _gmx_selelem_set_kwpos_type().
*/
static void
-init_kwpos(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_kwpos(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/*! \brief
* Initializes the \p cog selection method.
*
* \returns 0 on success, a non-zero error code on error.
*/
static void
-init_cog(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_cog(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/*! \brief
* Initializes the \p cog selection method.
*
* \returns 0 on success, a non-zero error code on error.
*/
static void
-init_com(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_com(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/*! \brief
* Initializes output for position evaluation selection methods.
*
* \returns 0 for success.
*/
static void
-init_output_pos(t_topology *top, gmx_ana_selvalue_t *out, void *data);
+init_output_pos(const gmx_mtop_t *top, gmx_ana_selvalue_t *out, void *data);
/** Frees the data allocated for position evaluation selection methods. */
static void
free_data_pos(void *data);
/** Evaluates position evaluation selection methods. */
static void
-evaluate_pos(t_topology * /* top */, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data);
+evaluate_pos(const gmx::SelMethodEvalContext &context,
+ gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data);
/** Parameters for position keyword evaluation. */
static gmx_ana_selparam_t smparams_keyword_pos[] = {
/** Selection method data for the \p com method. */
gmx_ana_selmethod_t sm_com = {
- "com", POS_VALUE, SMETH_REQTOP | SMETH_DYNAMIC | SMETH_SINGLEVAL,
+ "com", POS_VALUE, SMETH_REQMASS | SMETH_DYNAMIC | SMETH_SINGLEVAL,
asize(smparams_com), smparams_com,
&init_data_pos,
&set_poscoll_pos,
return d->type == NULL;
}
+/*! \brief
+ * Updates selection method flags about required topology information.
+ *
+ * Sets the flags to require topology and/or masses if the position calculation
+ * requires them.
+ */
+static void set_pos_method_flags(gmx_ana_selmethod_t *method,
+ t_methoddata_pos *d)
+{
+ const bool forces = (d->flags != -1 && (d->flags & POS_FORCES));
+ switch (gmx::PositionCalculationCollection::requiredTopologyInfoForType(d->type, forces))
+ {
+ case gmx::PositionCalculationCollection::RequiredTopologyInfo::TopologyAndMasses:
+ method->flags |= SMETH_REQMASS;
+ // fallthrough
+ case gmx::PositionCalculationCollection::RequiredTopologyInfo::Topology:
+ method->flags |= SMETH_REQTOP;
+ break;
+ case gmx::PositionCalculationCollection::RequiredTopologyInfo::None:
+ break;
+ }
+}
+
/*!
* \param[in,out] sel Selection element to initialize.
* \param[in] type One of the enum values acceptable for
}
if (!d->type && type)
{
- d->type = gmx_strdup(type);
- /* FIXME: It would be better not to have the string here hardcoded. */
- if (type[0] != 'a')
- {
- sel->u.expr.method->flags |= SMETH_REQTOP;
- }
+ d->type = gmx_strdup(type);
+ set_pos_method_flags(sel->u.expr.method, d);
}
}
}
if (d->flags == -1)
{
+ GMX_RELEASE_ASSERT(d->type != nullptr,
+ "Position type should be set before flags");
d->flags = flags;
+ set_pos_method_flags(sel->u.expr.method, d);
}
}
static void
-init_kwpos(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_kwpos(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
{
t_methoddata_pos *d = (t_methoddata_pos *)data;
}
static void
-init_cog(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_cog(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
{
t_methoddata_pos *d = (t_methoddata_pos *)data;
}
static void
-init_com(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_com(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
{
t_methoddata_pos *d = (t_methoddata_pos *)data;
}
static void
-init_output_pos(t_topology * /* top */, gmx_ana_selvalue_t *out, void *data)
+init_output_pos(const gmx_mtop_t * /* top */, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_pos *d = (t_methoddata_pos *)data;
* in \c t_methoddata_pos::g and stores the results in \p out->u.p.
*/
static void
-evaluate_pos(t_topology * /* top */, t_trxframe *fr, t_pbc *pbc,
+evaluate_pos(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_pos *d = (t_methoddata_pos *)data;
- gmx_ana_poscalc_update(d->pc, out->u.p, &d->g, fr, pbc);
+ gmx_ana_poscalc_update(d->pc, out->u.p, &d->g, context.fr, context.pbc);
}
/*
* 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.
* \returns 0 on success, -1 on failure.
*/
static void
-init_same(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+init_same(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/** Frees the data allocated for the \p same selection method. */
static void
free_data_same(void *data);
/*! \brief
* Initializes the evaluation of the \p same selection method for a frame.
*
- * \param[in] top Not used.
- * \param[in] fr Current frame.
- * \param[in] pbc PBC structure.
+ * \param[in] context Not used.
* \param data Should point to a \ref t_methoddata_same.
*
* Sorts the \c data->as.i array and removes identical values for faster and
* simpler lookup.
*/
static void
-init_frame_same_int(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
+init_frame_same_int(const gmx::SelMethodEvalContext &context, void *data);
/** Evaluates the \p same selection method. */
static void
-evaluate_same_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_same_int(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/*! \brief
* Initializes the evaluation of the \p same selection method for a frame.
*
- * \param[in] top Not used.
- * \param[in] fr Current frame.
- * \param[in] pbc PBC structure.
+ * \param[in] context Not used.
* \param data Should point to a \ref t_methoddata_same.
*
* Sorts the \c data->as.s array and removes identical values for faster and
* simpler lookup.
*/
static void
-init_frame_same_str(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
+init_frame_same_str(const gmx::SelMethodEvalContext &context, void *data);
/** Evaluates the \p same selection method. */
static void
-evaluate_same_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_same_str(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Parameters for the \p same selection method. */
}
static void
-init_same(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
+init_same(const gmx_mtop_t * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
{
t_methoddata_same *d = (t_methoddata_same *)data;
}
static void
-init_frame_same_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */, void *data)
+init_frame_same_int(const gmx::SelMethodEvalContext & /*context*/, void *data)
{
t_methoddata_same *d = (t_methoddata_same *)data;
int i, j;
* \c data->val.
*/
static void
-evaluate_same_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_same_int(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_same *d = (t_methoddata_same *)data;
}
static void
-init_frame_same_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */, void *data)
+init_frame_same_str(const gmx::SelMethodEvalContext & /*context*/, void *data)
{
t_methoddata_same *d = (t_methoddata_same *)data;
int i, j;
* \c data->val.
*/
static void
-evaluate_same_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_same_str(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
{
t_methoddata_same *d = (t_methoddata_same *)data;
#include <cctype>
#include "gromacs/selection/position.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/arraysize.h"
#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/gmxassert.h"
#include "selmethod.h"
/** Evaluates the \p all selection keyword. */
static void
-evaluate_all(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_all(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p none selection keyword. */
static void
-evaluate_none(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_none(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p atomnr selection keyword. */
static void
-evaluate_atomnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_atomnr(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p resnr selection keyword. */
static void
-evaluate_resnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_resnr(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p resindex selection keyword. */
static void
-evaluate_resindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_resindex(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/*! \brief
* Checks whether molecule information is present in the topology.
* If molecule information is not found, also prints an error message.
*/
static void
-check_molecules(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+check_molecules(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/** Evaluates the \p molindex selection keyword. */
static void
-evaluate_molindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_molindex(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p atomname selection keyword. */
static void
-evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_atomname(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p pdbatomname selection keyword. */
static void
-evaluate_pdbatomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_pdbatomname(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/*! \brief
* Checks whether atom types are present in the topology.
* \param npar Not used.
* \param param Not used.
* \param data Not used.
- * \returns 0 if atom types are present in the topology, -1 otherwise.
- *
- * If the atom types are not found, also prints an error message.
*/
static void
-check_atomtype(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+check_atomtype(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/** Evaluates the \p atomtype selection keyword. */
static void
-evaluate_atomtype(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_atomtype(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p insertcode selection keyword. */
static void
-evaluate_insertcode(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_insertcode(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p chain selection keyword. */
static void
-evaluate_chain(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_chain(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p mass selection keyword. */
static void
-evaluate_mass(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_mass(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+/*! \brief
+ * Checks whether charges are present in the topology.
+ *
+ * \param[in] top Topology structure.
+ * \param npar Not used.
+ * \param param Not used.
+ * \param data Not used.
+ */
+static void
+check_charge(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/** Evaluates the \p charge selection keyword. */
static void
-evaluate_charge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_charge(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/*! \brief
* Checks whether PDB info is present in the topology.
* If PDB info is not found, also prints an error message.
*/
static void
-check_pdbinfo(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
+check_pdbinfo(const gmx_mtop_t *top, int npar, gmx_ana_selparam_t *param, void *data);
/** Evaluates the \p altloc selection keyword. */
static void
-evaluate_altloc(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_altloc(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p occupancy selection keyword. */
static void
-evaluate_occupancy(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_occupancy(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p betafactor selection keyword. */
static void
-evaluate_betafactor(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_betafactor(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p resname selection keyword. */
static void
-evaluate_resname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_resname(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p x selection keyword. */
static void
-evaluate_x(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_x(const gmx::SelMethodEvalContext &context,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p y selection keyword. */
static void
-evaluate_y(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_y(const gmx::SelMethodEvalContext &context,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
/** Evaluates the \p z selection keyword. */
static void
-evaluate_z(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_z(const gmx::SelMethodEvalContext &context,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
//! Help title for atom name selection keywords.
/** Selection method data for \p mass selection keyword. */
gmx_ana_selmethod_t sm_mass = {
- "mass", REAL_VALUE, SMETH_REQTOP,
+ "mass", REAL_VALUE, SMETH_REQMASS,
0, NULL,
NULL,
NULL,
0, NULL,
NULL,
NULL,
- NULL,
+ &check_charge,
NULL,
NULL,
NULL,
* Copies \p g to \p out->u.g.
*/
static void
-evaluate_all(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_all(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
gmx_ana_index_copy(out->u.g, g, false);
* Returns an empty \p out->u.g.
*/
static void
-evaluate_none(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_none(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void * /* data */)
{
out->u.g->isize = 0;
* Returns the indices for each atom in \p out->u.i.
*/
static void
-evaluate_atomnr(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_atomnr(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
int i;
* Returns the residue numbers for each atom in \p out->u.i.
*/
static void
-evaluate_resnr(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_resnr(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
- int resind;
-
- out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ out->nr = g->isize;
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- resind = top->atoms.atom[g->index[i]].resind;
- out->u.i[i] = top->atoms.resinfo[resind].nr;
+ mtopGetAtomAndResidueName(context.top, g->index[i], &molb,
+ nullptr, &out->u.i[i], nullptr, nullptr);
}
}
* Returns the residue indices for each atom in \p out->u.i.
*/
static void
-evaluate_resindex(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_resindex(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
-
- out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ out->nr = g->isize;
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- out->u.i[i] = top->atoms.atom[g->index[i]].resind + 1;
+ int resind;
+ mtopGetAtomAndResidueName(context.top, g->index[i], &molb,
+ nullptr, nullptr, nullptr, &resind);
+ out->u.i[i] = resind + 1;
}
}
static void
-check_molecules(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
+check_molecules(const gmx_mtop_t *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
{
bool bOk;
* Returns the molecule indices for each atom in \p out->u.i.
*/
static void
-evaluate_molindex(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_molindex(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
int i, j;
out->nr = g->isize;
for (i = j = 0; i < g->isize; ++i)
{
- while (top->mols.index[j + 1] <= g->index[i])
+ while (context.top->mols.index[j + 1] <= g->index[i])
{
++j;
}
* Returns the atom name for each atom in \p out->u.s.
*/
static void
-evaluate_atomname(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_atomname(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
-
out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- out->u.s[i] = *top->atoms.atomname[g->index[i]];
+ const char *atom_name;
+ mtopGetAtomAndResidueName(context.top, g->index[i], &molb,
+ &atom_name, nullptr, nullptr, nullptr);
+ out->u.s[i] = const_cast<char *>(atom_name);
}
}
* Returns the PDB atom name for each atom in \p out->u.s.
*/
static void
-evaluate_pdbatomname(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_pdbatomname(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
-
out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- char *s = top->atoms.pdbinfo[g->index[i]].atomnm;
+ const char *s = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).atomnm;
while (std::isspace(*s))
{
++s;
}
- out->u.s[i] = s;
+ out->u.s[i] = const_cast<char *>(s);
}
}
static void
-check_atomtype(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
+check_atomtype(const gmx_mtop_t *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
{
- bool bOk;
-
- bOk = (top != NULL && top->atoms.atomtype != NULL);
- if (!bOk)
+ if (!gmx_mtop_has_atomtypes(top))
{
GMX_THROW(gmx::InconsistentInputError("Atom types not available in topology"));
}
* Segfaults if atom types are not found in the topology.
*/
static void
-evaluate_atomtype(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_atomtype(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
-
out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- out->u.s[i] = *top->atoms.atomtype[g->index[i]];
+ int atomIndexInMolecule;
+ mtopGetMolblockIndex(context.top, g->index[i], &molb,
+ nullptr, &atomIndexInMolecule);
+ const gmx_moltype_t &moltype = context.top->moltype[context.top->molblock[molb].type];
+ out->u.s[i] = *moltype.atoms.atomtype[atomIndexInMolecule];
}
}
* Returns the residue name for each atom in \p out->u.s.
*/
static void
-evaluate_resname(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_resname(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
- int resind;
-
out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- resind = top->atoms.atom[g->index[i]].resind;
- out->u.s[i] = *top->atoms.resinfo[resind].name;
+ out->u.s[i] = *mtopGetResidueInfo(context.top, g->index[i], &molb).name;
}
}
* Returns the insertion code for each atom in \p out->u.s.
*/
static void
-evaluate_insertcode(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_insertcode(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
- int resind;
-
out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- resind = top->atoms.atom[g->index[i]].resind;
- out->u.s[i][0] = top->atoms.resinfo[resind].ic;
+ out->u.s[i][0] = mtopGetResidueInfo(context.top, g->index[i], &molb).ic;
}
}
* Returns the chain for each atom in \p out->u.s.
*/
static void
-evaluate_chain(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_chain(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
- int resind;
-
out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- resind = top->atoms.atom[g->index[i]].resind;
- out->u.s[i][0] = top->atoms.resinfo[resind].chainid;
+ out->u.s[i][0] = mtopGetResidueInfo(context.top, g->index[i], &molb).chainid;
}
}
* Returns the mass for each atom in \p out->u.r.
*/
static void
-evaluate_mass(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_mass(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
-
+ GMX_RELEASE_ASSERT(gmx_mtop_has_masses(context.top),
+ "Masses not available for evaluation");
out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
+ {
+ out->u.r[i] = mtopGetAtomMass(context.top, g->index[i], &molb);
+ }
+}
+
+
+static void
+check_charge(const gmx_mtop_t *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
+{
+ if (!gmx_mtop_has_charges(top))
{
- out->u.r[i] = top->atoms.atom[g->index[i]].m;
+ GMX_THROW(gmx::InconsistentInputError("Charges not available in topology"));
}
}
* Returns the charge for each atom in \p out->u.r.
*/
static void
-evaluate_charge(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_charge(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
-
out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- out->u.r[i] = top->atoms.atom[g->index[i]].q;
+ out->u.r[i] = mtopGetAtomParameters(context.top, g->index[i], &molb).q;
}
}
static void
-check_pdbinfo(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
+check_pdbinfo(const gmx_mtop_t *top, int /* npar */, gmx_ana_selparam_t * /* param */, void * /* data */)
{
- bool bOk;
-
- bOk = (top != NULL && top->atoms.pdbinfo != NULL);
- if (!bOk)
+ if (!gmx_mtop_has_pdbinfo(top))
{
GMX_THROW(gmx::InconsistentInputError("PDB info not available in topology"));
}
* Returns the alternate location identifier for each atom in \p out->u.s.
*/
static void
-evaluate_altloc(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_altloc(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
-
out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- out->u.s[i][0] = top->atoms.pdbinfo[g->index[i]].altloc;
+ out->u.s[i][0] = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).altloc;
}
}
* Segfaults if PDB info is not found in the topology.
*/
static void
-evaluate_occupancy(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_occupancy(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
-
out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- out->u.r[i] = top->atoms.pdbinfo[g->index[i]].occup;
+ out->u.r[i] = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).occup;
}
}
* Segfaults if PDB info is not found in the topology.
*/
static void
-evaluate_betafactor(t_topology *top, t_trxframe * /* fr */, t_pbc * /* pbc */,
+evaluate_betafactor(const gmx::SelMethodEvalContext &context,
gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void * /* data */)
{
- int i;
-
out->nr = g->isize;
- for (i = 0; i < g->isize; ++i)
+ int molb = 0;
+ for (int i = 0; i < g->isize; ++i)
{
- out->u.r[i] = top->atoms.pdbinfo[g->index[i]].bfac;
+ out->u.r[i] = mtopGetAtomPdbInfo(context.top, g->index[i], &molb).bfac;
}
}
* Returns the \p x coordinate for each position in \p out->u.r.
*/
static void
-evaluate_x(t_topology * /*top*/, t_trxframe * /*fr*/, t_pbc * /*pbc*/,
+evaluate_x(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void * /*data*/)
{
out->nr = pos->count();
* Returns the \p y coordinate for each position in \p out->u.r.
*/
static void
-evaluate_y(t_topology * /*top*/, t_trxframe * /*fr*/, t_pbc * /*pbc*/,
+evaluate_y(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void * /*data*/)
{
out->nr = pos->count();
* Returns the \p z coordinate for each position in \p out->u.r.
*/
static void
-evaluate_z(t_topology * /*top*/, t_trxframe * /*fr*/, t_pbc * /*pbc*/,
+evaluate_z(const gmx::SelMethodEvalContext & /*context*/,
gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void * /*data*/)
{
out->nr = pos->count();
topManager_.initAtoms(15);
topManager_.initUniformResidues(3);
- t_topology *top = topManager_.topology();
+ gmx_mtop_t *top = topManager_.topology();
setGroup(group1);
EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
const int group1[] = { 3, 4, 5, 6, 7, 8, 12, 13 };
const int group2[] = { 3, 4, 5, 6, 7, 12, 13, 14 };
const int group3[] = { 4, 5, 6, 7, 8, 12, 13, 14 };
+ const int group4[] = { 3, 4, 5, 6, 8, 12, 13, 14 };
topManager_.initAtoms(18);
topManager_.initUniformResidues(3);
- t_topology *top = topManager_.topology();
+ gmx_mtop_t *top = topManager_.topology();
setGroup(group1);
EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
setGroup(group3);
EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
+
+ setGroup(group4);
+ EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
}
TEST_F(IndexBlockTest, ChecksGroupForCompleteMoleculesPositive)
topManager_.initAtoms(15);
topManager_.initUniformMolecules(3);
- t_topology *top = topManager_.topology();
+ gmx_mtop_t *top = topManager_.topology();
setGroup(group);
EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
topManager_.initAtoms(18);
topManager_.initUniformMolecules(3);
- t_topology *top = topManager_.topology();
+ gmx_mtop_t *top = topManager_.topology();
setGroup(group1);
EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
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_);
{
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;
/*
* 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.
void PositionCalculationTest::generateCoordinates()
{
- t_topology *top = topManager_.topology();
+ t_atoms &atoms = topManager_.atoms();
t_trxframe *frame = topManager_.frame();
- for (int i = 0; i < top->atoms.nr; ++i)
+ for (int i = 0; i < atoms.nr; ++i)
{
frame->x[i][XX] = i;
- frame->x[i][YY] = top->atoms.atom[i].resind;
+ frame->x[i][YY] = atoms.atom[i].resind;
frame->x[i][ZZ] = 0.0;
if (frame->bV)
{
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;
}
flags |= POS_FORCES;
}
gmx_ana_poscalc_t *pc = createCalculation(type, flags);
- EXPECT_EQ(bExpectTop, gmx_ana_poscalc_requires_top(pc));
+ const bool requiresTopology
+ = gmx_ana_poscalc_required_topology_info(pc)
+ != gmx::PositionCalculationCollection::RequiredTopologyInfo::None;
+ EXPECT_EQ(bExpectTop, requiresTopology);
setMaximumGroup(pc, atoms);
gmx_ana_pos_t *p = initPositions(pc, NULL);
checkInitialized();
const gmx::ConstArrayRef<int> &index)
{
gmx_ana_poscalc_t *pc = createCalculation(type, flags | POS_DYNAMIC);
- EXPECT_EQ(bExpectTop, gmx_ana_poscalc_requires_top(pc));
+ const bool requiresTopology
+ = gmx_ana_poscalc_required_topology_info(pc)
+ != gmx::PositionCalculationCollection::RequiredTopologyInfo::None;
+ EXPECT_EQ(bExpectTop, requiresTopology);
setMaximumGroup(pc, initAtoms);
gmx_ana_pos_t *p = initPositions(pc, NULL);
checkInitialized();
std::vector<gmx_ana_poscalc_t *>::const_iterator pci;
for (pci = pcList_.begin(); pci != pcList_.end(); ++pci)
{
- if (gmx_ana_poscalc_requires_top(*pci))
+ const bool requiresTopology
+ = gmx_ana_poscalc_required_topology_info(*pci)
+ != gmx::PositionCalculationCollection::RequiredTopologyInfo::None;
+ if (requiresTopology)
{
bTopSet_ = true;
pcc_.setTopology(topManager_.topology());
gmx::test::TopologyManager topManager_;
gmx::SelectionCollection sc_;
gmx::SelectionList sel_;
- t_topology *top_;
gmx_ana_indexgrps_t *grps_;
};
#endif
SelectionCollectionTest::SelectionCollectionTest()
- : top_(NULL), grps_(NULL)
+ : grps_(NULL)
{
topManager_.requestFrame();
sc_.setDebugLevel(s_debugLevel);
void
SelectionCollectionTest::setTopology()
{
- top_ = topManager_.topology();
-
- ASSERT_NO_THROW_GMX(sc_.setTopology(top_, -1));
+ ASSERT_NO_THROW_GMX(sc_.setTopology(topManager_.topology(), -1));
}
void
TEST_F(SelectionCollectionTest, HandlesNoSelections)
{
- EXPECT_FALSE(sc_.requiresTopology());
+ EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
EXPECT_NO_THROW_GMX(sc_.compile());
+ EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
+}
+
+TEST_F(SelectionCollectionTest, HandlesNoSelectionsWithDefaultPositionType)
+{
+ EXPECT_NO_THROW_GMX(sc_.setOutputPosType("res_com"));
+ EXPECT_TRUE(sc_.requiredTopologyProperties().needsTopology);
+ EXPECT_TRUE(sc_.requiredTopologyProperties().needsMasses);
+ EXPECT_NO_THROW_GMX(sc_.setOutputPosType("res_cog"));
+ EXPECT_TRUE(sc_.requiredTopologyProperties().needsTopology);
+ EXPECT_FALSE(sc_.requiredTopologyProperties().needsMasses);
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("atom of atomnr 1 to 10"));
+ ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+ ASSERT_NO_THROW_GMX(sc_.compile());
+ EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
}
TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
{
ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
+ EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
ASSERT_EQ(2U, sel_.size());
ASSERT_NO_THROW_GMX(sel_[0].setEvaluateVelocities(true));
ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
+ EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
ASSERT_NO_THROW_GMX(sc_.compile());
+ EXPECT_FALSE(sc_.requiredTopologyProperties().hasAny());
EXPECT_TRUE(sel_[0].hasVelocities());
EXPECT_TRUE(sel_[1].hasVelocities());
EXPECT_TRUE(sel_[0].hasForces());
EXPECT_TRUE(sel_[1].hasForces());
}
+TEST_F(SelectionCollectionTest, HandlesForceRequestForCenterOfGeometry)
+{
+ ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("res_cog of atomnr 1 to 10"));
+ EXPECT_TRUE(sc_.requiredTopologyProperties().needsTopology);
+ ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+ ASSERT_EQ(1U, sel_.size());
+ ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
+ // In principle, the code could know here that the masses are required, but
+ // currently it only knows this after compilation.
+ ASSERT_NO_THROW_GMX(sc_.compile());
+ EXPECT_TRUE(sc_.requiredTopologyProperties().needsMasses);
+ EXPECT_TRUE(sel_[0].hasForces());
+}
+
TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
{
ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromFile(
{
const int index[] = { 0, 1, 2, 3, 4, 5, 6, 9, 10, 11 };
// Evaluating the positions will require atoms 1-3, 7-12.
- ASSERT_NO_THROW_GMX(sc_.parseFromString("whole_res_com of atomnr 2 7 11"));
+ ASSERT_NO_THROW_GMX(sc_.parseFromString("whole_res_cog of atomnr 2 7 11"));
ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
ASSERT_NO_THROW_GMX(sc_.compile());
topManager_.initFrameIndices(index);
"molecule 2 3 5"
};
ASSERT_NO_FATAL_FAILURE(runParser(selections));
- ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+ ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
topManager_.initUniformMolecules(3);
+ ASSERT_NO_FATAL_FAILURE(setTopology());
ASSERT_NO_FATAL_FAILURE(runCompiler());
}
"atomtype CA"
};
ASSERT_NO_FATAL_FAILURE(runParser(selections));
- ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
+ ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
const char *const types[] = { "CA", "SA", "SB" };
topManager_.initAtomTypes(types);
+ ASSERT_NO_FATAL_FAILURE(setTopology());
ASSERT_NO_FATAL_FAILURE(runCompiler());
}
"mass > 5"
};
ASSERT_NO_FATAL_FAILURE(runParser(selections));
- ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
- for (int i = 0; i < top_->atoms.nr; ++i)
+ EXPECT_TRUE(sc_.requiredTopologyProperties().needsMasses);
+ ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
+ t_atoms &atoms = topManager_.atoms();
+ for (int i = 0; i < atoms.nr; ++i)
{
- top_->atoms.atom[i].m = 1.0 + i;
+ atoms.atom[i].m = 1.0 + i;
}
+ atoms.haveMass = TRUE;
+ ASSERT_NO_FATAL_FAILURE(setTopology());
ASSERT_NO_FATAL_FAILURE(runCompiler());
}
"charge < 0.5"
};
ASSERT_NO_FATAL_FAILURE(runParser(selections));
- ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
- for (int i = 0; i < top_->atoms.nr; ++i)
+ ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
+ t_atoms &atoms = topManager_.atoms();
+ for (int i = 0; i < atoms.nr; ++i)
{
- top_->atoms.atom[i].q = i / 10.0;
+ atoms.atom[i].q = i / 10.0;
}
- //ensure exact representation of 0.5 is used, so the test is always reproducible
- top_->atoms.atom[5].q = 0.5;
+ // Ensure exact representation of 0.5 is used, so that the test is
+ // reproducible.
+ atoms.atom[5].q = 0.5;
+ atoms.haveCharge = TRUE;
+ ASSERT_NO_FATAL_FAILURE(setTopology());
ASSERT_NO_FATAL_FAILURE(runCompiler());
}
setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms
| efTestPositionMasses | efTestPositionCharges);
ASSERT_NO_FATAL_FAILURE(runParser(selections));
- ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
- for (int i = 0; i < top_->atoms.nr; ++i)
+ ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
+ t_atoms &atoms = topManager_.atoms();
+ for (int i = 0; i < atoms.nr; ++i)
{
- top_->atoms.atom[i].m = 1.0 + i / 100.0;
- top_->atoms.atom[i].q = -(1.0 + i / 100.0);
+ atoms.atom[i].m = 1.0 + i / 100.0;
+ atoms.atom[i].q = -(1.0 + i / 100.0);
}
+ atoms.haveMass = TRUE;
+ atoms.haveCharge = TRUE;
+ ASSERT_NO_FATAL_FAILURE(setTopology());
ASSERT_NO_FATAL_FAILURE(runCompiler());
ASSERT_NO_FATAL_FAILURE(runEvaluate());
ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
"charge {0.05 to -0.3 -0.05 to 0.55}"
};
ASSERT_NO_FATAL_FAILURE(runParser(selections));
- ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
- for (int i = 0; i < top_->atoms.nr; ++i)
+ ASSERT_NO_FATAL_FAILURE(topManager_.loadTopology("simple.gro"));
+ t_atoms &atoms = topManager_.atoms();
+ for (int i = 0; i < atoms.nr; ++i)
{
- top_->atoms.atom[i].q = i / 10.0 - 0.5;
+ atoms.atom[i].q = i / 10.0 - 0.5;
}
+ atoms.haveCharge = TRUE;
+ ASSERT_NO_FATAL_FAILURE(setTopology());
ASSERT_NO_FATAL_FAILURE(runCompiler());
}
/*
* 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.
};
SelectionOptionTestBase::SelectionOptionTestBase()
- : manager_(&sc_), options_(NULL, NULL)
+ : manager_(&sc_)
{
options_.addManager(&manager_);
sc_.setReferencePosType("atom");
#include "gromacs/fileio/trxio.h"
#include "gromacs/math/vec.h"
#include "gromacs/topology/atoms.h"
+#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
#include "gromacs/trajectory/trajectoryframe.h"
#include "gromacs/utility/arrayref.h"
{
TopologyManager::TopologyManager()
- : top_(NULL), frame_(NULL)
+ : mtop_(nullptr), frame_(nullptr)
{
}
TopologyManager::~TopologyManager()
{
- if (top_ != NULL)
+ if (mtop_ != nullptr)
{
- done_top(top_);
- sfree(top_);
+ done_mtop(mtop_);
+ sfree(mtop_);
}
- if (frame_ != NULL)
+ if (frame_ != nullptr)
{
sfree(frame_->x);
sfree(frame_->v);
sfree(frame_->index);
sfree(frame_);
}
+
+ for (char *atomtype : atomtypes_)
+ {
+ sfree(atomtype);
+ }
}
void TopologyManager::requestFrame()
{
- GMX_RELEASE_ASSERT(top_ == NULL,
+ GMX_RELEASE_ASSERT(mtop_ == NULL,
"Frame must be requested before initializing topology");
if (frame_ == NULL)
{
void TopologyManager::loadTopology(const char *filename)
{
+ bool fullTopology;
int ePBC;
rvec *xtop = NULL;
matrix box;
- GMX_RELEASE_ASSERT(top_ == NULL, "Topology initialized more than once");
- snew(top_, 1);
- read_tps_conf(gmx::test::TestFileManager::getInputFilePath(filename).c_str(),
- top_, &ePBC, frame_ != NULL ? &xtop : NULL,
- NULL, box, FALSE);
+ GMX_RELEASE_ASSERT(mtop_ == nullptr, "Topology initialized more than once");
+ snew(mtop_, 1);
+ readConfAndTopology(
+ gmx::test::TestFileManager::getInputFilePath(filename).c_str(),
+ &fullTopology, mtop_, &ePBC, frame_ != NULL ? &xtop : NULL,
+ NULL, box);
if (frame_ != NULL)
{
- frame_->natoms = top_->atoms.nr;
+ frame_->natoms = mtop_->natoms;
frame_->bX = TRUE;
snew(frame_->x, frame_->natoms);
std::memcpy(frame_->x, xtop, sizeof(*frame_->x) * frame_->natoms);
void TopologyManager::initAtoms(int count)
{
- GMX_RELEASE_ASSERT(top_ == NULL, "Topology initialized more than once");
- snew(top_, 1);
- init_t_atoms(&top_->atoms, count, FALSE);
+ GMX_RELEASE_ASSERT(mtop_ == NULL, "Topology initialized more than once");
+ snew(mtop_, 1);
+ mtop_->nmoltype = 1;
+ snew(mtop_->moltype, 1);
+ init_t_atoms(&mtop_->moltype[0].atoms, count, FALSE);
+ mtop_->nmolblock = 1;
+ snew(mtop_->molblock, 1);
+ mtop_->molblock[0].type = 0;
+ mtop_->molblock[0].nmol = 1;
+ mtop_->molblock[0].natoms_mol = count;
+ mtop_->natoms = count;
+ mtop_->maxres_renum = 0;
+ gmx_mtop_finalize(mtop_);
+ GMX_RELEASE_ASSERT(mtop_->maxres_renum == 0, "maxres_renum in mtop can be modified by an env.var., that is not supported in this test");
+ t_atoms &atoms = this->atoms();
for (int i = 0; i < count; ++i)
{
- top_->atoms.atom[i].m = (i % 3 == 0 ? 2.0 : 1.0);
+ atoms.atom[i].m = (i % 3 == 0 ? 2.0 : 1.0);
}
+ atoms.haveMass = TRUE;
if (frame_ != NULL)
{
frame_->natoms = count;
void TopologyManager::initAtomTypes(const ConstArrayRef<const char *> &types)
{
- GMX_RELEASE_ASSERT(top_ != NULL, "Topology not initialized");
+ GMX_RELEASE_ASSERT(mtop_ != nullptr, "Topology not initialized");
atomtypes_.reserve(types.size());
for (const char *type : types)
{
atomtypes_.push_back(gmx_strdup(type));
}
- snew(top_->atoms.atomtype, top_->atoms.nr);
- size_t j = 0;
- for (int i = 0; i < top_->atoms.nr; ++i, ++j)
+ t_atoms &atoms = this->atoms();
+ snew(atoms.atomtype, atoms.nr);
+ size_t j = 0;
+ for (int i = 0; i < atoms.nr; ++i, ++j)
{
if (j == types.size())
{
j = 0;
}
- top_->atoms.atomtype[i] = &atomtypes_[j];
+ atoms.atomtype[i] = &atomtypes_[j];
}
+ atoms.haveType = TRUE;
}
void TopologyManager::initUniformResidues(int residueSize)
{
- GMX_RELEASE_ASSERT(top_ != NULL, "Topology not initialized");
- int residueIndex = -1;
- for (int i = 0; i < top_->atoms.nr; ++i)
+ GMX_RELEASE_ASSERT(mtop_ != NULL, "Topology not initialized");
+ t_atoms &atoms = this->atoms();
+ int residueIndex = -1;
+ for (int i = 0; i < atoms.nr; ++i)
{
if (i % residueSize == 0)
{
++residueIndex;
}
- top_->atoms.atom[i].resind = residueIndex;
+ atoms.atom[i].resind = residueIndex;
}
}
void TopologyManager::initUniformMolecules(int moleculeSize)
{
- GMX_RELEASE_ASSERT(top_ != NULL, "Topology not initialized");
+ GMX_RELEASE_ASSERT(mtop_ != NULL, "Topology not initialized");
int index = 0;
- top_->mols.nalloc_index = (top_->atoms.nr + moleculeSize - 1) / moleculeSize + 1;
- snew(top_->mols.index, top_->mols.nalloc_index);
- top_->mols.nr = 0;
- while (index < top_->atoms.nr)
+ mtop_->mols.nalloc_index = (mtop_->natoms + moleculeSize - 1) / moleculeSize + 1;
+ srenew(mtop_->mols.index, mtop_->mols.nalloc_index);
+ mtop_->mols.nr = 0;
+ while (index < mtop_->natoms)
{
- top_->mols.index[top_->mols.nr] = index;
- ++top_->mols.nr;
+ mtop_->mols.index[mtop_->mols.nr] = index;
+ ++mtop_->mols.nr;
index += moleculeSize;
}
- top_->mols.index[top_->mols.nr] = top_->atoms.nr;
+ mtop_->mols.index[mtop_->mols.nr] = mtop_->natoms;
}
void TopologyManager::initFrameIndices(const ConstArrayRef<int> &index)
frame_->natoms = index.size();
}
+t_atoms &TopologyManager::atoms()
+{
+ GMX_RELEASE_ASSERT(mtop_ != nullptr, "Topology not initialized");
+ GMX_RELEASE_ASSERT(mtop_->natoms == mtop_->moltype[0].atoms.nr,
+ "Test setup assumes all atoms in a single molecule type");
+ return mtop_->moltype[0].atoms;
+}
+
} // namespace test
} // namespace gmx
/*
* 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.
#include <vector>
-struct t_topology;
+struct gmx_mtop_t;
+struct t_atoms;
struct t_trxframe;
namespace gmx
void initFrameIndices(const ConstArrayRef<int> &index);
- t_topology *topology() { return top_; }
+ gmx_mtop_t *topology() { return mtop_; }
+ t_atoms &atoms();
t_trxframe *frame() { return frame_; }
private:
- t_topology *top_;
+ gmx_mtop_t *mtop_;
t_trxframe *frame_;
std::vector<char *> atomtypes_;
};
/*
* 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.
static inline void
simdPrefetch(const void * m)
{
-#if defined(__ibmxl__) || defined(__xlC__)
- __dcbt(m);
-#elif defined __GNUC__
+#if defined __GNUC__
__builtin_prefetch(m);
#endif
}
/*
* 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.
#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__
/*
* 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.
#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
#include "gromacs/mdtypes/md_enums.h"
#include "gromacs/pbcutil/pbc.h"
#include "gromacs/timing/wallcycle.h"
-#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/cstringutil.h"
#include "gromacs/utility/fatalerror.h"
int igroup,
t_swap *s,
gmx_bool bVerbose,
- const gmx_mtop_atomlookup_t alook,
gmx_mtop_t *mtop)
{
- int molb, molnr, atnr_mol;
t_swapgrp *g = &s->group[igroup];
int *ind = s->group[igroup].ind;
int nat = s->group[igroup].nat;
/* Determine the number of solvent atoms per solvent molecule from the
* first solvent atom: */
- gmx_mtop_atomnr_to_molblock_ind(alook, ind[0], &molb, &molnr, &atnr_mol);
+ int molb = 0;
+ mtopGetMolblockIndex(mtop, ind[0], &molb, NULL, NULL);
int apm = mtop->molblock[molb].natoms_mol;
if (bVerbose)
/* Check whether this is also true for all other solvent atoms */
for (int i = 1; i < nat; i++)
{
- gmx_mtop_atomnr_to_molblock_ind(alook, ind[i], &molb, &molnr, &atnr_mol);
+ mtopGetMolblockIndex(mtop, ind[i], &molb, NULL, NULL);
if (apm != mtop->molblock[molb].natoms_mol)
{
gmx_fatal(FARGS, "Not all molecules of swap group %d consist of %d atoms.",
gmx_bool bVerbose,
t_commrec *cr)
{
- t_atom *atom;
- gmx_mtop_atomlookup_t alook = gmx_mtop_atomlookup_init(mtop);
t_swapGroup *g = &sc->grp[3];
/* Loop through the atom indices of group #3 (anions) and put all indices
snew(indAnions, g->nat);
snew(indCations, g->nat);
+ int molb = 0;
for (int i = 0; i < g->nat; i++)
{
- gmx_mtop_atomnr_to_atom(alook, g->ind[i], &atom);
- if (atom->q < 0)
+ const t_atom &atom = mtopGetAtomParameters(mtop, g->ind[i], &molb);
+ if (atom.q < 0)
{
// This is an anion, add it to the list of anions
indAnions[nAnions++] = g->ind[i];
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)
{
t_swapcoords *sc;
t_swap *s;
- t_atom *atom;
t_swapgrp *g;
swapstateIons_t *gs;
gmx_bool bAppend, bStartFromCpt, bRerun;
- gmx_mtop_atomlookup_t alook = NULL;
matrix boxCopy;
- alook = gmx_mtop_atomlookup_init(mtop);
-
if ( (PAR(cr)) && !DOMAINDECOMP(cr) )
{
gmx_fatal(FARGS, "Position swapping is only implemented for domain decomposition!");
}
}
+ if (*swapstatePtr == NULL)
+ {
+ snew(*swapstatePtr, 1);
+ }
+ swapstate_t *swapstate = *swapstatePtr;
+
if (MASTER(cr))
{
init_swapstate(swapstate, sc, mtop, x, box, ir->ePBC);
real charge;
g = &(s->group[ig]);
- g->apm = get_group_apm_check(ig, s, MASTER(cr) && bVerbose, alook, mtop);
+ g->apm = get_group_apm_check(ig, s, MASTER(cr) && bVerbose, mtop);
/* Since all molecules of a group are equal, we only need enough space
* to determine properties of a single molecule at at time */
snew(g->m, g->apm); /* For the center of mass */
charge = 0; /* To determine the charge imbalance */
+ int molb = 0;
for (int j = 0; j < g->apm; j++)
{
- gmx_mtop_atomnr_to_atom(alook, g->ind[j], &atom);
- g->m[j] = atom->m;
- charge += atom->q;
+ const t_atom &atom = mtopGetAtomParameters(mtop, g->ind[j], &molb);
+ g->m[j] = atom.m;
+ charge += atom.q;
}
/* Total charge of one molecule of this group: */
g->q = charge;
{
/* Save the split group masses if mass-weighting is requested */
snew(g->m, g->nat);
+ int molb = 0;
for (int i = 0; i < g->nat; i++)
{
- gmx_mtop_atomnr_to_atom(alook, g->ind[i], &atom);
- g->m[i] = atom->m;
+ g->m[i] = mtopGetAtomMass(mtop, g->ind[i], &molb);
}
}
}
gmx_wallcycle_t wcycle,
rvec x[],
matrix box,
- gmx_mtop_t *mtop,
gmx_bool bVerbose,
gmx_bool bRerun)
{
t_swapgrp *g, *gsol;
int isol, iion;
rvec com_solvent, com_particle; /* solvent and swap molecule's center of mass */
- gmx_mtop_atomlookup_t alook = NULL;
wallcycle_start(wcycle, ewcSWAP);
}
/* Now actually perform the particle exchanges, one swap group after another */
- alook = gmx_mtop_atomlookup_init(mtop);
gsol = &s->group[eGrpSolvent];
for (ig = eSwapFixedGrpNR; ig < s->ngrp; ig++)
{
SwS, nswaps, nswaps > 1 ? "s" : "", step, g->molname);
}
}
- gmx_mtop_atomlookup_destroy(alook);
if (s->fpout != NULL)
{
* \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
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);
* \param[in] wcycle Count wallcycles of swap routines for diagnostic output.
* \param[in] x Positions of home particles this node owns.
* \param[in] box The simulation box.
- * \param[in] mtop Molecular topology.
* \param[in] bVerbose Should we be quiet or verbose?
* \param[in] bRerun Are we doing a rerun?
*
gmx_wallcycle_t wcycle,
rvec x[],
matrix box,
- gmx_mtop_t *mtop,
gmx_bool bVerbose,
gmx_bool bRerun);
#
# 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.
set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${TABLE_SOURCES} PARENT_SCOPE)
if (BUILD_TESTING)
-# add_subdirectory(tests)
+ add_subdirectory(tests)
endif()
--- /dev/null
+/*
+ * 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 for cubic spline table functions
+ *
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#include "gmxpre.h"
+
+#include "cubicsplinetable.h"
+
+#include <cmath>
+
+#include <algorithm>
+#include <functional>
+#include <initializer_list>
+#include <utility>
+#include <vector>
+
+#include "gromacs/tables/tableinput.h"
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/real.h"
+
+#include "splineutil.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+/*! \brief Calculate table elements from function/derivative data
+ *
+ * \param functionValue0 Function value for the present table index
+ * \param functionValue1 Function value for the next table index
+ * \param derivativeValue0 Derivative value for the present table index
+ * \param derivativeValue1 Derivative value for the next table index
+ * \param spacing Distance between table points
+ * \param Y Function value for table index
+ * \param F Component to multiply with offset eps
+ * \param G Component to multiply with eps^2
+ * \param H Component to multiply with eps^3
+ */
+void
+calculateCubicSplineCoefficients(double functionValue0,
+ double functionValue1,
+ double derivativeValue0,
+ double derivativeValue1,
+ double spacing,
+ double *Y,
+ double *F,
+ double *G,
+ double *H)
+{
+ *Y = functionValue0;
+ *F = spacing * derivativeValue0;
+ *G = 3.0*( functionValue1 - functionValue0) - spacing * (derivativeValue1 + 2.0 * derivativeValue0);
+ *H = -2.0*( functionValue1 - functionValue0) + spacing * (derivativeValue1 + derivativeValue0);
+}
+
+/*! \brief Perform cubic spline interpolation in interval from function/derivative
+ *
+ * \param functionValue0 Function value for the present table index
+ * \param functionValue1 Function value for the next table index
+ * \param derivativeValue0 Derivative value for the present table index
+ * \param derivativeValue1 Derivative value for the next table index
+ * \param spacing Distance between table points
+ * \param eps Offset from lower table point for evaluation
+ * \param[out] interpolatedFunctionValue Output function value
+ * \param[out] interpolatedDerivativeValue Output derivative value
+ */
+void
+cubicSplineInterpolationFromFunctionAndDerivative(double functionValue0,
+ double functionValue1,
+ double derivativeValue0,
+ double derivativeValue1,
+ double spacing,
+ double eps,
+ double *interpolatedFunctionValue,
+ double *interpolatedDerivativeValue)
+{
+ double Y, F, G, H;
+
+ calculateCubicSplineCoefficients(functionValue0, functionValue1,
+ derivativeValue0, derivativeValue1,
+ spacing,
+ &Y, &F, &G, &H);
+
+ double Fp = fma(fma(H, eps, G), eps, F);
+
+ *interpolatedFunctionValue = fma(Fp, eps, Y);
+ *interpolatedDerivativeValue = fma(eps, fma(2.0*eps, H, G), Fp)/spacing;
+}
+
+
+
+/*! \brief Construct the data for a single cubic table from analytical functions
+ *
+ * \param[in] function Analytical functiojn
+ * \param[in] derivative Analytical derivative
+ * \param[in] range Upper/lower limit of region to tabulate
+ * \param[in] spacing Distance between table points
+ * \param[out] yfghTableData Output cubic spline table with Y,F,G,H entries
+ */
+void
+fillSingleCubicSplineTableData(const std::function<double(double)> &function,
+ const std::function<double(double)> &derivative,
+ const std::pair<real, real> &range,
+ double spacing,
+ std::vector<real> *yfghTableData)
+{
+ int endIndex = range.second / spacing + 2;
+
+ yfghTableData->resize(4*endIndex);
+
+ double maxMagnitude = 0.0001*GMX_REAL_MAX;
+ bool functionIsInRange = true;
+ std::size_t lastIndexInRange = endIndex - 1;
+
+ for (int i = endIndex - 1; i >= 0; i--)
+ {
+ double x = i * spacing;
+ double tmpFunctionValue;
+ double tmpDerivativeValue;
+ double nextHigherFunction;
+ double nextHigherDerivative;
+ double Y, F, G, H;
+
+ if (range.first > 0 && i == 0)
+ {
+ // Avoid x==0 if it is not in the range, since it can lead to
+ // singularities even if the value for i==1 was within or required magnitude
+ functionIsInRange = false;
+ }
+
+ if (functionIsInRange)
+ {
+ tmpFunctionValue = function(x);
+ tmpDerivativeValue = derivative(x);
+ nextHigherFunction = ((i+1) < endIndex) ? function(x+spacing) : 0.0;
+ nextHigherDerivative = ((i+1) < endIndex) ? derivative(x+spacing) : 0.0;
+
+ if (std::abs(tmpFunctionValue) > maxMagnitude || std::abs(tmpDerivativeValue) > maxMagnitude)
+ {
+ functionIsInRange = false; // Once this happens, it never resets to true again
+ }
+ }
+
+ if (functionIsInRange)
+ {
+ calculateCubicSplineCoefficients(tmpFunctionValue, nextHigherFunction,
+ tmpDerivativeValue, nextHigherDerivative,
+ spacing,
+ &Y, &F, &G, &H);
+ lastIndexInRange--;
+ }
+ else
+ {
+ double lastIndexY = (*yfghTableData)[4*lastIndexInRange];
+ double lastIndexF = (*yfghTableData)[4*lastIndexInRange + 1];
+
+ Y = lastIndexY + lastIndexF * (i - lastIndexInRange);
+ F = lastIndexF;
+ G = 0.0;
+ H = 0.0;
+ }
+
+ (*yfghTableData)[4*i ] = Y;
+ (*yfghTableData)[4*i+1] = F;
+ (*yfghTableData)[4*i+2] = G;
+ (*yfghTableData)[4*i+3] = H;
+ }
+}
+
+
+/*! \brief Construct the data for a single cubic table from vector data
+ *
+ * \param[in] function Input vector with function data
+ * \param[in] derivative Input vector with derivative data
+ * \param[in] inputSpacing Distance between points in input vectors
+ * \param[in] range Upper/lower limit of region to tabulate
+ * \param[in] spacing Distance between table points
+ * \param[out] yfghTableData Output cubic spline table with Y,F,G,H entries
+ */
+void
+fillSingleCubicSplineTableData(ConstArrayRef<double> function,
+ ConstArrayRef<double> derivative,
+ double inputSpacing,
+ const std::pair<real, real> &range,
+ double spacing,
+ std::vector<real> *yfghTableData)
+{
+ int endIndex = range.second / spacing + 2;
+
+ std::vector<double> tmpFunction(endIndex);
+ std::vector<double> tmpDerivative(endIndex);
+
+ double maxMagnitude = 0.0001*GMX_REAL_MAX;
+ bool functionIsInRange = true;
+ std::size_t lastIndexInRange = endIndex - 1;
+
+ // Interpolate function and derivative values in positions needed for output
+ for (int i = endIndex - 1; i >= 0; i--)
+ {
+ double x = i * spacing;
+ double xtab = x / inputSpacing;
+ int index = xtab;
+ double eps = xtab - index;
+
+ if (range.first > 0 && i == 0)
+ {
+ // Avoid x==0 if it is not in the range, since it can lead to
+ // singularities even if the value for i==1 was within or required magnitude
+ functionIsInRange = false;
+ }
+
+ if (functionIsInRange && (std::abs(function[index]) > maxMagnitude || std::abs(derivative[index]) > maxMagnitude))
+ {
+ functionIsInRange = false; // Once this happens, it never resets to true again
+ }
+
+ if (functionIsInRange)
+ {
+ cubicSplineInterpolationFromFunctionAndDerivative(function[index],
+ function[index+1],
+ derivative[index],
+ derivative[index+1],
+ inputSpacing,
+ eps,
+ &(tmpFunction[i]),
+ &(tmpDerivative[i]));
+ lastIndexInRange--;
+ }
+ else
+ {
+ double lastIndexFunction = tmpFunction[lastIndexInRange];
+ double lastIndexDerivative = tmpDerivative[lastIndexInRange];
+ tmpFunction[i] = lastIndexFunction + lastIndexDerivative * (i - lastIndexInRange) * spacing;
+ tmpDerivative[i] = lastIndexDerivative;
+ }
+ }
+
+ yfghTableData->resize(4*endIndex);
+
+ for (int i = 0; i < endIndex; i++)
+ {
+ double Y, F, G, H;
+
+ double nextFunction = ((i+1) < endIndex) ? tmpFunction[i+1] : 0.0;
+ double nextDerivative = ((i+1) < endIndex) ? tmpDerivative[i+1] : 0.0;
+
+ calculateCubicSplineCoefficients(tmpFunction[i], nextFunction,
+ tmpDerivative[i], nextDerivative,
+ spacing,
+ &Y, &F, &G, &H);
+ (*yfghTableData)[4*i ] = Y;
+ (*yfghTableData)[4*i+1] = F;
+ (*yfghTableData)[4*i+2] = G;
+ (*yfghTableData)[4*i+3] = H;
+ }
+
+}
+
+} // namespace anonymous
+
+
+
+#if GMX_DOUBLE
+const real
+CubicSplineTable::defaultTolerance = 1e-10;
+#else
+const real
+CubicSplineTable::defaultTolerance = 10.0 * GMX_FLOAT_EPS;
+#endif
+
+CubicSplineTable::CubicSplineTable(std::initializer_list<AnalyticalSplineTableInput> analyticalInputList,
+ const std::pair<real, real> &range,
+ real tolerance)
+ : numFuncInTable_(analyticalInputList.size()), range_(range)
+{
+ // Sanity check on input values
+ if (range_.first < 0.0 || (range_.second-range_.first) < 0.001)
+ {
+ GMX_THROW(InvalidInputError("Range to tabulate cannot include negative values and must span at least 0.001"));
+ }
+
+ if (tolerance < GMX_REAL_EPS)
+ {
+ GMX_THROW(ToleranceError("Table tolerance cannot be smaller than GMX_REAL_EPS"));
+ }
+
+ double minQuotient = GMX_REAL_MAX;
+
+ // loop over all functions to find smallest spacing
+ for (auto thisFuncInput : analyticalInputList)
+ {
+ try
+ {
+ internal::throwUnlessDerivativeIsConsistentWithFunction(thisFuncInput.function, thisFuncInput.derivative, range_);
+ }
+ catch (gmx::GromacsException &ex)
+ {
+ ex.prependContext("Error generating cubic spline table for function '" + thisFuncInput.desc + "'");
+ throw;
+ }
+ // Calculate the required table spacing h. The error we make with linear interpolation
+ // of the derivative will be described by the third-derivative correction term.
+ // This means we can compute the required spacing as h = sqrt(12*tolerance*min(f'/f''')),
+ // where f'/f''' is the first and third derivative of the function, respectively.
+
+ double thisMinQuotient = internal::findSmallestQuotientOfFunctionAndThirdDerivative(thisFuncInput.derivative, range_);
+
+ minQuotient = std::min(minQuotient, thisMinQuotient);
+ }
+
+ double spacing = 0.5 * std::cbrt(72.0 * std::sqrt(3.0) * tolerance * minQuotient);
+
+ tableScale_ = 1.0 / spacing;
+
+ if (range_.second * tableScale_ > 2e6)
+ {
+ GMX_THROW(ToleranceError("Over a million points would be required for table; decrease range or increase tolerance"));
+ }
+
+ // Loop over all tables again.
+ // Here we create the actual table for each function, and then
+ // combine them into a multiplexed table function.
+ std::size_t funcIndex = 0;
+
+ for (auto thisFuncInput : analyticalInputList)
+ {
+ try
+ {
+ std::vector<real> tmpYfghTableData;
+
+ fillSingleCubicSplineTableData(thisFuncInput.function,
+ thisFuncInput.derivative,
+ range_,
+ spacing,
+ &tmpYfghTableData);
+
+ internal::fillMultiplexedTableData(tmpYfghTableData, &yfghMultiTableData_,
+ 4, numFuncInTable_, funcIndex);
+
+ funcIndex++;
+ }
+ catch (gmx::GromacsException &ex)
+ {
+ ex.prependContext("Error generating cubic spline table for function '" + thisFuncInput.desc + "'");
+ throw;
+ }
+ }
+}
+
+
+CubicSplineTable::CubicSplineTable(std::initializer_list<NumericalSplineTableInput> numericalInputList,
+ const std::pair<real, real> &range,
+ real tolerance)
+ : numFuncInTable_(numericalInputList.size()), range_(range)
+{
+ // Sanity check on input values
+ if (range.first < 0.0 || (range.second-range.first) < 0.001)
+ {
+ GMX_THROW(InvalidInputError("Range to tabulate cannot include negative values and must span at least 0.001"));
+ }
+
+ if (tolerance < GMX_REAL_EPS)
+ {
+ GMX_THROW(ToleranceError("Table tolerance cannot be smaller than GMX_REAL_EPS"));
+ }
+
+ double minQuotient = GMX_REAL_MAX;
+
+ // loop over all functions to find smallest spacing
+ for (auto thisFuncInput : numericalInputList)
+ {
+ try
+ {
+ // We do not yet know what the margin is, but we need to test that we at least cover
+ // the requested range before starting to calculate derivatives
+ if (thisFuncInput.function.size() < range_.second / thisFuncInput.spacing + 1)
+ {
+ GMX_THROW(InconsistentInputError("Table input vectors must cover requested range, and a margin beyond the upper endpoint"));
+ }
+
+ if (thisFuncInput.function.size() != thisFuncInput.derivative.size())
+ {
+ GMX_THROW(InconsistentInputError("Function and derivative vectors have different lengths"));
+ }
+
+ internal::throwUnlessDerivativeIsConsistentWithFunction(thisFuncInput.function, thisFuncInput.derivative, thisFuncInput.spacing, range_);
+ }
+ catch (gmx::GromacsException &ex)
+ {
+ ex.prependContext("Error generating cubic spline table for function '" + thisFuncInput.desc + "'");
+ throw;
+ }
+ // Calculate the required table spacing h. The error we make with linear interpolation
+ // of the derivative will be described by the third-derivative correction term.
+ // This means we can compute the required spacing as h = sqrt(12*tolerance*min(f'/f''')),
+ // where f'/f''' is the first and third derivative of the function, respectively.
+
+ double thisMinQuotient = internal::findSmallestQuotientOfFunctionAndThirdDerivative(thisFuncInput.derivative, thisFuncInput.spacing, range_);
+
+ minQuotient = std::min(minQuotient, thisMinQuotient);
+ }
+
+ double spacing = std::cbrt(72.0 * std::sqrt(3.0) * tolerance * minQuotient);
+
+ tableScale_ = 1.0 / spacing;
+
+ if (range_.second * tableScale_ > 1e6)
+ {
+ GMX_THROW(ToleranceError("Requested tolerance would require over a million points in table"));
+ }
+
+ // Loop over all tables again.
+ // Here we create the actual table for each function, and then
+ // combine them into a multiplexed table function.
+ std::size_t funcIndex = 0;
+
+ for (auto thisFuncInput : numericalInputList)
+ {
+ try
+ {
+ if (spacing < thisFuncInput.spacing)
+ {
+ GMX_THROW(ToleranceError("Input vector spacing cannot achieve tolerance requested"));
+ }
+
+ std::vector<real> tmpYfghTableData;
+
+ fillSingleCubicSplineTableData(thisFuncInput.function,
+ thisFuncInput.derivative,
+ thisFuncInput.spacing,
+ range,
+ spacing,
+ &tmpYfghTableData);
+
+ internal::fillMultiplexedTableData(tmpYfghTableData, &yfghMultiTableData_,
+ 4, numFuncInTable_, funcIndex);
+
+ funcIndex++;
+ }
+ catch (gmx::GromacsException &ex)
+ {
+ ex.prependContext("Error generating cubic spline table for function '" + thisFuncInput.desc + "'");
+ throw;
+ }
+ }
+}
+
+} // namespace gmx
--- /dev/null
+/*
+ * 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 cubic spline table
+ *
+ * \inlibraryapi
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#ifndef GMX_TABLES_CUBICSPLINETABLE_H
+#define GMX_TABLES_CUBICSPLINETABLE_H
+
+#include <initializer_list>
+#include <vector>
+
+#include "gromacs/simd/simd.h"
+#include "gromacs/tables/tableinput.h"
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/real.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief Cubic spline interpolation table.
+ *
+ * This class interpolates a function specified either as an analytical
+ * expression or from user-provided table data.
+ *
+ * At initialization, you provide the reference function of vectors
+ * as a list of tuples that contain a brief name, the function, and
+ * derivative for each function to tabulate. To create a table with
+ * two functions this initializer list can for instance look like
+ *
+ * { {"LJ6", lj6Func, lj6Der}, {"LJ12", lj12Func, lj12Der} }
+ *
+ * The names are only used so exceptions during initialization can
+ * be traced to a specific table.
+ *
+ * When interpolating, there are methods to interpolate either 1, 2, or 3
+ * functions in one go. By default these interpolation routines will
+ * operate on tables with the same number of functions as specified in
+ * the interpolation method (debug builds check that this is consistent with
+ * the table). However, it is also possible to use optional template
+ * parameters that specify the total number of functions in a table, and
+ * what function index to interpolate. For instance, to interpolate the
+ * derivative of the second function (i.e., index 1) in a
+ * multi-function-table with three functions in total, you can write
+ *
+ * table.evaluateDerivative<3,1>(x,&der);
+ *
+ * Here too, debug builds will check that the template parameters are
+ * consistent with the table.
+ *
+ * This class interpolates a function specified either as an analytical
+ * expression or from user-provided table data. The coefficients for each
+ * table point are precalculated such that we simply evaluate
+ *
+ * \f{eqnarray*}{
+ * V(x) = Y + F \epsilon + G \epsilon^2 + H \epsilon^3
+ * V'(x) = (F + 2 G \epsilon + 3 H \epsilon^2)/h
+ * \f}
+ *
+ * Where h is the spacing and epsilon the fractional offset from table point.
+ *
+ * While it is possible to create tables only from function values
+ * (i.e., no derivatives), it is recommended to provide derivatives for higher
+ * accuracy and to avoid issues with numerical differentiation. Note that the
+ * table input should be smooth, i.e. it should not contain noise e.g. from an
+ * (iterative) Boltzmann inversion procedure - you have been warned.
+ *
+ * \note This class is responsible for fundamental interpolation of any function,
+ * which might or might not correspond to a potential. For this reason
+ * both input and output derivatives are proper function derivatives, and
+ * we do not swap any signs to get forces directly from the table.
+ *
+ * \note There will be a small additional accuracy loss from the internal
+ * operation where we calculate the epsilon offset from the nearest table
+ * point, since the integer part we subtract can get large in those cases.
+ *
+ * While this is technically possible to solve with extended precision
+ * arithmetics, that would introduce extra instructions in some highly
+ * performance-sensitive code parts. For typical GROMACS interaction
+ * functions the derivatives will decay faster than the potential, which
+ * means it will never play any role. For other functions it will only
+ * cause a small increase in the relative error for arguments where the
+ * magnitude of the function or derivative is very small.
+ * Since we typically sum several results in GROMACS, this should never
+ * show up in any real cases, and for this reason we choose not to do
+ * the extended precision arithmetics.
+ *
+ * \note These routines are not suitable for table ranges starting far away
+ * from zero, since we allocate memory and calculate indices starting from
+ * range zero for efficiency reasons.
+ */
+class CubicSplineTable
+{
+ private:
+ /*! \brief Change that function value falls inside range when debugging
+ *
+ * \tparam T Lookup argument floating-point type, typically SimdReal or real.
+ * \param r Lookup argument to test
+ *
+ * \throws Debug builds will throw gmx::RangeError for values that are
+ * larger than the upper limit of the range, or smaller than 0.
+ * We allow the table to be called with arguments between 0 and
+ * the lower limit of the range, since this might in theory occur
+ * once-in-a-blue-moon with some algorithms.
+ */
+ template <typename T>
+ void
+ rangeCheck(T gmx_unused r) const
+ {
+#ifndef NDEBUG
+ // Check that all values fall in range when debugging
+ if (anyTrue( r < T(0.0) || T(range_.second) <= r ) )
+ {
+ GMX_THROW(RangeError("Interpolation input value falls outside table definition range"));
+ }
+#endif
+ }
+
+ public:
+
+ /*! \brief Default tolerance for cubic spline tables
+ *
+ * This is 10*GMX_FLOAT_EPS in single precision, and
+ * 1e-10 for double precision. It might not be worth setting
+ * this tolerance lower than 1e-10 in double precision, both because
+ * you will end up with very large tables, and because
+ * functions like r^-12 become so large for small values of r the
+ * table generation code will lead to some precision loss even
+ * in double precision.
+ */
+ static const real defaultTolerance;
+
+ /*! \brief Initialize table data from function
+ *
+ * \param analyticalInputList Initializer list with one or more functions to tabulate,
+ * specified as elements with a string description and
+ * the function as well as derivative. The function will also
+ * be called for values smaller than the lower limit of the
+ * range, but we avoid calling it for 0.0 if that value
+ * is not included in the range.
+ * Constructor will throw gmx::APIError for negative values.
+ * Due to the way the numerical derivative evaluation depends
+ * on machine precision internally, this range must be
+ * at least 0.001, or the constructor throws gmx::APIError.
+ * \param range Range over which the function will be tabulated.
+ * Constructor will throw gmx::APIError for negative values,
+ * or if the value/derivative vector does not cover the
+ * range.
+ * \param tolerance Requested accuracy of the table. This will be used to
+ * calculate the required internal spacing. If this cannot
+ * be achieved (for instance because the table would require
+ * too much memory) the constructor will throw gmx::ToleranceError.
+ *
+ * \note The functions are always defined in double precision to avoid
+ * losing accuracy when constructing tables.
+ *
+ * \note Since we fill the table for values below range.first, you can achieve
+ * a smaller table by using a smaller range where the tolerance has to be
+ * met, and accept that a few function calls below range.first do not
+ * quite reach the tolerance.
+ *
+ * \warning For efficiency reasons (since this code is used in some inner
+ * (kernels), we always allocate memory and calculate table indices
+ * for the complete interval [0,range.second], although the data will
+ * not be valid outside the definition range to avoid calling the
+ * function there. This means you should \a not use this class
+ * to tabulate functions for small ranges very far away from zero,
+ * since you would both waste a huge amount of memory and incur
+ * truncation errors when calculating the index.
+ *
+ * \throws gmx::ToleranceError if the requested tolerance cannot be achieved,
+ * and gmx::APIError for other incorrect input.
+ */
+ CubicSplineTable(std::initializer_list<AnalyticalSplineTableInput> analyticalInputList,
+ const std::pair<real, real> &range,
+ real tolerance = defaultTolerance);
+
+ /*! \brief Initialize table data from tabulated values and derivatives
+ *
+ * \param numericalInputList Initializer list with one or more functions to tabulate,
+ * specified as a string description, vectors with function and
+ * derivative values, and the input spacing. Data points are
+ * separated by the spacing parameter, starting from 0.
+ * Values below the lower limit of the range will be used to
+ * attempt defining the table, but we avoid using index 0
+ * unless 0.0 is included in the range. Some extra points beyond
+ * range.second are required to re-interpolate values, so add
+ * some margin. The constructor will throw gmx::APIError if the
+ * input vectors are too short to cover the requested range
+ * (and they must always be at least five points).
+ * \param range Range over which the function will be tabulated.
+ * Constructor will throw gmx::APIError for negative values,
+ * or if the value/derivative vector does not cover the
+ * range.
+ * \param tolerance Requested accuracy of the table. This will be used to
+ * calculate the required internal spacing and possibly
+ * re-interpolate. The constructor will throw
+ * gmx::ToleranceError if the input spacing is too coarse
+ * to achieve this accuracy.
+ *
+ * \note The input data vectors are always double precision to avoid
+ * losing accuracy when constructing tables.
+ *
+ * \note Since we fill the table for values below range.first, you can achieve
+ * a smaller table by using a smaller range where the tolerance has to be
+ * met, and accept that a few function calls below range.first do not
+ * quite reach the tolerance.
+ *
+ * \warning For efficiency reasons (since this code is used in some inner
+ * (kernels), we always allocate memory and calculate table indices
+ * for the complete interval [0,range.second], although the data will
+ * not be valid outside the definition range to avoid calling the
+ * function there. This means you should \a not use this class
+ * to tabulate functions for small ranges very far away from zero,
+ * since you would both waste a huge amount of memory and incur
+ * truncation errors when calculating the index.
+ */
+ CubicSplineTable(std::initializer_list<NumericalSplineTableInput> numericalInputList,
+ const std::pair<real, real> &range,
+ real tolerance = defaultTolerance);
+
+
+ /************************************************************
+ * Evaluation methods for single functions *
+ ************************************************************/
+
+ /*! \brief Evaluate both function and derivative, single table function
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 1
+ * \tparam funcIndex Index of function to evaluate in table, default is 0
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function and derivative
+ * \param[out] functionValue Function value
+ * \param[out] derivativeValue Function derivative
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+ void
+ evaluateFunctionAndDerivative(T r,
+ T * functionValue,
+ T * derivativeValue) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex < numFuncInTable, "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+ T Y, F, G, H;
+
+ // Load Derivative, Delta, Function, and Zero values for each table point.
+ // The 4 refers to these four values - not any SIMD width.
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex, tabIndex, &Y, &F, &G, &H);
+ *functionValue = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+ *derivativeValue = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+ }
+
+ /*! \brief Evaluate function value only, single table function
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 1
+ * \tparam funcIndex Index of function to evaluate in table, default is 0
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function value
+ * \param[out] functionValue Function value
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+ void
+ evaluateFunction(T r,
+ T * functionValue) const
+ {
+ T der gmx_unused;
+
+ evaluateFunctionAndDerivative<numFuncInTable, funcIndex>(r, functionValue, &der);
+ }
+
+ /*! \brief Evaluate function derivative only, single table function
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 1
+ * \tparam funcIndex Index of function to evaluate in table, default is 0
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function derivative
+ * \param[out] derivativeValue Function derivative
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+ void
+ evaluateDerivative(T r,
+ T * derivativeValue) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex < numFuncInTable, "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+ T Y, F, G, H;
+
+ // Load Derivative, Delta, Function, and Zero values for each table point.
+ // The 4 refers to these four values - not any SIMD width.
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex, tabIndex, &Y, &F, &G, &H);
+ *derivativeValue = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+ }
+
+ /************************************************************
+ * Evaluation methods for two functions *
+ ************************************************************/
+
+ /*! \brief Evaluate both function and derivative, two table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 2
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function and derivative
+ * \param[out] functionValue0 Interpolated value for first function
+ * \param[out] derivativeValue0 Interpolated derivative for first function
+ * \param[out] functionValue1 Interpolated value for second function
+ * \param[out] derivativeValue1 Interpolated derivative for second function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+ void
+ evaluateFunctionAndDerivative(T r,
+ T * functionValue0,
+ T * derivativeValue0,
+ T * functionValue1,
+ T * derivativeValue1) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable, "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+ T Y, F, G, H;
+
+ // Load Derivative, Delta, Function, and Zero values for each table point.
+ // The 4 refers to these four values - not any SIMD width.
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex0, tabIndex, &Y, &F, &G, &H);
+ *functionValue0 = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+ *derivativeValue0 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex1, tabIndex, &Y, &F, &G, &H);
+ *functionValue1 = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+ *derivativeValue1 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+ }
+
+ /*! \brief Evaluate function value only, two table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 2
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function value
+ * \param[out] functionValue0 Interpolated value for first function
+ * \param[out] functionValue1 Interpolated value for second function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+ void
+ evaluateFunction(T r,
+ T * functionValue0,
+ T * functionValue1) const
+ {
+ T der0 gmx_unused;
+ T der1 gmx_unused;
+
+ evaluateFunctionAndDerivative<numFuncInTable, funcIndex0, funcIndex1>(r, functionValue0, &der0, functionValue1, &der1);
+ }
+
+ /*! \brief Evaluate function derivative only, two table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 2
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function derivative
+ * \param[out] derivativeValue0 Interpolated derivative for first function
+ * \param[out] derivativeValue1 Interpolated derivative for second function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+ void
+ evaluateDerivative(T r,
+ T * derivativeValue0,
+ T * derivativeValue1) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable, "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+ T Y, F, G, H;
+
+ // Load Derivative, Delta, Function, and Zero values for each table point.
+ // The 4 refers to these four values - not any SIMD width.
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex0, tabIndex, &Y, &F, &G, &H);
+ *derivativeValue0 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex1, tabIndex, &Y, &F, &G, &H);
+ *derivativeValue1 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+ }
+
+ /************************************************************
+ * Evaluation methods for three functions *
+ ************************************************************/
+
+
+ /*! \brief Evaluate both function and derivative, three table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 3
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam funcIndex2 Index of 3rd function to evaluate in table, default is 2
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function and derivative
+ * \param[out] functionValue0 Interpolated value for first function
+ * \param[out] derivativeValue0 Interpolated derivative for first function
+ * \param[out] functionValue1 Interpolated value for second function
+ * \param[out] derivativeValue1 Interpolated derivative for second function
+ * \param[out] functionValue2 Interpolated value for third function
+ * \param[out] derivativeValue2 Interpolated derivative for third function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+ void
+ evaluateFunctionAndDerivative(T r,
+ T * functionValue0,
+ T * derivativeValue0,
+ T * functionValue1,
+ T * derivativeValue1,
+ T * functionValue2,
+ T * derivativeValue2) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable && funcIndex2 < numFuncInTable, "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+ T Y, F, G, H;
+
+ // Load Derivative, Delta, Function, and Zero values for each table point.
+ // The 4 refers to these four values - not any SIMD width.
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex0, tabIndex, &Y, &F, &G, &H);
+ *functionValue0 = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+ *derivativeValue0 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex1, tabIndex, &Y, &F, &G, &H);
+ *functionValue1 = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+ *derivativeValue1 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4*funcIndex2, tabIndex, &Y, &F, &G, &H);
+ *functionValue2 = fma(fma(fma(H, eps, G), eps, F), eps, Y);
+ *derivativeValue2 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+ }
+
+ /*! \brief Evaluate function value only, three table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 3
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam funcIndex2 Index of 3rd function to evaluate in table, default is 2
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function value
+ * \param[out] functionValue0 Interpolated value for first function
+ * \param[out] functionValue1 Interpolated value for second function
+ * \param[out] functionValue2 Interpolated value for third function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+ void
+ evaluateFunction(T r,
+ T * functionValue0,
+ T * functionValue1,
+ T * functionValue2) const
+ {
+ T der0 gmx_unused;
+ T der1 gmx_unused;
+ T der2 gmx_unused;
+
+ evaluateFunctionAndDerivative<numFuncInTable, funcIndex0, funcIndex1, funcIndex2>(r, functionValue0, &der0, functionValue1, &der1, functionValue2, &der2);
+ }
+
+ /*! \brief Evaluate function derivative only, three table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 3
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam funcIndex2 Index of 3rd function to evaluate in table, default is 2
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function derivative
+ * \param[out] derivativeValue0 Interpolated derivative for first function
+ * \param[out] derivativeValue1 Interpolated derivative for second function
+ * \param[out] derivativeValue2 Interpolated derivative for third function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+ void
+ evaluateDerivative(T r,
+ T * derivativeValue0,
+ T * derivativeValue1,
+ T * derivativeValue2) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable && funcIndex2 < numFuncInTable, "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+ T Y, F, G, H;
+
+ // Load Derivative, Delta, Function, and Zero values for each table point.
+ // The 4 refers to these four values - not any SIMD width.
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex0, tabIndex, &Y, &F, &G, &H);
+ *derivativeValue0 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex1, tabIndex, &Y, &F, &G, &H);
+ *derivativeValue1 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(yfghMultiTableData_.data() + 4 * funcIndex2, tabIndex, &Y, &F, &G, &H);
+ *derivativeValue2 = tableScale_ * fma(fma(T(3.0)*H, eps, T(2.0)*G), eps, F);
+ }
+
+ /*! \brief Return the table spacing (distance between points)
+ *
+ * You should never have to use this for normal code, but due to the
+ * way tables are constructed internally we need this in the unit tests
+ * to check relative tolerances over each interval.
+ *
+ * \return table spacing.
+ */
+ real
+ tableSpacing() const { return 1.0 / tableScale_; }
+
+ private:
+
+ std::size_t numFuncInTable_; //!< Number of separate tabluated functions
+ std::pair<real, real> range_; //!< Range for which table evaluation is allowed
+ real tableScale_; //!< Table scale (inverse of spacing between points)
+
+ /*! \brief Vector with combined table data to save calculations after lookup.
+ *
+ * For table point i, this vector contains the four coefficients
+ * Y,F,G,H that we use to express the function value as
+ * V(x) = Y + F e + G e^2 + H e^3, where e is the epsilon offset from
+ * the nearest table point.
+ *
+ * To allow aligned SIMD loads we need to use an aligned allocator for
+ * this container.
+ */
+ std::vector<real, AlignedAllocator<real> > yfghMultiTableData_;
+
+ // There should never be any reason to copy the table since it is read-only
+ GMX_DISALLOW_COPY_AND_ASSIGN(CubicSplineTable);
+};
+
+
+} // namespace gmx
+
+#endif // GMX_TABLES_CUBICSPLINETABLE_H
#ifndef GMX_TABLES_FORCETABLE_H
#define GMX_TABLES_FORCETABLE_H
+/*! \libinternal \file
+ * \brief
+ * Old routines for table generation (will eventually be replaced)
+ *
+ * \inlibraryapi
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+
#include <cstdio>
#include "gromacs/mdtypes/fcdata.h"
#include "gromacs/mdtypes/interaction_const.h"
#include "gromacs/utility/real.h"
+/*! \brief Flag to select user tables for make_tables */
#define GMX_MAKETABLES_FORCEUSER (1<<0)
+/*! \brief Flag to only make 1,4 pair tables for make_tables */
#define GMX_MAKETABLES_14ONLY (1<<1)
-/* Index in the tables that says which function to use */
+/*! \brief Enumerated type to describe the interaction types in a table */
enum {
- etiCOUL, etiLJ6, etiLJ12, etiNR
+ etiCOUL, //!< Coulomb
+ etiLJ6, //!< Dispersion
+ etiLJ12, //!< Repulsion
+ etiNR //!< Total number of interaction types
};
-typedef double (*real_space_grid_contribution_computer)(double, double);
-/* Function pointer used to tell table_spline3_fill_ewald_lr whether it
+/*! \brief Function pointer to calculate the grid contribution for coulomb/LJ
+ *
+ * Used to tell table_spline3_fill_ewald_lr whether it
* should calculate the grid contribution for electrostatics or LJ.
*/
+typedef double (*real_space_grid_contribution_computer)(double, double);
+
+/*! \brief Fill tables with the Ewald long-range force interaction
+ *
+ * Fill tables of ntab points with spacing dr with the ewald long-range
+ * (mesh) force.
+ * There are three separate tables with format FDV0, F, and V.
+ * This function interpolates the Ewald mesh potential contribution
+ * with coefficient beta using a quadratic spline.
+ * The force can then be interpolated linearly.
+ *
+ * \param table_F Force table
+ * \param table_V Potential table
+ * \param table_FDV0 Combined table optimized for SIMD loads
+ * \param ntab Number of points in tables
+ * \param dx Spacing
+ * \param beta Ewald splitting paramter
+ * \param v_lr Pointer to function calculating real-space grid contribution
+ */
void table_spline3_fill_ewald_lr(real *table_F,
real *table_V,
real *table_FDV0,
double dx,
real beta,
real_space_grid_contribution_computer v_lr);
-/* Fill tables of ntab points with spacing dr with the ewald long-range
- * (mesh) force.
- * There are three separate tables with format FDV0, F, and V.
- * This function interpolates the Ewald mesh potential contribution
- * with coefficient beta using a quadratic spline.
- * The force can then be interpolated linearly.
- */
+/*! \brief Compute scaling for the Ewald quadratic spline tables.
+ *
+ * \param ic Pointer to interaction constant structure
+ * \return The scaling factor
+ */
real ewald_spline3_table_scale(const interaction_const_t *ic);
-/* Return the scaling for the Ewald quadratic spline tables. */
+/*! \brief Return the real space grid contribution for Ewald
+ *
+ * \param beta Ewald splitting parameter
+ * \param r Distance for which to calculate the real-space contrib
+ * \return Real space grid contribution for Ewald electrostatics
+ */
double v_q_ewald_lr(double beta, double r);
-/* Return the real space grid contribution for Ewald*/
+/*! \brief Return the real space grid contribution for LJ-Ewald
+ *
+ * \param beta Ewald splitting parameter
+ * \param r Distance for which to calculate the real-space contrib
+ * \return Real space grid contribution for Ewald Lennard-Jones interaction
+ */
double v_lj_ewald_lr(double beta, double r);
-/* Return the real space grid contribution for LJ-Ewald*/
+/*! \brief Return tables for inner loops.
+ *
+ * \param fp Log file pointer
+ * \param fr Force record
+ * \param fn File name from which to read user tables
+ * \param rtab Largest interaction distance to tabulate
+ * \param flags Flags to select table settings
+ *
+ * \return Pointer to inner loop table structure
+ */
t_forcetable *make_tables(FILE *fp,
const t_forcerec *fr,
const char *fn, real rtab, int flags);
-/* Return tables for inner loops. */
-bondedtable_t make_bonded_table(FILE *fplog, const char *fn, int angle);
-/* Return a table for bonded interactions,
- * angle should be: bonds 0, angles 1, dihedrals 2
+/*! \brief Return a table for bonded interactions,
+ *
+ * \param fplog Pointer to log file
+ * \param fn File name
+ * \param angle Type of angle: bonds 0, angles 1, dihedrals 2
+ * \return New bonded table datatype
*/
+bondedtable_t make_bonded_table(FILE *fplog, const char *fn, int angle);
-/* Return a table for GB calculations */
+/*! \brief Return a table for GB calculations
+ *
+ * \param fr Force record
+ * \return Pointer to new gb table structure
+ */
t_forcetable *make_gb_table(const t_forcerec *fr);
/*! \brief Construct and return tabulated dispersion and repulsion interactions
--- /dev/null
+/*
+ * 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 for quadratic spline table functions
+ *
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#include "gmxpre.h"
+
+#include "quadraticsplinetable.h"
+
+#include <cmath>
+
+#include <algorithm>
+#include <functional>
+#include <initializer_list>
+#include <utility>
+#include <vector>
+
+#include "gromacs/tables/tableinput.h"
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/real.h"
+
+#include "splineutil.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+/*! \brief Construct the data for a single quadratic table from analytical functions
+ *
+ * \param[in] function Analytical functiojn
+ * \param[in] derivative Analytical derivative
+ * \param[in] range Upper/lower limit of region to tabulate
+ * \param[in] spacing Distance between table points
+ * \param[out] functionTableData Output table with function data
+ * \param[out] derivativeTableData OUtput table with (adjusted) derivative data
+ */
+void
+fillSingleQuadraticSplineTableData(const std::function<double(double)> &function,
+ const std::function<double(double)> &derivative,
+ const std::pair<real, real> &range,
+ double spacing,
+ std::vector<real> *functionTableData,
+ std::vector<real> *derivativeTableData)
+{
+ std::size_t endIndex = range.second / spacing + 2;
+
+ functionTableData->resize(endIndex);
+ derivativeTableData->resize(endIndex);
+
+ double maxMagnitude = 0.0001*GMX_REAL_MAX;
+ bool functionIsInRange = true;
+ std::size_t lastIndexInRange = endIndex - 1;
+
+ for (int i = endIndex - 1; i >= 0; i--)
+ {
+ double x = i * spacing;
+ double tmpFunctionValue;
+ double tmpDerivativeValue;
+
+ if (range.first > 0 && i == 0)
+ {
+ // Avoid x==0 if it is not in the range, since it can lead to
+ // singularities even if the value for i==1 was within or required magnitude
+ functionIsInRange = false;
+ }
+
+ if (functionIsInRange)
+ {
+ tmpFunctionValue = function(x);
+
+ // Calculate third derivative term (2nd derivative of the derivative)
+ // Make sure we stay in range. In practice this means we use one-sided
+ // interpolation at the interval endpoints (indentical to an offset for 3-point formula)
+ const double h = std::pow( GMX_DOUBLE_EPS, 0.25 );
+ double y = std::min( std::max(x, range.first + h), range.second - h);
+ double thirdDerivativeValue = ( derivative(y+h) - 2.0 * derivative(y) + derivative(y-h) ) / ( h * h );
+
+ tmpDerivativeValue = derivative(x) - spacing * spacing * thirdDerivativeValue / 12.0;
+
+ if (std::abs(tmpFunctionValue) > maxMagnitude || std::abs(tmpDerivativeValue) > maxMagnitude)
+ {
+ functionIsInRange = false; // Once this happens, it never resets to true again
+ }
+ }
+
+ if (functionIsInRange)
+ {
+ (*functionTableData)[i] = tmpFunctionValue;
+ (*derivativeTableData)[i] = tmpDerivativeValue;
+ lastIndexInRange--;
+ }
+ else
+ {
+ // Once the function or derivative (more likely) has reached very large values,
+ // we simply make a linear function from the last in-range value of the derivative.
+ double lastIndexFunction = (*functionTableData)[lastIndexInRange];
+ double lastIndexDerivative = (*derivativeTableData)[lastIndexInRange];
+ (*functionTableData)[i] = lastIndexFunction + lastIndexDerivative * (i - lastIndexInRange) * spacing;
+ (*derivativeTableData)[i] = lastIndexDerivative;
+ }
+ }
+}
+
+
+/*! \brief Construct the data for a single quadratic table from vector data
+ *
+ * \param[in] function Input vector with function data
+ * \param[in] derivative Input vector with derivative data
+ * \param[in] inputSpacing Distance between points in input vectors
+ * \param[in] range Upper/lower limit of region to tabulate
+ * \param[in] spacing Distance between table points
+ * \param[out] functionTableData Output table with function data
+ * \param[out] derivativeTableData OUtput table with (adjusted) derivative data
+ */
+void
+fillSingleQuadraticSplineTableData(ConstArrayRef<double> function,
+ ConstArrayRef<double> derivative,
+ double inputSpacing,
+ const std::pair<real, real> &range,
+ double spacing,
+ std::vector<real> *functionTableData,
+ std::vector<real> *derivativeTableData)
+{
+ std::size_t endIndex = range.second / spacing + 2;
+
+ functionTableData->resize(endIndex);
+ derivativeTableData->resize(endIndex);
+
+ std::vector<double> thirdDerivative(internal::vectorSecondDerivative(derivative, inputSpacing));
+
+ double maxMagnitude = 0.0001*GMX_REAL_MAX;
+ bool functionIsInRange = true;
+ std::size_t lastIndexInRange = endIndex - 1;
+
+ for (int i = endIndex - 1; i >= 0; i--)
+ {
+ double x = i * spacing;
+ double tmpFunctionValue;
+ double tmpDerivativeValue;
+
+ if (range.first > 0 && i == 0)
+ {
+ // Avoid x==0 if it is not in the range, since it can lead to
+ // singularities even if the value for i==1 was within or required magnitude
+ functionIsInRange = false;
+ }
+
+ if (functionIsInRange)
+ {
+ // Step 1: Interpolate the function value at x from input table.
+ double inputXTab = x / inputSpacing;
+ int inputIndex = inputXTab;
+ double inputEps = inputXTab - inputIndex;
+
+ // Linear interpolation of input derivative and third derivative
+ double thirdDerivativeValue = (1.0 - inputEps) * thirdDerivative[inputIndex] + inputEps * thirdDerivative[inputIndex+1];
+ double derivativeValue = (1.0 - inputEps) * derivative[inputIndex] + inputEps * derivative[inputIndex+1];
+
+ // Quadratic interpolation for function value
+ tmpFunctionValue = function[inputIndex] + 0.5 * (derivative[inputIndex] + derivativeValue) * inputEps * inputSpacing;
+ tmpDerivativeValue = derivativeValue - spacing * spacing * thirdDerivativeValue / 12.0;
+
+ if (std::abs(tmpFunctionValue) > maxMagnitude || std::abs(tmpDerivativeValue) > maxMagnitude)
+ {
+ functionIsInRange = false; // Once this happens, it never resets to true again
+ }
+ }
+
+ if (functionIsInRange)
+ {
+ (*functionTableData)[i] = tmpFunctionValue;
+ (*derivativeTableData)[i] = tmpDerivativeValue;
+ lastIndexInRange--;
+ }
+ else
+ {
+ // Once the function or derivative (more likely) has reached very large values,
+ // we simply make a linear function from the last in-range value of the derivative.
+ double lastIndexFunction = (*functionTableData)[lastIndexInRange];
+ double lastIndexDerivative = (*derivativeTableData)[lastIndexInRange];
+ (*functionTableData)[i] = lastIndexFunction + lastIndexDerivative * (i - lastIndexInRange) * spacing;
+ (*derivativeTableData)[i] = lastIndexDerivative;
+ }
+ }
+}
+
+/*! \brief Create merged DDFZ vector from function & derivative data
+ *
+ * \param functionTableData Function values
+ * \param derivativeTableData Derivative values. We have already subtracted the
+ * small third derivative component when calling this
+ * function, but in practice it is just an arbitrary
+ * vector here.
+ * \param ddfzTableData Vector four times longer, filled with
+ * the derivative, the difference to the next derivative
+ * point, the function value, and zero.
+ *
+ * \throws If the vector lengths do not match.
+ */
+void
+fillDdfzTableData(const std::vector<real> &functionTableData,
+ const std::vector<real> &derivativeTableData,
+ std::vector<real> *ddfzTableData)
+{
+ GMX_ASSERT(functionTableData.size() == derivativeTableData.size(), "Mismatching vector lengths");
+
+ std::size_t points = functionTableData.size();
+
+ ddfzTableData->resize(4 * points);
+
+ for (std::size_t i = 0; i < points; i++)
+ {
+ (*ddfzTableData)[4*i] = derivativeTableData[i];
+
+ double nextDerivative = ( i < functionTableData.size() - 1 ) ? derivativeTableData[i+1] : 0.0;
+
+ (*ddfzTableData)[4*i + 1] = nextDerivative - derivativeTableData[i];
+ (*ddfzTableData)[4*i + 2] = functionTableData[i];
+ (*ddfzTableData)[4*i + 3] = 0.0;
+ }
+}
+
+} // namespace anonymous
+
+
+
+const real
+QuadraticSplineTable::defaultTolerance = 10.0 * GMX_FLOAT_EPS;
+
+
+QuadraticSplineTable::QuadraticSplineTable(std::initializer_list<AnalyticalSplineTableInput> analyticalInputList,
+ const std::pair<real, real> &range,
+ real tolerance)
+ : numFuncInTable_(analyticalInputList.size()), range_(range)
+{
+ // Sanity check on input values
+ if (range_.first < 0.0 || (range_.second-range_.first) < 0.001)
+ {
+ GMX_THROW(InvalidInputError("Range to tabulate cannot include negative values and must span at least 0.001"));
+ }
+
+ if (tolerance < GMX_REAL_EPS)
+ {
+ GMX_THROW(ToleranceError("Table tolerance cannot be smaller than GMX_REAL_EPS"));
+ }
+
+ double minQuotient = GMX_REAL_MAX;
+
+ // loop over all functions to find smallest spacing
+ for (auto thisFuncInput : analyticalInputList)
+ {
+ try
+ {
+ internal::throwUnlessDerivativeIsConsistentWithFunction(thisFuncInput.function, thisFuncInput.derivative, range_);
+ }
+ catch (gmx::GromacsException &ex)
+ {
+ ex.prependContext("Error generating quadratic spline table for function '" + thisFuncInput.desc + "'");
+ throw;
+ }
+ // Calculate the required table spacing h. The error we make with linear interpolation
+ // of the derivative will be described by the third-derivative correction term.
+ // This means we can compute the required spacing as h = sqrt(12*tolerance*min(f'/f''')),
+ // where f'/f''' is the first and third derivative of the function, respectively.
+
+ double thisMinQuotient = internal::findSmallestQuotientOfFunctionAndSecondDerivative(thisFuncInput.derivative, range_);
+
+ minQuotient = std::min(minQuotient, thisMinQuotient);
+ }
+
+ double spacing = std::sqrt(12.0 * tolerance * minQuotient);
+
+ halfSpacing_ = 0.5 * spacing;
+ tableScale_ = 1.0 / spacing;
+
+ if (range_.second * tableScale_ > 1e6)
+ {
+ GMX_THROW(ToleranceError("Over a million points would be required for table; decrease range or increase tolerance"));
+ }
+
+ // Loop over all tables again.
+ // Here we create the actual table for each function, and then
+ // combine them into a multiplexed table function.
+ std::size_t funcIndex = 0;
+
+ for (auto thisFuncInput : analyticalInputList)
+ {
+ try
+ {
+ std::vector<real> tmpFuncTableData;
+ std::vector<real> tmpDerTableData;
+ std::vector<real> tmpDdfzTableData;
+
+ fillSingleQuadraticSplineTableData(thisFuncInput.function,
+ thisFuncInput.derivative,
+ range_,
+ spacing,
+ &tmpFuncTableData,
+ &tmpDerTableData);
+
+ fillDdfzTableData(tmpFuncTableData, tmpDerTableData, &tmpDdfzTableData);
+
+ internal::fillMultiplexedTableData(tmpDerTableData, &derivativeMultiTableData_,
+ 1, numFuncInTable_, funcIndex);
+
+ internal::fillMultiplexedTableData(tmpDdfzTableData, &ddfzMultiTableData_,
+ 4, numFuncInTable_, funcIndex);
+
+ funcIndex++;
+ }
+ catch (gmx::GromacsException &ex)
+ {
+ ex.prependContext("Error generating quadratic spline table for function '" + thisFuncInput.desc + "'");
+ throw;
+ }
+ }
+}
+
+
+QuadraticSplineTable::QuadraticSplineTable(std::initializer_list<NumericalSplineTableInput> numericalInputList,
+ const std::pair<real, real> &range,
+ real tolerance)
+ : numFuncInTable_(numericalInputList.size()), range_(range)
+{
+ // Sanity check on input values
+ if (range.first < 0.0 || (range.second-range.first) < 0.001)
+ {
+ GMX_THROW(InvalidInputError("Range to tabulate cannot include negative values and must span at least 0.001"));
+ }
+
+ if (tolerance < GMX_REAL_EPS)
+ {
+ GMX_THROW(ToleranceError("Table tolerance cannot be smaller than GMX_REAL_EPS"));
+ }
+
+ double minQuotient = GMX_REAL_MAX;
+
+ // loop over all functions to find smallest spacing
+ for (auto thisFuncInput : numericalInputList)
+ {
+ try
+ {
+ // We do not yet know what the margin is, but we need to test that we at least cover
+ // the requested range before starting to calculate derivatives
+ if (thisFuncInput.function.size() < range_.second / thisFuncInput.spacing + 1)
+ {
+ GMX_THROW(InconsistentInputError("Table input vectors must cover requested range, and a margin beyond the upper endpoint"));
+ }
+
+ if (thisFuncInput.function.size() != thisFuncInput.derivative.size())
+ {
+ GMX_THROW(InconsistentInputError("Function and derivative vectors have different lengths"));
+ }
+
+ internal::throwUnlessDerivativeIsConsistentWithFunction(thisFuncInput.function, thisFuncInput.derivative, thisFuncInput.spacing, range_);
+ }
+ catch (gmx::GromacsException &ex)
+ {
+ ex.prependContext("Error generating quadratic spline table for function '" + thisFuncInput.desc + "'");
+ throw;
+ }
+ // Calculate the required table spacing h. The error we make with linear interpolation
+ // of the derivative will be described by the third-derivative correction term.
+ // This means we can compute the required spacing as h = sqrt(12*tolerance*min(f'/f''')),
+ // where f'/f''' is the first and third derivative of the function, respectively.
+
+ double thisMinQuotient = internal::findSmallestQuotientOfFunctionAndSecondDerivative(thisFuncInput.derivative, thisFuncInput.spacing, range_);
+
+ minQuotient = std::min(minQuotient, thisMinQuotient);
+ }
+
+ double spacing = std::sqrt(12.0 * tolerance * minQuotient);
+
+ halfSpacing_ = 0.5 * spacing;
+ tableScale_ = 1.0 / spacing;
+
+ if (range_.second * tableScale_ > 1e6)
+ {
+ GMX_THROW(ToleranceError("Requested tolerance would require over a million points in table"));
+ }
+
+ // Loop over all tables again.
+ // Here we create the actual table for each function, and then
+ // combine them into a multiplexed table function.
+ std::size_t funcIndex = 0;
+
+ for (auto thisFuncInput : numericalInputList)
+ {
+ try
+ {
+ if (spacing < thisFuncInput.spacing)
+ {
+ GMX_THROW(ToleranceError("Input vector spacing cannot achieve tolerance requested"));
+ }
+
+ std::vector<real> tmpFuncTableData;
+ std::vector<real> tmpDerTableData;
+ std::vector<real> tmpDdfzTableData;
+
+ fillSingleQuadraticSplineTableData(thisFuncInput.function,
+ thisFuncInput.derivative,
+ thisFuncInput.spacing,
+ range,
+ spacing,
+ &tmpFuncTableData,
+ &tmpDerTableData);
+
+ fillDdfzTableData(tmpFuncTableData, tmpDerTableData, &tmpDdfzTableData);
+
+ internal::fillMultiplexedTableData(tmpDerTableData, &derivativeMultiTableData_,
+ 1, numFuncInTable_, funcIndex);
+
+ internal::fillMultiplexedTableData(tmpDdfzTableData, &ddfzMultiTableData_,
+ 4, numFuncInTable_, funcIndex);
+
+ funcIndex++;
+ }
+ catch (gmx::GromacsException &ex)
+ {
+ ex.prependContext("Error generating quadratic spline table for function '" + thisFuncInput.desc + "'");
+ throw;
+ }
+ }
+}
+
+} // namespace gmx
--- /dev/null
+/*
+ * 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
+ * \defgroup module_tables Classes for table interpolation
+ * \ingroup group_utilitymodules
+ *
+ * \brief Table interpolation from analytical or numerical input
+ *
+ * This module provides quadratic spline interpolation tables used
+ * both for the nonbonded kernels and listed interactions.
+ *
+ * \author Erik Lindahl <erik.lindahl@scilifelab.se>
+ */
+
+
+/*! \libinternal \file
+ * \brief
+ * Declares classes for quadratic spline table
+ *
+ * \inlibraryapi
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#ifndef GMX_TABLES_QUADRATICSPLINETABLE_H
+#define GMX_TABLES_QUADRATICSPLINETABLE_H
+
+#include <functional>
+#include <initializer_list>
+#include <vector>
+
+#include "gromacs/simd/simd.h"
+#include "gromacs/tables/tableinput.h"
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/real.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief Quadratic spline interpolation table.
+ *
+ * This class interpolates a function specified either as an analytical
+ * expression or from user-provided table data.
+ *
+ * At initialization, you provide the reference function of vectors
+ * as a list of tuples that contain a brief name, the function, and
+ * derivative for each function to tabulate. To create a table with
+ * two functions this initializer list can for instance look like
+ *
+ * { {"LJ6", lj6Func, lj6Der}, {"LJ12", lj12Func, lj12Der} }
+ *
+ * The names are only used so exceptions during initialization can
+ * be traced to a specific table.
+ *
+ * When interpolating, there are methods to interpolate either 1, 2, or 3
+ * functions in one go. By default these interpolation routines will
+ * operate on tables with the same number of functions as specified in
+ * the interpolation method (debug builds check that this is consistent with
+ * the table). However, it is also possible to use optional template
+ * parameters that specify the total number of functions in a table, and
+ * what function index to interpolate. For instance, to interpolate the
+ * derivative of the second function (i.e., index 1) in a
+ * multi-function-table with three functions in total, you can write
+ *
+ * table.evaluateDerivative<3,1>(x,&der);
+ *
+ * Here too, debug builds will check that the template parameters are
+ * consistent with the table.
+ *
+ * The table data is internally adjusted to guarantee that the interpolated
+ * derivative is the true derivative of the interpolated potential, which is
+ * important to avoid systematic errors for the common case when the derivative
+ * is concave/convex in the entire interval.
+ * We do this by expressing the difference in the function value
+ * at a small offset h relative to a reference value in position 0 with a forward
+ * Taylor series expanded around 0, and then doing the opposite of expressing
+ * difference in the function at position 0 relative to a reference value in
+ * position h when using a backward Taylor expansion:
+ *
+ * \f{eqnarray*}{
+ * \Delta V & = & hV'(0) + \frac{1}{2} h^2 V''(0) + \frac{1}{6} h^3 V'''(0) + O(h^4) \\
+ * \Delta V & = & hV'(h) - \frac{1}{2} h^2 V''(h) + \frac{1}{6} h^3 V'''(h) + O(h^4)
+ * \f}
+ *
+ * Summing the equations leads to
+ *
+ * \f[
+ * 2 \Delta V = h(V'(0) + V'(h)) + \frac{1}{2} h^2 (V''(0)-V''(h)) + \frac{1}{6}h^3(V'''(0)+V'''(h)) + O(h^4)
+ * \f]
+ *
+ * To make the second term symmetric too, we can replace it with the average of
+ * the Taylor expansion at 0 and h (i.e., using the third derivative). This gives
+ *
+ * \f[
+ * 2 \Delta V = h(V'(0) + V'(h)) - \frac{1}{12} h^3 (V'''(0)+V'''(h)) + O(h^4)
+ * \f]
+ *
+ * Thus, if we replace the derivative in the internal quadratic table data with
+ *
+ * \f[
+ * V' - \frac{1}{12}h^2 V'''
+ * \f]
+ *
+ * we will cancel the h^3 term in the error. This will make the integral of the
+ * forces match the potential much better (The h^4 term actually disappears, so
+ * when summing over 1/h points the remaining error will be O(h^4).
+ *
+ * While it is possible to create tables only from function values
+ * (i.e., no derivatives), it is recommended to provide derivatives for higher
+ * accuracy and to avoid issues with numerical differentiation. Note that the
+ * table input should be smooth, i.e. it should not contain noise e.g. from an
+ * (iterative) Boltzmann inversion procedure - you have been warned.
+ *
+ * \note This class is responsible for fundamental interpolation of any function,
+ * which might or might not correspond to a potential. For this reason
+ * both input and output derivatives are proper function derivatives, and
+ * we do not swap any signs to get forces directly from the table.
+ *
+ * \note There will be a small additional accuracy loss from the internal
+ * operation where we calculate the epsilon offset from the nearest table
+ * point, since the integer part we subtract can get large in those cases.
+ * The absolute such error both in the function and derivative value will
+ * be roughly f''*x*GMX_REAL_EPS, where x is the argument and f'' the
+ * second derivative.
+ * While this is technically possible to solve with extended precision
+ * arithmetics, that would introduce extra instructions in some highly
+ * performance-sensitive code parts. For typical GROMACS interaction
+ * functions the derivatives will decay faster than the potential, which
+ * means it will never play any role. For other functions it will only
+ * cause a small increase in the relative error for arguments where the
+ * magnitude of the function or derivative is very small.
+ * Since we typically sum several results in GROMACS, this should never
+ * show up in any real cases, and for this reason we choose not to do
+ * the extended precision arithmetics.
+ *
+ * \note These routines are not suitable for table ranges starting far away
+ * from zero, since we allocate memory and calculate indices starting from
+ * range zero for efficiency reasons.
+ */
+class QuadraticSplineTable
+{
+ private:
+ /*! \brief Change that function value falls inside range when debugging
+ *
+ * \tparam T Lookup argument floating-point type, typically SimdReal or real.
+ * \param r Lookup argument to test
+ *
+ * \throws Debug builds will throw gmx::RangeError for values that are
+ * larger than the upper limit of the range, or smaller than 0.
+ * We allow the table to be called with arguments between 0 and
+ * the lower limit of the range, since this might in theory occur
+ * once-in-a-blue-moon with some algorithms.
+ */
+ template <typename T>
+ void
+ rangeCheck(T gmx_unused r) const
+ {
+#ifndef NDEBUG
+ // Check that all values fall in range when debugging
+ if (anyTrue( r < T(0.0) || T(range_.second) <= r ) )
+ {
+ GMX_THROW(RangeError("Interpolation input value falls outside table definition range"));
+ }
+#endif
+ }
+
+ public:
+
+ /*! \brief Default tolerance for tables is 10*GMX_FLOAT_EPS
+ *
+ * \note Even for double precision builds we set the tolerance to
+ * one order of magnitude above the single precision epsilon.
+ */
+ static const real defaultTolerance;
+
+ /*! \brief Initialize table data from function
+ *
+ * \param analyticalInputList Initializer list with one or more functions to tabulate,
+ * specified as pairs containing analytical
+ * functions and their derivatives. The function will also
+ * be called for values smaller than the lower limit of the
+ * range, but we avoid calling it for 0.0 if that value
+ * is not included in the range.
+ * \param range Range over which the function will be tabulated.
+ * Constructor will throw gmx::APIError for negative values.
+ * Due to the way the numerical derivative evaluation depends
+ * on machine precision internally, this range must be
+ * at least 0.001, or the constructor throws gmx::APIError.
+ * \param tolerance Requested accuracy of the table. This will be used to
+ * calculate the required internal spacing. If this cannot
+ * be achieved (for instance because the table would require
+ * too much memory) the constructor will throw gmx::ToleranceError.
+ *
+ * \note The functions are always defined in double precision to avoid
+ * losing accuracy when constructing tables.
+ *
+ * \note Since we fill the table for values below range.first, you can achieve
+ * a smaller table by using a smaller range where the tolerance has to be
+ * met, and accept that a few function calls below range.first do not
+ * quite reach the tolerance.
+ *
+ * \warning For efficiency reasons (since this code is used in some inner
+ * (kernels), we always allocate memory and calculate table indices
+ * for the complete interval [0,range.second], although the data will
+ * not be valid outside the definition range to avoid calling the
+ * function there. This means you should \a not use this class
+ * to tabulate functions for small ranges very far away from zero,
+ * since you would both waste a huge amount of memory and incur
+ * truncation errors when calculating the index.
+ *
+ * \throws gmx::ToleranceError if the requested tolerance cannot be achieved,
+ * and gmx::APIError for other incorrect input.
+ */
+ QuadraticSplineTable(std::initializer_list<AnalyticalSplineTableInput> analyticalInputList,
+ const std::pair<real, real> &range,
+ real tolerance = defaultTolerance);
+
+ /*! \brief Initialize table data from tabulated values and derivatives
+ *
+ * \param numericalInputList Initializer list with one or more functions to tabulate,
+ * specified as pairs containing containing vectors for the
+ * function values and their derivatives. Data points are
+ * separated by the spacing parameter, starting from 0.
+ * Values below the lower limit of the range will be used to
+ * attempt defining the table, but we avoid using index 0
+ * unless 0.0 is included in the range. Some extra points beyond
+ * range.second are required to re-interpolate values, so add
+ * some margin. The constructor will throw gmx::APIError if the
+ * input vectors are too short to cover the requested range
+ * (and they must always be at least five points).
+ * \param range Range over which the function will be tabulated.
+ * Constructor will throw gmx::APIError for negative values,
+ * or if the value/derivative vector does not cover the
+ * range.
+ * \param tolerance Requested accuracy of the table in the range. This will be
+ * used to calculate the required internal spacing and possibly
+ * re-interpolate. The constructor will throw
+ * gmx::ToleranceError if the input spacing is too coarse
+ * to achieve this accuracy.
+ *
+ * \note The input data vectors are always double precision to avoid
+ * losing accuracy when constructing tables.
+ *
+ * \note Since we fill the table for values below range.first, you can achieve
+ * a smaller table by using a smaller range where the tolerance has to be
+ * met, and accept that a few function calls below range.first do not
+ * quite reach the tolerance.
+ *
+ * \warning For efficiency reasons (since this code is used in some inner
+ * (kernels), we always allocate memory and calculate table indices
+ * for the complete interval [0,range.second], although the data will
+ * not be valid outside the definition range to avoid calling the
+ * function there. This means you should \a not use this class
+ * to tabulate functions for small ranges very far away from zero,
+ * since you would both waste a huge amount of memory and incur
+ * truncation errors when calculating the index.
+ */
+ QuadraticSplineTable(std::initializer_list<NumericalSplineTableInput> numericalInputList,
+ const std::pair<real, real> &range,
+ real tolerance = defaultTolerance);
+
+
+ /************************************************************
+ * Evaluation methods for single functions *
+ ************************************************************/
+
+ /*! \brief Evaluate both function and derivative, single table function
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 1
+ * \tparam funcIndex Index of function to evaluate in table, default is 0
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function and derivative
+ * \param[out] functionValue Function value
+ * \param[out] derivativeValue Function derivative
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+ void
+ evaluateFunctionAndDerivative(T r,
+ T * functionValue,
+ T * derivativeValue) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex < numFuncInTable, "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+ T t0;
+ T t1;
+ T t2;
+ T t3 gmx_unused;
+
+ // Load Derivative, Delta, Function, and Zero values for each table point.
+ // The 4 refers to these four values - not any SIMD width.
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4 * funcIndex, tabIndex, &t0, &t1, &t2, &t3);
+
+ t1 = t0 + eps * t1;
+ *functionValue = fma( eps * T(halfSpacing_), t0 + t1, t2);
+ *derivativeValue = t1;
+ }
+
+ /*! \brief Evaluate function value only, single table function
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 1
+ * \tparam funcIndex Index of function to evaluate in table, default is 0
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function value
+ * \param[out] functionValue Function value
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+ void
+ evaluateFunction(T r,
+ T * functionValue) const
+ {
+ T der gmx_unused;
+
+ evaluateFunctionAndDerivative<numFuncInTable, funcIndex>(r, functionValue, &der);
+ }
+
+ /*! \brief Evaluate function derivative only, single table function
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 1
+ * \tparam funcIndex Index of function to evaluate in table, default is 0
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function derivative
+ * \param[out] derivativeValue Function derivative
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 1, int funcIndex = 0, typename T>
+ void
+ evaluateDerivative(T r,
+ T * derivativeValue) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex < numFuncInTable, "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+ T t0;
+ T t1;
+ T t2 gmx_unused;
+
+ if (numFuncInTable == 1)
+ {
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex, tabIndex, &t0, &t1); // works for scalar T too
+ }
+ else
+ {
+ // This is not ideal, but we need a version of gatherLoadUBySimdIntTranspose that
+ // only loads a single value from memory to implement it better (will be written)
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex, tabIndex, &t0, &t2); // works for scalar T too
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex, tabIndex + T(1), &t1, &t2); // works for scalar T too
+ }
+
+ // (1-eps)*t0 + eps*t1
+ *derivativeValue = fma(t1-t0, eps, t0);
+ }
+
+ /************************************************************
+ * Evaluation methods for two functions *
+ ************************************************************/
+
+ /*! \brief Evaluate both function and derivative, two table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 2
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function and derivative
+ * \param[out] functionValue1 Interpolated value for first function
+ * \param[out] derivativeValue1 Interpolated derivative for first function
+ * \param[out] functionValue2 Interpolated value for second function
+ * \param[out] derivativeValue2 Interpolated derivative for second function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+ void
+ evaluateFunctionAndDerivative(T r,
+ T * functionValue1,
+ T * derivativeValue1,
+ T * functionValue2,
+ T * derivativeValue2) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable, "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+ T t0;
+ T t1;
+ T t2;
+ T t3 gmx_unused;
+
+ // Load Derivative, Delta, Function, and Zero values for each table point.
+ // The 4 refers to these four values - not any SIMD width.
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4*funcIndex0, tabIndex, &t0, &t1, &t2, &t3);
+ t1 = t0 + eps * t1;
+ *functionValue1 = fma( eps * T(halfSpacing_), t0 + t1, t2);
+ *derivativeValue1 = t1;
+
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4*funcIndex1, tabIndex, &t0, &t1, &t2, &t3);
+ t1 = t0 + eps * t1;
+ *functionValue2 = fma( eps * T(halfSpacing_), t0 + t1, t2);
+ *derivativeValue2 = t1;
+ }
+
+ /*! \brief Evaluate function value only, two table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 2
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function value
+ * \param[out] functionValue1 Interpolated value for first function
+ * \param[out] functionValue2 Interpolated value for second function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+ void
+ evaluateFunction(T r,
+ T * functionValue1,
+ T * functionValue2) const
+ {
+ T der1 gmx_unused;
+ T der2 gmx_unused;
+
+ evaluateFunctionAndDerivative<numFuncInTable, funcIndex0, funcIndex1>(r, functionValue1, &der1, functionValue2, &der2);
+ }
+
+ /*! \brief Evaluate function derivative only, two table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 2
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function derivative
+ * \param[out] derivativeValue1 Interpolated derivative for first function
+ * \param[out] derivativeValue2 Interpolated derivative for second function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 2, int funcIndex0 = 0, int funcIndex1 = 1, typename T>
+ void
+ evaluateDerivative(T r,
+ T * derivativeValue1,
+ T * derivativeValue2) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable, "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+
+ if (numFuncInTable == 2 && funcIndex0 == 0 && funcIndex1 == 1)
+ {
+ T t0A, t0B, t1A, t1B;
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data(), tabIndex, &t0A, &t0B); // works for scalar T too
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + 2, tabIndex, &t1A, &t1B); // works for scalar T too
+ *derivativeValue1 = fma(t1A-t0A, eps, t0A);
+ *derivativeValue2 = fma(t1B-t0B, eps, t0B);
+ }
+ else
+ {
+ T t0, t1, t2;
+ // This is not ideal, but we need a version of gatherLoadUBySimdIntTranspose that
+ // only loads a single value from memory to implement it better (will be written)
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex0, tabIndex, &t0, &t2); // works for scalar T too
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex0, tabIndex + T(1), &t1, &t2); // works for scalar T too
+ *derivativeValue1 = fma(t1-t0, eps, t0);
+
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex1, tabIndex, &t0, &t2); // works for scalar T too
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex1, tabIndex + T(1), &t1, &t2); // works for scalar T too
+ *derivativeValue2 = fma(t1-t0, eps, t0);
+ }
+ }
+
+ /************************************************************
+ * Evaluation methods for three functions *
+ ************************************************************/
+
+
+ /*! \brief Evaluate both function and derivative, three table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 3
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam funcIndex2 Index of 3rd function to evaluate in table, default is 2
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function and derivative
+ * \param[out] functionValue1 Interpolated value for first function
+ * \param[out] derivativeValue1 Interpolated derivative for first function
+ * \param[out] functionValue2 Interpolated value for second function
+ * \param[out] derivativeValue2 Interpolated derivative for second function
+ * \param[out] functionValue3 Interpolated value for third function
+ * \param[out] derivativeValue3 Interpolated derivative for third function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+ void
+ evaluateFunctionAndDerivative(T r,
+ T * functionValue1,
+ T * derivativeValue1,
+ T * functionValue2,
+ T * derivativeValue2,
+ T * functionValue3,
+ T * derivativeValue3) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable && funcIndex2 < numFuncInTable,
+ "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+ T t0;
+ T t1;
+ T t2;
+ T t3 gmx_unused;
+
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4*funcIndex0, tabIndex, &t0, &t1, &t2, &t3);
+ t1 = t0 + eps * t1;
+ *functionValue1 = fma( eps * T(halfSpacing_), t0 + t1, t2);
+ *derivativeValue1 = t1;
+
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4*funcIndex1, tabIndex, &t0, &t1, &t2, &t3);
+ t1 = t0 + eps * t1;
+ *functionValue2 = fma( eps * T(halfSpacing_), t0 + t1, t2);
+ *derivativeValue2 = t1;
+
+ gatherLoadBySimdIntTranspose<4*numFuncInTable>(ddfzMultiTableData_.data() + 4*funcIndex2, tabIndex, &t0, &t1, &t2, &t3);
+ t1 = t0 + eps * t1;
+ *functionValue3 = fma( eps * T(halfSpacing_), t0 + t1, t2);
+ *derivativeValue3 = t1;
+ }
+
+ /*! \brief Evaluate function value only, three table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 3
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam funcIndex2 Index of 3rd function to evaluate in table, default is 2
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function value
+ * \param[out] functionValue1 Interpolated value for first function
+ * \param[out] functionValue2 Interpolated value for second function
+ * \param[out] functionValue3 Interpolated value for third function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+ void
+ evaluateFunction(T r,
+ T * functionValue1,
+ T * functionValue2,
+ T * functionValue3) const
+ {
+ T der1 gmx_unused;
+ T der2 gmx_unused;
+ T der3 gmx_unused;
+
+ evaluateFunctionAndDerivative<numFuncInTable, funcIndex0, funcIndex1, funcIndex2>(r, functionValue1, &der1, functionValue2, &der2, functionValue3, &der3);
+ }
+
+ /*! \brief Evaluate function derivative only, three table functions
+ *
+ * This is a templated method where the template can be either real or SimdReal.
+ *
+ * \tparam numFuncInTable Number of separate functions in table, default is 3
+ * \tparam funcIndex0 Index of 1st function to evaluate in table, default is 0
+ * \tparam funcIndex1 Index of 2nd function to evaluate in table, default is 1
+ * \tparam funcIndex2 Index of 3rd function to evaluate in table, default is 2
+ * \tparam T Type (SimdReal or real) of lookup and result
+ * \param r Points for which to evaluate function derivative
+ * \param[out] derivativeValue1 Interpolated derivative for first function
+ * \param[out] derivativeValue2 Interpolated derivative for second function
+ * \param[out] derivativeValue3 Interpolated derivative for third function
+ *
+ * For debug builds we assert that the input values fall in the range
+ * specified when constructing the table.
+ */
+ template <int numFuncInTable = 3, int funcIndex0 = 0, int funcIndex1 = 1, int funcIndex2 = 2, typename T>
+ void
+ evaluateDerivative(T r,
+ T * derivativeValue1,
+ T * derivativeValue2,
+ T * derivativeValue3) const
+ {
+ rangeCheck(r);
+ GMX_ASSERT(numFuncInTable == numFuncInTable_, "Evaluation method not matching number of functions in table");
+ GMX_ASSERT(funcIndex0 < numFuncInTable && funcIndex1 < numFuncInTable && funcIndex2 < numFuncInTable,
+ "Function index not in range of the number of tables");
+
+ T rTable = r * T(tableScale_);
+ auto tabIndex = cvttR2I(rTable); // type is either std::int32_t or SimdInt32
+ T eps = rTable - trunc(rTable);
+
+ if (numFuncInTable == 3 && funcIndex0 == 0 && funcIndex1 == 1 && funcIndex2 == 2)
+ {
+ T t0A, t0B, t0C, t1A, t1B, t1C;
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data(), tabIndex, &t0A, &t0B);
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + 2, tabIndex, &t0C, &t1A);
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + 4, tabIndex, &t1B, &t1C);
+ *derivativeValue1 = fma(t1A-t0A, eps, t0A);
+ *derivativeValue2 = fma(t1B-t0B, eps, t0B);
+ *derivativeValue3 = fma(t1C-t0C, eps, t0C);
+ }
+ else
+ {
+ T t0, t1, t2;
+ // This is not ideal, but we need a version of gatherLoadUBySimdIntTranspose that
+ // only loads a single value from memory to implement it better (will be written)
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex0, tabIndex, &t0, &t2); // works for scalar T too
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex0, tabIndex + T(1), &t1, &t2); // works for scalar T too
+ *derivativeValue1 = fma(t1-t0, eps, t0);
+
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex1, tabIndex, &t0, &t2); // works for scalar T too
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex1, tabIndex + T(1), &t1, &t2); // works for scalar T too
+ *derivativeValue2 = fma(t1-t0, eps, t0);
+
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex2, tabIndex, &t0, &t2); // works for scalar T too
+ gatherLoadUBySimdIntTranspose<numFuncInTable>(derivativeMultiTableData_.data() + funcIndex2, tabIndex + T(1), &t1, &t2); // works for scalar T too
+ *derivativeValue3 = fma(t1-t0, eps, t0);
+ }
+ }
+
+ /*! \brief Return the table spacing (distance between points)
+ *
+ * You should never have to use this for normal code, but due to the
+ * way tables are constructed internally we need this in the unit tests
+ * to check relative tolerances over each interval.
+ *
+ * \return table spacing.
+ */
+ real
+ tableSpacing() const { return 1.0 / tableScale_; }
+
+ private:
+
+ std::size_t numFuncInTable_; //!< Number of separate tabluated functions
+ std::pair<real, real> range_; //!< Range for which table evaluation is allowed
+ real tableScale_; //!< Table scale (inverse of spacing between points)
+ real halfSpacing_; //!< 0.5*spacing (used for DDFZ table data)
+
+ //!< Derivative values only, with the third-derivative subtraction described in the class documentation.
+ std::vector<real> derivativeMultiTableData_;
+
+ /*! \brief Combined derivative, difference to next derivative, value, and zero.
+ *
+ * For table point i, this vector contains the four values:
+ * - derivative[i]
+ * - (derivative[i+1]-derivative[i])
+ * - value[i]
+ * - 0.0
+ *
+ * For the derivative terms we have subtracted the third-derivative term described
+ * in the main class documentation.
+ *
+ * This is typically more efficient than the individual tables, in particular
+ * when using SIMD. The result should be identical outside the class, so this
+ * is merely an internal implementation optimization. However, to allow
+ * aligned SIMD loads we need to use an aligned allocator for this container.
+ * We occasionally abbreviate this data as DDFZ.
+ */
+ std::vector<real, AlignedAllocator<real> > ddfzMultiTableData_;
+
+ // There should never be any reason to copy the table since it is read-only
+ GMX_DISALLOW_COPY_AND_ASSIGN(QuadraticSplineTable);
+};
+
+
+} // namespace gmx
+
+#endif // GMX_TABLES_QUADRATICSPLINETABLE_H
--- /dev/null
+/*
+ * 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 internal utility functions for spline tables
+ *
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#include "gmxpre.h"
+
+#include "splineutil.h"
+
+#include <cmath>
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+#include <vector>
+
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/real.h"
+#include "gromacs/utility/stringutil.h"
+
+namespace gmx
+{
+
+namespace internal
+{
+
+void
+throwUnlessDerivativeIsConsistentWithFunction(const std::function<double(double)> &function,
+ const std::function<double(double)> &derivative,
+ const std::pair<real, real> &range)
+{
+ // Since the numerical derivative will evaluate extra points
+ // we shrink the interval slightly to avoid calling the function with values
+ // outside the range specified.
+ double h = std::cbrt(GMX_DOUBLE_EPS); // ideal spacing
+ std::pair<double, double> newRange(range.first + h, range.second - h);
+ const int points = 1000; // arbitrary
+ double dx = (newRange.second - newRange.first) / points;
+ bool isConsistent = true;
+ double minFail = newRange.second;
+ double maxFail = newRange.first;
+
+ for (double x = newRange.first; x <= newRange.second; x += dx)
+ {
+ double analyticalDerivative = derivative(x);
+ double numericalDerivative = (function(x+h)-function(x-h))/(2*h);
+ double thirdDerivative = (derivative(x+h)-2.0*derivative(x)+derivative(x-h))/(h*h);
+
+ // We make two types of errors in numerical calculation of the derivative:
+ // - The truncation error: eps * |f| / h
+ // - The rounding error: h * h * |f'''| / 6.0
+ double expectedErr = GMX_DOUBLE_EPS*std::abs(function(x))/h + h*h*std::abs(thirdDerivative)/6.0;
+
+ // To avoid triggering false errors because of compiler optimization or numerical issues
+ // in the function evalulation we allow an extra factor of 10 in the expected error
+ if (std::abs(analyticalDerivative-numericalDerivative) > 10.0*expectedErr)
+ {
+ isConsistent = false;
+ minFail = std::min(minFail, x);
+ maxFail = std::max(maxFail, x);
+ }
+ }
+
+ if (!isConsistent)
+ {
+ GMX_THROW(InconsistentInputError(formatString("Derivative inconsistent with analytical function in range [%d,%d]", minFail, maxFail)));
+ }
+}
+
+
+void
+throwUnlessDerivativeIsConsistentWithFunction(ConstArrayRef<double> function,
+ ConstArrayRef<double> derivative,
+ double inputSpacing,
+ const std::pair<real, real> &range)
+{
+ std::size_t firstIndex = range.first / inputSpacing;
+ std::size_t lastIndex = range.second / inputSpacing;
+ bool isConsistent = true;
+ std::size_t minFail = lastIndex;
+ std::size_t maxFail = firstIndex;
+
+ // The derivative will access one extra point before/after each point, so reduce interval
+ for (std::size_t i = firstIndex + 1; (i + 1) < lastIndex; i++)
+ {
+ double inputDerivative = derivative[i];
+ double numericalDerivative = (function[i+1] - function[i-1]) / (2.0 * inputSpacing);
+ double thirdDerivative = (derivative[i+1] - 2.0*derivative[i] + derivative[i-1])/(inputSpacing * inputSpacing);
+
+ // We make two types of errors in numerical calculation of the derivative:
+ // - The truncation error: eps * |f| / h
+ // - The rounding error: h * h * |f'''| / 6.0
+ double expectedErr = GMX_DOUBLE_EPS*std::abs(function[i])/inputSpacing + inputSpacing*inputSpacing*std::abs(thirdDerivative)/6.0;
+
+ // To avoid triggering false errors because of compiler optimization or numerical issues
+ // in the function evalulation we allow an extra factor of 10 in the expected error
+ if (std::abs(inputDerivative-numericalDerivative) > 10.0*expectedErr)
+ {
+ isConsistent = false;
+ minFail = std::min(minFail, i);
+ maxFail = std::max(maxFail, i);
+ }
+ }
+ if (!isConsistent)
+ {
+ GMX_THROW(InconsistentInputError(formatString("Derivative inconsistent with numerical vector for elements %d-%d", minFail+1, maxFail+1)));
+ }
+}
+
+
+/*! \brief Update minQuotient if the ratio of this function value and its second derivative is smaller
+ *
+ * This is a utility function used in the functions to find the smallest quotient
+ * in a range.
+ *
+ * \param[in] previousPoint Value of function at x-h.
+ * \param[in] thisPoint Value of function at x.
+ * \param[in] nextPoint Value of function at x+h.
+ * \param[in] spacing Value of h.
+ * \param[inout] minQuotient Current minimum of such quotients, updated if this quotient is smaller.
+ */
+static void
+updateMinQuotientOfFunctionAndSecondDerivative(double previousPoint,
+ double thisPoint,
+ double nextPoint,
+ double spacing,
+ double * minQuotient)
+{
+ double value = std::abs( thisPoint );
+ double secondDerivative = std::abs( (previousPoint - 2.0 * thisPoint + nextPoint) / (spacing * spacing ) );
+
+ // Make sure we do not divide by zero. This limit is arbitrary,
+ // but it doesnt matter since this point will have a very large value,
+ // and the whole routine is searching for the smallest value.
+ secondDerivative = std::max(secondDerivative, static_cast<double>(std::sqrt(GMX_REAL_MIN)));
+
+ *minQuotient = std::min(*minQuotient, value / secondDerivative);
+}
+
+
+real
+findSmallestQuotientOfFunctionAndSecondDerivative(const std::function<double(double)> &f,
+ const std::pair<real, real> &range)
+{
+ // Since the numerical second derivative will evaluate extra points
+ // we shrink the interval slightly to avoid calling the function with values
+ // outside the range specified.
+ double h = std::pow( GMX_DOUBLE_EPS, 0.25 );
+ std::pair<double, double> newRange(range.first + h, range.second - h);
+ const int points = 1000; // arbitrary
+ double dx = (newRange.second - newRange.first) / points;
+ double minQuotient = GMX_REAL_MAX;
+
+ for (double x = newRange.first; x <= newRange.second; x += dx)
+ {
+ updateMinQuotientOfFunctionAndSecondDerivative(f(x-h), f(x), f(x+h), h, &minQuotient);
+ }
+ return static_cast<real>(minQuotient);
+}
+
+
+
+
+
+
+real
+findSmallestQuotientOfFunctionAndSecondDerivative(ConstArrayRef<double> function,
+ double inputSpacing,
+ const std::pair<real, real> &range)
+{
+
+ std::size_t firstIndex = range.first / inputSpacing;
+ std::size_t lastIndex = range.second / inputSpacing;
+ double minQuotient = GMX_REAL_MAX;
+
+ for (std::size_t i = firstIndex + 1; (i + 1) < lastIndex; i++)
+ {
+ updateMinQuotientOfFunctionAndSecondDerivative(function[i-1], function[i], function[i+1], inputSpacing, &minQuotient);
+ }
+ return static_cast<real>(minQuotient);
+}
+
+
+
+/*! \brief Update minQuotient if the ratio of this function value and its third derivative is smaller
+ *
+ * This is a utility function used in the functions to find the smallest quotient
+ * in a range.
+ *
+ * \param[in] previousPreviousPoint Value of function at x-2h.
+ * \param[in] previousPoint Value of function at x-h.
+ * \param[in] thisPoint Value of function at x.
+ * \param[in] nextPoint Value of function at x+h.
+ * \param[in] nextNextPoint Value of function at x+2h.
+ * \param[in] spacing Value of h.
+ * \param[inout] minQuotient Current minimum of such quotients, updated if this quotient is smaller.
+ */
+static void
+updateMinQuotientOfFunctionAndThirdDerivative(double previousPreviousPoint,
+ double previousPoint,
+ double thisPoint,
+ double nextPoint,
+ double nextNextPoint,
+ double spacing,
+ double * minQuotient)
+{
+ double value = std::abs( thisPoint );
+ double thirdDerivative = std::abs((nextNextPoint - 2 * nextPoint + 2 * previousPoint - previousPreviousPoint) / (2 * spacing * spacing * spacing));
+
+ // Make sure we do not divide by zero. This limit is arbitrary,
+ // but it doesnt matter since this point will have a very large value,
+ // and the whole routine is searching for the smallest value.
+ thirdDerivative = std::max(thirdDerivative, static_cast<double>(std::sqrt(GMX_REAL_MIN)));
+
+ *minQuotient = std::min(*minQuotient, value / thirdDerivative);
+}
+
+
+real
+findSmallestQuotientOfFunctionAndThirdDerivative(const std::function<double(double)> &f,
+ const std::pair<real, real> &range)
+{
+ // Since the numerical second derivative will evaluate extra points
+ // we shrink the interval slightly to avoid calling the function with values
+ // outside the range specified.
+ double h = std::pow( GMX_DOUBLE_EPS, 0.2 ); // optimal spacing for 3rd derivative
+ std::pair<double, double> newRange(range.first + 2*h, range.second - 2*h);
+ const int points = 1000; // arbitrary
+ double dx = (newRange.second - newRange.first) / points;
+ double minQuotient = GMX_REAL_MAX;
+
+ for (double x = newRange.first; x <= newRange.second; x += dx)
+ {
+ updateMinQuotientOfFunctionAndThirdDerivative(f(x-2*h), f(x-h), f(x), f(x+h), f(x+2*h), h, &minQuotient);
+ }
+ return static_cast<real>(minQuotient);
+}
+
+
+real
+findSmallestQuotientOfFunctionAndThirdDerivative(ConstArrayRef<double> function,
+ double inputSpacing,
+ const std::pair<real, real> &range)
+{
+
+ std::size_t firstIndex = range.first / inputSpacing;
+ std::size_t lastIndex = range.second / inputSpacing;
+ double minQuotient = GMX_REAL_MAX;
+
+ for (std::size_t i = firstIndex + 2; (i + 2) < lastIndex; i++)
+ {
+ updateMinQuotientOfFunctionAndThirdDerivative(function[i-2], function[i-1], function[i], function[i+1], function[i+2], inputSpacing, &minQuotient);
+ }
+ return static_cast<real>(minQuotient);
+}
+
+
+
+std::vector<double>
+vectorSecondDerivative(ConstArrayRef<double> f, double spacing)
+{
+ if (f.size() < 5)
+ {
+ GMX_THROW(APIError("Too few points in vector for 5-point differentiation"));
+ }
+
+ std::vector<double> d(f.size());
+ std::size_t i;
+
+ // 5-point formula evaluated for points 0,1
+ i = 0;
+ d[i] = (11 * f[i+4] - 56 * f[i+3] + 114 * f[i+2] - 104 * f[i+1] + 35 * f[i]) / ( 12 * spacing * spacing);
+ i = 1;
+ d[i] = (-f[i+3] + 4 * f[i+2] + 6 * f[i+1] - 20 * f[i] + 11 * f[i-1]) / ( 12 * spacing * spacing);
+
+ for (std::size_t i = 2; i < d.size() - 2; i++)
+ {
+ // 5-point formula evaluated for central point (2)
+ d[i] = (-f[i+2] + 16 * f[i+1] - 30 * f[i] + 16 * f[i-1] - f[i-2]) / (12 * spacing * spacing);
+ }
+
+ // 5-point formula evaluated for points 3,4
+ i = d.size() - 2;
+ d[i] = (11 * f[i+1] - 20 * f[i] + 6 * f[i-1] + 4 * f[i-2] - f[i-3]) / ( 12 * spacing * spacing);
+ i = d.size() - 1;
+ d[i] = (35 * f[i] - 104 * f[i-1] + 114 * f[i-2] - 56 * f[i-3] + 11 * f[i-4]) / ( 12 * spacing * spacing);
+
+ return d;
+}
+
+
+
+} // namespace internal
+
+} // namespace gmx
--- /dev/null
+/*
+ * 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
+ * Declares internal utility functions for spline tables
+ *
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#ifndef GMX_TABLES_SPLINEUTIL_H
+#define GMX_TABLES_SPLINEUTIL_H
+
+#include <functional>
+#include <utility>
+#include <vector>
+
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/real.h"
+
+namespace gmx
+{
+
+namespace internal
+{
+
+/*! \brief Ensure analytical derivative is the derivative of analytical function.
+ *
+ * This routine evaluates the numerical derivative of the function for
+ * a few (1000) points in the interval and checks that the relative difference
+ * between numerical and analytical derivative is within the expected error
+ * for the numerical derivative approximation we use.
+ *
+ * The main point of this routine is to make sure the user has not made a
+ * mistake or sign error when defining the functions.
+ *
+ * \param function Analytical function to differentiate
+ * \param derivative Analytical derivative to compare with
+ * \param range Range to test
+ *
+ * \throws If the provided derivative does not seem to match the function.
+ *
+ * \note The function/derivative are always double-valued to avoid accuracy loss.
+ */
+void
+throwUnlessDerivativeIsConsistentWithFunction(const std::function<double(double)> &function,
+ const std::function<double(double)> &derivative,
+ const std::pair<real, real> &range);
+
+/*! \brief Ensure vector of derivative values is the derivative of function vector.
+ *
+ * This routine differentiates a vector of numerical values and checks
+ * that the relative difference to a provided vector of numerical derivatives
+ * is smaller than the expected error from the numerical differentiation.
+ *
+ * The main point of this routine is to make sure the user has not made a
+ * mistake or sign error when defining the functions.
+ *
+ * To avoid problems if the vectors change from zero to finite values at the
+ * start/end of the interval, we only check inside the range requested.
+ *
+ * \param function Numerical function value vector to differentiate
+ * \param derivative Numerical derivative vector to compare with
+ * \param inputSpacing Distance between input points
+ * \param range Range to test
+ *
+ * \throws If the provided derivative does not seem to match the function.
+ *
+ * \note The function/derivative vectors and spacing are always double-valued
+ * to avoid accuracy loss.
+ */
+void
+throwUnlessDerivativeIsConsistentWithFunction(ConstArrayRef<double> function,
+ ConstArrayRef<double> derivative,
+ double inputSpacing,
+ const std::pair<real, real> &range);
+
+
+
+
+/*! \brief Find smallest quotient between analytical function and its 2nd derivative
+ *
+ * Used to calculate spacing for quadratic spline tables. This function divides the
+ * function value by the second derivative (or a very small number when that is zero),
+ * and returns the smallest such quotient found in the range.
+ *
+ * Our quadratic tables corresponds to linear interpolation of the derivative,
+ * which means the derivative will typically have larger error than the value
+ * when interpolating. The spacing required to reach a particular relative
+ * tolerance in the derivative depends on the quotient between the first
+ * derivative and the third derivative of the function itself.
+ *
+ * You should call this routine with the analytical derivative as the "function"
+ * parameter, and the quotient between "function and second derivative" will
+ * then correspond to the quotient bewteen the derivative and the third derivative
+ * of the actual function we want to tabulate.
+ *
+ * Since all functions that can be tabulated efficiently are reasonably smooth,
+ * we simply check 1,000 points in the interval rather than bother about
+ * implementing any complicated global optimization scheme.
+ *
+ * \param f Analytical function
+ * \param range Interval
+ *
+ * \return Smallest quotient found in range.
+ *
+ * \note The function is always double-valued to avoid accuracy loss.
+ */
+real
+findSmallestQuotientOfFunctionAndSecondDerivative(const std::function<double(double)> &f,
+ const std::pair<real, real> &range);
+
+
+
+
+
+/*! \brief Find smallest quotient between vector of values and its 2nd derivative
+ *
+ * Used to calculate spacing for quadratic spline tables. This function divides the
+ * function value by the second derivative (or a very small number when that is zero),
+ * and returns the smallest such quotient found in the range.
+ *
+ * Our quadratic tables corresponds to linear interpolation of the derivative,
+ * which means the derivative will typically have larger error than the value
+ * when interpolating. The spacing required to reach a particular relative
+ * tolerance in the derivative depends on the quotient between the first
+ * derivative and the third derivative of the function itself.
+ *
+ * You should call this routine with the analytical derivative as the "function"
+ * parameter, and the quotient between "function and second derivative" will
+ * then correspond to the quotient bewteen the derivative and the third derivative
+ * of the actual function we want to tabulate.
+ *
+ * \param function Vector with function values
+ * \param inputSpacing Spacing between function values
+ * \param range Interval to check
+ *
+ * \return Smallest quotient found in range.
+ *
+ * \note The function vector and input spacing are always double-valued to
+ * avoid accuracy loss.
+ */
+real
+findSmallestQuotientOfFunctionAndSecondDerivative(ConstArrayRef<double> function,
+ double inputSpacing,
+ const std::pair<real, real> &range);
+
+
+
+
+
+/*! \brief Find smallest quotient between analytical function and its 3rd derivative
+ *
+ * Used to calculate table spacing. This function divides the function value
+ * by the second derivative (or a very small number when that is zero), and
+ * returns the smallest such quotient found in the range.
+ *
+ * Our quadratic tables corresponds to linear interpolation of the derivative,
+ * which means the derivative will typically have larger error than the value
+ * when interpolating. The spacing required to reach a particular relative
+ * tolerance in the derivative depends on the quotient between the first
+ * derivative and the third derivative of the function itself.
+ *
+ * You should call this routine with the analytical derivative as the "function"
+ * parameter, and the quotient between "function and second derivative" will
+ * then correspond to the quotient bewteen the derivative and the third derivative
+ * of the actual function we want to tabulate.
+ *
+ * Since all functions that can be tabulated efficiently are reasonably smooth,
+ * we simply check 1,000 points in the interval rather than bother about
+ * implementing any complicated global optimization scheme.
+ *
+ * \param f Analytical function
+ * \param range Interval
+ *
+ * \return Smallest quotient found in range.
+ *
+ * \note The function is always double-valued to avoid accuracy loss.
+ */
+real
+findSmallestQuotientOfFunctionAndThirdDerivative(const std::function<double(double)> &f,
+ const std::pair<real, real> &range);
+
+
+
+
+/*! \brief Find smallest quotient between function and 2nd derivative (vectors)
+ *
+ * Used to calculate table spacing. This function divides the function value
+ * by the second derivative (or a very small number when that is zero), and
+ * returns the smallest such quotient found in the range.
+ *
+ * Our quadratic tables corresponds to linear interpolation of the derivative,
+ * which means the derivative will typically have larger error than the value
+ * when interpolating. The spacing required to reach a particular relative
+ * tolerance in the derivative depends on the quotient between the first
+ * derivative and the third derivative of the function itself.
+ *
+ * You should call this routine with the analytical derivative as the "function"
+ * parameter, and the quotient between "function and second derivative" will
+ * then correspond to the quotient bewteen the derivative and the third derivative
+ * of the actual function we want to tabulate.
+ *
+ * \param function Vector with function values
+ * \param inputSpacing Spacing between function values
+ * \param range Interval to check
+ *
+ * \return Smallest quotient found in range.
+ *
+ * \note The function vector and input spacing are always double-valued to
+ * avoid accuracy loss.
+ */
+real
+findSmallestQuotientOfFunctionAndThirdDerivative(ConstArrayRef<double> function,
+ double inputSpacing,
+ const std::pair<real, real> &range);
+
+
+/*! \brief Calculate second derivative of vector and return vector of same length
+ *
+ * 5-point approximations are used, with endpoints using non-center interpolation.
+ *
+ * \param f Vector (function) for which to calculate second derivative
+ * \param spacing Spacing of input data.
+ *
+ * \throws If the input vector has fewer than five data points.
+ *
+ * \note This function always uses double precision arguments since it is meant
+ * to be used on raw user input data for tables, where we want to avoid
+ * accuracy loss (since differentiation can be numerically fragile).
+ */
+std::vector<double>
+vectorSecondDerivative(ConstArrayRef<double> f,
+ double spacing);
+
+
+/*! \brief Copy (temporary) table data into aligned multiplexed vector
+ *
+ * This routine takes the temporary data generated for a single table
+ * and writes multiplexed output into a multiple-table-data vector.
+ * If the output vector is empty we will resize it to fit the data, and
+ * otherwise we assert the size is correct to add out input data.
+ *
+ * \tparam T Type of container for input data
+ * \tparam U Type of container for output data
+ *
+ * \param[in] inputData Input data for single table
+ * \param[inout] multiplexedOutputData Multiplexed output vector, many tables.
+ * \param[in] valuesPerTablePoint Number of real values for each table point,
+ * for instance 4 in DDFZ tables.
+ * \param[in] numTables Number of tables mixed into multiplexed output
+ * \param[in] thisTableIndex Index of this table in multiplexed output
+ *
+ * \note The output container type can be different from the input since the latter
+ * sometimes uses an aligned allocator so the data can be loaded efficiently
+ * in the GROMACS nonbonded kernels.
+ */
+template<class T, class U>
+void
+fillMultiplexedTableData(const T inputData,
+ U * multiplexedOutputData,
+ std::size_t valuesPerTablePoint,
+ std::size_t numTables,
+ std::size_t thisTableIndex)
+{
+ if (multiplexedOutputData->size() == 0)
+ {
+ multiplexedOutputData->resize( inputData.size() * numTables );
+ }
+ else
+ {
+ GMX_ASSERT(inputData.size() * numTables == multiplexedOutputData->size(),
+ "Size mismatch when multiplexing table data");
+ }
+
+ GMX_ASSERT(inputData.size() % valuesPerTablePoint == 0,
+ "Input table size must be a multiple of valuesPerTablePoint");
+
+ std::size_t points = inputData.size() / valuesPerTablePoint;
+
+ for (std::size_t i = 0; i < points; i++)
+ {
+ std::size_t inputOffset = valuesPerTablePoint * i;
+ std::size_t outputOffset = valuesPerTablePoint * ( numTables * i + thisTableIndex );
+
+ for (std::size_t j = 0; j < valuesPerTablePoint; j++)
+ {
+ (*multiplexedOutputData)[outputOffset + j] = inputData[inputOffset + j];
+ }
+ }
+}
+
+
+} // namespace internal
+
+} // namespace gmx
+
+#endif // GMX_TABLES_SPLINEUTIL_H
--- /dev/null
+/*
+ * 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 structures for analytical or numerical input data to construct tables
+ *
+ * \inlibraryapi
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+
+#ifndef GMX_TABLES_TABLEINPUT_H
+#define GMX_TABLES_TABLEINPUT_H
+
+#include <functional>
+#include <vector>
+
+#include "gromacs/utility/arrayref.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief Specification for analytical table function (name, function, derivative)
+ */
+struct
+AnalyticalSplineTableInput
+{
+ const std::string &desc; //!< \libinternal Brief description of function
+ std::function<double(double)> function; //!< \libinternal Analytical form of function
+ std::function<double(double)> derivative; //!< \libinternal Analytical derivative
+};
+
+/*! \libinternal \brief Specification for vector table function (name, function, derivative, spacing)
+ */
+struct
+NumericalSplineTableInput
+{
+ const std::string &desc; //!< \libinternal Brief description of function
+ ConstArrayRef<double> function; //!< \libinternal Vector with function values
+ ConstArrayRef<double> derivative; //!< \libinternal Vector with derivative values
+ double spacing; //!< \libinternal Distance between data points
+};
+
+
+} // namespace gmx
+
+
+#endif // GMX_TABLES_TABLEINPUT_H
--- /dev/null
+#
+# 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(TableUnitTests table-test
+ splinetable.cpp
+ )
--- /dev/null
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * 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.
+ *
+ * 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 simple math functions.eval
+ *
+ * \author Erik Lindahl <erik.lindahl@gmail.com>
+ * \ingroup module_tables
+ */
+#include "gmxpre.h"
+
+#include <cmath>
+
+#include <algorithm>
+#include <functional>
+#include <utility>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/math/utilities.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/simd/simd.h"
+#include "gromacs/tables/cubicsplinetable.h"
+#include "gromacs/tables/quadraticsplinetable.h"
+
+#include "testutils/testasserts.h"
+#include "testutils/testoptions.h"
+
+
+namespace gmx
+{
+
+namespace test
+{
+
+namespace
+{
+
+class SplineTableTestBase : public ::testing::Test
+{
+ public:
+ static int s_testPoints_; //!< Number of points to use. Public so we can set it as option
+};
+
+int
+SplineTableTestBase::s_testPoints_ = 100;
+
+/*! \cond */
+/*! \brief Command-line option to adjust the number of points used to test SIMD math functions. */
+GMX_TEST_OPTIONS(SplineTableTestOptions, options)
+{
+ options->addOption(::gmx::IntegerOption("npoints")
+ .store(&SplineTableTestBase::s_testPoints_)
+ .description("Number of points to test for spline table functions"));
+}
+/*! \endcond */
+
+
+
+
+/*! \brief Test fixture for table comparision with analytical/numerical functions */
+template <typename T>
+class SplineTableTest : public SplineTableTestBase
+{
+ public:
+ SplineTableTest() : tolerance_(T::defaultTolerance) {}
+
+ /*! \brief Set a new tolerance to be used in table function comparison
+ *
+ * \param tol New tolerance to use
+ */
+ void
+ setTolerance(real tol) { tolerance_ = tol; }
+
+ //! \cond internal
+ /*! \internal \brief
+ * Assertion predicate formatter for comparing table with function/derivative
+ */
+ template<int numFuncInTable = 1, int funcIndex = 0>
+ void
+ testSplineTableAgainstFunctions(const std::string &desc,
+ const std::function<double(double)> &refFunc,
+ const std::function<double(double)> &refDer,
+ const T &table,
+ const std::pair<real, real> &testRange);
+ //! \endcond
+
+ private:
+ real tolerance_; //!< Tolerance to use
+};
+
+template <class T>
+template<int numFuncInTable, int funcIndex>
+void
+SplineTableTest<T>::testSplineTableAgainstFunctions(const std::string &desc,
+ const std::function<double(double)> &refFunc,
+ const std::function<double(double)> &refDer,
+ const T &table,
+ const std::pair<real, real> &testRange)
+{
+ real dx = (testRange.second - testRange.first) / s_testPoints_;
+
+ FloatingPointTolerance funcTolerance(relativeToleranceAsFloatingPoint(0.0, tolerance_));
+
+ for (real x = testRange.first; x < testRange.second; x += dx)
+ {
+ real h = std::sqrt(GMX_REAL_EPS);
+ real secondDerivative = (refDer(x+h)-refDer(x))/h;
+
+ real testFuncValue;
+ real testDerValue;
+
+ table.template evaluateFunctionAndDerivative<numFuncInTable, funcIndex>(x, &testFuncValue, &testDerValue);
+
+ // Check that we get the same values from function/derivative-only methods
+ real tmpFunc, tmpDer;
+
+ table.template evaluateFunction<numFuncInTable, funcIndex>(x, &tmpFunc);
+
+ table.template evaluateDerivative<numFuncInTable, funcIndex>(x, &tmpDer);
+
+ if (testFuncValue != tmpFunc)
+ {
+ ADD_FAILURE()
+ << "Interpolation inconsistency for table " << desc << std::endl
+ << numFuncInTable << " function(s) in table, testing index " << funcIndex << std::endl
+ << "First failure at x = " << x << std::endl
+ << "Function value when evaluating function & derivative: " << testFuncValue << std::endl
+ << "Function value when evaluating only function: " << tmpFunc << std::endl;
+ return;
+ }
+ if (testDerValue != tmpDer)
+ {
+ ADD_FAILURE()
+ << "Interpolation inconsistency for table " << desc << std::endl
+ << numFuncInTable << " function(s) in table, testing index " << funcIndex << std::endl
+ << "First failure at x = " << x << std::endl
+ << "Derivative value when evaluating function & derivative: " << testDerValue << std::endl
+ << "Derivative value when evaluating only derivative: " << tmpDer << std::endl;
+ return;
+ }
+
+ // There are two sources of errors that we need to account for when checking the values,
+ // and we only fail the test if both of these tolerances are violated:
+ //
+ // 1) First, we have the normal relative error of the test vs. reference value. For this
+ // we use the normal testutils relative tolerance checking.
+ // However, there is an additional source of error: When we calculate the forces we
+ // use average higher derivatives over the interval to improve accuracy, but this
+ // also means we won't reproduce values at table points exactly. This is usually not
+ // an issue since the tolerances we have are much larger, but when the reference derivative
+ // value is exactly zero the relative error will be infinite. To account for this, we
+ // extract the spacing from the table and evaluate the reference derivative at a point
+ // this much larger too, and use the largest of the two values as the reference
+ // magnitude for the derivative when setting the relative tolerance.
+ // Note that according to the table function definitions, we should be allowed to evaluate
+ // it one table point beyond the range (this is done already for construction).
+ //
+ // 2) Second, due to the loss-of-accuracy when calculating the index through rtable
+ // there is an internal absolute tolerance that we can calculate.
+ // The source of this error is the subtraction eps=rtab-[rtab], which leaves an
+ // error proportional to eps_machine*rtab=eps_machine*x*tableScale.
+ // To lowest order, the term in the function and derivative values (respectively) that
+ // are proportional to eps will be the next-higher derivative multiplied by the spacing.
+ // This means the truncation error in the value is derivative*x*eps_machine, and in the
+ // derivative the error is 2nd_derivative*x*eps_machine.
+
+ real refFuncValue = refFunc(x);
+ real refDerValue = refDer(x);
+ real nextRefDerValue = refDer(x + table.tableSpacing());
+
+ real derMagnitude = std::max( std::abs(refDerValue), std::abs(nextRefDerValue));
+
+ // Since the reference magnitude will change over each interval we need to re-evaluate
+ // the derivative tolerance inside the loop.
+ FloatingPointTolerance derTolerance(relativeToleranceAsFloatingPoint(derMagnitude, tolerance_));
+
+ FloatingPointDifference funcDiff(refFuncValue, testFuncValue);
+ FloatingPointDifference derDiff(refDerValue, testDerValue);
+
+ real allowedAbsFuncErr = std::abs(refDerValue) * x * GMX_REAL_EPS;
+ real allowedAbsDerErr = std::abs(secondDerivative) * x * GMX_REAL_EPS;
+
+ if ((!funcTolerance.isWithin(funcDiff) && funcDiff.asAbsolute() > allowedAbsFuncErr) ||
+ (!derTolerance.isWithin(derDiff) && derDiff.asAbsolute() > allowedAbsDerErr))
+ {
+ ADD_FAILURE()
+ << "Failing comparison with function for table " << desc << std::endl
+ << numFuncInTable << " function(s) in table, testing index " << funcIndex << std::endl
+ << "Test range is ( " << testRange.first << " , " << testRange.second << " ) " << std::endl
+ << "Tolerance = " << tolerance_ << std::endl
+ << "First failure at x = " << x << std::endl
+ << "Reference function = " << refFuncValue << std::endl
+ << "Test table function = " << testFuncValue << std::endl
+ << "Reference derivative = " << refDerValue << std::endl
+ << "Test table derivative = " << testDerValue << std::endl;
+ return;
+ }
+ }
+}
+
+
+/*! \brief Function similar to coulomb electrostatics
+ *
+ * \param r argument
+ * \return r^-1
+ */
+double
+coulombFunction(double r)
+{
+ return 1.0/r;
+}
+
+/*! \brief Derivative (not force) of coulomb electrostatics
+ *
+ * \param r argument
+ * \return -r^-2
+ */
+double
+coulombDerivative(double r)
+{
+ return -1.0/(r*r);
+}
+
+/*! \brief Function similar to power-6 Lennard-Jones dispersion
+ *
+ * \param r argument
+ * \return r^-6
+ */
+double
+lj6Function(double r)
+{
+ return std::pow(r, -6.0);
+}
+
+/*! \brief Derivative (not force) of the power-6 Lennard-Jones dispersion
+ *
+ * \param r argument
+ * \return -6.0*r^-7
+ */
+double
+lj6Derivative(double r)
+{
+ return -6.0*std::pow(r, -7.0);
+}
+
+/*! \brief Function similar to power-12 Lennard-Jones repulsion
+ *
+ * \param r argument
+ * \return r^-12
+ */
+double
+lj12Function(double r)
+{
+ return std::pow(r, -12.0);
+}
+
+/*! \brief Derivative (not force) of the power-12 Lennard-Jones repulsion
+ *
+ * \param r argument
+ * \return -12.0*r^-13
+ */
+double
+lj12Derivative(double r)
+{
+ return -12.0*std::pow(r, -13.0);
+}
+
+/*! \brief The sinc function, sin(r)/r
+ *
+ * \param r argument
+ * \return sin(r)/r
+ */
+double
+sincFunction(double r)
+{
+ return std::sin(r)/r;
+}
+
+/*! \brief Derivative of the sinc function
+ *
+ * \param r argument
+ * \return derivative of sinc, (r*cos(r)-sin(r))/r^2
+ */
+double
+sincDerivative(double r)
+{
+ return (r*std::cos(r)-std::sin(r))/(r*r);
+}
+
+/*! \brief Function for the direct-space PME correction to 1/r
+ *
+ * \param r argument
+ * \return PME correction function, erf(r)/r
+ */
+double
+pmeCorrFunction(double r)
+{
+ if (r == 0)
+ {
+ return 2.0/std::sqrt(M_PI);
+ }
+ else
+ {
+ return std::erf(r)/r;
+ }
+}
+
+/*! \brief Derivative of the direct-space PME correction to 1/r
+ *
+ * \param r argument
+ * \return Derivative of the PME correction function.
+ */
+double
+pmeCorrDerivative(double r)
+{
+ if (r == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ return (2.0*std::exp(-r*r)/std::sqrt(3.14159265358979323846)*r-erf(r))/(r*r);
+ }
+}
+
+/*! \brief Typed-test list. We test QuadraticSplineTable and CubicSplineTable
+ */
+typedef ::testing::Types<QuadraticSplineTable, CubicSplineTable> SplineTableTypes;
+TYPED_TEST_CASE(SplineTableTest, SplineTableTypes);
+
+
+TYPED_TEST(SplineTableTest, HandlesIncorrectInput)
+{
+ // negative range
+ EXPECT_THROW_GMX(TypeParam( {{"LJ12", lj12Function, lj12Derivative}}, {-1.0, 0.0}), gmx::InvalidInputError);
+
+ // Too small range
+ EXPECT_THROW_GMX(TypeParam( {{"LJ12", lj12Function, lj12Derivative}}, {1.0, 1.00001}), gmx::InvalidInputError);
+
+ // bad tolerance
+ EXPECT_THROW_GMX(TypeParam( {{"LJ12", lj12Function, lj12Derivative}}, {1.0, 2.0}, 1e-20), gmx::ToleranceError);
+
+ // Range is so close to 0.0 that table would require >1e6 points
+ EXPECT_THROW_GMX(TypeParam( {{"LJ12", lj12Function, lj12Derivative}}, {1e-4, 2.0}), gmx::ToleranceError);
+
+ // mismatching function/derivative
+ EXPECT_THROW_GMX(TypeParam( { {"BadLJ12", lj12Derivative, lj12Function}}, {1.0, 2.0}), gmx::InconsistentInputError);
+}
+
+
+#ifndef NDEBUG
+TYPED_TEST(SplineTableTest, CatchesOutOfRangeValues)
+{
+ TypeParam table( {{"LJ12", lj12Function, lj12Derivative}}, {0.2, 1.0});
+ real x, func, der;
+
+ x = -GMX_REAL_EPS;
+ EXPECT_THROW_GMX(table.evaluateFunctionAndDerivative(x, &func, &der), gmx::RangeError);
+
+ x = 1.0;
+ EXPECT_THROW_GMX(table.evaluateFunctionAndDerivative(x, &func, &der), gmx::RangeError);
+}
+#endif
+
+
+TYPED_TEST(SplineTableTest, Sinc)
+{
+ std::pair<real, real> range(0.1, 10);
+
+ TypeParam sincTable( {{"Sinc", sincFunction, sincDerivative}}, range);
+
+ TestFixture::testSplineTableAgainstFunctions("Sinc", sincFunction, sincDerivative, sincTable, range);
+}
+
+
+TYPED_TEST(SplineTableTest, LJ12)
+{
+ std::pair<real, real> range(0.2, 2.0);
+
+ TypeParam lj12Table( {{"LJ12", lj12Function, lj12Derivative}}, range);
+
+ TestFixture::testSplineTableAgainstFunctions("LJ12", lj12Function, lj12Derivative, lj12Table, range);
+}
+
+
+TYPED_TEST(SplineTableTest, PmeCorrection)
+{
+ std::pair<real, real> range(0.0, 4.0);
+ real tolerance = 1e-5;
+
+ TypeParam pmeCorrTable( {{"PMECorr", pmeCorrFunction, pmeCorrDerivative}}, range, tolerance);
+
+ TestFixture::setTolerance(tolerance);
+ TestFixture::testSplineTableAgainstFunctions("PMECorr", pmeCorrFunction, pmeCorrDerivative, pmeCorrTable, range);
+}
+
+
+
+TYPED_TEST(SplineTableTest, HandlesIncorrectNumericalInput)
+{
+ // Lengths do not match
+ std::vector<double> functionValues(10);
+ std::vector<double> derivativeValues(20);
+ EXPECT_THROW_GMX(TypeParam( {{"EmptyVectors", functionValues, derivativeValues, 0.001}},
+ {1.0, 2.0}), gmx::InconsistentInputError);
+
+ // Upper range is 2.0, spacing 0.1. This requires at least 21 points. Make sure we get an error for 20.
+ functionValues.resize(20);
+ derivativeValues.resize(20);
+ EXPECT_THROW_GMX(TypeParam( {{"EmptyVectors", functionValues, derivativeValues, 0.1}},
+ {1.0, 2.0}), gmx::InconsistentInputError);
+
+ // Create some test data
+ functionValues.clear();
+ derivativeValues.clear();
+
+ std::vector<double> badDerivativeValues;
+ double spacing = 1e-3;
+
+ for (std::size_t i = 0; i < 1001; i++)
+ {
+ double x = i * spacing;
+ double func = (x >= 0.1) ? lj12Function(x) : 0.0;
+ double der = (x >= 0.1) ? lj12Derivative(x) : 0.0;
+
+ functionValues.push_back(func);
+ derivativeValues.push_back(der);
+ badDerivativeValues.push_back(-der);
+ }
+
+ // Derivatives not consistent with function
+ EXPECT_THROW_GMX(TypeParam( {{"NumericalBadLJ12", functionValues, badDerivativeValues, spacing}},
+ {0.2, 1.0}), gmx::InconsistentInputError);
+
+ // Spacing 1e-3 is not sufficient for r^-12 in range [0.1,1.0]
+ // Make sure we get a tolerance error
+ EXPECT_THROW_GMX(TypeParam( {{"NumericalLJ12", functionValues, derivativeValues, spacing}},
+ {0.2, 1.0}), gmx::ToleranceError);
+}
+
+
+TYPED_TEST(SplineTableTest, NumericalInputPmeCorr)
+{
+ std::pair<real, real> range(0.0, 4.0);
+ std::vector<double> functionValues;
+ std::vector<double> derivativeValues;
+
+ double inputSpacing = 1e-3;
+ real tolerance = 1e-5;
+
+ // We only need data up to the argument 4.0, but add 1% margin
+ for (std::size_t i = 0; i < range.second*1.01/inputSpacing; i++)
+ {
+ double x = i * inputSpacing;
+
+ functionValues.push_back(pmeCorrFunction(x));
+ derivativeValues.push_back(pmeCorrDerivative(x));
+ }
+
+ TypeParam pmeCorrTable( {{"NumericalPMECorr", functionValues, derivativeValues, inputSpacing}},
+ range, tolerance);
+
+ TestFixture::setTolerance(tolerance);
+ TestFixture::testSplineTableAgainstFunctions("NumericalPMECorr", pmeCorrFunction, pmeCorrDerivative, pmeCorrTable, range);
+}
+
+TYPED_TEST(SplineTableTest, TwoFunctions)
+{
+ std::pair<real, real> range(0.2, 2.0);
+
+ TypeParam table( {{"LJ6", lj6Function, lj6Derivative}, {"LJ12", lj12Function, lj12Derivative}}, range);
+
+ // Test entire range for each function. This will use the method that interpolates a single function
+ TestFixture::template testSplineTableAgainstFunctions<2, 0>("LJ6", lj6Function, lj6Derivative, table, range);
+ TestFixture::template testSplineTableAgainstFunctions<2, 1>("LJ12", lj12Function, lj12Derivative, table, range);
+
+ // Test the methods that evaluated both functions for one value
+ real x = 0.5 * (range.first + range.second);
+ real refFunc0 = lj6Function(x);
+ real refDer0 = lj6Derivative(x);
+ real refFunc1 = lj12Function(x);
+ real refDer1 = lj12Derivative(x);
+
+ real tstFunc0, tstDer0, tstFunc1, tstDer1;
+ real tmpFunc0, tmpFunc1, tmpDer0, tmpDer1;
+
+ // test that we reproduce the reference functions
+ table.evaluateFunctionAndDerivative(x, &tstFunc0, &tstDer0, &tstFunc1, &tstDer1);
+
+ real funcErr0 = std::abs(tstFunc0-refFunc0) / std::abs(refFunc0);
+ real funcErr1 = std::abs(tstFunc1-refFunc1) / std::abs(refFunc1);
+ real derErr0 = std::abs(tstDer0-refDer0) / std::abs(refDer0);
+ real derErr1 = std::abs(tstDer1-refDer1) / std::abs(refDer1);
+
+ // Use asserts, since the following ones compare to these values.
+ ASSERT_LT(funcErr0, TypeParam::defaultTolerance);
+ ASSERT_LT(derErr0, TypeParam::defaultTolerance);
+ ASSERT_LT(funcErr1, TypeParam::defaultTolerance);
+ ASSERT_LT(derErr1, TypeParam::defaultTolerance);
+
+ // Test that function/derivative-only interpolation methods work
+ table.evaluateFunction(x, &tmpFunc0, &tmpFunc1);
+ table.evaluateDerivative(x, &tmpDer0, &tmpDer1);
+ EXPECT_EQ(tstFunc0, tmpFunc0);
+ EXPECT_EQ(tstFunc1, tmpFunc1);
+ EXPECT_EQ(tstDer0, tmpDer0);
+
+ // Test that scrambled order interpolation methods work
+ table.template evaluateFunctionAndDerivative<2, 1, 0>(x, &tstFunc1, &tstDer1, &tstFunc0, &tstDer0);
+ EXPECT_EQ(tstFunc0, tmpFunc0);
+ EXPECT_EQ(tstFunc1, tmpFunc1);
+ EXPECT_EQ(tstDer0, tmpDer0);
+ EXPECT_EQ(tstDer1, tmpDer1);
+
+ // Test scrambled order for function/derivative-only methods
+ table.template evaluateFunction<2, 1, 0>(x, &tmpFunc1, &tmpFunc0);
+ table.template evaluateDerivative<2, 1, 0>(x, &tmpDer1, &tmpDer0);
+ EXPECT_EQ(tstFunc0, tmpFunc0);
+ EXPECT_EQ(tstFunc1, tmpFunc1);
+ EXPECT_EQ(tstDer0, tmpDer0);
+ EXPECT_EQ(tstDer1, tmpDer1);
+}
+
+TYPED_TEST(SplineTableTest, ThreeFunctions)
+{
+ std::pair<real, real> range(0.2, 2.0);
+
+ TypeParam table( {{"Coulomb", coulombFunction, coulombDerivative}, {"LJ6", lj6Function, lj6Derivative}, {"LJ12", lj12Function, lj12Derivative}}, range);
+
+ // Test entire range for each function
+ TestFixture::template testSplineTableAgainstFunctions<3, 0>("Coulomb", coulombFunction, coulombDerivative, table, range);
+ TestFixture::template testSplineTableAgainstFunctions<3, 1>("LJ6", lj6Function, lj6Derivative, table, range);
+ TestFixture::template testSplineTableAgainstFunctions<3, 2>("LJ12", lj12Function, lj12Derivative, table, range);
+
+ // Test the methods that evaluated both functions for one value
+ real x = 0.5 * (range.first + range.second);
+ real refFunc0 = coulombFunction(x);
+ real refDer0 = coulombDerivative(x);
+ real refFunc1 = lj6Function(x);
+ real refDer1 = lj6Derivative(x);
+ real refFunc2 = lj12Function(x);
+ real refDer2 = lj12Derivative(x);
+
+ real tstFunc0, tstDer0, tstFunc1, tstDer1, tstFunc2, tstDer2;
+ real tmpFunc0, tmpFunc1, tmpFunc2, tmpDer0, tmpDer1, tmpDer2;
+
+ // test that we reproduce the reference functions
+ table.evaluateFunctionAndDerivative(x, &tstFunc0, &tstDer0, &tstFunc1, &tstDer1, &tstFunc2, &tstDer2);
+
+ real funcErr0 = std::abs(tstFunc0-refFunc0) / std::abs(refFunc0);
+ real derErr0 = std::abs(tstDer0-refDer0) / std::abs(refDer0);
+ real funcErr1 = std::abs(tstFunc1-refFunc1) / std::abs(refFunc1);
+ real derErr1 = std::abs(tstDer1-refDer1) / std::abs(refDer1);
+ real funcErr2 = std::abs(tstFunc2-refFunc2) / std::abs(refFunc2);
+ real derErr2 = std::abs(tstDer2-refDer2) / std::abs(refDer2);
+
+ // Use asserts, since the following ones compare to these values.
+ ASSERT_LT(funcErr0, TypeParam::defaultTolerance);
+ ASSERT_LT(derErr0, TypeParam::defaultTolerance);
+ ASSERT_LT(funcErr1, TypeParam::defaultTolerance);
+ ASSERT_LT(derErr1, TypeParam::defaultTolerance);
+ ASSERT_LT(funcErr2, TypeParam::defaultTolerance);
+ ASSERT_LT(derErr2, TypeParam::defaultTolerance);
+
+ // Test that function/derivative-only interpolation methods work
+ table.evaluateFunction(x, &tmpFunc0, &tmpFunc1, &tmpFunc2);
+ table.evaluateDerivative(x, &tmpDer0, &tmpDer1, &tmpDer2);
+ EXPECT_EQ(tstFunc0, tmpFunc0);
+ EXPECT_EQ(tstFunc1, tmpFunc1);
+ EXPECT_EQ(tstFunc2, tmpFunc2);
+ EXPECT_EQ(tstDer0, tmpDer0);
+ EXPECT_EQ(tstDer1, tmpDer1);
+ EXPECT_EQ(tstDer2, tmpDer2);
+
+ // Test two functions out of three
+ table.template evaluateFunctionAndDerivative<3, 0, 1>(x, &tmpFunc0, &tmpDer0, &tmpFunc1, &tmpDer1);
+ EXPECT_EQ(tstFunc0, tmpFunc0);
+ EXPECT_EQ(tstFunc1, tmpFunc1);
+ EXPECT_EQ(tstDer0, tmpDer0);
+ EXPECT_EQ(tstDer1, tmpDer1);
+
+ // two out of three, function/derivative-only
+ table.template evaluateFunction<3, 0, 1>(x, &tmpFunc0, &tmpFunc1);
+ table.template evaluateDerivative<3, 0, 1>(x, &tmpDer0, &tmpDer1);
+ EXPECT_EQ(tstFunc0, tmpFunc0);
+ EXPECT_EQ(tstFunc1, tmpFunc1);
+ EXPECT_EQ(tstDer0, tmpDer0);
+ EXPECT_EQ(tstDer1, tmpDer1);
+
+ // Test that scrambled order interpolation methods work
+ table.template evaluateFunctionAndDerivative<3, 2, 1, 0>(x, &tstFunc2, &tstDer2, &tstFunc1, &tstDer1, &tstFunc0, &tstDer0);
+ EXPECT_EQ(tstFunc0, tmpFunc0);
+ EXPECT_EQ(tstFunc1, tmpFunc1);
+ EXPECT_EQ(tstFunc2, tmpFunc2);
+ EXPECT_EQ(tstDer0, tmpDer0);
+ EXPECT_EQ(tstDer1, tmpDer1);
+ EXPECT_EQ(tstDer2, tmpDer2);
+
+ // Test scrambled order for function/derivative-only methods
+ table.template evaluateFunction<3, 2, 1, 0>(x, &tmpFunc2, &tmpFunc1, &tmpFunc0);
+ table.template evaluateDerivative<3, 2, 1, 0>(x, &tmpDer2, &tmpDer1, &tmpDer0);
+ EXPECT_EQ(tstFunc0, tmpFunc0);
+ EXPECT_EQ(tstFunc1, tmpFunc1);
+ EXPECT_EQ(tstFunc2, tmpFunc2);
+ EXPECT_EQ(tstDer0, tmpDer0);
+ EXPECT_EQ(tstDer1, tmpDer1);
+ EXPECT_EQ(tstDer2, tmpDer2);
+}
+
+#if GMX_SIMD_HAVE_REAL
+TYPED_TEST(SplineTableTest, Simd)
+{
+ std::pair<real, real> range(0.2, 1.0);
+ TypeParam table( {{"LJ12", lj12Function, lj12Derivative}}, range);
+
+ // We already test that the SIMD operations handle the different elements
+ // correctly in the SIMD module, so here we only test that interpolation
+ // works for a single value in the middle of the interval
+
+ real x = 0.5 * (range.first + range.second);
+ real refFunc = lj12Function(x);
+ real refDer = lj12Derivative(x);
+ SimdReal tstFunc, tstDer;
+ real funcErr, derErr;
+ GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) alignedMem[GMX_SIMD_REAL_WIDTH];
+
+ table.evaluateFunctionAndDerivative(SimdReal(x), &tstFunc, &tstDer);
+
+ store(alignedMem, tstFunc);
+ funcErr = std::abs(alignedMem[0]-refFunc) / std::abs(refFunc);
+
+ store(alignedMem, tstDer);
+ derErr = std::abs(alignedMem[0]-refDer ) / std::abs(refDer );
+
+ EXPECT_LT(funcErr, TypeParam::defaultTolerance);
+ EXPECT_LT(derErr, TypeParam::defaultTolerance);
+}
+
+TYPED_TEST(SplineTableTest, SimdTwoFunctions)
+{
+ std::pair<real, real> range(0.2, 2.0);
+
+ TypeParam table( {{"LJ6", lj6Function, lj6Derivative}, {"LJ12", lj12Function, lj12Derivative}}, range);
+
+ // We already test that the SIMD operations handle the different elements
+ // correctly in the SIMD module, so here we only test that interpolation
+ // works for a single value in the middle of the interval
+
+ real x = 0.5 * (range.first + range.second);
+ real refFunc0 = lj6Function(x);
+ real refDer0 = lj6Derivative(x);
+ real refFunc1 = lj12Function(x);
+ real refDer1 = lj12Derivative(x);
+ SimdReal tstFunc0, tstDer0;
+ SimdReal tstFunc1, tstDer1;
+ real funcErr0, derErr0;
+ real funcErr1, derErr1;
+ GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) alignedMem[GMX_SIMD_REAL_WIDTH];
+
+ table.evaluateFunctionAndDerivative(SimdReal(x), &tstFunc0, &tstDer0, &tstFunc1, &tstDer1);
+
+ store(alignedMem, tstFunc0);
+ funcErr0 = std::abs(alignedMem[0]-refFunc0) / std::abs(refFunc0);
+
+ store(alignedMem, tstDer0);
+ derErr0 = std::abs(alignedMem[0]-refDer0 ) / std::abs(refDer0 );
+
+ store(alignedMem, tstFunc1);
+ funcErr1 = std::abs(alignedMem[0]-refFunc1) / std::abs(refFunc1);
+
+ store(alignedMem, tstDer1);
+ derErr1 = std::abs(alignedMem[0]-refDer1 ) / std::abs(refDer1 );
+
+ EXPECT_LT(funcErr0, TypeParam::defaultTolerance);
+ EXPECT_LT(derErr0, TypeParam::defaultTolerance);
+ EXPECT_LT(funcErr1, TypeParam::defaultTolerance);
+ EXPECT_LT(derErr1, TypeParam::defaultTolerance);
+}
+#endif
+
+#if GMX_SIMD_HAVE_REAL && !defined NDEBUG
+TYPED_TEST(SplineTableTest, CatchesOutOfRangeValuesSimd)
+{
+ std::pair<real, real> range(0.2, 1.0);
+ TypeParam table( {{"LJ12", lj12Function, lj12Derivative}}, range);
+ SimdReal x, func, der;
+
+ GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) alignedMem[GMX_SIMD_REAL_WIDTH];
+
+ // Make position 1 incorrect if width>=2, otherwise position 0
+ alignedMem[ (GMX_SIMD_REAL_WIDTH >= 2) ? 1 : 0] = -GMX_REAL_EPS;
+ x = load(alignedMem);
+
+ EXPECT_THROW_GMX(table.evaluateFunctionAndDerivative(x, &func, &der), gmx::RangeError);
+
+ for (std::size_t i = 0; i < GMX_SIMD_REAL_WIDTH; i++)
+ {
+ alignedMem[i] = range.second*(1.0-GMX_REAL_EPS);
+ }
+ // Make position 1 incorrect if width>=2, otherwise position 0
+ alignedMem[ (GMX_SIMD_REAL_WIDTH >= 2) ? 1 : 0] = range.second;
+ x = load(alignedMem);
+
+ EXPECT_THROW_GMX(table.evaluateFunctionAndDerivative(x, &func, &der), gmx::RangeError);
+}
+#endif
+
+} // namespace
+
+} // namespace test
+
+} // namespace gmx
#include <array>
-#include "gromacs/gmxlib/md_logging.h"
#include "gromacs/mdtypes/commrec.h"
#include "gromacs/timing/cyclecounter.h"
#include "gromacs/timing/gpu_timing.h"
#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"
}
-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)
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;
}
/* 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.");
}
}
}
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 &&
/* 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));
}
}
*
* 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 */
/* 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);
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;
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;
#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"
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], false);
+ top[1] = gmx_mtop_t_to_t_topology(&mtop[1], false);
+ 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], true);
+ 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;
gmx_mtop_atomloop_block_t aloop;
- t_atom *atom;
+ const t_atom *atom;
fprintf(fp, "\\subsection{Simulation system}\n");
aloop = gmx_mtop_atomloop_block_init(mtop);
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);
}
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;
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)
{
+++ /dev/null
-/*
- * 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);
-}
#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"
int *invindex;
int i;
- top = gmx_mtop_t_to_t_topology(mtop);
+ top = gmx_mtop_t_to_t_topology(mtop, false);
bKeep = bKeepIt(gnx, top.atoms.nr, index);
invindex = invind(gnx, top.atoms.nr, index);
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 }
};
/* 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)" },
"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 */
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));
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,
{
fprintf(stderr, "Will write subset %s of original tpx containing %d "
"atoms\n", grpname, gnx);
- reduce_topology_x(gnx, index, &mtop, state.x, state.v);
+ reduce_topology_x(gnx, index, &mtop, as_rvec_array(state.x.data()), as_rvec_array(state.v.data()));
state.natoms = gnx;
}
else if (bZeroQ)
#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"
#include "gromacs/utility/smalloc.h"
#include "gromacs/utility/txtdump.h"
-static void list_tpx(const char *fn, gmx_bool bShowNumbers, const char *mdpfn,
- gmx_bool bSysTop)
+static void list_tpx(const char *fn,
+ gmx_bool bShowNumbers,
+ gmx_bool bShowParameters,
+ const char *mdpfn,
+ gmx_bool bSysTop)
{
FILE *gp;
int indent, i, j, **gcount, atot;
- t_state state;
- t_inputrec ir;
+ t_state state {};
+ 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);
}
{
if (bSysTop)
{
- top = gmx_mtop_t_to_t_topology(&mtop);
+ top = gmx_mtop_t_to_t_topology(&mtop, false);
}
if (available(stdout, &tpx, 0, fn))
{
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));
if (!bSysTop)
{
- pr_mtop(stdout, indent, "topology", &(mtop), bShowNumbers);
+ pr_mtop(stdout, indent, "topology", &(mtop), bShowNumbers, bShowParameters);
}
else
{
- pr_top(stdout, indent, "topology", &(top), bShowNumbers);
+ pr_top(stdout, indent, "topology", &(top), bShowNumbers, bShowParameters);
}
pr_rvecs(stdout, indent, "box", tpx.bBox ? state.box : NULL, DIM);
pr_rvecs(stdout, indent, "svir_prev", tpx.bBox ? state.svir_prev : NULL, DIM);
pr_rvecs(stdout, indent, "fvir_prev", tpx.bBox ? state.fvir_prev : NULL, DIM);
/* leave nosehoover_xi in for now to match the tpr version */
- pr_doubles(stdout, indent, "nosehoover_xi", state.nosehoover_xi, state.ngtc);
+ pr_doubles(stdout, indent, "nosehoover_xi", state.nosehoover_xi.data(), state.ngtc);
/*pr_doubles(stdout,indent,"nosehoover_vxi",state.nosehoover_vxi,state.ngtc);*/
/*pr_doubles(stdout,indent,"therm_integral",state.therm_integral,state.ngtc);*/
- pr_rvecs(stdout, indent, "x", tpx.bX ? state.x : NULL, state.natoms);
- pr_rvecs(stdout, indent, "v", tpx.bV ? state.v : NULL, state.natoms);
+ pr_rvecs(stdout, indent, "x", tpx.bX ? as_rvec_array(state.x.data()) : NULL, state.natoms);
+ pr_rvecs(stdout, indent, "v", tpx.bV ? as_rvec_array(state.v.data()) : NULL, state.natoms);
}
groups = &mtop.groups;
}
sfree(gcount);
}
- done_state(&state);
}
static void list_top(const char *fn)
gmx_output_env_t *oenv;
/* Command line options */
static gmx_bool bShowNumbers = TRUE;
+ static gmx_bool bShowParams = FALSE;
static gmx_bool bSysTop = FALSE;
t_pargs pa[] = {
{ "-nr", FALSE, etBOOL, {&bShowNumbers}, "Show index numbers in output (leaving them out makes comparison easier, but creates a useless topology)" },
+ { "-param", FALSE, etBOOL, {&bShowParams}, "Show parameters for each bonded interaction (for comparing dumps, it is useful to combine this with -nonr)" },
{ "-sys", FALSE, etBOOL, {&bSysTop}, "List the atoms and bonded interactions for the whole system instead of for each molecule type" }
};
if (ftp2bSet(efTPR, NFILE, fnm))
{
- list_tpx(ftp2fn(efTPR, NFILE, fnm), bShowNumbers,
+ list_tpx(ftp2fn(efTPR, NFILE, fnm), bShowNumbers, bShowParams,
ftp2fn_null(efMDP, NFILE, fnm), bSysTop);
}
else if (ftp2bSet(efTRX, NFILE, fnm))
#include <algorithm>
+#include "gromacs/topology/atomprop.h"
#include "gromacs/topology/symtab.h"
+#include "gromacs/utility/compare.h"
+#include "gromacs/utility/fatalerror.h"
#include "gromacs/utility/smalloc.h"
#include "gromacs/utility/txtdump.h"
void init_atom(t_atoms *at)
{
- at->nr = 0;
- at->nres = 0;
- at->atom = NULL;
- at->resinfo = NULL;
- at->atomname = NULL;
- at->atomtype = NULL;
- at->atomtypeB = NULL;
- at->pdbinfo = NULL;
+ at->nr = 0;
+ at->nres = 0;
+ at->atom = NULL;
+ at->resinfo = NULL;
+ at->atomname = NULL;
+ at->atomtype = NULL;
+ at->atomtypeB = NULL;
+ at->pdbinfo = NULL;
+ at->haveMass = FALSE;
+ at->haveCharge = FALSE;
+ at->haveType = FALSE;
+ at->haveBState = FALSE;
+ at->havePdbInfo = FALSE;
}
void init_atomtypes(t_atomtypes *at)
atoms->atomtypeB = NULL;
snew(atoms->resinfo, natoms);
snew(atoms->atom, natoms);
- if (bPdbinfo)
+ atoms->haveMass = FALSE;
+ atoms->haveCharge = FALSE;
+ atoms->haveType = FALSE;
+ atoms->haveBState = FALSE;
+ atoms->havePdbInfo = bPdbinfo;
+ if (atoms->havePdbInfo)
{
snew(atoms->pdbinfo, natoms);
}
}
}
}
+
+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);
+ }
+ }
+}
+
+void atomsSetMassesBasedOnNames(t_atoms *atoms, gmx_bool printMissingMasses)
+{
+ if (atoms->haveMass)
+ {
+ /* We could decide to anyhow assign then or generate a fatal error,
+ * but it's probably most useful to keep the masses we have.
+ */
+ return;
+ }
+
+ int maxWarn = (printMissingMasses ? 10 : 0);
+ int numWarn = 0;
+
+ gmx_atomprop_t aps = gmx_atomprop_init();
+
+ gmx_bool haveMass = TRUE;
+ for (int i = 0; i < atoms->nr; i++)
+ {
+ if (!gmx_atomprop_query(aps, epropMass,
+ *atoms->resinfo[atoms->atom[i].resind].name,
+ *atoms->atomname[i],
+ &atoms->atom[i].m))
+ {
+ haveMass = FALSE;
+
+ if (numWarn < maxWarn)
+ {
+ fprintf(stderr, "Can not find mass in database for atom %s in residue %d %s\n",
+ *atoms->atomname[i],
+ atoms->resinfo[atoms->atom[i].resind].nr,
+ *atoms->resinfo[atoms->atom[i].resind].name);
+ numWarn++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ atoms->haveMass = haveMass;
+
+ gmx_atomprop_destroy(aps);
+}
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/real.h"
-#ifdef __cplusplus
-extern "C" {
-#endif
-
struct t_symtab;
/* The particle type */
typedef struct t_atoms
{
- int nr; /* Nr of atoms */
- t_atom *atom; /* Array of atoms (dim: nr) */
+ int nr; /* Nr of atoms */
+ t_atom *atom; /* Array of atoms (dim: nr) */
/* The following entries will not */
/* always be used (nres==0) */
- char ***atomname; /* Array of pointers to atom name */
+ char ***atomname; /* Array of pointers to atom name */
/* use: (*(atomname[i])) */
- char ***atomtype; /* Array of pointers to atom types */
+ char ***atomtype; /* Array of pointers to atom types */
/* use: (*(atomtype[i])) */
- char ***atomtypeB; /* Array of pointers to B atom types */
+ char ***atomtypeB; /* Array of pointers to B atom types */
/* use: (*(atomtypeB[i])) */
- int nres; /* The number of resinfo entries */
- t_resinfo *resinfo; /* Array of residue names and numbers */
- t_pdbinfo *pdbinfo; /* PDB Information, such as aniso. Bfac */
+ int nres; /* The number of resinfo entries */
+ t_resinfo *resinfo; /* Array of residue names and numbers */
+ t_pdbinfo *pdbinfo; /* PDB Information, such as aniso. Bfac */
+
+ /* Flags that tell if properties are set for all nr atoms.
+ * For B-state parameters, both haveBState and the mass/charge/type
+ * flag should be TRUE.
+ */
+ gmx_bool haveMass; /* Mass available */
+ gmx_bool haveCharge; /* Charge available */
+ gmx_bool haveType; /* Atom type available */
+ gmx_bool haveBState; /* B-state parameters available */
+ gmx_bool havePdbInfo; /* pdbinfo available */
} t_atoms;
typedef struct t_atomtypes
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);
+
+/*! \brief Set mass for each atom using the atom and residue names using a database
+ *
+ * If atoms->haveMass = TRUE does nothing.
+ * If printMissingMasss = TRUE, prints details for first 10 missing masses
+ * to stderr.
+ */
+void atomsSetMassesBasedOnNames(t_atoms *atoms, gmx_bool printMissingMasses);
#endif
*
* 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.
}
void pr_ilist(FILE *fp, int indent, const char *title,
- const t_functype *functype, const t_ilist *ilist, gmx_bool bShowNumbers)
+ const t_functype *functype, const t_ilist *ilist,
+ gmx_bool bShowNumbers,
+ gmx_bool bShowParameters, const t_iparams *iparams)
{
int i, j, k, type, ftype;
t_iatom *iatoms;
iatoms = ilist->iatoms;
for (i = j = 0; i < ilist->nr; )
{
-#ifndef DEBUG
pr_indent(fp, indent+INDENT);
type = *(iatoms++);
ftype = functype[type];
- fprintf(fp, "%d type=%d (%s)",
- bShowNumbers ? j : -1, bShowNumbers ? type : -1,
- interaction_function[ftype].name);
+ if (bShowNumbers)
+ {
+ fprintf(fp, "%d type=%d ", j, type);
+ }
j++;
+ printf("(%s)", interaction_function[ftype].name);
for (k = 0; k < interaction_function[ftype].nratoms; k++)
{
- fprintf(fp, " %d", *(iatoms++));
+ fprintf(fp, " %3d", *(iatoms++));
+ }
+ if (bShowParameters)
+ {
+ fprintf(fp, " ");
+ pr_iparams(fp, ftype, &iparams[type]);
}
fprintf(fp, "\n");
i += 1+interaction_function[ftype].nratoms;
-#else
- fprintf(fp, "%5d%5d\n", i, iatoms[i]);
- i++;
-#endif
}
}
}
pr_cmap(fp, indent, "cmap", &ffparams->cmap_grid, bShowNumbers);
}
-void pr_idef(FILE *fp, int indent, const char *title, const t_idef *idef, gmx_bool bShowNumbers)
+void pr_idef(FILE *fp, int indent, const char *title, const t_idef *idef,
+ gmx_bool bShowNumbers, gmx_bool bShowParameters)
{
int i, j;
for (j = 0; (j < F_NRE); j++)
{
pr_ilist(fp, indent, interaction_function[j].longname,
- idef->functype, &idef->il[j], bShowNumbers);
+ idef->functype, &idef->il[j], bShowNumbers,
+ bShowParameters, idef->iparams);
}
}
}
*
* 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.
void pr_iparams(FILE *fp, t_functype ftype, const t_iparams *iparams);
void pr_ilist(FILE *fp, int indent, const char *title,
- const t_functype *functype, const t_ilist *ilist, gmx_bool bShowNumbers);
+ const t_functype *functype, const t_ilist *ilist,
+ gmx_bool bShowNumbers,
+ gmx_bool bShowParameters, const t_iparams *iparams);
void pr_ffparams(FILE *fp, int indent, const char *title,
const gmx_ffparams_t *ffparams, gmx_bool bShowNumbers);
-void pr_idef(FILE *fp, int indent, const char *title, const t_idef *idef, gmx_bool bShowNumbers);
+void pr_idef(FILE *fp, int indent, const char *title, const t_idef *idef,
+ gmx_bool bShowNumbers, gmx_bool bShowParameters);
#ifdef __cplusplus
}
/* 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");
}
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");
}
n = strlen(s);
aa = -1;
/* first look for whole name match */
- if (aa == -1)
{
for (i = 0; i < ngrps; i++)
{
--- /dev/null
+/*
+ * 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 This file contains inline functions to look up atom information
+ * using the global atom index.
+ *
+ * \author Berk Hess <hess@kth.se>
+ * \inlibraryapi
+ * \ingroup module_mtop
+ */
+
+#ifndef GMX_TOPOLOGY_MTOP_LOOKUP_H
+#define GMX_TOPOLOGY_MTOP_LOOKUP_H
+
+#include "gromacs/topology/topology.h"
+#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/gmxassert.h"
+
+struct t_atom;
+
+/*! \brief Look up the molecule block and other indices of a global atom index
+ *
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ *
+ * \param[in] mtop The molecule topology
+ * \param[in] globalAtomIndex The global atom index to look up
+ * \param[in,out] moleculeBlock The molecule block index in \p mtop
+ * \param[out] moleculeIndex The index of the molecule in the block, can be NULL
+ * \param[out] atomIndexInMolecule The atom index in the molecule, can be NULL
+ */
+static inline void
+mtopGetMolblockIndex(const gmx_mtop_t *mtop,
+ int globalAtomIndex,
+ int *moleculeBlock,
+ int *moleculeIndex,
+ int *atomIndexInMolecule)
+{
+ GMX_ASSERT(globalAtomIndex >= 0 && globalAtomIndex < mtop->natoms, "The atom index to look up should be within range");
+ GMX_ASSERT(moleculeBlock != nullptr, "molBlock can not be NULL");
+ GMX_ASSERT(*moleculeBlock >= 0 && *moleculeBlock < mtop->nmolblock, "The starting molecule block index for the search should be within range");
+
+ /* Search the molecue block index using bisection */
+ int molBlock0 = -1;
+ int molBlock1 = mtop->nmolblock;
+
+ int globalAtomStart;
+ while (TRUE)
+ {
+ globalAtomStart = mtop->molblock[*moleculeBlock].globalAtomStart;
+ if (globalAtomIndex < globalAtomStart)
+ {
+ molBlock1 = *moleculeBlock;
+ }
+ else if (globalAtomIndex >= mtop->molblock[*moleculeBlock].globalAtomEnd)
+ {
+ molBlock0 = *moleculeBlock;
+ }
+ else
+ {
+ break;
+ }
+ *moleculeBlock = ((molBlock0 + molBlock1 + 1) >> 1);
+ }
+
+ int molIndex = (globalAtomIndex - globalAtomStart) / mtop->molblock[*moleculeBlock].natoms_mol;
+ if (moleculeIndex != nullptr)
+ {
+ *moleculeIndex = molIndex;
+ }
+ if (atomIndexInMolecule != nullptr)
+ {
+ *atomIndexInMolecule = globalAtomIndex - globalAtomStart - molIndex*mtop->molblock[*moleculeBlock].natoms_mol;
+ }
+}
+
+/*! \brief Returns the atom data for an atom based on global atom index
+ *
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ *
+ * \param[in] mtop The molecule topology
+ * \param[in] globalAtomIndex The global atom index to look up
+ * \param[in,out] moleculeBlock The molecule block index in \p mtop
+ */
+static inline const t_atom &
+mtopGetAtomParameters(const gmx_mtop_t *mtop,
+ int globalAtomIndex,
+ int *moleculeBlock)
+{
+ int atomIndexInMolecule;
+ mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock,
+ NULL, &atomIndexInMolecule);
+ const gmx_moltype_t &moltype = mtop->moltype[mtop->molblock[*moleculeBlock].type];
+ return moltype.atoms.atom[atomIndexInMolecule];
+}
+
+/*! \brief Returns the mass of an atom based on global atom index
+ *
+ * Returns that A-state mass of the atom with global index \p globalAtomIndex.
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ *
+ * \param[in] mtop The molecule topology
+ * \param[in] globalAtomIndex The global atom index to look up
+ * \param[in,out] moleculeBlock The molecule block index in \p mtop
+ */
+static inline real
+mtopGetAtomMass(const gmx_mtop_t *mtop,
+ int globalAtomIndex,
+ int *moleculeBlock)
+{
+ const t_atom &atom = mtopGetAtomParameters(mtop, globalAtomIndex, moleculeBlock);
+ return atom.m;
+}
+
+/*! \brief Look up the atom and residue name and residue number and index of a global atom index
+ *
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ * Note that this function does a (somewhat expensive) lookup. If you want
+ * to look up data sequentially for all atoms in a molecule or the system,
+ * use one of the mtop loop functionalities.
+ *
+ * \param[in] mtop The molecule topology
+ * \param[in] globalAtomIndex The global atom index to look up
+ * \param[in,out] moleculeBlock The molecule block index in \p mtop
+ * \param[out] atomName The atom name, input can be NULL
+ * \param[out] residueNumber The residue number, input can be NULL
+ * \param[out] residueName The residue name, input can be NULL
+ * \param[out] globalResidueIndex The gobal residue index, input can be NULL
+ */
+static inline void
+mtopGetAtomAndResidueName(const gmx_mtop_t *mtop,
+ int globalAtomIndex,
+ int *moleculeBlock,
+ const char **atomName,
+ int *residueNumber,
+ const char **residueName,
+ int *globalResidueIndex)
+{
+ int moleculeIndex;
+ int atomIndexInMolecule;
+ mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock,
+ &moleculeIndex, &atomIndexInMolecule);
+
+ const gmx_molblock_t &molb = mtop->molblock[*moleculeBlock];
+ const t_atoms &atoms = mtop->moltype[molb.type].atoms;
+ if (atomName != nullptr)
+ {
+ *atomName = *(atoms.atomname[atomIndexInMolecule]);
+ }
+ if (residueNumber != nullptr)
+ {
+ if (atoms.nres > mtop->maxres_renum)
+ {
+ *residueNumber = atoms.resinfo[atoms.atom[atomIndexInMolecule].resind].nr;
+ }
+ else
+ {
+ /* Single residue molecule, keep counting */
+ *residueNumber = molb.residueNumberStart + moleculeIndex*atoms.nres + atoms.atom[atomIndexInMolecule].resind;
+ }
+ }
+ if (residueName != nullptr)
+ {
+ *residueName = *(atoms.resinfo[atoms.atom[atomIndexInMolecule].resind].name);
+ }
+ if (globalResidueIndex != nullptr)
+ {
+ *globalResidueIndex = molb.globalResidueStart + moleculeIndex*atoms.nres + atoms.atom[atomIndexInMolecule].resind;
+ }
+}
+
+/*! \brief Returns residue information for an atom based on global atom index
+ *
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ *
+ * \param[in] mtop The molecule topology
+ * \param[in] globalAtomIndex The global atom index to look up
+ * \param[in,out] moleculeBlock The molecule block index in \p mtop
+ */
+static inline const t_resinfo &
+mtopGetResidueInfo(const gmx_mtop_t *mtop,
+ int globalAtomIndex,
+ int *moleculeBlock)
+{
+ int atomIndexInMolecule;
+ mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock,
+ NULL, &atomIndexInMolecule);
+ const gmx_moltype_t &moltype = mtop->moltype[mtop->molblock[*moleculeBlock].type];
+ const int resind = moltype.atoms.atom[atomIndexInMolecule].resind;
+ return moltype.atoms.resinfo[resind];
+}
+
+/*! \brief Returns PDB information for an atom based on global atom index
+ *
+ * The atom index has to be in range: 0 <= \p globalAtomIndex < \p mtop->natoms.
+ * The input value of moleculeBlock should be in range. Use 0 as starting value.
+ * For subsequent calls to this function, e.g. in a loop, pass in the previously
+ * returned value for best performance. Atoms in a group tend to be in the same
+ * molecule(block), so this minimizes the search time.
+ *
+ * \param[in] mtop The molecule topology
+ * \param[in] globalAtomIndex The global atom index to look up
+ * \param[in,out] moleculeBlock The molecule block index in \p mtop
+ */
+static inline const t_pdbinfo &
+mtopGetAtomPdbInfo(const gmx_mtop_t *mtop,
+ int globalAtomIndex,
+ int *moleculeBlock)
+{
+ int atomIndexInMolecule;
+ mtopGetMolblockIndex(mtop, globalAtomIndex, moleculeBlock,
+ NULL, &atomIndexInMolecule);
+ const gmx_moltype_t &moltype = mtop->moltype[mtop->molblock[*moleculeBlock].type];
+ GMX_ASSERT(moltype.atoms.havePdbInfo, "PDB information not present when requested");
+ return moltype.atoms.pdbinfo[atomIndexInMolecule];
+}
+
+#endif
return maxresnr;
}
+static void finalizeMolblocks(gmx_mtop_t *mtop)
+{
+ int atomIndex = 0;
+ int residueIndex = 0;
+ int residueNumberStart = mtop->maxresnr + 1;
+ for (int mb = 0; mb < mtop->nmolblock; mb++)
+ {
+ gmx_molblock_t *molb = &mtop->molblock[mb];
+ int numResPerMol = mtop->moltype[molb->type].atoms.nres;
+ molb->globalAtomStart = atomIndex;
+ molb->globalResidueStart = residueIndex;
+ atomIndex += molb->nmol*molb->natoms_mol;
+ residueIndex += molb->nmol*numResPerMol;
+ molb->globalAtomEnd = atomIndex;
+ molb->residueNumberStart = residueNumberStart;
+ if (numResPerMol <= mtop->maxres_renum)
+ {
+ residueNumberStart += molb->nmol*numResPerMol;
+ }
+ }
+}
+
void gmx_mtop_finalize(gmx_mtop_t *mtop)
{
char *env;
- mtop->maxres_renum = 1;
+ if (mtop->nmolblock == 1 && mtop->molblock[0].nmol == 1)
+ {
+ /* We have a single molecule only, no renumbering needed.
+ * This case also covers an mtop converted from pdb/gro/... input,
+ * so we retain the original residue numbering.
+ */
+ mtop->maxres_renum = 0;
+ }
+ else
+ {
+ /* We only renumber single residue molecules. Their intra-molecular
+ * residue numbering is anyhow irrelevant.
+ */
+ mtop->maxres_renum = 1;
+ }
env = getenv("GMX_MAXRESRENUM");
if (env != NULL)
}
mtop->maxresnr = gmx_mtop_maxresnr(mtop, mtop->maxres_renum);
+
+ finalizeMolblocks(mtop);
}
void gmx_mtop_count_atomtypes(const gmx_mtop_t *mtop, int state, int typecount[])
return ncg;
}
+int gmx_mtop_nres(const gmx_mtop_t *mtop)
+{
+ int nres = 0;
+ for (int mb = 0; mb < mtop->nmolblock; ++mb)
+ {
+ nres +=
+ mtop->molblock[mb].nmol*
+ mtop->moltype[mtop->molblock[mb].type].atoms.nres;
+ }
+ return nres;
+}
+
void gmx_mtop_remove_chargegroups(gmx_mtop_t *mtop)
{
int mt;
}
}
-
-typedef struct
-{
- int a_start;
- int a_end;
- int na_mol;
-} mb_at_t;
-
-typedef struct gmx_mtop_atomlookup
-{
- const gmx_mtop_t *mtop;
- int nmb;
- int mb_start;
- mb_at_t *mba;
-} t_gmx_mtop_atomlookup;
-
-
-gmx_mtop_atomlookup_t
-gmx_mtop_atomlookup_init(const gmx_mtop_t *mtop)
-{
- t_gmx_mtop_atomlookup *alook;
- int mb;
- int a_start, a_end, na, na_start = -1;
-
- snew(alook, 1);
-
- alook->mtop = mtop;
- alook->nmb = mtop->nmolblock;
- alook->mb_start = 0;
- snew(alook->mba, alook->nmb);
-
- a_start = 0;
- for (mb = 0; mb < mtop->nmolblock; mb++)
- {
- na = mtop->molblock[mb].nmol*mtop->molblock[mb].natoms_mol;
- a_end = a_start + na;
-
- alook->mba[mb].a_start = a_start;
- alook->mba[mb].a_end = a_end;
- alook->mba[mb].na_mol = mtop->molblock[mb].natoms_mol;
-
- /* We start the binary search with the largest block */
- if (mb == 0 || na > na_start)
- {
- alook->mb_start = mb;
- na_start = na;
- }
-
- a_start = a_end;
- }
-
- return alook;
-}
-
-gmx_mtop_atomlookup_t
-gmx_mtop_atomlookup_settle_init(const gmx_mtop_t *mtop)
-{
- t_gmx_mtop_atomlookup *alook;
- int mb;
- int na, na_start = -1;
-
- alook = gmx_mtop_atomlookup_init(mtop);
-
- /* Check if the starting molblock has settle */
- if (mtop->moltype[mtop->molblock[alook->mb_start].type].ilist[F_SETTLE].nr == 0)
- {
- /* Search the largest molblock with settle */
- alook->mb_start = -1;
- for (mb = 0; mb < mtop->nmolblock; mb++)
- {
- if (mtop->moltype[mtop->molblock[mb].type].ilist[F_SETTLE].nr > 0)
- {
- na = alook->mba[mb].a_end - alook->mba[mb].a_start;
- if (alook->mb_start == -1 || na > na_start)
- {
- alook->mb_start = mb;
- na_start = na;
- }
- }
- }
-
- if (alook->mb_start == -1)
- {
- gmx_incons("gmx_mtop_atomlookup_settle_init called without settles");
- }
- }
-
- return alook;
-}
-
-void
-gmx_mtop_atomlookup_destroy(gmx_mtop_atomlookup_t alook)
-{
- sfree(alook->mba);
- sfree(alook);
-}
-
-void gmx_mtop_atomnr_to_atom(const gmx_mtop_atomlookup_t alook,
- int atnr_global,
- t_atom **atom)
-{
- int mb0, mb1, mb;
- int a_start, atnr_mol;
-
-#ifdef DEBUG_MTOP
- if (atnr_global < 0 || atnr_global >= mtop->natoms)
- {
- gmx_fatal(FARGS, "gmx_mtop_atomnr_to_moltype was called with atnr_global=%d which is not in the atom range of this system (%d-%d)",
- atnr_global, 0, mtop->natoms-1);
- }
-#endif
-
- mb0 = -1;
- mb1 = alook->nmb;
- mb = alook->mb_start;
-
- while (TRUE)
- {
- a_start = alook->mba[mb].a_start;
- if (atnr_global < a_start)
- {
- mb1 = mb;
- }
- else if (atnr_global >= alook->mba[mb].a_end)
- {
- mb0 = mb;
- }
- else
- {
- break;
- }
- mb = ((mb0 + mb1 + 1)>>1);
- }
-
- atnr_mol = (atnr_global - a_start) % alook->mba[mb].na_mol;
-
- *atom = &alook->mtop->moltype[alook->mtop->molblock[mb].type].atoms.atom[atnr_mol];
-}
-
-void gmx_mtop_atomnr_to_ilist(const gmx_mtop_atomlookup_t alook,
- int atnr_global,
- t_ilist **ilist_mol, int *atnr_offset)
-{
- int mb0, mb1, mb;
- int a_start, atnr_local;
-
-#ifdef DEBUG_MTOP
- if (atnr_global < 0 || atnr_global >= mtop->natoms)
- {
- gmx_fatal(FARGS, "gmx_mtop_atomnr_to_moltype was called with atnr_global=%d which is not in the atom range of this system (%d-%d)",
- atnr_global, 0, mtop->natoms-1);
- }
-#endif
-
- mb0 = -1;
- mb1 = alook->nmb;
- mb = alook->mb_start;
-
- while (TRUE)
- {
- a_start = alook->mba[mb].a_start;
- if (atnr_global < a_start)
- {
- mb1 = mb;
- }
- else if (atnr_global >= alook->mba[mb].a_end)
- {
- mb0 = mb;
- }
- else
- {
- break;
- }
- mb = ((mb0 + mb1 + 1)>>1);
- }
-
- *ilist_mol = alook->mtop->moltype[alook->mtop->molblock[mb].type].ilist;
-
- atnr_local = (atnr_global - a_start) % alook->mba[mb].na_mol;
-
- *atnr_offset = atnr_global - atnr_local;
-}
-
-void gmx_mtop_atomnr_to_molblock_ind(const gmx_mtop_atomlookup_t alook,
- int atnr_global,
- int *molb, int *molnr, int *atnr_mol)
-{
- int mb0, mb1, mb;
- int a_start;
-
-#ifdef DEBUG_MTOP
- if (atnr_global < 0 || atnr_global >= mtop->natoms)
- {
- gmx_fatal(FARGS, "gmx_mtop_atomnr_to_moltype was called with atnr_global=%d which is not in the atom range of this system (%d-%d)",
- atnr_global, 0, mtop->natoms-1);
- }
-#endif
-
- mb0 = -1;
- mb1 = alook->nmb;
- mb = alook->mb_start;
-
- while (TRUE)
- {
- a_start = alook->mba[mb].a_start;
- if (atnr_global < a_start)
- {
- mb1 = mb;
- }
- else if (atnr_global >= alook->mba[mb].a_end)
- {
- mb0 = mb;
- }
- else
- {
- break;
- }
- mb = ((mb0 + mb1 + 1)>>1);
- }
-
- *molb = mb;
- *molnr = (atnr_global - a_start) / alook->mba[mb].na_mol;
- *atnr_mol = atnr_global - a_start - (*molnr)*alook->mba[mb].na_mol;
-}
-
-void gmx_mtop_atominfo_global(const gmx_mtop_t *mtop, int atnr_global,
- char **atomname, int *resnr, char **resname)
-{
- int mb, a_start, a_end, maxresnr, at_loc;
- t_atoms *atoms = NULL;
-
- if (atnr_global < 0 || atnr_global >= mtop->natoms)
- {
- gmx_fatal(FARGS, "gmx_mtop_atominfo_global was called with atnr_global=%d which is not in the atom range of this system (%d-%d)",
- atnr_global, 0, mtop->natoms-1);
- }
-
- mb = -1;
- a_end = 0;
- maxresnr = mtop->maxresnr;
- do
- {
- if (mb >= 0)
- {
- /* cppcheck-suppress nullPointer #6330 will be fixed in cppcheck 1.73 */
- if (atoms->nres <= mtop->maxres_renum)
- {
- /* Single residue molecule, keep counting */
- /* cppcheck-suppress nullPointer #6330 will be fixed in cppcheck 1.73 */
- maxresnr += mtop->molblock[mb].nmol*atoms->nres;
- }
- }
- mb++;
- atoms = &mtop->moltype[mtop->molblock[mb].type].atoms;
- a_start = a_end;
- a_end = a_start + mtop->molblock[mb].nmol*atoms->nr;
- }
- while (atnr_global >= a_end);
-
- at_loc = (atnr_global - a_start) % atoms->nr;
- *atomname = *(atoms->atomname[at_loc]);
- if (atoms->nres > mtop->maxres_renum)
- {
- *resnr = atoms->resinfo[atoms->atom[at_loc].resind].nr;
- }
- else
- {
- /* Single residue molecule, keep counting */
- *resnr = maxresnr + 1 + (atnr_global - a_start)/atoms->nr*atoms->nres + atoms->atom[at_loc].resind;
- }
- *resname = *(atoms->resinfo[atoms->atom[at_loc].resind].name);
-}
-
typedef struct gmx_mtop_atomloop_all
{
const gmx_mtop_t *mtop;
}
gmx_bool gmx_mtop_atomloop_all_next(gmx_mtop_atomloop_all_t aloop,
- int *at_global, t_atom **atom)
+ int *at_global, const t_atom **atom)
{
if (aloop == NULL)
{
}
gmx_bool gmx_mtop_atomloop_block_next(gmx_mtop_atomloop_block_t aloop,
- t_atom **atom, int *nmol)
+ const t_atom **atom, int *nmol)
{
if (aloop == NULL)
{
int srcnr = src->nr;
int destnr = dest->nr;
+ if (dest->nr == 0)
+ {
+ dest->haveMass = src->haveMass;
+ dest->haveType = src->haveType;
+ dest->haveCharge = src->haveCharge;
+ dest->haveBState = src->haveBState;
+ dest->havePdbInfo = src->havePdbInfo;
+ }
+ else
+ {
+ dest->haveMass = dest->haveMass && src->haveMass;
+ dest->haveType = dest->haveType && src->haveType;
+ dest->haveCharge = dest->haveCharge && src->haveCharge;
+ dest->haveBState = dest->haveBState && src->haveBState;
+ dest->havePdbInfo = dest->havePdbInfo && src->havePdbInfo;
+ }
+
if (srcnr)
{
size = destnr+copies*srcnr;
srenew(dest->atom, size);
srenew(dest->atomname, size);
- srenew(dest->atomtype, size);
- srenew(dest->atomtypeB, size);
+ if (dest->haveType)
+ {
+ srenew(dest->atomtype, size);
+ if (dest->haveBState)
+ {
+ srenew(dest->atomtypeB, size);
+ }
+ }
+ if (dest->havePdbInfo)
+ {
+ srenew(dest->pdbinfo, size);
+ }
}
if (src->nres)
{
for (l = destnr, j = 0; (j < copies); j++, l += srcnr)
{
- memcpy((char *) &(dest->atomname[l]), (char *) &(src->atomname[0]),
- (size_t)(srcnr*sizeof(src->atomname[0])));
- memcpy((char *) &(dest->atomtype[l]), (char *) &(src->atomtype[0]),
- (size_t)(srcnr*sizeof(src->atomtype[0])));
- memcpy((char *) &(dest->atomtypeB[l]), (char *) &(src->atomtypeB[0]),
- (size_t)(srcnr*sizeof(src->atomtypeB[0])));
memcpy((char *) &(dest->atom[l]), (char *) &(src->atom[0]),
(size_t)(srcnr*sizeof(src->atom[0])));
+ memcpy((char *) &(dest->atomname[l]), (char *) &(src->atomname[0]),
+ (size_t)(srcnr*sizeof(src->atomname[0])));
+ if (dest->haveType)
+ {
+ memcpy((char *) &(dest->atomtype[l]), (char *) &(src->atomtype[0]),
+ (size_t)(srcnr*sizeof(src->atomtype[0])));
+ if (dest->haveBState)
+ {
+ memcpy((char *) &(dest->atomtypeB[l]), (char *) &(src->atomtypeB[0]),
+ (size_t)(srcnr*sizeof(src->atomtypeB[0])));
+ }
+ }
+ if (dest->havePdbInfo)
+ {
+ memcpy((char *) &(dest->pdbinfo[l]), (char *) &(src->pdbinfo[0]),
+ (size_t)(srcnr*sizeof(src->pdbinfo[0])));
+ }
}
/* Increment residue indices */
real *qA, *qB;
gmx_mtop_atomloop_all_t aloop;
int ag;
- t_atom *atom;
top->atomtypes = mtop->atomtypes;
snew(qA, mtop->natoms);
snew(qB, mtop->natoms);
aloop = gmx_mtop_atomloop_all_init(mtop);
+ const t_atom *atom;
while (gmx_mtop_atomloop_all_next(aloop, &ag, &atom))
{
qA[ag] = atom->q;
return top;
}
-t_topology gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop)
+t_topology gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop, bool freeMTop)
{
int mt, mb;
gmx_localtop_t ltop;
top.bIntermolecularInteractions = mtop->bIntermolecularInteractions;
top.symtab = mtop->symtab;
- /* We only need to free the moltype and molblock data,
- * all other pointers have been copied to top.
- *
- * Well, except for the group data, but we can't free those, because they
- * are used somewhere even after a call to this function.
- */
- for (mt = 0; mt < mtop->nmoltype; mt++)
+ if (freeMTop)
{
- done_moltype(&mtop->moltype[mt]);
- }
- sfree(mtop->moltype);
+ // Free pointers that have not been copied to top.
+ for (mt = 0; mt < mtop->nmoltype; mt++)
+ {
+ done_moltype(&mtop->moltype[mt]);
+ }
+ sfree(mtop->moltype);
- for (mb = 0; mb < mtop->nmolblock; mb++)
- {
- done_molblock(&mtop->molblock[mb]);
+ for (mb = 0; mb < mtop->nmolblock; mb++)
+ {
+ done_molblock(&mtop->molblock[mb]);
+ }
+ sfree(mtop->molblock);
+
+ done_gmx_groups_t(&mtop->groups);
}
- sfree(mtop->molblock);
return top;
}
std::vector<size_t> atom_index;
gmx_mtop_atomloop_block_t aloopb = gmx_mtop_atomloop_block_init(mtop);
- t_atom *atom;
+ const t_atom *atom;
int nmol, j = 0;
while (gmx_mtop_atomloop_block_next(aloopb, &atom, &nmol))
{
}
return atom_index;
}
+
+void convertAtomsToMtop(t_symtab *symtab,
+ char **name,
+ t_atoms *atoms,
+ gmx_mtop_t *mtop)
+{
+ mtop->symtab = *symtab;
+
+ mtop->name = name;
+
+ mtop->nmoltype = 1;
+ // This snew clears all entries, we should replace it by an initializer
+ snew(mtop->moltype, mtop->nmoltype);
+ mtop->moltype[0].atoms = *atoms;
+ init_block(&mtop->moltype[0].cgs);
+ init_blocka(&mtop->moltype[0].excls);
+
+ mtop->nmolblock = 1;
+ // This snew clears all entries, we should replace it by an initializer
+ snew(mtop->molblock, mtop->nmolblock);
+ mtop->molblock[0].type = 0;
+ mtop->molblock[0].nmol = 1;
+ mtop->molblock[0].natoms_mol = atoms->nr;
+
+ mtop->bIntermolecularInteractions = FALSE;
+
+ mtop->natoms = atoms->nr;
+
+ gmx_mtop_finalize(mtop);
+}
#include <vector>
+#include "gromacs/topology/topology.h"
#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/gmxassert.h"
struct gmx_localtop_t;
-struct gmx_moltype_t;
-struct gmx_mtop_t;
struct t_atom;
struct t_atoms;
struct t_block;
struct t_ilist;
-struct t_topology;
+struct t_symtab;
/* Should be called after generating or reading mtop,
* to set some compute intesive variables to avoid
int
ncg_mtop(const gmx_mtop_t *mtop);
+/* Returns the total number of residues in mtop. */
+int gmx_mtop_nres(const gmx_mtop_t *mtop);
+
/* Removes the charge groups, i.e. makes single atom charge groups, in mtop */
void gmx_mtop_remove_chargegroups(gmx_mtop_t *mtop);
-
-/* Abstract data type for looking up atoms by global atom number */
-typedef struct gmx_mtop_atomlookup *gmx_mtop_atomlookup_t;
-
-/* Initialize atom lookup by global atom number */
-gmx_mtop_atomlookup_t
-gmx_mtop_atomlookup_init(const gmx_mtop_t *mtop);
-
-/* As gmx_mtop_atomlookup_init, but optimized for atoms involved in settle */
-gmx_mtop_atomlookup_t
-gmx_mtop_atomlookup_settle_init(const gmx_mtop_t *mtop);
-
-/* Destroy a gmx_mtop_atomlookup_t data structure */
-void
-gmx_mtop_atomlookup_destroy(gmx_mtop_atomlookup_t alook);
-
-
-/* Returns a pointer to the t_atom struct belonging to atnr_global.
- * This can be an expensive operation, so if possible use
- * one of the atom loop constructs below.
- */
-void
-gmx_mtop_atomnr_to_atom(const gmx_mtop_atomlookup_t alook,
- int atnr_global,
- t_atom **atom);
-
-
-/* Returns a pointer to the molecule interaction array ilist_mol[F_NRE]
- * and the local atom number in the molecule belonging to atnr_global.
- */
-void
-gmx_mtop_atomnr_to_ilist(const gmx_mtop_atomlookup_t alook,
- int atnr_global,
- t_ilist **ilist_mol, int *atnr_offset);
-
-
-/* Returns the molecule block index
- * and the molecule number in the block
- * and the atom number offset for the atom indices in moltype
- * belonging to atnr_global.
- */
-void
-gmx_mtop_atomnr_to_molblock_ind(const gmx_mtop_atomlookup_t alook,
- int atnr_global,
- int *molb, int *molnr, int *atnr_mol);
-
-
-/* Returns atom name, global resnr and residue name of atom atnr_global */
-void
-gmx_mtop_atominfo_global(const gmx_mtop_t *mtop, int atnr_global,
- char **atomname, int *resnr, char **resname);
-
-
/* Abstract type for atom loop over all atoms */
typedef struct gmx_mtop_atomloop_all *gmx_mtop_atomloop_all_t;
*/
gmx_bool
gmx_mtop_atomloop_all_next(gmx_mtop_atomloop_all_t aloop,
- int *at_global, t_atom **atom);
+ int *at_global, const t_atom **atom);
/* Return the atomname, the residue number and residue name
* of the current atom in the loop.
*/
gmx_bool
gmx_mtop_atomloop_block_next(gmx_mtop_atomloop_block_t aloop,
- t_atom **atom, int *nmol);
+ const t_atom **atom, int *nmol);
/* Abstract type for ilist loop over all ilists */
/* Generate a 'local' topology for the whole system.
- * When feeEnergyInteractionsAtEnd == true, the free energy interactions will
+ * When freeEnergyInteractionsAtEnd == true, the free energy interactions will
* be sorted to the end.
*/
gmx_localtop_t *
/* Converts a gmx_mtop_t struct to t_topology.
- * All memory relating only to mtop will be freed.
+ *
+ * If freeMTop == true, memory related to mtop will be freed so that done_top()
+ * on the result value will free all memory.
+ * If freeMTop == false, mtop and the return value will share some of their
+ * memory, and there is currently no way to consistently free all the memory.
*/
t_topology
-gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop);
+gmx_mtop_t_to_t_topology(gmx_mtop_t *mtop, bool freeMTop);
/*! \brief Get vector of atoms indices from topology
*
*/
std::vector<size_t> get_atom_index(const gmx_mtop_t *mtop);
+/*! \brief Converts a t_atoms struct to an mtop struct
+ *
+ * All pointers contained in \p atoms will be copied into \p mtop.
+ * Note that this will produce one moleculetype encompassing the whole system.
+ *
+ * \param[in] symtab The symbol table
+ * \param[in] name Pointer to the name for the topology
+ * \param[in] atoms The atoms to convert
+ * \param[out] mtop The molecular topology output containing atoms.
+ */
+void
+convertAtomsToMtop(t_symtab *symtab,
+ char **name,
+ t_atoms *atoms,
+ gmx_mtop_t *mtop);
+
#endif
*
* 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.
* Returns a pointer to a static area which contains a copy
* of s without leading or trailing spaces. Strings are
* truncated to BUFSIZE positions.
+ *
+ * TODO This partially duplicates code in trim(), but perhaps
+ * replacing symtab with a std::map is a better fix.
*/
{
int len, i;
s, strlen(s), maxlen-1);
}
- for (; (*s) && ((*s) == ' '); s++)
+ for (; (*s) == ' '; s++)
{
;
}
*
* 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"
}
}
-void done_mtop(gmx_mtop_t *mtop, gmx_bool bDoneSymtab)
+void done_gmx_groups_t(gmx_groups_t *g)
{
- if (bDoneSymtab)
+ int i;
+
+ for (i = 0; (i < egcNR); i++)
{
- done_symtab(&mtop->symtab);
+ if (NULL != g->grps[i].nm_ind)
+ {
+ sfree(g->grps[i].nm_ind);
+ g->grps[i].nm_ind = NULL;
+ }
+ if (NULL != g->grpnr[i])
+ {
+ sfree(g->grpnr[i]);
+ g->grpnr[i] = NULL;
+ }
}
+ /* The contents of this array is in symtab, don't free it here */
+ sfree(g->grpname);
+}
+
+void done_mtop(gmx_mtop_t *mtop)
+{
+ done_symtab(&mtop->symtab);
sfree(mtop->ffparams.functype);
sfree(mtop->ffparams.iparams);
done_molblock(&mtop->molblock[i]);
}
sfree(mtop->molblock);
+ done_atomtypes(&mtop->atomtypes);
+ done_gmx_groups_t(&mtop->groups);
done_block(&mtop->mols);
}
done_blocka(&(top->excls));
}
+void done_top_mtop(t_topology *top, gmx_mtop_t *mtop)
+{
+ if (mtop != nullptr)
+ {
+ if (top != nullptr)
+ {
+ for (int f = 0; f < F_NRE; ++f)
+ {
+ sfree(top->idef.il[f].iatoms);
+ top->idef.il[f].iatoms = NULL;
+ top->idef.il[f].nalloc = 0;
+ }
+ done_atom(&top->atoms);
+ done_block(&top->cgs);
+ done_blocka(&top->excls);
+ done_symtab(&top->symtab);
+ open_symtab(&mtop->symtab);
+ }
+ done_mtop(mtop);
+ }
+}
+
+bool gmx_mtop_has_masses(const gmx_mtop_t *mtop)
+{
+ if (mtop == nullptr)
+ {
+ return false;
+ }
+ return mtop->nmoltype == 0 || mtop->moltype[0].atoms.haveMass;
+}
+
+bool gmx_mtop_has_charges(const gmx_mtop_t *mtop)
+{
+ if (mtop == nullptr)
+ {
+ return false;
+ }
+ return mtop->nmoltype == 0 || mtop->moltype[0].atoms.haveCharge;
+}
+
+bool gmx_mtop_has_atomtypes(const gmx_mtop_t *mtop)
+{
+ if (mtop == nullptr)
+ {
+ return false;
+ }
+ return mtop->nmoltype == 0 || mtop->moltype[0].atoms.haveType;
+}
+
+bool gmx_mtop_has_pdbinfo(const gmx_mtop_t *mtop)
+{
+ if (mtop == nullptr)
+ {
+ return false;
+ }
+ return mtop->nmoltype == 0 || mtop->moltype[0].atoms.havePdbInfo;
+}
+
static void pr_grps(FILE *fp, const char *title, const t_grps grps[], char **grpname[])
{
int i, j;
static void pr_moltype(FILE *fp, int indent, const char *title,
const gmx_moltype_t *molt, int n,
const gmx_ffparams_t *ffparams,
- gmx_bool bShowNumbers)
+ gmx_bool bShowNumbers, gmx_bool bShowParameters)
{
int j;
for (j = 0; (j < F_NRE); j++)
{
pr_ilist(fp, indent, interaction_function[j].longname,
- ffparams->functype, &molt->ilist[j], bShowNumbers);
+ ffparams->functype, &molt->ilist[j],
+ bShowNumbers, bShowParameters, ffparams->iparams);
}
}
}
void pr_mtop(FILE *fp, int indent, const char *title, const gmx_mtop_t *mtop,
- gmx_bool bShowNumbers)
+ gmx_bool bShowNumbers, gmx_bool bShowParameters)
{
int mt, mb, j;
{
pr_ilist(fp, indent, interaction_function[j].longname,
mtop->ffparams.functype,
- &mtop->intermolecular_ilist[j], bShowNumbers);
+ &mtop->intermolecular_ilist[j],
+ bShowNumbers, bShowParameters, mtop->ffparams.iparams);
}
}
pr_ffparams(fp, indent, "ffparams", &(mtop->ffparams), bShowNumbers);
for (mt = 0; mt < mtop->nmoltype; mt++)
{
pr_moltype(fp, indent, "moltype", &mtop->moltype[mt], mt,
- &mtop->ffparams, bShowNumbers);
+ &mtop->ffparams, bShowNumbers, bShowParameters);
}
pr_groups(fp, indent, &mtop->groups, bShowNumbers);
}
}
-void pr_top(FILE *fp, int indent, const char *title, const t_topology *top, gmx_bool bShowNumbers)
+void pr_top(FILE *fp, int indent, const char *title, const t_topology *top,
+ gmx_bool bShowNumbers, gmx_bool bShowParameters)
{
if (available(fp, top, indent, title))
{
pr_str(fp, indent, "bIntermolecularInteractions",
gmx::boolToString(top->bIntermolecularInteractions));
pr_blocka(fp, indent, "excls", &top->excls, bShowNumbers);
- pr_idef(fp, indent, "idef", &top->idef, bShowNumbers);
+ pr_idef(fp, indent, "idef", &top->idef, bShowNumbers, bShowParameters);
+ }
+}
+
+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.
+ */
}
*
* 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,
t_blocka excls; /* The exclusions */
} gmx_moltype_t;
+/*! \brief Block of molecules of the same type, used in gmx_mtop_t */
typedef struct gmx_molblock_t
{
- int type; /* The molcule type index in mtop.moltype */
- int nmol; /* The number of molecules in this block */
- int natoms_mol; /* The number of atoms in one molecule */
- int nposres_xA; /* The number of posres coords for top A */
- rvec *posres_xA; /* The posres coords for top A */
- int nposres_xB; /* The number of posres coords for top B */
- rvec *posres_xB; /* The posres coords for top B */
+ int type; /**< The molecule type index in mtop.moltype */
+ int nmol; /**< The number of molecules in this block */
+ int nposres_xA; /**< The number of posres coords for top A */
+ rvec *posres_xA; /**< Position restraint coordinates for top A */
+ int nposres_xB; /**< The number of posres coords for top B */
+ rvec *posres_xB; /**< Position restraint coordinates for top B */
+
+ /* Convenience information, derived from other gmx_mtop_t contents */
+ int natoms_mol; /**< The number of atoms in one molecule */
+ int globalAtomStart; /**< Global atom index of the first atom in the block */
+ int globalAtomEnd; /**< Global atom index + 1 of the last atom in the block */
+ int globalResidueStart; /**< Global residue index of the first residue in the block */
+ int residueNumberStart; /**< Residue numbers start from this value if the number of residues per molecule is <= maxres_renum */
} gmx_molblock_t;
typedef struct gmx_groups_t
void init_top(t_topology *top);
void done_moltype(gmx_moltype_t *molt);
void done_molblock(gmx_molblock_t *molb);
-void done_mtop(gmx_mtop_t *mtop, gmx_bool bDoneSymtab);
+void done_gmx_groups_t(gmx_groups_t *g);
+void done_mtop(gmx_mtop_t *mtop);
void done_top(t_topology *top);
+// Frees both t_topology and gmx_mtop_t when the former has been created from
+// the latter.
+void done_top_mtop(t_topology *top, gmx_mtop_t *mtop);
-t_atoms *mtop2atoms(gmx_mtop_t *mtop);
-/* generate a t_atoms struct for the system from gmx_mtop_t */
+bool gmx_mtop_has_masses(const gmx_mtop_t *mtop);
+bool gmx_mtop_has_charges(const gmx_mtop_t *mtop);
+bool gmx_mtop_has_atomtypes(const gmx_mtop_t *mtop);
+bool gmx_mtop_has_pdbinfo(const gmx_mtop_t *mtop);
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);
+ gmx_bool bShowNumbers, gmx_bool bShowParameters);
+void pr_top(FILE *fp, int indent, const char *title, const t_topology *top,
+ gmx_bool bShowNumbers, gmx_bool bShowParameters);
-#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
#
# 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
)
-
--- /dev/null
+/*
+ * 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);
+ }
+}
* 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"
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
/*
* 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.
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);
}
/*
* 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 "gromacs/commandline/cmdlineoptionsmodule.h"
#include "gromacs/fileio/trxio.h"
#include "gromacs/math/vec.h"
+#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/arrayref.h"
#include "gromacs/utility/exceptions.h"
*/
TopologyInformation::TopologyInformation()
- : top_(NULL), bTop_(false), xtop_(NULL), ePBC_(-1)
+ : mtop_(NULL), top_(NULL), bTop_(false), xtop_(NULL), ePBC_(-1)
{
clear_mat(boxtop_);
}
TopologyInformation::~TopologyInformation()
{
- if (top_)
+ done_top_mtop(top_, mtop_);
+ sfree(mtop_);
+ sfree(top_);
+ sfree(xtop_);
+}
+
+
+t_topology *TopologyInformation::topology() const
+{
+ if (top_ == nullptr && mtop_ != nullptr)
{
- done_top(top_);
- sfree(top_);
+ snew(top_, 1);
+ *top_ = gmx_mtop_t_to_t_topology(mtop_, false);
}
- sfree(xtop_);
+ return top_;
}
/*
* 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 "gromacs/options/timeunitmanager.h"
#include "gromacs/utility/classhelpers.h"
+struct gmx_mtop_t;
struct t_topology;
namespace gmx
{
public:
//! Returns true if a topology file was loaded.
- bool hasTopology() const { return top_ != NULL; }
+ bool hasTopology() const { return mtop_ != NULL; }
//! Returns true if a full topology file was loaded.
bool hasFullTopology() const { return bTop_; }
//! Returns the loaded topology, or NULL if not loaded.
- t_topology *topology() const { return top_; }
+ const gmx_mtop_t *mtop() const { return mtop_; }
+ //! Returns the loaded topology, or NULL if not loaded.
+ t_topology *topology() const;
//! Returns the ePBC field from the topology.
int ePBC() const { return ePBC_; }
/*! \brief
TopologyInformation();
~TopologyInformation();
+ gmx_mtop_t *mtop_;
//! The topology structure, or NULL if no topology loaded.
- t_topology *top_;
+ // TODO: Replace fully with mtop.
+ mutable t_topology *top_;
//! true if full tpx file was loaded, false otherwise.
bool bTop_;
//! Coordinates from the topology (can be NULL).
/*
* 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.
#include "modules/rdf.h"
#include "modules/sasa.h"
#include "modules/select.h"
+#include "modules/trajectory.h"
namespace gmx
{
registerModule<RdfInfo>(manager, group);
registerModule<SasaInfo>(manager, group);
registerModule<SelectInfo>(manager, group);
+ registerModule<TrajectoryInfo>(manager, group);
}
//! \endcond
/*
* 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.
real dist = norm(dx);
bool bPresent = p1.selected() && p2.selected();
distHandle.setPoint(n, dist, bPresent);
- xyzHandle.setPoints(n*3, 3, dx);
+ xyzHandle.setPoints(n*3, 3, dx, bPresent);
}
}
distHandle.finishFrame();
/*
* 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.
}
//! Helper function to initialize the grouping for a selection.
-int initSelectionGroups(Selection *sel, t_topology *top, int type)
+int initSelectionGroups(Selection *sel, const gmx_mtop_t *top, int type)
{
e_index_t indexType = INDEX_UNKNOWN;
switch (type)
PairDistance::initAnalysis(const TrajectoryAnalysisSettings &settings,
const TopologyInformation &top)
{
- refGroupCount_ = initSelectionGroups(&refSel_, top.topology(), refGroupType_);
+ refGroupCount_ = initSelectionGroups(&refSel_, top.mtop(), refGroupType_);
maxGroupCount_ = 0;
distances_.setDataSetCount(sel_.size());
for (size_t i = 0; i < sel_.size(); ++i)
{
const int selGroupCount
- = initSelectionGroups(&sel_[i], top.topology(), selGroupType_);
+ = initSelectionGroups(&sel_[i], top.mtop(), selGroupType_);
const int columnCount = refGroupCount_ * selGroupCount;
maxGroupCount_ = std::max(maxGroupCount_, columnCount);
distances_.setColumnCount(i, columnCount);
GMX_THROW(InconsistentInputError("-surf only works with -ref that consists of atoms"));
}
const e_index_t type = (surface_ == SurfaceType_Molecule ? INDEX_MOL : INDEX_RES);
- surfaceGroupCount_ = refSel_.initOriginalIdsToGroup(top.topology(), type);
+ surfaceGroupCount_ = refSel_.initOriginalIdsToGroup(top.mtop(), type);
}
if (bExclusions_)
dgsFactor_.reserve(surfaceSel_.posCount());
}
- const int resCount = surfaceSel_.initOriginalIdsToGroup(top_, INDEX_RES);
+ const int resCount = surfaceSel_.initOriginalIdsToGroup(top.mtop(), INDEX_RES);
// TODO: Not exception-safe, but nice solution would be to have a C++
// atom properties class...
/*
* 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.
{
std::string newName(name);
std::replace(newName.begin(), newName.end(), ' ', '_');
- groups_.push_back(GroupInfo(newName, bDynamic));
+ groups_.emplace_back(newName, bDynamic);
}
private:
SelectionList sel_;
- SelectionOptionInfo *selOpt_;
std::string fnSize_;
std::string fnFrac_;
};
Select::Select()
- : selOpt_(NULL), bTotNorm_(false), bFracNorm_(false), bResInd_(false),
+ : bTotNorm_(false), bFracNorm_(false), bResInd_(false),
bCumulativeLifetimes_(true), resNumberType_(ResidueNumbering_ByNumber),
pdbAtoms_(PdbAtomsSelection_All), top_(NULL),
occupancyModule_(new AnalysisDataAverageModule()),
"be combined with output from other programs and/or external",
"analysis programs to calculate more complex things.",
"For detailed help on the selection syntax, please use",
- "[TT]gmx help selections[tt].[PAR]",
+ "[TT]gmx help selections[tt].",
+ "",
"Any combination of the output options is possible, but note",
"that [TT]-om[tt] only operates on the first selection.",
"Also note that if you provide no output options, no output is",
- "produced.[PAR]",
+ "produced.",
+ "",
"With [TT]-os[tt], calculates the number of positions in each",
"selection for each frame. With [TT]-norm[tt], the output is",
"between 0 and 1 and describes the fraction from the maximum",
"RA residues). With [TT]-cfnorm[tt], the output is divided",
"by the fraction covered by the selection.",
"[TT]-norm[tt] and [TT]-cfnorm[tt] can be specified independently",
- "of one another.[PAR]",
+ "of one another.",
+ "",
"With [TT]-oc[tt], the fraction covered by each selection is",
- "written out as a function of time.[PAR]",
+ "written out as a function of time.",
+ "",
"With [TT]-oi[tt], the selected atoms/residues/molecules are",
"written out as a function of time. In the output, the first",
"column contains the frame time, the second contains the number",
"of positions, followed by the atom/residue/molecule numbers.",
"If more than one selection is specified, the size of the second",
"group immediately follows the last number of the first group",
- "and so on.[PAR]",
+ "and so on.",
+ "",
"With [TT]-on[tt], the selected atoms are written as a index file",
"compatible with [TT]make_ndx[tt] and the analyzing tools. Each selection",
"is written as a selection group and for dynamic selections a",
- "group is written for each frame.[PAR]",
+ "group is written for each frame.",
+ "",
"For residue numbers, the output of [TT]-oi[tt] can be controlled",
"with [TT]-resnr[tt]: [TT]number[tt] (default) prints the residue",
"numbers as they appear in the input file, while [TT]index[tt] prints",
"unique numbers assigned to the residues in the order they appear",
"in the input file, starting with 1. The former is more intuitive,",
"but if the input contains multiple residues with the same number,",
- "the output can be less useful.[PAR]",
+ "the output can be less useful.",
+ "",
"With [TT]-om[tt], a mask is printed for the first selection",
"as a function of time. Each line in the output corresponds to",
"one frame, and contains either 0/1 for each atom/residue/molecule",
"possibly selected. 1 stands for the atom/residue/molecule being",
- "selected for the current frame, 0 for not selected.[PAR]",
+ "selected for the current frame, 0 for not selected.",
+ "",
"With [TT]-of[tt], the occupancy fraction of each position (i.e.,",
"the fraction of frames where the position is selected) is",
- "printed.[PAR]",
+ "printed.",
+ "",
"With [TT]-ofpdb[tt], a PDB file is written out where the occupancy",
"column is filled with the occupancy fraction of each atom in the",
"selection. The coordinates in the PDB file will be those from the",
"appear in the output PDB file: with [TT]all[tt] all atoms are",
"present, with [TT]maxsel[tt] all atoms possibly selected by the",
"selection are present, and with [TT]selected[tt] only atoms that are",
- "selected at least in one frame are present.[PAR]",
+ "selected at least in one frame are present.",
+ "",
"With [TT]-olt[tt], a histogram is produced that shows the number of",
"selected positions as a function of the time the position was",
"continuously selected. [TT]-cumlt[tt] can be used to control whether",
"subintervals of longer intervals are included in the histogram.[PAR]",
"[TT]-om[tt], [TT]-of[tt], and [TT]-olt[tt] only make sense with",
- "dynamic selections."
+ "dynamic selections.",
+ "",
+ "To plot coordinates for selections, use [gmx-trajectory]."
};
settings->setHelpText(desc);
.store(&fnLifetime_).defaultBasename("lifetime")
.description("Lifetime histogram"));
- selOpt_ = options->addOption(SelectionOption("select").storeVector(&sel_)
- .required().multiValue()
- .description("Selections to analyze"));
+ options->addOption(SelectionOption("select").storeVector(&sel_)
+ .required().multiValue()
+ .description("Selections to analyze"));
options->addOption(BooleanOption("norm").store(&bTotNorm_)
.description("Normalize by total number of positions with -os"));
t_pdbinfo *pdbinfo;
snew(pdbinfo, atoms.nr);
scoped_guard_sfree pdbinfoGuard(pdbinfo);
- if (atoms.pdbinfo != NULL)
+ if (atoms.havePdbInfo)
{
std::memcpy(pdbinfo, atoms.pdbinfo, atoms.nr*sizeof(*pdbinfo));
}
+ else
+ {
+ atoms.havePdbInfo = TRUE;
+ }
atoms.pdbinfo = pdbinfo;
for (int i = 0; i < atoms.nr; ++i)
{
--- /dev/null
+/*
+ * 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 gmx::analysismodules::Trajectory.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_trajectoryanalysis
+ */
+#include "gmxpre.h"
+
+#include "trajectory.h"
+
+#include <algorithm>
+
+#include "gromacs/analysisdata/analysisdata.h"
+#include "gromacs/analysisdata/modules/plot.h"
+#include "gromacs/fileio/trxio.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/filenameoption.h"
+#include "gromacs/options/ioptionscontainer.h"
+#include "gromacs/selection/selection.h"
+#include "gromacs/selection/selectionoption.h"
+#include "gromacs/trajectory/trajectoryframe.h"
+#include "gromacs/trajectoryanalysis/analysissettings.h"
+
+namespace gmx
+{
+
+namespace analysismodules
+{
+
+namespace
+{
+
+/********************************************************************
+ * Trajectory
+ */
+
+class Trajectory : public TrajectoryAnalysisModule
+{
+ public:
+ Trajectory();
+
+ virtual void initOptions(IOptionsContainer *options,
+ TrajectoryAnalysisSettings *settings);
+ virtual void optionsFinished(TrajectoryAnalysisSettings *settings);
+ virtual void initAnalysis(const TrajectoryAnalysisSettings &settings,
+ const TopologyInformation &top);
+
+ virtual void analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
+ TrajectoryAnalysisModuleData *pdata);
+
+ virtual void finishAnalysis(int nframes);
+ virtual void writeOutput();
+
+ private:
+ SelectionList sel_;
+
+ std::string fnX_;
+ std::string fnV_;
+ std::string fnF_;
+ bool dimMask_[4];
+ bool maskSet_[4];
+
+ AnalysisData xdata_;
+ AnalysisData vdata_;
+ AnalysisData fdata_;
+};
+
+Trajectory::Trajectory()
+{
+ std::fill(std::begin(dimMask_), std::end(dimMask_), true);
+ dimMask_[DIM] = false;
+ std::fill(std::begin(maskSet_), std::end(maskSet_), false);
+ registerAnalysisDataset(&xdata_, "x");
+ registerAnalysisDataset(&vdata_, "v");
+ registerAnalysisDataset(&fdata_, "f");
+}
+
+
+void
+Trajectory::initOptions(IOptionsContainer *options, TrajectoryAnalysisSettings *settings)
+{
+ static const char *const desc[] = {
+ "[THISMODULE] plots coordinates, velocities, and/or forces for",
+ "provided selections. By default, the X, Y, and Z components for",
+ "the requested vectors are plotted, but specifying one or more of",
+ "[TT]-len[tt], [TT]-x[tt], [TT]-y[tt], and [TT]-z[tt] overrides this.",
+ "",
+ "For dynamic selections, currently the values are written out for",
+ "all positions that the selection could select."
+ };
+
+ settings->setHelpText(desc);
+
+ options->addOption(FileNameOption("ox").filetype(eftPlot).outputFile()
+ .store(&fnX_).defaultBasename("coord")
+ .description("Coordinates for each position as a function of time"));
+ options->addOption(FileNameOption("ov").filetype(eftPlot).outputFile()
+ .store(&fnV_).defaultBasename("veloc")
+ .description("Velocities for each position as a function of time"));
+ options->addOption(FileNameOption("of").filetype(eftPlot).outputFile()
+ .store(&fnF_).defaultBasename("force")
+ .description("Forces for each position as a function of time"));
+
+ options->addOption(SelectionOption("select").storeVector(&sel_)
+ .required().dynamicMask().multiValue()
+ .description("Selections to analyze"));
+
+ options->addOption(BooleanOption("x").store(&dimMask_[XX])
+ .storeIsSet(&maskSet_[XX])
+ .description("Plot X component"));
+ options->addOption(BooleanOption("y").store(&dimMask_[YY])
+ .storeIsSet(&maskSet_[YY])
+ .description("Plot Y component"));
+ options->addOption(BooleanOption("z").store(&dimMask_[ZZ])
+ .storeIsSet(&maskSet_[ZZ])
+ .description("Plot Z component"));
+ options->addOption(BooleanOption("len").store(&dimMask_[DIM])
+ .storeIsSet(&maskSet_[DIM])
+ .description("Plot vector length"));
+}
+
+
+void
+Trajectory::optionsFinished(TrajectoryAnalysisSettings *settings)
+{
+ int frameFlags = TRX_NEED_X;
+ if (!fnV_.empty())
+ {
+ frameFlags |= TRX_READ_V;
+ }
+ if (!fnF_.empty())
+ {
+ frameFlags |= TRX_READ_F;
+ }
+ settings->setFrameFlags(frameFlags);
+ if (std::count(std::begin(maskSet_), std::end(maskSet_), true) > 0)
+ {
+ for (int i = 0; i <= DIM; ++i)
+ {
+ if (!maskSet_[i])
+ {
+ dimMask_[i] = false;
+ }
+ }
+ }
+}
+
+
+void
+Trajectory::initAnalysis(const TrajectoryAnalysisSettings &settings,
+ const TopologyInformation & /*top*/)
+{
+ if (!fnX_.empty())
+ {
+ xdata_.setDataSetCount(sel_.size());
+ for (size_t g = 0; g < sel_.size(); ++g)
+ {
+ xdata_.setColumnCount(g, 3*sel_[g].posCount());
+ }
+ AnalysisDataVectorPlotModulePointer plot(
+ new AnalysisDataVectorPlotModule(settings.plotSettings()));
+ plot->setWriteMask(dimMask_);
+ plot->setFileName(fnX_);
+ plot->setTitle("Coordinates");
+ plot->setXAxisIsTime();
+ plot->setYLabel("Value [nm]");
+ xdata_.addModule(plot);
+ }
+ if (!fnV_.empty())
+ {
+ vdata_.setDataSetCount(sel_.size());
+ for (size_t g = 0; g < sel_.size(); ++g)
+ {
+ sel_[g].setEvaluateVelocities(true);
+ vdata_.setColumnCount(g, 3*sel_[g].posCount());
+ }
+ AnalysisDataVectorPlotModulePointer plot(
+ new AnalysisDataVectorPlotModule(settings.plotSettings()));
+ plot->setWriteMask(dimMask_);
+ plot->setFileName(fnV_);
+ plot->setTitle("Velocities");
+ plot->setXAxisIsTime();
+ plot->setYLabel("Value [nm/ps]");
+ vdata_.addModule(plot);
+ }
+ if (!fnF_.empty())
+ {
+ fdata_.setDataSetCount(sel_.size());
+ for (size_t g = 0; g < sel_.size(); ++g)
+ {
+ sel_[g].setEvaluateForces(true);
+ fdata_.setColumnCount(g, 3*sel_[g].posCount());
+ }
+ AnalysisDataVectorPlotModulePointer plot(
+ new AnalysisDataVectorPlotModule(settings.plotSettings()));
+ plot->setWriteMask(dimMask_);
+ plot->setFileName(fnF_);
+ plot->setTitle("Forces");
+ plot->setXAxisIsTime();
+ plot->setYLabel("Value [kJ mol\\S-1\\N nm\\S-1\\N]");
+ fdata_.addModule(plot);
+ }
+}
+
+
+void
+Trajectory::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc * /* pbc */,
+ TrajectoryAnalysisModuleData *pdata)
+{
+ const SelectionList &sel = pdata->parallelSelections(sel_);
+
+ // There is some duplication here, but cppcheck cannot handle function
+ // types that return rvec references, and MSVC also apparently segfaults
+ // when using std::function with a member function here...
+ {
+ AnalysisDataHandle dh = pdata->dataHandle(xdata_);
+ if (dh.isValid())
+ {
+ dh.startFrame(frnr, fr.time);
+ for (size_t g = 0; g < sel.size(); ++g)
+ {
+ dh.selectDataSet(g);
+ for (int i = 0; i < sel[g].posCount(); ++i)
+ {
+ const SelectionPosition &pos = sel[g].position(i);
+ dh.setPoints(i*3, 3, pos.x(), pos.selected());
+ }
+ }
+ dh.finishFrame();
+ }
+ }
+ if (fr.bV)
+ {
+ AnalysisDataHandle dh = pdata->dataHandle(xdata_);
+ if (dh.isValid())
+ {
+ dh.startFrame(frnr, fr.time);
+ for (size_t g = 0; g < sel.size(); ++g)
+ {
+ dh.selectDataSet(g);
+ for (int i = 0; i < sel[g].posCount(); ++i)
+ {
+ const SelectionPosition &pos = sel[g].position(i);
+ dh.setPoints(i*3, 3, pos.v(), pos.selected());
+ }
+ }
+ dh.finishFrame();
+ }
+ }
+ if (fr.bF)
+ {
+ AnalysisDataHandle dh = pdata->dataHandle(xdata_);
+ if (dh.isValid())
+ {
+ dh.startFrame(frnr, fr.time);
+ for (size_t g = 0; g < sel.size(); ++g)
+ {
+ dh.selectDataSet(g);
+ for (int i = 0; i < sel[g].posCount(); ++i)
+ {
+ const SelectionPosition &pos = sel[g].position(i);
+ dh.setPoints(i*3, 3, pos.f(), pos.selected());
+ }
+ }
+ dh.finishFrame();
+ }
+ }
+}
+
+
+void
+Trajectory::finishAnalysis(int /*nframes*/)
+{
+}
+
+
+void
+Trajectory::writeOutput()
+{
+}
+
+} // namespace
+
+const char TrajectoryInfo::name[] = "trajectory";
+const char TrajectoryInfo::shortDescription[] =
+ "Print coordinates, velocities, and/or forces for selections";
+
+TrajectoryAnalysisModulePointer TrajectoryInfo::create()
+{
+ return TrajectoryAnalysisModulePointer(new Trajectory);
+}
+
+} // namespace analysismodules
+
+} // namespace gmx
--- /dev/null
+/*
+ * 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
+ * Declares trajectory analysis module for basic trajectory information.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_trajectoryanalysis
+ */
+#ifndef GMX_TRAJECTORYANALYSIS_MODULES_TRAJECTORY_H
+#define GMX_TRAJECTORYANALYSIS_MODULES_TRAJECTORY_H
+
+#include "gromacs/trajectoryanalysis/analysismodule.h"
+
+namespace gmx
+{
+
+namespace analysismodules
+{
+
+class TrajectoryInfo
+{
+ public:
+ static const char name[];
+ static const char shortDescription[];
+ static TrajectoryAnalysisModulePointer create();
+};
+
+} // namespace analysismodules
+
+} // namespace gmx
+
+#endif
void finishTrajectory();
// From ITopologyProvider
- virtual t_topology *getTopology(bool required)
+ virtual gmx_mtop_t *getTopology(bool required)
{
initTopology(required);
- return topInfo_.topology();
+ return topInfo_.mtop_;
}
virtual int getAtomCount()
{
// Load the topology if requested.
if (!topfile_.empty())
{
- snew(topInfo_.top_, 1);
- topInfo_.bTop_ = read_tps_conf(topfile_.c_str(), topInfo_.top_, &topInfo_.ePBC_,
- &topInfo_.xtop_, NULL, topInfo_.boxtop_, TRUE);
+ snew(topInfo_.mtop_, 1);
+ readConfAndTopology(topfile_.c_str(), &topInfo_.bTop_, topInfo_.mtop_,
+ &topInfo_.ePBC_, &topInfo_.xtop_, NULL,
+ topInfo_.boxtop_);
+ // TODO: Only load this here if the tool actually needs it; selections
+ // take care of themselves.
+ for (int i = 0; i < topInfo_.mtop_->nmoltype; ++i)
+ {
+ gmx_moltype_t &moltype = topInfo_.mtop_->moltype[i];
+ if (!moltype.atoms.haveMass)
+ {
+ // Try to read masses from database, be silent about missing masses
+ atomsSetMassesBasedOnNames(&moltype.atoms, FALSE);
+ }
+ }
if (hasTrajectory()
&& !settings_.hasFlag(TrajectoryAnalysisSettings::efUseTopX))
{
sasa.cpp
select.cpp
surfacearea.cpp
+ trajectory.cpp
$<TARGET_OBJECTS:analysisdata-test-shared>)
add_executable(test_selection ${UNITTEST_TARGET_OPTIONS} test_selection.cpp)
</DataValue>
<DataValue>
<Real Name="Value">0</Real>
+ <Bool Name="Present">false</Bool>
</DataValue>
<DataValue>
<Real Name="Value">1</Real>
+ <Bool Name="Present">false</Bool>
</DataValue>
<DataValue>
<Real Name="Value">0</Real>
+ <Bool Name="Present">false</Bool>
</DataValue>
<DataValue>
<Real Name="Value">0</Real>
+ <Bool Name="Present">false</Bool>
</DataValue>
<DataValue>
<Real Name="Value">1</Real>
+ <Bool Name="Present">false</Bool>
</DataValue>
<DataValue>
<Real Name="Value">0</Real>
+ <Bool Name="Present">false</Bool>
</DataValue>
</DataValues>
</DataFrame>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="CommandLine">trajectory -select 'resnr 1' 'resnr 3'</String>
+ <OutputData Name="Data">
+ <AnalysisData Name="x">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0</Real>
+ <DataValues>
+ <Int Name="Count">9</Int>
+ <Int Name="DataSet">0</Int>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">1</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">3</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ </DataValues>
+ <DataValues>
+ <Int Name="Count">9</Int>
+ <Int Name="DataSet">1</Int>
+ <DataValue>
+ <Real Name="Value">1</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">1</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ </DataValues>
+ </DataFrame>
+ <DataFrame Name="Frame1">
+ <Real Name="X">0</Real>
+ <DataValues>
+ <Int Name="Count">9</Int>
+ <Int Name="DataSet">0</Int>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">3</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ </DataValues>
+ <DataValues>
+ <Int Name="Count">9</Int>
+ <Int Name="DataSet">1</Int>
+ <DataValue>
+ <Real Name="Value">1</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">3</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ </DataValues>
+ </DataFrame>
+ </AnalysisData>
+ </OutputData>
+ <OutputFiles Name="Files">
+ <File Name="-ox"></File>
+ </OutputFiles>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="CommandLine">trajectory -select 'resnr 1' 'resnr 3'</String>
+ <OutputData Name="Data">
+ <AnalysisData Name="f"></AnalysisData>
+ </OutputData>
+ <OutputFiles Name="Files">
+ <File Name="-of"></File>
+ </OutputFiles>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="CommandLine">trajectory -select 'resnr 1' 'resnr 3'</String>
+ <OutputData Name="Data">
+ <AnalysisData Name="v"></AnalysisData>
+ </OutputData>
+ <OutputFiles Name="Files">
+ <File Name="-ov"></File>
+ </OutputFiles>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="CommandLine">trajectory -select 'resnr 1' 'resnr 3' -x</String>
+ <OutputData Name="Data">
+ <AnalysisData Name="x">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0</Real>
+ <DataValues>
+ <Int Name="Count">9</Int>
+ <Int Name="DataSet">0</Int>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">1</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">3</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ </DataValues>
+ <DataValues>
+ <Int Name="Count">9</Int>
+ <Int Name="DataSet">1</Int>
+ <DataValue>
+ <Real Name="Value">1</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">1</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ </DataValues>
+ </DataFrame>
+ <DataFrame Name="Frame1">
+ <Real Name="X">0</Real>
+ <DataValues>
+ <Int Name="Count">9</Int>
+ <Int Name="DataSet">0</Int>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">3</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ </DataValues>
+ <DataValues>
+ <Int Name="Count">9</Int>
+ <Int Name="DataSet">1</Int>
+ <DataValue>
+ <Real Name="Value">1</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">3</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">4</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0</Real>
+ </DataValue>
+ </DataValues>
+ </DataFrame>
+ </AnalysisData>
+ </OutputData>
+ <OutputFiles Name="Files">
+ <File Name="-ox"></File>
+ </OutputFiles>
+</ReferenceData>
{
index_.push_back(x_.size());
}
- x_.push_back(gmx::RVec(x, y, z));
+ x_.emplace_back(x, y, z);
radius_.push_back(radius);
}
--- /dev/null
+/*
+ * 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 functionality of the "trajectory" trajectory analysis module.
+ *
+ * Line coverage for the module code is good, but due to missing input data
+ * with velocities or forces, the output of these quantities is not really
+ * tested. But the values are only computed in the selection engine, and
+ * at least the low-level computation is tested there.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \ingroup module_trajectoryanalysis
+ */
+#include "gmxpre.h"
+
+#include "gromacs/trajectoryanalysis/modules/trajectory.h"
+
+#include <gtest/gtest.h>
+
+#include "testutils/cmdlinetest.h"
+#include "testutils/textblockmatchers.h"
+
+#include "moduletest.h"
+
+namespace
+{
+
+using gmx::test::CommandLine;
+using gmx::test::NoTextMatch;
+
+/********************************************************************
+ * Tests for gmx::analysismodules::Trajectory.
+ */
+
+//! Test fixture for the select analysis module.
+typedef gmx::test::TrajectoryAnalysisModuleTestFixture<gmx::analysismodules::TrajectoryInfo>
+ TrajectoryModuleTest;
+
+TEST_F(TrajectoryModuleTest, BasicTest)
+{
+ const char *const cmdline[] = {
+ "trajectory",
+ "-select", "resnr 1", "resnr 3"
+ };
+ setTopology("simple.gro");
+ setTrajectory("simple.gro");
+ setOutputFile("-ox", "coord.xvg", NoTextMatch());
+ includeDataset("x");
+ runTest(CommandLine(cmdline));
+}
+
+TEST_F(TrajectoryModuleTest, PlotsXOnly)
+{
+ const char *const cmdline[] = {
+ "trajectory",
+ "-select", "resnr 1", "resnr 3",
+ "-x"
+ };
+ setTopology("simple.gro");
+ setTrajectory("simple.gro");
+ setOutputFile("-ox", "coord.xvg", NoTextMatch());
+ includeDataset("x");
+ runTest(CommandLine(cmdline));
+}
+
+TEST_F(TrajectoryModuleTest, HandlesNoVelocities)
+{
+ const char *const cmdline[] = {
+ "trajectory",
+ "-select", "resnr 1", "resnr 3",
+ };
+ setTopology("simple.gro");
+ setTrajectory("simple.gro");
+ setOutputFile("-ov", "vel.xvg", NoTextMatch());
+ includeDataset("v");
+ runTest(CommandLine(cmdline));
+}
+
+TEST_F(TrajectoryModuleTest, HandlesNoForces)
+{
+ const char *const cmdline[] = {
+ "trajectory",
+ "-select", "resnr 1", "resnr 3",
+ };
+ setTopology("simple.gro");
+ setTrajectory("simple.gro");
+ setOutputFile("-of", "force.xvg", NoTextMatch());
+ includeDataset("f");
+ runTest(CommandLine(cmdline));
+}
+
+} // namespace
/*
* 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
/*
* 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.
*/
template<class T2>
bool
- operator==(const AlignedAllocator<T2> &gmx_unused rhs) const { return std::is_same<T, T2>::value; }
+ operator==(const AlignedAllocator<T2> &gmx_unused rhs) const { return std::is_same<T, T2>::value; GMX_UNUSED_VALUE(rhs); }
/*! \brief Return true if two allocators are different
*
/*
* 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 <cstddef>
+#include <array>
#include <iterator>
#include <stdexcept>
#include <utility>
*/
struct EmptyArrayRef {};
-/*! \brief
- * STL-like container for an interface to a C array (or part of a std::vector).
+/*! \brief STL-like container for an interface to a C array of T (or part
+ * of a std::vector<T> or std::array<T>).
*
* \tparam T Value type of elements.
*
* following main differences:
* - This class does not have its own storage. Instead, it references an
* existing array of values (either a C-style array or part of an existing
- * std::vector<T>).
+ * std::vector<T> or std::array<T>).
* - It is only possible to modify the values themselves through ArrayRef;
* it is not possible to add or remove values.
* - Copying objects of this type is cheap, and the copies behave identically
* to the original object: the copy references the same set of values.
*
- * This class is useful for writing wrappers that expose a different view of
- * the internal data stored as a single vector/array.
+ * This class is useful for writing wrappers that expose a view of the
+ * internal data stored as a single vector/array, which can be a whole
+ * or part of the underlying storage.
*
* Methods in this class do not throw, except where indicated.
*
GMX_ASSERT(end >= begin, "Invalid range");
}
/*! \brief
- * Constructs a reference to a whole vector.
+ * Constructs a reference to a whole std::vector<T>.
*
* \param[in] v Vector to reference.
*
* lifetime of this object.
*
* This constructor is not explicit to allow directly passing
- * std::vector to a method that takes ArrayRef.
+ * std::vector<T> to a method that takes ArrayRef.
*/
ArrayRef(std::vector<T> &v)
: begin_((!v.empty()) ? &v[0] : NULL),
end_((!v.empty()) ? &v[0] + v.size() : NULL)
{
}
+ /*! \brief
+ * Constructs a reference to a whole std::array<T>.
+ *
+ * \param[in] a Array to reference.
+ *
+ * Passed array must remain valid for the lifetime of this
+ * object.
+ *
+ * This constructor is not explicit to allow directly passing
+ * std::array<T> to a method that takes ArrayRef.
+ */
+ template <size_t count>
+ ArrayRef(std::array<T, count> &a)
+ : begin_((!a.empty()) ? &a[0] : NULL),
+ end_((!a.empty()) ? &a[0] + a.size() : NULL)
+ {
+ }
//! \cond
// Doxygen 1.8.5 doesn't parse the declaration correctly...
/*! \brief
*
* 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])
-/*! \brief
- * STL-like container for non-mutable interface to a C array (or part of a
- * std::vector).
+/*! \brief STL-like container for non-mutable interface to a C array of T
+ * (or part of a std::vector<T> or std::array<T>).
*
* \tparam T Value type of elements.
*
* following main differences:
* - This class does not have its own storage. Instead, it references an
* existing array of values (either a C-style array or part of an existing
- * std::vector<T>).
+ * std::vector<T> or std::array<T>).
* - Only const methods are provided to access the stored values.
* It is not possible to alter the referenced array.
* - Copying objects of this type is cheap, and the copies behave identically
* to the original object: the copy references the same set of values.
*
- * This class is useful for writing wrappers that expose a different view of
- * the internal data stored as a single vector/array.
+ * This class is useful for writing wrappers that expose a view of the
+ * internal data stored as a single vector/array, which can be a whole
+ * or part of the underlying storage.
*
* Methods in this class do not throw, except where indicated.
*
* 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.
*
GMX_ASSERT(end >= begin, "Invalid range");
}
/*! \brief
- * Constructs a reference to a whole vector.
+ * Constructs a reference to a whole std::vector<T>.
*
* \param[in] v Vector to reference.
*
* lifetime of this object.
*
* This constructor is not explicit to allow directly passing
- * std::vector to a method that takes ConstArrayRef.
+ * std::vector<T> to a method that takes ConstArrayRef.
*/
ConstArrayRef(const std::vector<T> &v)
: begin_((!v.empty()) ? &v[0] : NULL),
end_((!v.empty()) ? &v[0] + v.size() : NULL)
{
}
+ /*! \brief
+ * Constructs a reference to a whole std::array<T>.
+ *
+ * \param[in] a Array to reference.
+ *
+ * Passed array must remain valid for the lifetime of this
+ * object.
+ *
+ * This constructor is not explicit to allow directly passing
+ * std::array<T> to a method that takes ConstArrayRef.
+ */
+ template <size_t count>
+ ConstArrayRef(const std::array<T, count> &a)
+ : begin_((!a.empty()) ? &a[0] : NULL),
+ end_((!a.empty()) ? &a[0] + a.size() : NULL)
+ {
+ }
//! \cond
// Doxygen 1.8.5 doesn't parse the declaration correctly...
/*! \brief
*
* 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])
\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.
namespace gmx
{
+#ifdef DOXYGEN
/*! \brief
* Macro to declare a class non-copyable and non-assignable.
*
*
* \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.
*
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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
{ "They don't have half hours in the north", "Carl Caleman" },
{ "Safety lights are for dudes", "Ghostbusters 2016" },
{ "It's 2040 now. Our President is a plant.", "Ghostbusters 2016" },
+ { "It's just B I O L O G Y, can't you see?" "Joe Jackson" },
+ { "Input, output, electricity", "Joni Mitchell" },
+ { "Your daddy ain't your daddy but your daddy don't know", "Dalahan" },
+ { "Why is the Earth moving 'round the sun? Floating in the vacuum with no purpose, not a one", "Fleet Foxes" },
+ { "If you leave markets to act as governments, then sure as night follows day, the market will make people suffer and it will turn the world into a wilderness", "Ann Pettifor" },
+ { "If you look back to the fifties, what all economist call the golden age of economics, 1945-1970 was a period of economic stability, economic activity, pretty much full employment because we managed capital flows, we managed interest rates, we managed exchange rates. We coordinated at an international level to maintain balance in the global economy, we had a golden age. And now we're being told, you can't have another golden age, now we have to go through a period of fascism, this is necessary. Excuse me?", "Ann Pettifor" },
};
if (beCool())
".", 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)
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);
}
}
}
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_)
/*
* 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.
"System I/O error",
"Error in user input",
"Inconsistency in user input",
+ "Requested tolerance cannot be achieved",
"Simulation instability detected",
"Feature not implemented",
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2010,2011,2012,2013,2015, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013,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.
eeInvalidInput,
//! Invalid user input (conflicting or unsupported settings).
eeInconsistentInput,
+ //! Requested tolerance cannot be achieved.
+ eeTolerance,
//! Simulation instability detected.
eeInstability,
return eeInconsistentInput;
}
+int ToleranceError::errorCode() const
+{
+ return eeTolerance;
+}
+
int SimulationInstabilityError::errorCode() const
{
return eeInstability;
return eeAPIError;
}
+int RangeError::errorCode() const
+{
+ return eeRange;
+}
+
int NotImplementedError::errorCode() const
{
return eeNotImplemented;
virtual int errorCode() const;
};
+/*! \brief
+ * Exception class when a specified tolerance cannot be achieved.
+ *
+ * \inpublicapi
+ */
+class ToleranceError : public GromacsException
+{
+ public:
+ /*! \brief
+ * Creates an exception object with the provided initializer/reason.
+ *
+ * \param[in] details Initializer for the exception.
+ * \throws std::bad_alloc if out of memory.
+ *
+ * It is possible to call this constructor either with an explicit
+ * ExceptionInitializer object (useful for more complex cases), or
+ * a simple string if only a reason string needs to be provided.
+ */
+ explicit ToleranceError(const ExceptionInitializer &details)
+ : GromacsException(details) {}
+
+ virtual int errorCode() const;
+};
+
/*! \brief
* Exception class for simulation instabilities.
*
virtual int errorCode() const;
};
+/*! \brief
+ * Exception class for out-of-range values or indices
+ *
+ * \inpublicapi
+ */
+class RangeError : public GromacsException
+{
+ public:
+ //! \copydoc FileIOError::FileIOError()
+ explicit RangeError(const ExceptionInitializer &details)
+ : GromacsException(details) {}
+
+ virtual int errorCode() const;
+};
+
/*! \brief
* Exception class for use of an unimplemented feature.
*
virtual int errorCode() const;
};
-
/*! \brief
* Macro for throwing an exception.
*
*/
/*! \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
--- /dev/null
+/*
+ * 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 "ikeyvaluetreeerror.h"
+
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/stringutil.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+class DefaultKeyValueTreeErrorHandler : public IKeyValueTreeErrorHandler
+{
+ public:
+ virtual bool onError(UserInputError *ex, const KeyValueTreePath &context)
+ {
+ std::string message
+ = formatString("While processing '%s':", context.toString().c_str());
+ ex->prependContext(message);
+ return false;
+ }
+};
+
+} // namespace
+
+IKeyValueTreeErrorHandler::~IKeyValueTreeErrorHandler()
+{
+}
+
+//! \cond libapi
+IKeyValueTreeErrorHandler *defaultKeyValueTreeErrorHandler()
+{
+ static DefaultKeyValueTreeErrorHandler instance;
+ return &instance;
+}
+//! \endcond
+
+} // namespace gmx
--- /dev/null
+/*
+ * 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 an error handling interface for key-value tree operations.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_KEYVALUETREEERROR_H
+#define GMX_UTILITY_KEYVALUETREEERROR_H
+
+namespace gmx
+{
+
+class KeyValueTreePath;
+class UserInputError;
+
+class IKeyValueTreeErrorHandler
+{
+ public:
+ virtual bool onError(UserInputError *ex, const KeyValueTreePath &context) = 0;
+
+ protected:
+ ~IKeyValueTreeErrorHandler();
+};
+
+//! \cond libapi
+/*! \brief
+ * Returns a default IKeyValueTreeErrorHandler that throws on first exception.
+ *
+ * \ingroup module_utility
+ */
+IKeyValueTreeErrorHandler *defaultKeyValueTreeErrorHandler();
+//! \endcond
+
+} // namespace gmx
+
+#endif
--- /dev/null
+/*
+ * 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 generic serialization interface that supports both directions.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_ISERIALIZER_H
+#define GMX_UTILITY_ISERIALIZER_H
+
+#include <string>
+
+namespace gmx
+{
+
+class ISerializer
+{
+ public:
+ virtual ~ISerializer() {}
+
+ virtual bool reading() const = 0;
+
+ virtual void doUChar(unsigned char *value) = 0;
+ virtual void doInt(int *value) = 0;
+ virtual void doFloat(float *value) = 0;
+ virtual void doDouble(double *value) = 0;
+ virtual void doString(std::string *value) = 0;
+};
+
+} // namespace gmx
+
+#endif
--- /dev/null
+/*
+ * 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 "keyvaluetree.h"
+
+#include <string>
+#include <vector>
+
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/stringutil.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * KeyValueTreePath
+ */
+
+namespace
+{
+
+//! Helper function to split a KeyValueTreePath to its components
+std::vector<std::string> splitPathElements(const std::string &path)
+{
+ GMX_ASSERT(!path.empty() && path[0] == '/',
+ "Paths to KeyValueTree should start with '/'");
+ return splitDelimitedString(path.substr(1), '/');
+}
+
+} // namespace
+
+KeyValueTreePath::KeyValueTreePath(const std::string &path)
+ : path_(splitPathElements(path))
+{
+}
+
+std::string KeyValueTreePath::toString() const
+{
+ return "/" + joinStrings(path_, "/");
+}
+
+} // namespace gmx
--- /dev/null
+/*
+ * 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 KeyValueTreePath
+{
+ public:
+ KeyValueTreePath() = default;
+ KeyValueTreePath(const std::string &path);
+
+ void append(const std::string &key) { path_.push_back(key); }
+ void pop_back() { return path_.pop_back(); }
+ std::string pop_last()
+ {
+ std::string result = std::move(path_.back());
+ path_.pop_back();
+ return result;
+ }
+
+ bool empty() const { return path_.empty(); }
+ size_t size() const { return path_.size(); }
+ const std::string &operator[](int i) const { return path_[i]; }
+ const std::vector<std::string> &elements() const { return path_; }
+
+ std::string toString() const;
+
+ private:
+ std::vector<std::string> path_;
+};
+
+class KeyValueTreeValue
+{
+ public:
+ bool isArray() const;
+ bool isObject() const;
+ template <typename T>
+ bool isType() const { return value_.isType<T>(); }
+ std::type_index type() const { return value_.type(); }
+
+ const KeyValueTreeArray &asArray() const;
+ const KeyValueTreeObject &asObject() const;
+ template <typename T>
+ const T &cast() const { return value_.cast<T>(); }
+
+ 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
--- /dev/null
+/*
+ * 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 KeyValueTreeArrayBuilder;
+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();
+ KeyValueTreeArrayBuilder createArray();
+
+ KeyValueTreeValue build() { return KeyValueTreeValue(std::move(value_)); }
+
+ private:
+ Variant value_;
+};
+
+class KeyValueTreeArrayBuilderBase
+{
+ protected:
+ explicit KeyValueTreeArrayBuilderBase(KeyValueTreeArray *array)
+ : array_(array)
+ {
+ }
+
+ KeyValueTreeValue &addRawValue(Variant &&value)
+ {
+ KeyValueTreeValueBuilder builder;
+ builder.setVariantValue(std::move(value));
+ array_->values_.push_back(builder.build());
+ return array_->values_.back();
+ }
+ KeyValueTreeValue &addRawValue(KeyValueTreeValue &&value)
+ {
+ array_->values_.push_back(std::move(value));
+ return array_->values_.back();
+ }
+
+ private:
+ KeyValueTreeArray *array_;
+};
+
+class KeyValueTreeArrayBuilder : public KeyValueTreeArrayBuilderBase
+{
+ public:
+ using KeyValueTreeArrayBuilderBase::addRawValue;
+
+ private:
+ explicit KeyValueTreeArrayBuilder(KeyValueTreeArray *array)
+ : KeyValueTreeArrayBuilderBase(array)
+ {
+ }
+
+ friend class KeyValueTreeObjectBuilder;
+ friend class KeyValueTreeValueBuilder;
+};
+
+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));
+ }
+ void addRawValue(const std::string &key, Variant &&value)
+ {
+ object_->addProperty(key, KeyValueTreeValue(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);
+ }
+ KeyValueTreeArrayBuilder addArray(const std::string &key)
+ {
+ auto iter = object_->addProperty(key, KeyValueTreeBuilder::createValue<KeyValueTreeArray>());
+ return KeyValueTreeArrayBuilder(&iter->second.asArray());
+ }
+ 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 KeyValueTreeArrayBuilder KeyValueTreeValueBuilder::createArray()
+{
+ value_ = Variant::create<KeyValueTreeArray>(KeyValueTreeArray());
+ return KeyValueTreeArrayBuilder(&value_.castRef<KeyValueTreeArray>());
+}
+
+inline KeyValueTreeObjectBuilder KeyValueTreeObjectArrayBuilder::addObject()
+{
+ auto &value = addRawValue(KeyValueTreeBuilder::createValue<KeyValueTreeObject>());
+ return KeyValueTreeObjectBuilder(&value);
+}
+
+} // namespace gmx
+
+#endif
--- /dev/null
+/*
+ * 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 "keyvaluetreeserializer.h"
+
+#include "gromacs/utility/iserializer.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/mutex.h"
+
+namespace gmx
+{
+
+namespace
+{
+
+class ValueSerializer
+{
+ public:
+ static void initSerializers();
+
+ static void serialize(const KeyValueTreeValue &value, ISerializer *serializer);
+ static KeyValueTreeValue deserialize(ISerializer *serializer);
+
+ private:
+ ValueSerializer();
+
+ typedef void (*SerializerFunction)(const KeyValueTreeValue &value, ISerializer *serializer);
+ typedef void (*DeserializerFunction)(KeyValueTreeValueBuilder *builder, ISerializer *serializer);
+
+ struct Serializer
+ {
+ unsigned char typeTag;
+ SerializerFunction serialize;
+ DeserializerFunction deserialize;
+ };
+
+ static Mutex s_initMutex;
+ static std::map<std::type_index, Serializer> s_serializers;
+ static std::map<unsigned char, DeserializerFunction> s_deserializers;
+};
+
+Mutex ValueSerializer::s_initMutex;
+std::map<std::type_index, ValueSerializer::Serializer> ValueSerializer::s_serializers;
+std::map<unsigned char, ValueSerializer::DeserializerFunction> ValueSerializer::s_deserializers;
+
+template <typename T>
+struct SerializationTraits
+{
+};
+
+template <>
+struct SerializationTraits<KeyValueTreeObject>
+{
+ static void serialize(const KeyValueTreeObject &value, ISerializer *serializer)
+ {
+ int count = value.properties().size();
+ serializer->doInt(&count);
+ for (const auto &prop : value.properties())
+ {
+ serializer->doString(const_cast<std::string *>(&prop.key()));
+ ValueSerializer::serialize(prop.value(), serializer);
+ }
+ }
+ static void deserialize(KeyValueTreeValueBuilder *value, ISerializer *serializer)
+ {
+ KeyValueTreeObjectBuilder builder(value->createObject());
+ deserializeObject(&builder, serializer);
+ }
+ static void deserializeObject(KeyValueTreeObjectBuilder *builder, ISerializer *serializer)
+ {
+ int count;
+ std::string key;
+ serializer->doInt(&count);
+ for (int i = 0; i < count; ++i)
+ {
+ serializer->doString(&key);
+ builder->addRawValue(key, ValueSerializer::deserialize(serializer));
+ }
+ }
+};
+
+template <>
+struct SerializationTraits<KeyValueTreeArray>
+{
+ static void serialize(const KeyValueTreeArray &array, ISerializer *serializer)
+ {
+ int count = array.values().size();
+ serializer->doInt(&count);
+ for (const auto &value : array.values())
+ {
+ ValueSerializer::serialize(value, serializer);
+ }
+ }
+ static void deserialize(KeyValueTreeValueBuilder *value, ISerializer *serializer)
+ {
+ KeyValueTreeArrayBuilder builder(value->createArray());
+ int count;
+ serializer->doInt(&count);
+ for (int i = 0; i < count; ++i)
+ {
+ builder.addRawValue(ValueSerializer::deserialize(serializer));
+ }
+ }
+};
+
+template <>
+struct SerializationTraits<std::string>
+{
+ static void serialize(const std::string &value, ISerializer *serializer)
+ {
+ serializer->doString(const_cast<std::string *>(&value));
+ }
+ static void deserialize(KeyValueTreeValueBuilder *builder, ISerializer *serializer)
+ {
+ std::string value;
+ serializer->doString(&value);
+ builder->setValue<std::string>(value);
+ }
+};
+
+template <>
+struct SerializationTraits<int>
+{
+ static void serialize(int value, ISerializer *serializer)
+ {
+ serializer->doInt(&value);
+ }
+ static void deserialize(KeyValueTreeValueBuilder *builder, ISerializer *serializer)
+ {
+ int value;
+ serializer->doInt(&value);
+ builder->setValue<int>(value);
+ }
+};
+
+template <>
+struct SerializationTraits<float>
+{
+ static void serialize(float value, ISerializer *serializer)
+ {
+ serializer->doFloat(&value);
+ }
+ static void deserialize(KeyValueTreeValueBuilder *builder, ISerializer *serializer)
+ {
+ float value;
+ serializer->doFloat(&value);
+ builder->setValue<float>(value);
+ }
+};
+
+template <>
+struct SerializationTraits<double>
+{
+ static void serialize(double value, ISerializer *serializer)
+ {
+ serializer->doDouble(&value);
+ }
+ static void deserialize(KeyValueTreeValueBuilder *builder, ISerializer *serializer)
+ {
+ double value;
+ serializer->doDouble(&value);
+ builder->setValue<double>(value);
+ }
+};
+
+//! Helper function for serializing values of a certain type.
+template <typename T>
+void serializeValueType(const KeyValueTreeValue &value, ISerializer *serializer)
+{
+ SerializationTraits<T>::serialize(value.cast<T>(), serializer);
+}
+
+#define SERIALIZER(tag, type) \
+ { std::type_index(typeid(type)), \
+ { tag, &serializeValueType<type>, &SerializationTraits<type>::deserialize } \
+ }
+
+// static
+void ValueSerializer::initSerializers()
+{
+ lock_guard<Mutex> lock(s_initMutex);
+ if (!s_serializers.empty())
+ {
+ return;
+ }
+ s_serializers = {
+ SERIALIZER('O', KeyValueTreeObject),
+ SERIALIZER('A', KeyValueTreeArray),
+ SERIALIZER('s', std::string),
+ SERIALIZER('i', int),
+ SERIALIZER('f', float),
+ SERIALIZER('d', double),
+ };
+ for (const auto item : s_serializers)
+ {
+ s_deserializers[item.second.typeTag] = item.second.deserialize;
+ }
+}
+
+void ValueSerializer::serialize(const KeyValueTreeValue &value, ISerializer *serializer)
+{
+ auto iter = s_serializers.find(value.type());
+ GMX_RELEASE_ASSERT(iter != s_serializers.end(),
+ "Unknown value type for serializization");
+ unsigned char typeTag = iter->second.typeTag;
+ serializer->doUChar(&typeTag);
+ iter->second.serialize(value, serializer);
+}
+
+KeyValueTreeValue ValueSerializer::deserialize(ISerializer *serializer)
+{
+ unsigned char typeTag;
+ serializer->doUChar(&typeTag);
+ auto iter = s_deserializers.find(typeTag);
+ GMX_RELEASE_ASSERT(iter != s_deserializers.end(),
+ "Unknown type tag for deserializization");
+ KeyValueTreeValueBuilder builder;
+ iter->second(&builder, serializer);
+ return builder.build();
+}
+
+} // namespace
+
+//! \cond libapi
+void serializeKeyValueTree(const KeyValueTreeObject &root, ISerializer *serializer)
+{
+ GMX_RELEASE_ASSERT(!serializer->reading(),
+ "Incorrect serializer direction");
+ ValueSerializer::initSerializers();
+ SerializationTraits<KeyValueTreeObject>::serialize(root, serializer);
+}
+
+KeyValueTreeObject deserializeKeyValueTree(ISerializer *serializer)
+{
+ GMX_RELEASE_ASSERT(serializer->reading(),
+ "Incorrect serializer direction");
+ ValueSerializer::initSerializers();
+ KeyValueTreeBuilder builder;
+ KeyValueTreeObjectBuilder obj(builder.rootObject());
+ SerializationTraits<KeyValueTreeObject>::deserializeObject(&obj, serializer);
+ return builder.build();
+}
+//! \endcond
+
+} // namespace gmx
--- /dev/null
+/*
+ * 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 serialization routines for KeyValueTree objects.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_KEYVALUETREESERIALIZER_H
+#define GMX_UTILITY_KEYVALUETREESERIALIZER_H
+
+namespace gmx
+{
+
+class KeyValueTreeObject;
+class ISerializer;
+
+//! \cond libapi
+/*! \brief
+ * Serializes a KeyValueTreeObject with given serializer.
+ *
+ * \ingroup module_utility
+ */
+void serializeKeyValueTree(const KeyValueTreeObject &root, ISerializer *serializer);
+/*! \brief
+ * Deserializes a KeyValueTreeObject from a given serializer.
+ *
+ * \ingroup module_utility
+ */
+KeyValueTreeObject deserializeKeyValueTree(ISerializer *serializer);
+//! \endcond
+
+} // namespace gmx
+
+#endif
--- /dev/null
+/*
+ * 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 <functional>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/ikeyvaluetreeerror.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/stringcompare.h"
+#include "gromacs/utility/stringutil.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * IKeyValueTreeTransformRules
+ */
+
+IKeyValueTreeTransformRules::~IKeyValueTreeTransformRules()
+{
+}
+
+/********************************************************************
+ * IKeyValueTreeBackMapping
+ */
+
+IKeyValueTreeBackMapping::~IKeyValueTreeBackMapping()
+{
+}
+
+namespace
+{
+
+class KeyValueTreeBackMapping : public IKeyValueTreeBackMapping
+{
+ public:
+ class Entry
+ {
+ public:
+ Entry() = default;
+ explicit Entry(const KeyValueTreePath &path) : sourcePath_(path) {}
+
+ Entry *getOrCreateChildEntry(const std::string &key)
+ {
+ auto iter = childEntries_.find(key);
+ if (iter == childEntries_.end())
+ {
+ iter = childEntries_.insert(std::make_pair(key, Entry())).first;
+ }
+ return &iter->second;
+ }
+ void setMapping(const KeyValueTreePath &path,
+ const KeyValueTreeValue &value)
+ {
+ if (value.isObject())
+ {
+ const KeyValueTreeObject &object = value.asObject();
+ for (const auto &prop : object.properties())
+ {
+ childEntries_[prop.key()] = Entry(path);
+ }
+ }
+ else
+ {
+ sourcePath_ = path;
+ }
+ }
+
+ KeyValueTreePath sourcePath_;
+ std::map<std::string, Entry> childEntries_;
+ };
+
+ virtual KeyValueTreePath
+ originalPath(const KeyValueTreePath &path) const
+ {
+ const Entry *entry = &rootEntry_;
+ for (const auto &element : path.elements())
+ {
+ auto iter = entry->childEntries_.find(element);
+ if (iter == entry->childEntries_.end())
+ {
+ break;
+ }
+ entry = &iter->second;
+ }
+ GMX_RELEASE_ASSERT(entry->childEntries_.empty()
+ && !entry->sourcePath_.empty(),
+ "Requested path not uniquely mapped");
+ return entry->sourcePath_;
+ }
+
+ Entry *rootEntry() { return &rootEntry_; }
+
+ private:
+ Entry rootEntry_;
+};
+
+} // namespace
+
+namespace internal
+{
+
+/********************************************************************
+ * KeyValueTreeTransformerImpl
+ */
+
+class KeyValueTreeTransformerImpl : public IKeyValueTreeTransformRules
+{
+ public:
+ class Rule
+ {
+ public:
+ typedef std::function<void(KeyValueTreeValueBuilder *, const KeyValueTreeValue &)>
+ TransformFunction;
+ typedef std::map<std::string, Rule, StringCompare> ChildRuleMap;
+
+ explicit Rule(StringCompareType keyMatchType)
+ : childRules_(keyMatchType)
+ {
+ }
+
+ 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())
+ {
+ return createChildRule(key, StringCompareType::Exact);
+ }
+ return &iter->second;
+ }
+ Rule *createChildRule(const std::string &key,
+ StringCompareType keyMatchType)
+ {
+ auto result = childRules_.insert(std::make_pair(key, Rule(keyMatchType)));
+ GMX_RELEASE_ASSERT(result.second,
+ "Cannot specify key match type after child rules");
+ return &result.first->second;
+ }
+
+ void collectMappedPaths(const KeyValueTreePath &prefix,
+ std::vector<KeyValueTreePath> *result) const
+ {
+ for (const auto &value : childRules_)
+ {
+ KeyValueTreePath path = prefix;
+ path.append(value.first);
+ const Rule &rule = value.second;
+ if (rule.transform_)
+ {
+ result->push_back(path);
+ }
+ else
+ {
+ rule.collectMappedPaths(path, result);
+ }
+ }
+ }
+
+ KeyValueTreePath targetPath_;
+ std::string targetKey_;
+ TransformFunction transform_;
+ ChildRuleMap childRules_;
+ };
+
+ class Transformer
+ {
+ public:
+ explicit Transformer(IKeyValueTreeErrorHandler *errorHandler)
+ : errorHandler_(errorHandler),
+ backMapping_(new KeyValueTreeBackMapping)
+ {
+ if (errorHandler_ == nullptr)
+ {
+ errorHandler_ = defaultKeyValueTreeErrorHandler();
+ }
+ }
+
+ void transform(const Rule *rootRule, const KeyValueTreeObject &tree)
+ {
+ if (rootRule != nullptr)
+ {
+ doChildTransforms(rootRule, tree);
+ }
+ }
+
+ KeyValueTreeTransformResult result()
+ {
+ return KeyValueTreeTransformResult(builder_.build(),
+ std::move(backMapping_));
+ }
+
+ private:
+ void doTransform(const Rule *rule, const KeyValueTreeValue &value);
+ void doChildTransforms(const Rule *rule, const KeyValueTreeObject &object);
+ void applyTransformedValue(const Rule *rule, KeyValueTreeValue &&value);
+
+ IKeyValueTreeErrorHandler *errorHandler_;
+ KeyValueTreeBuilder builder_;
+ std::unique_ptr<KeyValueTreeBackMapping> backMapping_;
+ KeyValueTreePath context_;
+ };
+
+ virtual KeyValueTreeTransformRuleBuilder addRule()
+ {
+ return KeyValueTreeTransformRuleBuilder(this);
+ }
+
+ Rule *getOrCreateRootRule()
+ {
+ if (rootRule_ == nullptr)
+ {
+ createRootRule(StringCompareType::Exact);
+ }
+ return rootRule_.get();
+ }
+ void createRootRule(StringCompareType keyMatchType)
+ {
+ GMX_RELEASE_ASSERT(rootRule_ == nullptr,
+ "Cannot specify key match type after child rules");
+ rootRule_.reset(new Rule(keyMatchType));
+ }
+
+ std::unique_ptr<Rule> rootRule_;
+};
+
+/********************************************************************
+ * KeyValueTreeTransformerImpl::Transformer
+ */
+
+void KeyValueTreeTransformerImpl::Transformer::doTransform(
+ const Rule *rule, const KeyValueTreeValue &value)
+{
+ if (rule->transform_)
+ {
+ KeyValueTreeValueBuilder valueBuilder;
+ try
+ {
+ rule->transform_(&valueBuilder, value);
+ }
+ catch (UserInputError &ex)
+ {
+ if (!errorHandler_->onError(&ex, context_))
+ {
+ throw;
+ }
+ return;
+ }
+ applyTransformedValue(rule, valueBuilder.build());
+ return;
+ }
+ if (!rule->childRules_.empty())
+ {
+ doChildTransforms(rule, value.asObject());
+ }
+}
+
+void KeyValueTreeTransformerImpl::Transformer::doChildTransforms(
+ const Rule *rule, const KeyValueTreeObject &object)
+{
+ for (const auto &prop : object.properties())
+ {
+ const Rule *childRule = rule->findMatchingChildRule(prop.key());
+ if (childRule != nullptr)
+ {
+ context_.append(prop.key());
+ doTransform(childRule, prop.value());
+ context_.pop_back();
+ }
+ }
+}
+
+void KeyValueTreeTransformerImpl::Transformer::applyTransformedValue(
+ const Rule *rule, KeyValueTreeValue &&value)
+{
+ KeyValueTreeObjectBuilder objBuilder = builder_.rootObject();
+ KeyValueTreeBackMapping::Entry *mapEntry = backMapping_->rootEntry();
+ for (const std::string &key : rule->targetPath_.elements())
+ {
+ if (objBuilder.keyExists(key))
+ {
+ objBuilder = objBuilder.getObject(key);
+ }
+ else
+ {
+ objBuilder = objBuilder.addObject(key);
+ }
+ mapEntry = mapEntry->getOrCreateChildEntry(key);
+ }
+ mapEntry = mapEntry->getOrCreateChildEntry(rule->targetKey_);
+ mapEntry->setMapping(context_, value);
+ if (objBuilder.keyExists(rule->targetKey_))
+ {
+ objBuilder.getObject(rule->targetKey_).mergeObject(std::move(value));
+ }
+ else
+ {
+ objBuilder.addRawValue(rule->targetKey_, std::move(value));
+ }
+}
+
+} // namespace internal
+
+/********************************************************************
+ * KeyValueTreeTransformer
+ */
+
+KeyValueTreeTransformer::KeyValueTreeTransformer()
+ : impl_(new internal::KeyValueTreeTransformerImpl)
+{
+}
+
+KeyValueTreeTransformer::~KeyValueTreeTransformer()
+{
+}
+
+IKeyValueTreeTransformRules *KeyValueTreeTransformer::rules()
+{
+ return impl_.get();
+}
+
+std::vector<KeyValueTreePath> KeyValueTreeTransformer::mappedPaths() const
+{
+ std::vector<KeyValueTreePath> result;
+ if (impl_->rootRule_)
+ {
+ impl_->rootRule_->collectMappedPaths(KeyValueTreePath(), &result);
+ }
+ return result;
+}
+
+KeyValueTreeTransformResult
+KeyValueTreeTransformer::transform(const KeyValueTreeObject &tree,
+ IKeyValueTreeErrorHandler *errorHandler) const
+{
+ internal::KeyValueTreeTransformerImpl::Transformer transformer(errorHandler);
+ transformer.transform(impl_->rootRule_.get(), tree);
+ return transformer.result();
+}
+
+/********************************************************************
+ * KeyValueTreeTransformRuleBuilder::Data
+ */
+
+class KeyValueTreeTransformRuleBuilder::Data
+{
+ public:
+ typedef internal::KeyValueTreeTransformerImpl::Rule Rule;
+
+ Data() : keyMatchType_(StringCompareType::Exact) {}
+
+ void createRule(internal::KeyValueTreeTransformerImpl *impl)
+ {
+ if (toPath_.empty())
+ {
+ createRuleWithKeyMatchType(impl);
+ return;
+ }
+ Rule *rule = impl->getOrCreateRootRule();
+ for (const std::string &key : fromPath_.elements())
+ {
+ rule = rule->getOrCreateChildRule(key);
+ }
+ rule->targetKey_ = toPath_.pop_last();
+ rule->targetPath_ = std::move(toPath_);
+ rule->transform_ = transform_;
+ }
+
+ void createRuleWithKeyMatchType(internal::KeyValueTreeTransformerImpl *impl)
+ {
+ if (fromPath_.empty())
+ {
+ impl->createRootRule(keyMatchType_);
+ }
+ else
+ {
+ std::string lastKey = fromPath_.pop_last();
+ Rule *rule = impl->getOrCreateRootRule();
+ for (const std::string &key : fromPath_.elements())
+ {
+ rule = rule->getOrCreateChildRule(key);
+ }
+ rule->createChildRule(lastKey, keyMatchType_);
+ }
+ }
+
+ KeyValueTreePath fromPath_;
+ KeyValueTreePath toPath_;
+ Rule::TransformFunction transform_;
+ StringCompareType keyMatchType_;
+};
+
+/********************************************************************
+ * 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::setKeyMatchType(StringCompareType keyMatchType)
+{
+ data_->keyMatchType_ = keyMatchType;
+}
+
+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
--- /dev/null
+/*
+ * 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 <vector>
+
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/variant.h"
+
+namespace gmx
+{
+
+class IKeyValueTreeErrorHandler;
+class KeyValueTreeObjectBuilder;
+
+enum class StringCompareType;
+
+class KeyValueTreeTransformRuleBuilder;
+
+namespace internal
+{
+class KeyValueTreeTransformerImpl;
+}
+
+class IKeyValueTreeTransformRules
+{
+ public:
+ virtual KeyValueTreeTransformRuleBuilder addRule() = 0;
+
+ protected:
+ ~IKeyValueTreeTransformRules();
+};
+
+class IKeyValueTreeBackMapping
+{
+ public:
+ virtual ~IKeyValueTreeBackMapping();
+
+ virtual KeyValueTreePath
+ originalPath(const KeyValueTreePath &path) const = 0;
+};
+
+class KeyValueTreeTransformResult
+{
+ public:
+ KeyValueTreeObject object() { return std::move(object_); }
+ const IKeyValueTreeBackMapping &backMapping() const { return *mapping_; }
+
+ private:
+ typedef std::unique_ptr<IKeyValueTreeBackMapping> MappingPointer;
+
+ KeyValueTreeTransformResult(KeyValueTreeObject &&object,
+ MappingPointer &&mapping)
+ : object_(std::move(object)), mapping_(std::move(mapping))
+ {
+ }
+
+ KeyValueTreeObject object_;
+ std::unique_ptr<IKeyValueTreeBackMapping> mapping_;
+
+ friend class internal::KeyValueTreeTransformerImpl;
+};
+
+class KeyValueTreeTransformer
+{
+ public:
+ KeyValueTreeTransformer();
+ ~KeyValueTreeTransformer();
+
+ IKeyValueTreeTransformRules *rules();
+
+ std::vector<KeyValueTreePath> mappedPaths() const;
+
+ KeyValueTreeTransformResult
+ transform(const KeyValueTreeObject &tree,
+ IKeyValueTreeErrorHandler *errorHandler) 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);
+ }
+ void keyMatchType(const std::string &path, StringCompareType keyMatchType)
+ {
+ setFromPath(path);
+ setKeyMatchType(keyMatchType);
+ }
+
+ private:
+ void setFromPath(const std::string &path);
+ void setToPath(const std::string &path);
+ void setKeyMatchType(StringCompareType keyMatchType);
+ 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
/*
* 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
/*
* 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.
void MessageStringCollector::startContext(const char *name)
{
- impl_->contexts_.push_back(name);
+ impl_->contexts_.emplace_back(name);
}
void MessageStringCollector::append(const std::string &message)
*
* 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.
"GROMACS: High performance molecular simulations through multi-level parallelism from laptops to supercomputers",
"SoftwareX",
1, 2015, "19-25" },
+ { "Ballenegger2009",
+ "V. Ballenegger, A. Arnold, J. J. Cerdà ",
+ "Simulations of non-neutral slab systems with long-range electrostatic interactions in two-dimensional periodic boundary conditions",
+ "J. Chem. Phys",
+ 131, 2009, "094107" },
+ { "Hub2014a",
+ "J. S. Hub, B. L. de Groot, H. Grubmueller, G. Groenhof",
+ "Quantifying Artifacts in Ewald Simulations of Inhomogeneous Systems with a Net Charge",
+ "J. Chem. Theory Comput.",
+ 10, 2014, "381-393" },
};
#define NSTR (int)asize(citedb)
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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 utility functionst for string comparison.
+ *
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+#ifndef GMX_UTILITY_STRINGCOMPARE_H
+#define GMX_UTILITY_STRINGCOMPARE_H
+
+#include <string>
+
+#include "gromacs/utility/cstringutil.h"
+
+namespace gmx
+{
+
+//! \cond libapi
+/*! \brief
+ * Specifies how strings should be compared in various contexts.
+ *
+ * \ingroup module_utility
+ */
+enum class StringCompareType
+{
+ //! Only exact matches are accepted.
+ Exact,
+ //! Case-insensitive comparison.
+ CaseInsensitive,
+ //! Case-insensitive comparison that also ignores '-' and '_'.
+ CaseAndDashInsensitive
+};
+//! \endcond
+
+/*! \libinternal \brief
+ * Compare object for std::string STL containers and algorithms that supports
+ * run-time decision on how to compare.
+ *
+ * \inlibraryapi
+ * \ingroup module_utility
+ */
+class StringCompare
+{
+ public:
+ /*! \brief
+ * Creates a comparer with the given type
+ *
+ * This is not explicit, which allows passing \ref StringCompareType
+ * directly to, e.g., `std::map` constructors.
+ */
+ StringCompare(StringCompareType type = StringCompareType::Exact)
+ : type_(type) {}
+
+ //! The comparison operation.
+ bool operator()(const std::string &a, const std::string &b) const
+ {
+ switch (type_)
+ {
+ case StringCompareType::Exact:
+ return a < b;
+ case StringCompareType::CaseInsensitive:
+ return gmx_strcasecmp(a.c_str(), b.c_str()) < 0;
+ case StringCompareType::CaseAndDashInsensitive:
+ return gmx_strcasecmp_min(a.c_str(), b.c_str()) < 0;
+ }
+ return a < b;
+ }
+
+ private:
+ StringCompareType type_;
+};
+
+} // namespace gmx
+
+#endif
/*
* 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.
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;
// 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);
}
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;
}
#ifndef GMX_UTILITY_STRINGUTIL_H
#define GMX_UTILITY_STRINGUTIL_H
+#include <cstdarg>
#include <cstring>
#include <string>
* 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. */
* 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.
arrayref.cpp
basedefinitions.cpp
bitmask32.cpp bitmask64.cpp bitmask128.cpp
+ keyvaluetreeserializer.cpp
+ keyvaluetreetransform.cpp
+ logger.cpp
path.cpp
stringutil.cpp
textwriter.cpp
#include "gromacs/utility/arrayref.h"
-#include "config.h"
-
#include <vector>
#include <gtest/gtest.h>
*
* 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)
{
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
--- /dev/null
+/*
+ * 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/keyvaluetreeserializer.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/iserializer.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+
+#include "testutils/refdata.h"
+
+namespace
+{
+
+class RefDataWriteSerializer : public gmx::ISerializer
+{
+ public:
+ RefDataWriteSerializer(gmx::test::TestReferenceChecker *parentChecker,
+ const char *id)
+ : checker_(parentChecker->checkCompound("SerializedData", id))
+ {
+ }
+
+ virtual bool reading() const { return false; }
+
+ virtual void doUChar(unsigned char *value)
+ {
+ checker_.checkUChar(*value, nullptr);
+ }
+ virtual void doInt(int *value)
+ {
+ checker_.checkInteger(*value, nullptr);
+ }
+ virtual void doFloat(float *value)
+ {
+ checker_.checkFloat(*value, nullptr);
+ }
+ virtual void doDouble(double *value)
+ {
+ checker_.checkDouble(*value, nullptr);
+ }
+ virtual void doString(std::string *value)
+ {
+ checker_.checkString(*value, nullptr);
+ }
+
+ private:
+ gmx::test::TestReferenceChecker checker_;
+};
+
+class RefDataReadSerializer : public gmx::ISerializer
+{
+ public:
+ RefDataReadSerializer(gmx::test::TestReferenceChecker *parentChecker,
+ const char *id)
+ : checker_(parentChecker->checkCompound("SerializedData", id))
+ {
+ }
+
+ virtual bool reading() const { return true; }
+
+ virtual void doUChar(unsigned char *value)
+ {
+ *value = checker_.readUChar(nullptr);
+ }
+ virtual void doInt(int *value)
+ {
+ *value = checker_.readInteger(nullptr);
+ }
+ virtual void doFloat(float *value)
+ {
+ *value = checker_.readFloat(nullptr);
+ }
+ virtual void doDouble(double *value)
+ {
+ *value = checker_.readDouble(nullptr);
+ }
+ virtual void doString(std::string *value)
+ {
+ *value = checker_.readString(nullptr);
+ }
+
+ private:
+ gmx::test::TestReferenceChecker checker_;
+};
+
+class KeyValueTreeSerializerTest : public ::testing::Test
+{
+ public:
+ void runTest()
+ {
+ gmx::KeyValueTreeObject input(builder_.build());
+ gmx::test::TestReferenceData data;
+ gmx::test::TestReferenceChecker checker(data.rootChecker());
+ checker.checkKeyValueTreeObject(input, "Input");
+ {
+ RefDataWriteSerializer serializer(&checker, "Stream");
+ gmx::serializeKeyValueTree(input, &serializer);
+ }
+ {
+ RefDataReadSerializer serializer(&checker, "Stream");
+ gmx::KeyValueTreeObject output
+ = gmx::deserializeKeyValueTree(&serializer);
+ checker.checkKeyValueTreeObject(output, "Input");
+ }
+ }
+
+ gmx::KeyValueTreeBuilder builder_;
+};
+
+TEST_F(KeyValueTreeSerializerTest, EmptyTree)
+{
+ runTest();
+}
+
+TEST_F(KeyValueTreeSerializerTest, SimpleObject)
+{
+ builder_.rootObject().addValue<int>("foo", 1);
+ builder_.rootObject().addValue<std::string>("bar", "a");
+ builder_.rootObject().addValue<float>("f", 1.5);
+ builder_.rootObject().addValue<double>("d", 2.5);
+ runTest();
+}
+
+TEST_F(KeyValueTreeSerializerTest, ObjectWithArrays)
+{
+ auto arr1 = builder_.rootObject().addUniformArray<int>("a");
+ arr1.addValue(1);
+ arr1.addValue(2);
+ auto arr2 = builder_.rootObject().addUniformArray<std::string>("b");
+ arr2.addValue("foo");
+ arr2.addValue("bar");
+ runTest();
+}
+
+TEST_F(KeyValueTreeSerializerTest, ObjectWithObjects)
+{
+ auto obj1 = builder_.rootObject().addObject("obj");
+ obj1.addValue<int>("a", 1);
+ obj1.addValue<std::string>("b", "foo");
+ auto obj2 = builder_.rootObject().addObject("obj2");
+ obj2.addValue<int>("c", 2);
+ obj2.addValue<std::string>("d", "bar");
+ builder_.rootObject().addValue<int>("foo", 3);
+ runTest();
+}
+
+} // namespace
--- /dev/null
+/*
+ * 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/exceptions.h"
+#include "gromacs/utility/keyvaluetree.h"
+#include "gromacs/utility/keyvaluetreebuilder.h"
+#include "gromacs/utility/strconvert.h"
+#include "gromacs/utility/stringcompare.h"
+#include "gromacs/utility/stringutil.h"
+
+#include "testutils/refdata.h"
+#include "testutils/testasserts.h"
+
+namespace
+{
+
+class TreeValueTransformTest : public ::testing::Test
+{
+ public:
+ void testTransform(const gmx::KeyValueTreeObject &input,
+ const gmx::KeyValueTreeTransformer &transform)
+ {
+ gmx::KeyValueTreeTransformResult result = transform.transform(input, nullptr);
+ gmx::KeyValueTreeObject object = result.object();
+
+ gmx::test::TestReferenceData data;
+ gmx::test::TestReferenceChecker checker(data.rootChecker());
+ checker.checkKeyValueTreeObject(input, "Input");
+ auto mappedPaths = transform.mappedPaths();
+ checker.checkSequence(mappedPaths.begin(), mappedPaths.end(), "MappedPaths",
+ &TreeValueTransformTest::checkMappedPath);
+ checker.checkKeyValueTreeObject(object, "Tree");
+ checkBackMapping(&checker, object, result.backMapping());
+ }
+
+ private:
+ static void checkMappedPath(gmx::test::TestReferenceChecker *checker,
+ const gmx::KeyValueTreePath &path)
+ {
+ checker->checkString(path.toString(), nullptr);
+ }
+ void checkBackMapping(gmx::test::TestReferenceChecker *checker,
+ const gmx::KeyValueTreeObject &object,
+ const gmx::IKeyValueTreeBackMapping &mapping)
+ {
+ auto compound(checker->checkCompound("BackMapping", "Mapping"));
+ checkBackMappingImpl(&compound, object, mapping, gmx::KeyValueTreePath());
+ }
+
+ void checkBackMappingImpl(gmx::test::TestReferenceChecker *checker,
+ const gmx::KeyValueTreeObject &object,
+ const gmx::IKeyValueTreeBackMapping &mapping,
+ const gmx::KeyValueTreePath &prefix)
+ {
+ for (const auto &prop : object.properties())
+ {
+ gmx::KeyValueTreePath path = prefix;
+ path.append(prop.key());
+ if (prop.value().isObject())
+ {
+ checkBackMappingImpl(checker, prop.value().asObject(), mapping, path);
+ }
+ else
+ {
+ gmx::KeyValueTreePath orgPath = mapping.originalPath(path);
+ checker->checkString(orgPath.toString(), path.toString().c_str());
+ }
+ }
+ }
+};
+
+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, SimpleTransformsCaseAndDashInsensitive)
+{
+ gmx::KeyValueTreeBuilder builder;
+ builder.rootObject().addValue<std::string>("a-x", "1");
+ builder.rootObject().addValue<std::string>("by", "2");
+ gmx::KeyValueTreeObject input = builder.build();
+
+ gmx::KeyValueTreeTransformer transform;
+ transform.rules()->addRule()
+ .keyMatchType("/", gmx::StringCompareType::CaseAndDashInsensitive);
+ transform.rules()->addRule()
+ .from<std::string>("/Ax").to<int>("/i").transformWith(&gmx::fromStdString<int>);
+ transform.rules()->addRule()
+ .from<std::string>("/B-Y").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);
+}
+
+/********************************************************************
+ * Tests for errors
+ */
+
+TEST(TreeValueTransformErrorTest, ConversionError)
+{
+ gmx::KeyValueTreeBuilder builder;
+ builder.rootObject().addValue<std::string>("a", "foo");
+ gmx::KeyValueTreeObject input = builder.build();
+
+ gmx::KeyValueTreeTransformer transform;
+ transform.rules()->addRule()
+ .from<std::string>("/a").to<int>("/i").transformWith(&gmx::fromStdString<int>);
+
+ EXPECT_THROW_GMX(transform.transform(input, nullptr), gmx::InvalidInputError);
+}
+
+} // namespace
--- /dev/null
+/*
+ * 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
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input"></Object>
+ <SerializedData Name="Stream">
+ <Int>0</Int>
+ </SerializedData>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input">
+ <Sequence Name="a">
+ <Int Name="Length">2</Int>
+ <Int>1</Int>
+ <Int>2</Int>
+ </Sequence>
+ <Sequence Name="b">
+ <Int Name="Length">2</Int>
+ <String>foo</String>
+ <String>bar</String>
+ </Sequence>
+ </Object>
+ <SerializedData Name="Stream">
+ <Int>2</Int>
+ <String>a</String>
+ <UChar>65</UChar>
+ <Int>2</Int>
+ <UChar>105</UChar>
+ <Int>1</Int>
+ <UChar>105</UChar>
+ <Int>2</Int>
+ <String>b</String>
+ <UChar>65</UChar>
+ <Int>2</Int>
+ <UChar>115</UChar>
+ <String>foo</String>
+ <UChar>115</UChar>
+ <String>bar</String>
+ </SerializedData>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input">
+ <Object Name="obj">
+ <Int Name="a">1</Int>
+ <String Name="b">foo</String>
+ </Object>
+ <Object Name="obj2">
+ <Int Name="c">2</Int>
+ <String Name="d">bar</String>
+ </Object>
+ <Int Name="foo">3</Int>
+ </Object>
+ <SerializedData Name="Stream">
+ <Int>3</Int>
+ <String>obj</String>
+ <UChar>79</UChar>
+ <Int>2</Int>
+ <String>a</String>
+ <UChar>105</UChar>
+ <Int>1</Int>
+ <String>b</String>
+ <UChar>115</UChar>
+ <String>foo</String>
+ <String>obj2</String>
+ <UChar>79</UChar>
+ <Int>2</Int>
+ <String>c</String>
+ <UChar>105</UChar>
+ <Int>2</Int>
+ <String>d</String>
+ <UChar>115</UChar>
+ <String>bar</String>
+ <String>foo</String>
+ <UChar>105</UChar>
+ <Int>3</Int>
+ </SerializedData>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input">
+ <Int Name="foo">1</Int>
+ <String Name="bar">a</String>
+ <Real Name="f">1.5</Real>
+ <Real Name="d">2.5</Real>
+ </Object>
+ <SerializedData Name="Stream">
+ <Int>4</Int>
+ <String>foo</String>
+ <UChar>105</UChar>
+ <Int>1</Int>
+ <String>bar</String>
+ <UChar>115</UChar>
+ <String>a</String>
+ <String>f</String>
+ <UChar>102</UChar>
+ <Real>1.5</Real>
+ <String>d</String>
+ <UChar>100</UChar>
+ <Real>2.5</Real>
+ </SerializedData>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="Output"><![CDATA[
+par
+]]></String>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="Output"><![CDATA[
+line
+
+par
+
+line2
+]]></String>
+</ReferenceData>
--- /dev/null
+<?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>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="Output"><![CDATA[
+line
+
+par
+
+line2
+]]></String>
+</ReferenceData>
--- /dev/null
+<?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>
+ <Sequence Name="MappedPaths">
+ <Int Name="Length">2</Int>
+ <String>/a</String>
+ <String>/b</String>
+ </Sequence>
+ <Object Name="Tree">
+ <Object Name="foo">
+ <Int Name="a">1</Int>
+ <Int Name="b">2</Int>
+ <Int Name="c">3</Int>
+ </Object>
+ </Object>
+ <BackMapping Name="Mapping">
+ <String Name="/foo/a">/a</String>
+ <String Name="/foo/b">/b</String>
+ <String Name="/foo/c">/b</String>
+ </BackMapping>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input">
+ <String Name="a">1 2</String>
+ </Object>
+ <Sequence Name="MappedPaths">
+ <Int Name="Length">1</Int>
+ <String>/a</String>
+ </Sequence>
+ <Object Name="Tree">
+ <Object Name="foo">
+ <Int Name="a">1</Int>
+ <Int Name="b">2</Int>
+ </Object>
+ </Object>
+ <BackMapping Name="Mapping">
+ <String Name="/foo/a">/a</String>
+ <String Name="/foo/b">/a</String>
+ </BackMapping>
+</ReferenceData>
--- /dev/null
+<?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>
+ <Sequence Name="MappedPaths">
+ <Int Name="Length">2</Int>
+ <String>/a</String>
+ <String>/b</String>
+ </Sequence>
+ <Object Name="Tree">
+ <Int Name="i">1</Int>
+ <Int Name="j">2</Int>
+ </Object>
+ <BackMapping Name="Mapping">
+ <String Name="/i">/a</String>
+ <String Name="/j">/b</String>
+ </BackMapping>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <Object Name="Input">
+ <String Name="a-x">1</String>
+ <String Name="by">2</String>
+ </Object>
+ <Sequence Name="MappedPaths">
+ <Int Name="Length">2</Int>
+ <String>/Ax</String>
+ <String>/B-Y</String>
+ </Sequence>
+ <Object Name="Tree">
+ <Int Name="i">1</Int>
+ <Int Name="j">2</Int>
+ </Object>
+ <BackMapping Name="Mapping">
+ <String Name="/i">/a-x</String>
+ <String Name="/j">/by</String>
+ </BackMapping>
+</ReferenceData>
--- /dev/null
+<?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>
+ <Sequence Name="MappedPaths">
+ <Int Name="Length">2</Int>
+ <String>/a</String>
+ <String>/b</String>
+ </Sequence>
+ <Object Name="Tree">
+ <Object Name="foo">
+ <Int Name="i">1</Int>
+ <Int Name="j">2</Int>
+ </Object>
+ </Object>
+ <BackMapping Name="Mapping">
+ <String Name="/foo/i">/a</String>
+ <String Name="/foo/j">/b</String>
+ </BackMapping>
+</ReferenceData>
/*
* 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.
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()
*/
--- /dev/null
+/*
+ * 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
#include <stdlib.h>
#include <algorithm>
+#include <memory>
#include "thread_mpi/threads.h"
#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"
#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"
}
}
-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,
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))
{
}
/*! \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,
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,
gmx_mtop_t *top_global,
t_fcdata *fcd,
t_state *state_global,
+ energyhistory_t *energyHistory,
t_mdatoms *mdatoms,
t_nrnb *nrnb, gmx_wallcycle_t wcycle,
gmx_edsam_t ed, t_forcerec *fr,
t_trxstatus *status;
rvec mu_tot;
t_vcm *vcm;
- matrix pcoupl_mu, M;
+ matrix parrinellorahmanMu, M;
t_trxframe rerun_fr;
gmx_repl_ex_t repl_ex = NULL;
int nchkpt = 1;
gmx_localtop_t *top;
t_mdebin *mdebin = NULL;
- t_state *state = NULL;
gmx_enerdata_t *enerd;
- rvec *f = NULL;
+ PaddedRVecVector f {};
gmx_global_stat_t gstat;
gmx_update_t *upd = NULL;
t_graph *graph = NULL;
nstglobalcomm = 1;
}
- nstglobalcomm = check_nstglobalcomm(fplog, cr, nstglobalcomm, ir);
+ nstglobalcomm = check_nstglobalcomm(mdlog, nstglobalcomm, ir);
bGStatEveryStep = (nstglobalcomm == 1);
if (bRerunMD)
{
/* Initialize ion swapping code */
init_swapcoords(fplog, bVerbose, ir, opt2fn_master("-swap", nfile, fnm, cr),
- top_global, state_global->x, state_global->box, &state_global->swapstate, cr, oenv, Flags);
+ top_global, as_rvec_array(state_global->x.data()), state_global->box, &state_global->swapstate, cr, oenv, Flags);
}
/* Initial values */
- init_md(fplog, cr, ir, oenv, &t, &t0, state_global->lambda,
+ init_md(fplog, cr, ir, oenv, &t, &t0, &state_global->lambda,
&(state_global->fep_state), lam0,
nrnb, top_global, &upd,
nfile, fnm, &outf, &mdebin,
snew(enerd, 1);
init_enerdata(top_global->groups.grps[egcENER].nr, ir->fepvals->n_lambda,
enerd);
- if (DOMAINDECOMP(cr))
- {
- f = NULL;
- }
- else
+ if (!DOMAINDECOMP(cr))
{
- snew(f, top_global->natoms);
+ f.resize(top_global->natoms + 1);
}
/* Kinetic energy data */
}
}
+ std::unique_ptr<t_state> stateInstance;
+ t_state * state;
+
if (DOMAINDECOMP(cr))
{
top = dd_init_local_top(top_global);
- snew(state, 1);
+ stateInstance = std::unique_ptr<t_state>(new t_state {});
+ state = stateInstance.get();
dd_init_local_state(cr->dd, state_global, state);
}
else
{
- top = gmx_mtop_generate_local_top(top_global, ir->efep != efepNO);
-
- state = serial_init_local_state(state_global);
+ /* Copy the pointer to the global state */
+ state = state_global;
- atoms2md(top_global, ir, 0, NULL, top_global->natoms, mdatoms);
+ snew(top, 1);
+ mdAlgorithmsSetupAtomData(cr, ir, top_global, top, fr,
+ &graph, mdatoms, vsite, shellfc);
- 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);
-
- update_realloc(upd, state->nalloc);
+ update_realloc(upd, state->natoms);
}
/* Set up interactive MD (IMD) */
- init_IMD(ir, cr, top_global, fplog, ir->nstcalcenergy, state_global->x,
+ init_IMD(ir, cr, top_global, fplog, ir->nstcalcenergy, as_rvec_array(state_global->x.data()),
nfile, fnm, oenv, imdport, Flags);
if (DOMAINDECOMP(cr))
vsite, constr,
nrnb, NULL, FALSE);
shouldCheckNumberOfBondedInteractions = true;
- update_realloc(upd, state->nalloc);
+ update_realloc(upd, state->natoms);
}
update_mdatoms(mdatoms, state->lambda[efptMASS]);
if (ir->bExpanded)
{
- init_expanded_ensemble(startingFromCheckpoint, ir, &state->dfhist);
+ init_expanded_ensemble(startingFromCheckpoint, ir, state->dfhist);
}
if (MASTER(cr))
/* Update mdebin with energy history if appending to output files */
if (Flags & MD_APPENDFILES)
{
- restore_energyhistory_from_state(mdebin, state_global->enerhist);
+ restore_energyhistory_from_state(mdebin, energyHistory);
}
else
{
/* We might have read an energy history from checkpoint,
* free the allocated memory and reset the counts.
*/
- done_energyhistory(state_global->enerhist);
- init_energyhistory(state_global->enerhist);
+ *energyHistory = {};
}
}
/* Set the initial energy history in state by updating once */
- update_energyhistory(state_global->enerhist, mdebin);
+ update_energyhistory(energyHistory, mdebin);
}
/* Initialize constraints */
!(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);
}
if (!ir->bContinuation && !bRerunMD)
{
- if (mdatoms->cFREEZE && (state->flags & (1<<estV)))
+ if (state->flags & (1 << estV))
{
- /* Set the velocities of frozen particles to zero */
+ /* Set the velocities of vsites, shells and frozen atoms to zero */
for (i = 0; i < mdatoms->homenr; i++)
{
- for (m = 0; m < DIM; m++)
+ if (mdatoms->ptype[i] == eptVSite ||
+ mdatoms->ptype[i] == eptShell)
{
- if (ir->opts.nFreeze[mdatoms->cFREEZE[i]][m])
+ clear_rvec(state->v[i]);
+ }
+ else if (mdatoms->cFREEZE)
+ {
+ for (m = 0; m < DIM; m++)
{
- state->v[i][m] = 0;
+ if (ir->opts.nFreeze[mdatoms->cFREEZE[i]][m])
+ {
+ state->v[i][m] = 0;
+ }
}
}
}
if (vsite)
{
/* Construct the virtual sites for the initial configuration */
- construct_vsites(vsite, state->x, ir->delta_t, NULL,
+ construct_vsites(vsite, as_rvec_array(state->x.data()), ir->delta_t, NULL,
top->idef.iparams, top->idef.il,
fr->ePBC, fr->bMolPBC, cr, state->box);
}
{
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!");
}
}
/* 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,
/* Following is necessary because the graph may get out of sync
* with the coordinates if we only have every N'th coordinate set
*/
- mk_mshift(fplog, graph, fr->ePBC, state->box, state->x);
- shift_self(graph, state->box, state->x);
+ mk_mshift(fplog, graph, fr->ePBC, state->box, as_rvec_array(state->x.data()));
+ shift_self(graph, state->box, as_rvec_array(state->x.data()));
}
- construct_vsites(vsite, state->x, ir->delta_t, state->v,
+ construct_vsites(vsite, as_rvec_array(state->x.data()), ir->delta_t, as_rvec_array(state->v.data()),
top->idef.iparams, top->idef.il,
fr->ePBC, fr->bMolPBC, cr, state->box);
if (graph)
{
- unshift_self(graph, state->box, state->x);
+ unshift_self(graph, state->box, as_rvec_array(state->x.data()));
}
}
}
nrnb, wcycle,
do_verbose && !bPMETunePrinting);
shouldCheckNumberOfBondedInteractions = true;
- update_realloc(upd, state->nalloc);
+ update_realloc(upd, state->natoms);
}
}
relax_shell_flexcon(fplog, cr, bVerbose, step,
ir, bNS, force_flags, top,
constr, enerd, fcd,
- state, f, force_vir, mdatoms,
+ state, &f, force_vir, mdatoms,
nrnb, wcycle, graph, groups,
shellfc, fr, bBornRadii, t, mu_tot,
- vsite, mdoutf_get_fp_field(outf));
+ vsite);
}
else
{
* Check comments in sim_util.c
*/
do_force(fplog, cr, ir, step, nrnb, wcycle, top, groups,
- state->box, state->x, &state->hist,
- f, force_vir, mdatoms, enerd, fcd,
- state->lambda, graph,
- fr, vsite, mu_tot, t, mdoutf_get_fp_field(outf), ed, bBornRadii,
+ state->box, &state->x, &state->hist,
+ &f, force_vir, mdatoms, enerd, fcd,
+ &state->lambda, graph,
+ fr, vsite, mu_tot, t, ed, bBornRadii,
(bNS ? GMX_FORCE_NS : 0) | force_flags);
}
* so that the input is actually the initial step.
*/
snew(vbuf, state->natoms);
- copy_rvecn(state->v, vbuf, 0, state->natoms); /* should make this better for parallelizing? */
+ copy_rvecn(as_rvec_array(state->v.data()), vbuf, 0, state->natoms); /* should make this better for parallelizing? */
}
else
{
trotter_update(ir, step, ekind, enerd, state, total_vir, mdatoms, &MassQ, trotter_seq, ettTSEQ1);
}
- update_coords(fplog, step, ir, mdatoms, state, f, fcd,
+ update_coords(fplog, step, ir, mdatoms, state, &f, fcd,
ekind, M, upd, etrtVELOCITY1,
cr, constr);
{
wallcycle_stop(wcycle, ewcUPDATE);
update_constraints(fplog, step, NULL, ir, mdatoms,
- state, fr->bMolPBC, graph, f,
+ state, fr->bMolPBC, graph, &f,
&top->idef, shake_vir,
cr, nrnb, wcycle, upd, constr,
TRUE, bCalcVir);
{
/* Need to unshift here if a do_force has been
called in the previous step */
- unshift_self(graph, state->box, state->x);
+ unshift_self(graph, state->box, as_rvec_array(state->x.data()));
}
/* if VV, compute the pressure and constraints */
/* For VV2, we strictly only need this if using pressure
/* if it's the initial step, we performed this first step just to get the constraint virial */
if (ir->eI == eiVV && bInitStep)
{
- copy_rvecn(vbuf, state->v, 0, state->natoms);
+ copy_rvecn(vbuf, as_rvec_array(state->v.data()), 0, state->natoms);
sfree(vbuf);
}
wallcycle_stop(wcycle, ewcUPDATE);
/* compute the conserved quantity */
if (EI_VV(ir->eI))
{
- saved_conserved_quantity = compute_conserved_from_auxiliary(ir, state, &MassQ);
+ saved_conserved_quantity = NPT_energy(ir, state, &MassQ);
if (ir->eI == eiVV)
{
last_ekin = enerd->term[F_EKIN];
/* sum up the foreign energy and dhdl terms for vv. currently done every step so that dhdl is correct in the .edr */
if (ir->efep != efepNO && !bRerunMD)
{
- sum_dhdl(enerd, state->lambda, ir->fepvals);
+ sum_dhdl(enerd, &state->lambda, ir->fepvals);
}
}
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, as_rvec_array(state->v.data()), 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
* the update.
*/
do_md_trajectory_writing(fplog, cr, nfile, fnm, step, step_rel, t,
- ir, state, state_global, top_global, fr,
- outf, mdebin, ekind, f,
+ ir, state, state_global, energyHistory,
+ top_global, fr,
+ outf, mdebin, ekind, &f,
&nchkpt,
bCPT, bRerunMD, bLastStep, (Flags & MD_CONFOUT),
bSumEkinhOld);
/* Check if IMD step and do IMD communication, if bIMD is TRUE. */
- bIMDstep = do_IMD(ir->bIMD, step, cr, bNS, state->box, state->x, ir, t, wcycle);
+ bIMDstep = do_IMD(ir->bIMD, step, cr, bNS, state->box, as_rvec_array(state->x.data()), ir, t, wcycle);
/* kludge -- virial is lost with restart for MTTK NPT control. Must reload (saved earlier). */
if (startingFromCheckpoint && bTrotter)
if (constr && bIfRandomize)
{
update_constraints(fplog, step, NULL, ir, mdatoms,
- state, fr->bMolPBC, graph, f,
+ state, fr->bMolPBC, graph, &f,
&top->idef, tmp_vir,
cr, nrnb, wcycle, upd, constr,
TRUE, bCalcVir);
else
{
update_tcouple(step, ir, state, ekind, &MassQ, mdatoms);
- update_pcouple(fplog, step, ir, state, pcoupl_mu, M, bInitStep);
+ update_pcouple_before_coordinates(fplog, step, ir, state,
+ parrinellorahmanMu, M,
+ bInitStep);
}
if (EI_VV(ir->eI))
{
/* velocity half-step update */
- update_coords(fplog, step, ir, mdatoms, state, f, fcd,
+ update_coords(fplog, step, ir, mdatoms, state, &f, fcd,
ekind, M, upd, etrtVELOCITY2,
cr, constr);
}
cbuf_nalloc = state->natoms;
srenew(cbuf, cbuf_nalloc);
}
- copy_rvecn(state->x, cbuf, 0, state->natoms);
+ copy_rvecn(as_rvec_array(state->x.data()), cbuf, 0, state->natoms);
}
- update_coords(fplog, step, ir, mdatoms, state, f, fcd,
+ update_coords(fplog, step, ir, mdatoms, state, &f, fcd,
ekind, M, upd, etrtPOSITION, cr, constr);
wallcycle_stop(wcycle, ewcUPDATE);
update_constraints(fplog, step, &dvdl_constr, ir, mdatoms, state,
- fr->bMolPBC, graph, f,
+ fr->bMolPBC, graph, &f,
&top->idef, shake_vir,
cr, nrnb, wcycle, upd, constr,
FALSE, bCalcVir);
wallcycle_start(wcycle, ewcUPDATE);
trotter_update(ir, step, ekind, enerd, state, total_vir, mdatoms, &MassQ, trotter_seq, ettTSEQ4);
/* now we know the scaling, we can compute the positions again again */
- copy_rvecn(cbuf, state->x, 0, state->natoms);
+ copy_rvecn(cbuf, as_rvec_array(state->x.data()), 0, state->natoms);
- update_coords(fplog, step, ir, mdatoms, state, f, fcd,
+ update_coords(fplog, step, ir, mdatoms, state, &f, fcd,
ekind, M, upd, etrtPOSITION, cr, constr);
wallcycle_stop(wcycle, ewcUPDATE);
- /* do we need an extra constraint here? just need to copy out of state->v to upd->xp? */
+ /* do we need an extra constraint here? just need to copy out of as_rvec_array(state->v.data()) to upd->xp? */
/* are the small terms in the shake_vir here due
* to numerical errors, or are they important
* physically? I'm thinking they are just errors, but not completely sure.
* For now, will call without actually constraining, constr=NULL*/
update_constraints(fplog, step, NULL, ir, mdatoms,
- state, fr->bMolPBC, graph, f,
+ state, fr->bMolPBC, graph, &f,
&top->idef, tmp_vir,
cr, nrnb, wcycle, upd, NULL,
FALSE, bCalcVir);
else if (graph)
{
/* Need to unshift here */
- unshift_self(graph, state->box, state->x);
+ unshift_self(graph, state->box, as_rvec_array(state->x.data()));
}
if (vsite != NULL)
wallcycle_start(wcycle, ewcVSITECONSTR);
if (graph != NULL)
{
- shift_self(graph, state->box, state->x);
+ shift_self(graph, state->box, as_rvec_array(state->x.data()));
}
- construct_vsites(vsite, state->x, ir->delta_t, state->v,
+ construct_vsites(vsite, as_rvec_array(state->x.data()), ir->delta_t, as_rvec_array(state->v.data()),
top->idef.iparams, top->idef.il,
fr->ePBC, fr->bMolPBC, cr, state->box);
if (graph != NULL)
{
- unshift_self(graph, state->box, state->x);
+ unshift_self(graph, state->box, as_rvec_array(state->x.data()));
}
wallcycle_stop(wcycle, ewcVSITECONSTR);
}
{
/* Sum up the foreign energy and dhdl terms for md and sd.
Currently done every step so that dhdl is correct in the .edr */
- sum_dhdl(enerd, state->lambda, ir->fepvals);
+ sum_dhdl(enerd, &state->lambda, ir->fepvals);
}
- update_box(fplog, step, ir, mdatoms, state, f,
- pcoupl_mu, nrnb, upd);
+
+ update_pcouple_after_coordinates(fplog, step, ir, mdatoms,
+ pres, parrinellorahmanMu,
+ state, nrnb, upd);
/* ################# END UPDATE STEP 2 ################# */
/* #### We now have r(t+dt) and v(t+dt/2) ############# */
}
else
{
- enerd->term[F_ECONSERVED] = enerd->term[F_ETOT] + compute_conserved_from_auxiliary(ir, state, &MassQ);
+ enerd->term[F_ECONSERVED] = enerd->term[F_ETOT] + NPT_energy(ir, state, &MassQ);
}
/* ######### END PREPARING EDR OUTPUT ########### */
{
/* 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)
{
do_per_step(step, ir->swap->nstswap))
{
bNeedRepartition = do_swapcoords(cr, step, t, ir, wcycle,
- bRerunMD ? rerun_fr.x : state->x,
+ bRerunMD ? rerun_fr.x : as_rvec_array(state->x.data()),
bRerunMD ? rerun_fr.box : state->box,
- top_global, MASTER(cr) && bVerbose, bRerunMD);
+ MASTER(cr) && bVerbose, bRerunMD);
if (bNeedRepartition && DOMAINDECOMP(cr))
{
vsite, constr,
nrnb, wcycle, FALSE);
shouldCheckNumberOfBondedInteractions = true;
- update_realloc(upd, state->nalloc);
+ update_realloc(upd, state->natoms);
}
bFirstStep = FALSE;
if ( (membed != NULL) && (!bLastStep) )
{
- rescale_membed(step_rel, membed, state_global->x);
+ rescale_membed(step_rel, membed, as_rvec_array(state_global->x.data()));
}
if (bRerunMD)
"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))
}
}
- done_mdoutf(outf);
+ done_mdoutf(outf, ir);
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);
#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"
if (!parse_common_args(&argc, argv, PCA_Flags, NFILE, fnm, asize(pa), pa,
asize(desc), desc, 0, NULL, &oenv))
{
+ sfree(cr);
return 0;
}
#include "gromacs/mdtypes/state.h"
#include "gromacs/pbcutil/pbc.h"
#include "gromacs/topology/index.h"
+#include "gromacs/topology/mtop_lookup.h"
#include "gromacs/topology/mtop_util.h"
#include "gromacs/topology/topology.h"
#include "gromacs/utility/cstringutil.h"
int mol_id = 0;
int i;
int atnr_mol;
- gmx_mtop_atomlookup_t alook;
- alook = gmx_mtop_atomlookup_settle_init(mtop);
- gmx_mtop_atomnr_to_molblock_ind(alook, at, block, &mol_id, &atnr_mol);
+ *block = 0;
+ mtopGetMolblockIndex(mtop, at, block, &mol_id, &atnr_mol);
for (i = 0; i < *block; i++)
{
mol_id += mtop->molblock[i].nmol;
}
*type = mtop->molblock[*block].type;
- gmx_mtop_atomlookup_destroy(alook);
-
return mol_id;
}
mtop->mols.index = new_mols;
mtop->natoms -= n;
state->natoms -= n;
- state->nalloc = state->natoms;
- snew(x_tmp, state->nalloc);
- snew(v_tmp, state->nalloc);
+ snew(x_tmp, state->natoms);
+ snew(v_tmp, state->natoms);
for (i = 0; i < egcNR; i++)
{
}
}
}
- sfree(state->x);
- state->x = x_tmp;
- sfree(state->v);
- state->v = v_tmp;
+ for (int i = 0; i < state->natoms; i++)
+ {
+ copy_rvec(x_tmp[i], state->x[i]);
+ }
+ sfree(x_tmp);
+ for (int i = 0; i < state->natoms; i++)
+ {
+ copy_rvec(v_tmp[i], state->v[i]);
+ }
+ sfree(v_tmp);
for (i = 0; i < egcNR; i++)
{
/* Check that moleculetypes in insertion group are not part of the rest of the system */
check_types(ins_at, rest_at, mtop);
- init_mem_at(mem_p, mtop, state->x, state->box, pos_ins);
+ init_mem_at(mem_p, mtop, as_rvec_array(state->x.data()), state->box, pos_ins);
- prot_area = est_prot_area(pos_ins, state->x, ins_at, mem_p);
+ prot_area = est_prot_area(pos_ins, as_rvec_array(state->x.data()), ins_at, mem_p);
if ( (prot_area > prot_vs_box) && ( (state->box[XX][XX]*state->box[YY][YY]-state->box[XX][YY]*state->box[YY][XX]) < box_vs_prot) )
{
warn++;
/* resize the protein by xy and by z if necessary*/
snew(r_ins, ins_at->nr);
- init_resize(ins_at, r_ins, pos_ins, mem_p, state->x, bALLOW_ASYMMETRY);
+ init_resize(ins_at, r_ins, pos_ins, mem_p, as_rvec_array(state->x.data()), bALLOW_ASYMMETRY);
membed->fac[0] = membed->fac[1] = xy_fac;
membed->fac[2] = z_fac;
membed->xy_step = (xy_max-xy_fac)/(double)(it_xy);
membed->z_step = (z_max-z_fac)/(double)(it_z-1);
- resize(r_ins, state->x, pos_ins, membed->fac);
+ resize(r_ins, as_rvec_array(state->x.data()), pos_ins, membed->fac);
/* remove overlapping lipids and water from the membrane box*/
/*mark molecules to be removed*/
set_pbc(pbc, inputrec->ePBC, state->box);
snew(rm_p, 1);
- lip_rm = gen_rm_list(rm_p, ins_at, rest_at, pbc, mtop, state->x, mem_p, pos_ins,
+ lip_rm = gen_rm_list(rm_p, ins_at, rest_at, pbc, mtop, as_rvec_array(state->x.data()), mem_p, pos_ins,
probe_rad, low_up_rm, bALLOW_ASYMMETRY);
lip_rm -= low_up_rm;
exchange_rvecs(ms, b, state->svir_prev, DIM);
exchange_rvecs(ms, b, state->fvir_prev, DIM);
exchange_rvecs(ms, b, state->pres_prev, DIM);
- exchange_doubles(ms, b, state->nosehoover_xi, ngtc);
- exchange_doubles(ms, b, state->nosehoover_vxi, ngtc);
- exchange_doubles(ms, b, state->nhpres_xi, nnhpres);
- exchange_doubles(ms, b, state->nhpres_vxi, nnhpres);
- exchange_doubles(ms, b, state->therm_integral, state->ngtc);
- exchange_rvecs(ms, b, state->x, state->natoms);
- exchange_rvecs(ms, b, state->v, state->natoms);
+ exchange_doubles(ms, b, state->nosehoover_xi.data(), ngtc);
+ exchange_doubles(ms, b, state->nosehoover_vxi.data(), ngtc);
+ exchange_doubles(ms, b, state->nhpres_xi.data(), nnhpres);
+ exchange_doubles(ms, b, state->nhpres_vxi.data(), nnhpres);
+ exchange_doubles(ms, b, state->therm_integral.data(), state->ngtc);
+ exchange_rvecs(ms, b, as_rvec_array(state->x.data()), state->natoms);
+ exchange_rvecs(ms, b, as_rvec_array(state->v.data()), state->natoms);
}
-static void copy_rvecs(rvec *s, rvec *d, int n)
+static void copy_state_serial(const t_state *src, t_state *dest)
{
- int i;
-
- if (d != NULL)
- {
- for (i = 0; i < n; i++)
- {
- copy_rvec(s[i], d[i]);
- }
- }
-}
-
-static void copy_doubles(const double *s, double *d, int n)
-{
- int i;
-
- if (d != NULL)
- {
- for (i = 0; i < n; i++)
- {
- d[i] = s[i];
- }
- }
-}
-
-static void copy_reals(const real *s, real *d, int n)
-{
- int i;
-
- if (d != NULL)
+ if (dest != src)
{
- for (i = 0; i < n; i++)
- {
- d[i] = s[i];
- }
- }
-}
-
-static void copy_ints(const int *s, int *d, int n)
-{
- int i;
-
- if (d != NULL)
- {
- for (i = 0; i < n; i++)
- {
- d[i] = s[i];
- }
+ /* Currently the local state is always a pointer to the global
+ * in serial, so we should never end up here.
+ * TODO: Implement a (trivial) t_state copy once converted to C++.
+ */
+ GMX_RELEASE_ASSERT(false, "State copying is currently not implemented in replica exchange");
}
}
-#define scopy_rvecs(v, n) copy_rvecs(state->v, state_local->v, n);
-#define scopy_doubles(v, n) copy_doubles(state->v, state_local->v, n);
-#define scopy_reals(v, n) copy_reals(state->v, state_local->v, n);
-#define scopy_ints(v, n) copy_ints(state->v, state_local->v, n);
-
-static void copy_state_nonatomdata(t_state *state, t_state *state_local)
-{
- /* When t_state changes, this code should be updated. */
- int ngtc, nnhpres;
- ngtc = state->ngtc * state->nhchainlength;
- nnhpres = state->nnhpres* state->nhchainlength;
- scopy_rvecs(box, DIM);
- scopy_rvecs(box_rel, DIM);
- scopy_rvecs(boxv, DIM);
- state_local->veta = state->veta;
- state_local->vol0 = state->vol0;
- scopy_rvecs(svir_prev, DIM);
- scopy_rvecs(fvir_prev, DIM);
- scopy_rvecs(pres_prev, DIM);
- scopy_doubles(nosehoover_xi, ngtc);
- scopy_doubles(nosehoover_vxi, ngtc);
- scopy_doubles(nhpres_xi, nnhpres);
- scopy_doubles(nhpres_vxi, nnhpres);
- scopy_doubles(therm_integral, state->ngtc);
- scopy_rvecs(x, state->natoms);
- scopy_rvecs(v, state->natoms);
- copy_ints(&(state->fep_state), &(state_local->fep_state), 1);
- scopy_reals(lambda, efptNR);
-}
-
static void scale_velocities(t_state *state, real fac)
{
int i;
- if (state->v)
+ if (as_rvec_array(state->v.data()))
{
for (i = 0; i < state->natoms; i++)
{
}
else
{
- copy_state_nonatomdata(state_local, state);
+ copy_state_serial(state_local, state);
}
if (MASTER(cr))
if (!DOMAINDECOMP(cr))
{
/* Copy the global state to the local state data structure */
- copy_state_nonatomdata(state, state_local);
+ copy_state_serial(state, state_local);
}
}
#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"
#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"
}
-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
{
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;
}
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)
{
{
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;
}
}
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)
{
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;
if (bNtOmpOptionSet)
{
- md_print_warn(cr, fplog, "NOTE: %s\n", buf);
+ GMX_LOG(mdlog.warning).asParagraph().appendTextFormatted("NOTE: %s", buf);
}
else
{
*/
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
{
/* 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 */
}
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.
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);
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,
#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"
#include "gromacs/hardware/detecthardware.h"
+#include "gromacs/hardware/hardwareassign.h"
#include "gromacs/listed-forces/disre.h"
#include "gromacs/listed-forces/orires.h"
#include "gromacs/math/calculate-ewald-splitting-coefficient.h"
#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/energyhistory.h"
#include "gromacs/mdtypes/inputrec.h"
#include "gromacs/mdtypes/md_enums.h"
#include "gromacs/mdtypes/state.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"
real rlistWithReferenceNstlist, rlist_inc, rlist_ok, rlist_max;
real rlist_new, rlist_prev;
size_t nstlist_ind = 0;
- t_state state_tmp;
gmx_bool bBox, bDD, bCont;
const char *nstl_gpu = "\nFor optimal performance with a GPU nstlist (now %d) should be larger.\nThe optimum depends on your CPU and GPU resources.\nYou might want to try several nstlist values.\n";
const char *nve_err = "Can not increase nstlist because an NVE ensemble is used";
{
gmx_incons("Changing nstlist with domain decomposition and unbounded dimensions is not implemented yet");
}
+ t_state state_tmp {};
copy_mat(box, state_tmp.box);
bDD = change_dd_cutoff(cr, &state_tmp, ir, rlist_new);
}
*
* 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)
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)
{
}
}
+//! 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,
{
gmx_bool bForceUseGPU, bTryUseGPU, bRerunMD;
t_inputrec *inputrec;
- t_state *state = NULL;
matrix box;
gmx_ddbox_t ddbox = {0};
int npme_major, npme_minor;
/* 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)
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)
{
please_cite(fplog, "Berendsen95a");
}
- snew(state, 1);
+ std::unique_ptr<t_state> stateInstance = std::unique_ptr<t_state>(new t_state {});
+ t_state * state = stateInstance.get();
+
if (SIMMASTER(cr))
{
/* Read (nearly) all data required for the simulation */
* 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)
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)
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
hw_opt->nthreads_tmpi = get_nthreads_mpi(hwinfo,
hw_opt,
inputrec, mtop,
- cr, fplog, bUseGPU,
+ mdlog, bUseGPU,
doMembed);
if (hw_opt->nthreads_tmpi > 1)
/* This needs to be called before read_checkpoint to extend the state */
init_disres(fplog, mtop, inputrec, cr, fcd, state, repl_ex_nst > 0);
- init_orires(fplog, mtop, state->x, inputrec, cr, &(fcd->orires),
+ init_orires(fplog, mtop, as_rvec_array(state->x.data()), inputrec, cr, &(fcd->orires),
state);
if (inputrecDeform(inputrec))
tMPI_Thread_mutex_unlock(&deform_init_box_mutex);
}
+ energyhistory_t energyHistory;
+
if (Flags & MD_STARTFROMCPT)
{
/* Check if checkpoint file exists before doing continuation.
load_checkpoint(opt2fn_master("-cpi", nfile, fnm, cr), &fplog,
cr, ddxyz, &npme,
- inputrec, state, &bReadEkin,
+ inputrec, state, &bReadEkin, &energyHistory,
(Flags & MD_APPENDFILES),
(Flags & MD_APPENDFILESSET),
(Flags & MD_REPRODUCIBLE));
}
}
- 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))
{
dddlb_opt, dlb_scale,
ddcsx, ddcsy, ddcsz,
mtop, inputrec,
- box, state->x,
+ box, as_rvec_array(state->x.data()),
&ddbox, &npme_major, &npme_minor);
}
else
#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
/* 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,
if (bUseGPU)
{
/* Select GPU id's to use */
- gmx_select_gpu_ids(fplog, cr, &hwinfo->gpu_info, bForceUseGPU,
- &hw_opt->gpu_opt);
+ gmx_select_rank_gpu_ids(mdlog, cr, &hwinfo->gpu_info, bForceUseGPU,
+ &hw_opt->gpu_opt);
}
else
{
/* 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))
{
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),
/* Make molecules whole at start of run */
if (fr->ePBC != epbcNONE)
{
- do_pbc_first_mtop(fplog, inputrec->ePBC, box, mtop, state->x);
+ do_pbc_first_mtop(fplog, inputrec->ePBC, box, mtop, as_rvec_array(state->x.data()));
}
if (vsite)
{
* for the initial distribution in the domain decomposition
* and for the initial shell prediction.
*/
- construct_vsites_mtop(vsite, mtop, state->x);
+ construct_vsites_mtop(vsite, mtop, as_rvec_array(state->x.data()));
}
}
/* This is a PME only node */
/* We don't need the state */
- done_state(state);
+ stateInstance.reset();
+ state = NULL;
ewaldcoeff_q = calc_ewaldcoeff_q(inputrec->rcoulomb, inputrec->ewald_rtol);
ewaldcoeff_lj = calc_ewaldcoeff_lj(inputrec->rvdw, inputrec->ewald_rtol_lj);
* - 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,
{
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);
if (inputrec->bRot)
{
/* Initialize enforced rotation code */
- init_rot(fplog, inputrec, nfile, fnm, cr, state->x, state->box, mtop, oenv,
+ init_rot(fplog, inputrec, nfile, fnm, cr, as_rvec_array(state->x.data()), state->box, mtop, oenv,
bVerbose, Flags);
}
}
/* 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,
nstepout, inputrec, mtop,
- fcd, state,
+ fcd, state, &energyHistory,
mdatoms, nrnb, wcycle, ed, fr,
repl_ex_nst, repl_ex_nex, repl_ex_seed,
membed,
/* 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);
# 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")
# 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)
#include "testutils/cmdlinetest.h"
#include "testutils/integrationtests.h"
+#include "testutils/mpitest.h"
#include "testutils/testoptions.h"
namespace gmx
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;
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"));
#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
* 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)
* version. */
const char *trajectoryFileNames[] = {
"../../../gromacs/gmxana/legacytests/spc2-traj.trr",
-#if defined GMX_USE_TNG && HAVE_ZLIB
+#if GMX_USE_TNG
"../../../gromacs/gmxana/legacytests/spc2-traj.tng",
#endif
"../../../gromacs/gmxana/legacytests/spc2-traj.xtc",
*
* Copyright (c) 1991-2000, University of Groningen, The Netherlands.
* Copyright (c) 2001-2013, 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.
{
t_gmx *gmx;
- gmx = (t_gmx *)data;
+ gmx = static_cast<t_gmx *>(data);
if (dlg_mess == DLG_EXIT)
{
hide_mb(gmx);
char *set, void *data)
{
t_gmx *gmx;
- gmx = (t_gmx *)data;
+ gmx = static_cast<t_gmx *>(data);
hide_mb(gmx);
if (dlg_mess == DLG_EXIT)
t_gmx *gmx;
t_dlg *dlg;
- gmx = (t_gmx *)data;
+ gmx = static_cast<t_gmx *>(data);
dlg = gmx->dlgs[edExport];
switch (dlg_mess)
{
t_gmx *gmx;
char *endptr;
- gmx = (t_gmx *)data;
+ gmx = static_cast<t_gmx *>(data);
if (ebond == -1)
{
ebond = gmx->man->molw->bond_type;
*
* 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.
{
t_windata *wd;
- wd = (t_windata *)data;
+ wd = static_cast<t_windata *>(data);
switch (event->type)
{
case Expose:
t_manager *man;
int width, height;
- man = (t_manager *)data;
+ man = static_cast<t_manager *>(data);
switch (event->type)
{
case ConfigureNotify:
*
* Copyright (c) 1991-2000, University of Groningen, The Netherlands.
* Copyright (c) 2001-2013, 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.
Window To;
XEvent letter;
- mw = (t_molwin *)data;
+ mw = static_cast<t_molwin *>(data);
To = mw->wd.Parent;
letter.type = ClientMessage;
letter.xclient.display = x11->disp;
int compare_obj(const void *a, const void *b)
{
- t_object *oa, *ob;
- real z;
+ const t_object *oa, *ob;
+ real z;
- oa = (t_object *)a;
- ob = (t_object *)b;
+ oa = static_cast<const t_object *>(a);
+ ob = static_cast<const t_object *>(b);
z = oa->z-ob->z;
# 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
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)
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(_labels GTest)
+ set(_timeout 30)
+ if (ARG_INTEGRATION_TEST)
+ list(APPEND _labels IntegrationTest)
+ set(_timeout 120)
+ gmx_get_test_prefix_cmd(_prefix_cmd IGNORE_LEAKS)
# 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)
+ gmx_get_test_prefix_cmd(_prefix_cmd)
endif()
+ set(_cmd ${_prefix_cmd} $<TARGET_FILE:${EXENAME}>)
+ 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} ${_cmd} ${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()
}
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
/*
* 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.
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_;
void InteractiveTestHelper::checkSession()
{
impl_->checkOutput();
- impl_->checkPendingInput();
+ impl_->checker_.checkUnusedEntries();
}
} // namespace test
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
#include "gromacs/utility/basedefinitions.h"
#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/strconvert.h"
#include "gromacs/utility/stringutil.h"
#include "testutils/refdata-impl.h"
std::string value_;
};
-//! Helper function to parse a floating-point value.
-// TODO: Move this into src/gromacs/utility/, and consolidate with similar code
-// elsewhere.
-double convertDouble(const std::string &value)
-{
- char *endptr;
- double convertedValue = std::strtod(value.c_str(), &endptr);
- // TODO: Check for overflow
- if (*endptr != '\0')
- {
- GMX_THROW(InvalidInputError("Invalid floating-point value: " + value));
- }
- return convertedValue;
-}
//! Helper function to parse a floating-point reference data value.
double convertDoubleReferenceValue(const std::string &value)
{
try
{
- return convertDouble(value);
+ return fromString<double>(value);
}
catch (const InvalidInputError &ex)
{
virtual ::testing::AssertionResult
checkEntry(const ReferenceDataEntry &entry, const std::string &fullId) const
{
- FloatType value = static_cast<FloatType>(convertDouble(value_));
+ FloatType value = fromString<FloatType>(value_);
FloatType refValue = static_cast<FloatType>(convertDoubleReferenceValue(entry.value()));
FloatingPointDifference diff(refValue, value);
if (tolerance_.isWithin(diff))
FloatingPointTolerance tolerance_;
};
+template <typename ValueType>
+class ValueExtractor : public IReferenceDataEntryChecker
+{
+ public:
+ explicit ValueExtractor(ValueType *value)
+ : value_(value)
+ {
+ }
+
+ virtual void fillEntry(ReferenceDataEntry *) const
+ {
+ GMX_THROW(TestException("Extracting value from non-existent reference data entry"));
+ }
+ virtual ::testing::AssertionResult
+ checkEntry(const ReferenceDataEntry &entry, const std::string &) const
+ {
+ extractValue(entry.value());
+ return ::testing::AssertionSuccess();
+ }
+
+ void extractValue(const std::string &value) const
+ {
+ *value_ = fromString<ValueType>(value);
+ }
+
+ private:
+ ValueType *value_;
+};
+
+template <> inline void
+ValueExtractor<std::string>::extractValue(const std::string &value) const
+{
+ *value_ = value;
+}
+
} // namespace test
} // namespace gmx
/*
* 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.
ReferenceDataEntry(const char *type, const char *id)
: type_(type), id_(id != NULL ? id : ""), isTextBlock_(false),
- correspondingOutputEntry_(NULL)
+ hasBeenChecked_(false), correspondingOutputEntry_(NULL)
{
}
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()));
std::string value_;
bool isTextBlock_;
ChildList children_;
+ bool hasBeenChecked_;
ReferenceDataEntry *correspondingOutputEntry_;
};
#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"
}
};
+//! 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)
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_, "");
}
}
static const char * const cBooleanNodeName;
//! String constant for naming XML elements for string values.
static const char * const cStringNodeName;
+ //! String constant for naming XML elements for unsigned char values.
+ static const char * const cUCharNodeName;
//! String constant for naming XML elements for integer values.
static const char * const cIntegerNodeName;
//! String constant for naming XML elements for int64 values.
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.
/*! \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_;
};
const char *const TestReferenceChecker::Impl::cBooleanNodeName = "Bool";
const char *const TestReferenceChecker::Impl::cStringNodeName = "String";
+const char *const TestReferenceChecker::Impl::cUCharNodeName = "UChar";
const char *const TestReferenceChecker::Impl::cIntegerNodeName = "Int";
const char *const TestReferenceChecker::Impl::cInt64NodeName = "Int64";
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";
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)
{
}
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)
{
}
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;
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)
{
{
return TestReferenceChecker(new TestReferenceChecker::Impl(true));
}
+ impl_->compareRootEntry_->setChecked();
return TestReferenceChecker(
new TestReferenceChecker::Impl("", impl_->compareRootEntry_.get(),
impl_->outputRootEntry_.get(),
}
+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)
ADD_FAILURE() << "Reference data item " << fullId << " not found";
return TestReferenceChecker(new Impl(true));
}
+ entry->setChecked();
if (impl_->updateMismatchingEntries_)
{
entry->makeCompound(type);
}
+void TestReferenceChecker::checkUChar(unsigned char value, const char *id)
+{
+ EXPECT_PLAIN(impl_->processItem(Impl::cUCharNodeName, id,
+ ExactStringChecker(formatString("%d", value))));
+}
+
void TestReferenceChecker::checkInteger(int value, const char *id)
{
EXPECT_PLAIN(impl_->processItem(Impl::cIntegerNodeName, 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)
{
return compound;
}
+
+unsigned char TestReferenceChecker::readUChar(const char *id)
+{
+ if (impl_->shouldIgnore())
+ {
+ GMX_THROW(TestException("Trying to read from non-existent reference data value"));
+ }
+ int value = 0;
+ EXPECT_PLAIN(impl_->processItem(Impl::cUCharNodeName, id,
+ ValueExtractor<int>(&value)));
+ return value;
+}
+
+
+int TestReferenceChecker::readInteger(const char *id)
+{
+ if (impl_->shouldIgnore())
+ {
+ GMX_THROW(TestException("Trying to read from non-existent reference data value"));
+ }
+ int value = 0;
+ EXPECT_PLAIN(impl_->processItem(Impl::cIntegerNodeName, id,
+ ValueExtractor<int>(&value)));
+ return value;
+}
+
+
+float TestReferenceChecker::readFloat(const char *id)
+{
+ if (impl_->shouldIgnore())
+ {
+ GMX_THROW(TestException("Trying to read from non-existent reference data value"));
+ }
+ float value = 0;
+ EXPECT_PLAIN(impl_->processItem(Impl::cRealNodeName, id,
+ ValueExtractor<float>(&value)));
+ return value;
+}
+
+
+double TestReferenceChecker::readDouble(const char *id)
+{
+ if (impl_->shouldIgnore())
+ {
+ GMX_THROW(TestException("Trying to read from non-existent reference data value"));
+ }
+ double value = 0;
+ EXPECT_PLAIN(impl_->processItem(Impl::cRealNodeName, id,
+ ValueExtractor<double>(&value)));
+ return value;
+}
+
+
+std::string TestReferenceChecker::readString(const char *id)
+{
+ if (impl_->shouldIgnore())
+ {
+ GMX_THROW(TestException("Trying to read from non-existent reference data value"));
+ }
+ std::string value;
+ EXPECT_PLAIN(impl_->processItem(Impl::cStringNodeName, id,
+ ValueExtractor<std::string>(&value)));
+ return value;
+}
+
} // namespace test
} // namespace gmx
{
class IOptionsContainer;
+class KeyValueTreeObject;
+class KeyValueTreeValue;
+class Variant;
namespace test
{
*/
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.
*
* is easier to edit by hand to set the desired output formatting.
*/
void checkTextBlock(const std::string &value, const char *id);
+ //! Check a single unsigned char value.
+ void checkUChar(unsigned char value, const char *id);
//! Check a single integer value.
void checkInteger(int value, const char *id);
//! Check a single int64 value.
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 Methods to read values from reference data
+ *
+ * These methods assume that a value with the given `id` has already
+ * been created in the test with `check*()` methods, and that it has
+ * the correct type.
+ *
+ * Currently, these methods do not work correctly if the reference data
+ * file does not exist, so a test using them may fail with exceptions
+ * before the reference data has been generated.
+ * \{
+ */
+ //! Reads an unsigned char value.
+ unsigned char readUChar(const char *id);
+ //! Reads an integer value.
+ int readInteger(const char *id);
+ //! Reads a float value.
+ float readFloat(const char *id);
+ //! Reads a double value.
+ double readDouble(const char *id);
+ //! Reads a string value.
+ std::string readString(const char *id);
+ //! \}
/*! \name Overloaded versions of simple checker methods
*
{
checkVector(value, id);
}
+ //! Check a generic key-value tree value.
+ void checkValue(const KeyValueTreeValue &value, const char *id)
+ {
+ checkKeyValueTreeValue(value, id);
+ }
/*!\}*/
/*! \brief
/*
* 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.
* 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;
}
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" : "");
}
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;
}
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_)
{
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
/*
* 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.
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.
//! 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_;
* 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.
* 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
* 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
*/
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)
private:
float singleAbsoluteTolerance_;
double doubleAbsoluteTolerance_;
+ float singleRelativeTolerance_;
+ double doubleRelativeTolerance_;
gmx_uint64_t singleUlpTolerance_;
gmx_uint64_t doubleUlpTolerance_;
bool bSignMustMatch_;
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
* \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
* 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
{
return FloatingPointTolerance(magnitude*singleUlpDiff*GMX_FLOAT_EPS,
magnitude*doubleUlpDiff*GMX_DOUBLE_EPS,
+ 0.0, 0.0,
singleUlpDiff, doubleUlpDiff, false);
}
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);
}
//! \}
-/*! \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`.
/*
* 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.
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_;
}
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;
}
{
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());
}
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.
#
# 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.
refdata_tests.cpp
testasserts_tests.cpp
xvgtest_tests.cpp)
+
+gmx_add_mpi_unit_test(TestUtilsMpiUnitTests testutils-mpi-test 2
+ mpitest.cpp)
void addOutput(const char *output)
{
- events_.push_back(Event(WriteOutput, output));
+ events_.emplace_back(WriteOutput, output);
}
void addInputLine(const char *inputLine)
{
}
void addReadInput()
{
- events_.push_back(Event(ReadInput, ""));
+ events_.emplace_back(ReadInput, "");
}
void addInput(const char *inputLine)
{
{
addInputLine(inputLine);
helper_.setLastNewline(false);
- events_.push_back(Event(ReadInputNoNewline, ""));
+ events_.emplace_back(ReadInputNoNewline, "");
}
void run()
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 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.
*/
-/* This file is completely threadsafe - keep it that way! */
+/*! \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 "energyhistory.h"
+#include "testutils/mpitest.h"
-#include <cstring>
+#include "config.h"
-#include <algorithm>
+#include <gtest/gtest.h>
-#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/gmxmpi.h"
-static void done_delta_h_history(delta_h_history_t *dht)
+namespace
{
- int i;
-
- for (i = 0; i < dht->nndh; i++)
- {
- sfree(dht->dh[i]);
- }
- sfree(dht->dh);
- sfree(dht->ndh);
-}
-void init_energyhistory(energyhistory_t * enerhist)
+class MpiSelfTest : public ::testing::Test
{
- enerhist->nener = 0;
+ public:
+ MpiSelfTest() : reached {0, 0}
+ {}
- enerhist->ener_ave = NULL;
- enerhist->ener_sum = NULL;
- enerhist->ener_sum_sim = NULL;
- enerhist->dht = NULL;
+ int reached[2];
+};
- enerhist->nsteps = 0;
- enerhist->nsum = 0;
- enerhist->nsteps_sim = 0;
- enerhist->nsum_sim = 0;
-
- enerhist->dht = NULL;
-}
-
-void done_energyhistory(energyhistory_t * enerhist)
+TEST_F(MpiSelfTest, Runs)
{
- sfree(enerhist->ener_ave);
- sfree(enerhist->ener_sum);
- sfree(enerhist->ener_sum_sim);
-
- if (enerhist->dht != NULL)
+ 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)
{
- done_delta_h_history(enerhist->dht);
- sfree(enerhist->dht);
+ EXPECT_EQ(1, reached[0]);
+ EXPECT_EQ(1, reached[1]);
}
}
+
+} // namespace
#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"
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"), "");
}
}
}
+TEST(ReferenceDataTest, HandlesReadingValues)
+{
+ {
+ TestReferenceData data(gmx::test::erefdataUpdateAll);
+ TestReferenceChecker checker(data.rootChecker());
+ checker.checkUChar('A', "char");
+ checker.checkInteger(1, "int");
+ checker.checkString("Test", "string");
+ }
+ {
+ TestReferenceData data(gmx::test::erefdataCompare);
+ TestReferenceChecker checker(data.rootChecker());
+ EXPECT_EQ('A', checker.readUChar("char"));
+ EXPECT_EQ(1, checker.readInteger("int"));
+ EXPECT_EQ("Test", checker.readString("string"));
+ }
+}
+
+
TEST(ReferenceDataTest, HandlesUpdateChangedWithoutChanges)
{
{
}
}
+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
/*
* 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.
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");
}
}
/*
* 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.
&checkXvgDataPoint);
++dataRowCount;
}
- if (settings.testData)
- {
- dataChecker.checkPresent(false, formatString("Row%d", dataRowCount).c_str());
- }
+ dataChecker.checkUnusedEntries();
legendChecker.checkTextBlock(legendText, "XvgLegend");
}
#
# 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.
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.")
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)
--- /dev/null
+#
+# 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()
--suppress=invalidscanf
--suppress=sizeofCalculation
--suppress=invalidscanf_libc
- --suppress=missingInclude:src/programs/mdrun/gmx_gpu_utils/gmx_gpu_utils.cu
--suppress=*:src/external/Random123-1.08/include/Random123/features/compilerfeatures.h
- --suppress=invalidPointerCast:src/gromacs/mdlib/nbnxn_cuda/nbnxn_cuda_kernel.cuh
- --suppress=passedByValue:src/gromacs/mdlib/nbnxn_cuda/nbnxn_cuda_kernel.cuh
- --suppress=passedByValue:src/gromacs/mdlib/nbnxn_cuda/nbnxn_cuda_kernel_utils.cuh
- --suppress=shiftTooManyBits:src/gromacs/gpu_utils/gpu_utils.cu
)
set(_cxx_flags
-D__cplusplus
--suppress=passedByValue:src/gromacs/simd/tests/*
--suppress=redundantAssignment:src/gromacs/simd/simd_math.h #seems to be a bug in cppcheck
--suppress=noExplicitConstructor # can't be selective about this, see http://sourceforge.net/p/cppcheck/discussion/general/thread/db1e4ba7/
+ --suppress=unusedStructMember:src/gromacs/onlinehelp/tests/helpmanager.cpp
+ --suppress=unusedStructMember:src/gromacs/commandline/cmdlinehelpmodule.cpp
+ --suppress=unusedStructMember:src/gromacs/selection/selhelp.cpp
+ --suppress=redundantPointerOp:src/gromacs/fileio/gmxfio-xdr.cpp
+ --suppress=passedByValue # See comment below
+ --suppress=shiftTooManyBits:src/gromacs/gpu_utils/gpu_utils.cu # CUDA kernel launch false positive
)
+ # Passing non-trivial objects by value is rarely a problem for
+ # GROMACS in performance-sensitive code, and shouldn't be
+ # enforced for types that are intended to be used like value
+ # types (e.g. SIMD wrapper types, ArrayRef) , nor for
+ # move-enabled types. cppcheck isn't sensitive to these
+ # subtleties yet.
# This list will hold the list of all files with cppcheck errors
# (one per input file)
set(_target_name cppcheck-${_filename}.${_outputext})
string(REPLACE "/" "_" _target_name ${_target_name})
list(APPEND _filelist ${_target_name})
- if (_filename MATCHES "\\.cpp$")
+ if (_filename MATCHES "\\.cpp$" OR _filename MATCHES "\\.cu$")
set(_lang CXX)
set(_lang_flags ${_cxx_flags})
else()