Merge branch 'master' into pygromacs
authorAlexey Shvetsov <alexxy@omrb.pnpi.spb.ru>
Mon, 27 Jul 2015 18:53:14 +0000 (21:53 +0300)
committerAlexey Shvetsov <alexxy@omrb.pnpi.spb.ru>
Mon, 27 Jul 2015 18:53:14 +0000 (21:53 +0300)
42 files changed:
.gitattributes
CMakeLists.txt
cmake/FindNumPy.cmake [new file with mode: 0644]
cmake/FindPythonLibrary.cmake [new file with mode: 0644]
cmake/FindSIP.cmake [new file with mode: 0644]
cmake/FindSIP.py [new file with mode: 0644]
cmake/PythonCompile.py [new file with mode: 0644]
cmake/PythonMacros.cmake [new file with mode: 0644]
cmake/SIPMacros.cmake [new file with mode: 0644]
src/CMakeLists.txt
src/gromacs/trajectoryanalysis/analysismodule.h
src/gromacs/trajectoryanalysis/cmdlinerunner.cpp
src/gromacs/trajectoryanalysis/cmdlinerunner.h
src/gromacs/trajectoryanalysis/runnercommon.cpp
src/python/CMakeLists.txt [new file with mode: 0644]
src/python/__init__.py [new file with mode: 0644]
src/python/include/numpy_conv.h [new file with mode: 0644]
src/python/pipeline_test.py [new file with mode: 0644]
src/python/runner/__init__.py [new file with mode: 0644]
src/python/runner/pipeline.py [new file with mode: 0644]
src/python/sip/definitions.sip [new file with mode: 0644]
src/python/sip/options/Options.sip [new file with mode: 0644]
src/python/sip/options/abstractoption.sip [new file with mode: 0644]
src/python/sip/options/basicoptions.sip [new file with mode: 0644]
src/python/sip/options/filenameoption.sip [new file with mode: 0644]
src/python/sip/options/options.sip [new file with mode: 0644]
src/python/sip/options/pyoptionsholder.sip [new file with mode: 0644]
src/python/sip/options/selectionoption.sip [new file with mode: 0644]
src/python/sip/selection/Selection.sip [new file with mode: 0644]
src/python/sip/selection/selection.sip [new file with mode: 0644]
src/python/sip/string.sip [new file with mode: 0644]
src/python/sip/topology/Topology.sip [new file with mode: 0644]
src/python/sip/topology/atoms.sip [new file with mode: 0644]
src/python/sip/topology/pstringlistwrapper.sip [new file with mode: 0644]
src/python/sip/topology/topology.sip [new file with mode: 0644]
src/python/sip/trajectoryanalysis/TrajectoryAnalysis.sip [new file with mode: 0644]
src/python/sip/trajectoryanalysis/analysisdata.sip [new file with mode: 0644]
src/python/sip/trajectoryanalysis/analysismodule.sip [new file with mode: 0644]
src/python/sip/trajectoryanalysis/analysissettings.sip [new file with mode: 0644]
src/python/sip/trajectoryanalysis/modules.sip [new file with mode: 0644]
src/python/sip/vector.sip [new file with mode: 0644]
src/python/test.py [new file with mode: 0644]

index 1f069f17776485f5a38735a0ae313c9eafb2b280..86fb3cf8ea0b2d982ce834ce65473537050a5808 100644 (file)
@@ -22,6 +22,9 @@ cmake/CheckC*CompilerFlag.cmake         !filter
 cmake/FindBLAS.cmake                    !filter
 cmake/FindLAPACK.cmake                  !filter
 cmake/ThreadMPI.cmake                   !filter
+cmake/FindPythonLibrary.cmake          !filter
+cmake/FindNumPy.cmake                  !filter
+cmake/FindSIP.*                                !filter
 cmake/Platform/BluegeneQ*.cmake         !filter
 cmake/*.c                               -filter -gmx-doxygen
 cmake/*.cpp                             -filter -gmx-doxygen
index c6a2cf3e38e4f220264b5e5e7c7948122923b952..014b34980000184c9a6c49ed53919443f0e0c95a 100644 (file)
@@ -907,6 +907,15 @@ if ((CUDA_NOTFOUND_AUTO AND GMX_DETECT_GPU_AVAILABLE) AND NOT GMX_GPU_DETECTION_
 endif()
 set(GMX_GPU_DETECTION_DONE TRUE CACHE INTERNAL "Whether GPU detection has already been done")
 
+#######################
+## Python bindings
+#######################
+
+# We only set option here, actual detection goes to
+# src/python/CMakeLists.txt due to bugs in FindSIP
+option(GMX_PYTHON_BINDINGS "Enable GROMACS Python API bindings"        OFF)
+
+
 #######################
 ## uninstall target
 #######################
diff --git a/cmake/FindNumPy.cmake b/cmake/FindNumPy.cmake
new file mode 100644 (file)
index 0000000..f14142f
--- /dev/null
@@ -0,0 +1,102 @@
+# - Find the NumPy libraries
+# This module finds if NumPy is installed, and sets the following variables
+# indicating where it is.
+#
+# TODO: Update to provide the libraries and paths for linking npymath lib.
+#
+#  NUMPY_FOUND               - was NumPy found
+#  NUMPY_VERSION             - the version of NumPy found as a string
+#  NUMPY_VERSION_MAJOR       - the major version number of NumPy
+#  NUMPY_VERSION_MINOR       - the minor version number of NumPy
+#  NUMPY_VERSION_PATCH       - the patch version number of NumPy
+#  NUMPY_VERSION_DECIMAL     - e.g. version 1.6.1 is 10601
+#  NUMPY_INCLUDE_DIRS        - path to the NumPy include files
+
+#============================================================================
+# Copyright 2012 Continuum Analytics, Inc.
+#
+# MIT License
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to permit
+# persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be included
+# in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+#============================================================================
+
+# Finding NumPy involves calling the Python interpreter
+if(NumPy_FIND_REQUIRED)
+    find_package(PythonInterp REQUIRED)
+else()
+    find_package(PythonInterp)
+endif()
+
+if(NOT PYTHONINTERP_FOUND)
+    set(NUMPY_FOUND FALSE)
+    return()
+endif()
+
+execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c"
+    "import numpy as n; print(n.__version__); print(n.get_include());"
+    RESULT_VARIABLE _NUMPY_SEARCH_SUCCESS
+    OUTPUT_VARIABLE _NUMPY_VALUES_OUTPUT
+    ERROR_VARIABLE _NUMPY_ERROR_VALUE
+    OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+if(NOT _NUMPY_SEARCH_SUCCESS MATCHES 0)
+    if(NumPy_FIND_REQUIRED)
+        message(FATAL_ERROR
+            "NumPy import failure:\n${_NUMPY_ERROR_VALUE}")
+    endif()
+    set(NUMPY_FOUND FALSE)
+    return()
+endif()
+
+# Convert the process output into a list
+string(REGEX REPLACE ";" "\\\\;" _NUMPY_VALUES ${_NUMPY_VALUES_OUTPUT})
+string(REGEX REPLACE "\n" ";" _NUMPY_VALUES ${_NUMPY_VALUES})
+# Just in case there is unexpected output from the Python command.
+list(GET _NUMPY_VALUES -2 NUMPY_VERSION)
+list(GET _NUMPY_VALUES -1 NUMPY_INCLUDE_DIRS)
+
+string(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+" _VER_CHECK "${NUMPY_VERSION}")
+if("${_VER_CHECK}" STREQUAL "")
+    # The output from Python was unexpected. Raise an error always
+    # here, because we found NumPy, but it appears to be corrupted somehow.
+    message(FATAL_ERROR
+        "Requested version and include path from NumPy, got instead:\n${_NUMPY_VALUES_OUTPUT}\n")
+    return()
+endif()
+
+# Make sure all directory separators are '/'
+string(REGEX REPLACE "\\\\" "/" NUMPY_INCLUDE_DIRS ${NUMPY_INCLUDE_DIRS})
+
+# Get the major and minor version numbers
+string(REGEX REPLACE "\\." ";" _NUMPY_VERSION_LIST ${NUMPY_VERSION})
+list(GET _NUMPY_VERSION_LIST 0 NUMPY_VERSION_MAJOR)
+list(GET _NUMPY_VERSION_LIST 1 NUMPY_VERSION_MINOR)
+list(GET _NUMPY_VERSION_LIST 2 NUMPY_VERSION_PATCH)
+string(REGEX MATCH "[0-9]*" NUMPY_VERSION_PATCH ${NUMPY_VERSION_PATCH})
+math(EXPR NUMPY_VERSION_DECIMAL
+    "(${NUMPY_VERSION_MAJOR} * 10000) + (${NUMPY_VERSION_MINOR} * 100) + ${NUMPY_VERSION_PATCH}")
+
+find_package_message(NUMPY
+    "Found NumPy: version \"${NUMPY_VERSION}\" ${NUMPY_INCLUDE_DIRS}"
+    "${NUMPY_INCLUDE_DIRS}${NUMPY_VERSION}")
+
+set(NUMPY_FOUND TRUE)
+
diff --git a/cmake/FindPythonLibrary.cmake b/cmake/FindPythonLibrary.cmake
new file mode 100644 (file)
index 0000000..975cb8e
--- /dev/null
@@ -0,0 +1,74 @@
+# Find Python
+# ~~~~~~~~~~~
+# Find the Python interpreter and related Python directories.
+#
+# This file defines the following variables:
+#
+# PYTHON_EXECUTABLE - The path and filename of the Python interpreter.
+#
+# PYTHON_SHORT_VERSION - The version of the Python interpreter found,
+#     excluding the patch version number. (e.g. 2.5 and not 2.5.1))
+#
+# PYTHON_LONG_VERSION - The version of the Python interpreter found as a human
+#     readable string.
+#
+# PYTHON_SITE_PACKAGES_INSTALL_DIR - this cache variable can be used for installing
+#                              own python modules. You may want to adjust this to be the
+#                              same as ${PYTHON_SITE_PACKAGES_DIR}, but then admin
+#                              privileges may be required for installation.
+#
+# PYTHON_SITE_PACKAGES_DIR - Location of the Python site-packages directory.
+#
+# PYTHON_INCLUDE_PATH - Directory holding the python.h include file.
+#
+# PYTHON_LIBRARY, PYTHON_LIBRARIES- Location of the Python library.
+
+# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
+# Copyright (c) 2012, Luca Beltrame <lbeltrame@kde.org>
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+include(FindPackageHandleStandardArgs)
+
+find_package(PythonInterp)
+
+if (PYTHONINTERP_FOUND)
+
+    option(INSTALL_PYTHON_FILES_IN_PYTHON_PREFIX "Install the Python files in the Python packages dir" FALSE)
+
+    # Set the Python libraries to what we actually found for interpreters
+    set(Python_ADDITIONAL_VERSIONS "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}")
+    # These are kept for compatibility
+    set(PYTHON_SHORT_VERSION "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}")
+    set(PYTHON_LONG_VERSION ${PYTHON_VERSION_STRING})
+
+    find_package(PythonLibs QUIET)
+
+    if(PYTHONLIBS_FOUND)
+        set(PYTHON_LIBRARY ${PYTHON_LIBRARIES})
+    endif(PYTHONLIBS_FOUND)
+
+    # Auto detect Python site-packages directory
+    execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True))"
+                    OUTPUT_VARIABLE PYTHON_SITE_PACKAGES_DIR
+                    OUTPUT_STRIP_TRAILING_WHITESPACE
+                   )
+
+    message(STATUS "Python system site-packages directory: ${PYTHON_SITE_PACKAGES_DIR}")
+    if(INSTALL_PYTHON_FILES_IN_PYTHON_PREFIX)
+        set(PYTHON_SITE_PACKAGES_INSTALL_DIR ${PYTHON_SITE_PACKAGES_DIR})
+    else()
+        execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(True, prefix='${CMAKE_INSTALL_PREFIX}'))"
+                        OUTPUT_VARIABLE PYTHON_SITE_PACKAGES_INSTALL_DIR
+                        OUTPUT_STRIP_TRAILING_WHITESPACE
+                       )
+    endif()
+
+    if(NOT PYTHON_SITE_PACKAGES_INSTALL_DIR STREQUAL PYTHON_SITE_PACKAGES_DIR)
+        message(STATUS "The Python files will be installed to ${PYTHON_SITE_PACKAGES_INSTALL_DIR}. Make sure to add them to the Python search path (e.g. by setting PYTHONPATH)")
+    endif()
+
+endif(PYTHONINTERP_FOUND)
+
+find_package_handle_standard_args(PythonLibrary DEFAULT_MSG PYTHON_LIBRARY)
+
diff --git a/cmake/FindSIP.cmake b/cmake/FindSIP.cmake
new file mode 100644 (file)
index 0000000..d6090a3
--- /dev/null
@@ -0,0 +1,65 @@
+# Find SIP
+# ~~~~~~~~
+#
+# SIP website: http://www.riverbankcomputing.co.uk/sip/index.php
+#
+# Find the installed version of SIP. FindSIP should be called after Python
+# has been found.
+#
+# This file defines the following variables:
+#
+# SIP_VERSION - The version of SIP found expressed as a 6 digit hex number
+#     suitable for comparison as a string.
+#
+# SIP_VERSION_STR - The version of SIP found as a human readable string.
+#
+# SIP_EXECUTABLE - Path and filename of the SIP command line executable.
+#
+# SIP_INCLUDE_DIR - Directory holding the SIP C++ header file.
+#
+# SIP_DEFAULT_SIP_DIR - Default directory where .sip files should be installed
+#     into.
+
+# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+
+IF(SIP_VERSION)
+  # Already in cache, be silent
+  SET(SIP_FOUND TRUE)
+ELSE(SIP_VERSION)
+
+  FIND_FILE(_find_sip_py FindSIP.py PATHS ${CMAKE_MODULE_PATH})
+
+  EXECUTE_PROCESS(COMMAND ${PYTHON_EXECUTABLE} ${_find_sip_py} OUTPUT_VARIABLE sip_config)
+  IF(sip_config)
+    STRING(REGEX REPLACE "^sip_version:([^\n]+).*$" "\\1" SIP_VERSION ${sip_config})
+    STRING(REGEX REPLACE ".*\nsip_version_str:([^\n]+).*$" "\\1" SIP_VERSION_STR ${sip_config})
+    STRING(REGEX REPLACE ".*\nsip_bin:([^\n]+).*$" "\\1" SIP_EXECUTABLE ${sip_config})
+    IF(NOT SIP_DEFAULT_SIP_DIR)
+        STRING(REGEX REPLACE ".*\ndefault_sip_dir:([^\n]+).*$" "\\1" SIP_DEFAULT_SIP_DIR ${sip_config})
+    ENDIF(NOT SIP_DEFAULT_SIP_DIR)
+    STRING(REGEX REPLACE ".*\nsip_inc_dir:([^\n]+).*$" "\\1" SIP_INCLUDE_DIR ${sip_config})
+    FILE(TO_CMAKE_PATH ${SIP_DEFAULT_SIP_DIR} SIP_DEFAULT_SIP_DIR)
+    FILE(TO_CMAKE_PATH ${SIP_INCLUDE_DIR} SIP_INCLUDE_DIR)
+    IF(EXISTS ${SIP_EXECUTABLE})
+      SET(SIP_FOUND TRUE)
+    ELSE()
+      MESSAGE(STATUS "Found SIP configuration but the sip executable could not be found.")
+    ENDIF()
+  ENDIF(sip_config)
+
+  IF(SIP_FOUND)
+    IF(NOT SIP_FIND_QUIETLY)
+      MESSAGE(STATUS "Found SIP version: ${SIP_VERSION_STR}")
+    ENDIF(NOT SIP_FIND_QUIETLY)
+  ELSE(SIP_FOUND)
+    IF(SIP_FIND_REQUIRED)
+      MESSAGE(FATAL_ERROR "Could not find SIP")
+    ENDIF(SIP_FIND_REQUIRED)
+  ENDIF(SIP_FOUND)
+
+ENDIF(SIP_VERSION)
+
diff --git a/cmake/FindSIP.py b/cmake/FindSIP.py
new file mode 100644 (file)
index 0000000..5e35d9f
--- /dev/null
@@ -0,0 +1,16 @@
+# FindSIP.py
+#
+# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+import sys
+import sipconfig
+
+sipcfg = sipconfig.Configuration()
+print("sip_version:%06.0x" % sipcfg.sip_version)
+print("sip_version_str:%s" % sipcfg.sip_version_str)
+print("sip_bin:%s" % sipcfg.sip_bin)
+print("default_sip_dir:%s" % sipcfg.default_sip_dir)
+print("sip_inc_dir:%s" % sipcfg.sip_inc_dir)
+
diff --git a/cmake/PythonCompile.py b/cmake/PythonCompile.py
new file mode 100644 (file)
index 0000000..e7cc17e
--- /dev/null
@@ -0,0 +1,5 @@
+# By Simon Edwards <simon@simonzone.com>
+# This file is in the public domain.
+import py_compile, sys
+sys.exit(py_compile.main())
+
diff --git a/cmake/PythonMacros.cmake b/cmake/PythonMacros.cmake
new file mode 100644 (file)
index 0000000..3a40095
--- /dev/null
@@ -0,0 +1,83 @@
+# Python macros
+# ~~~~~~~~~~~~~
+# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
+# Copyright (c) 2012, Luca Beltrame <lbeltrame@kde.org>
+# Copyright (c) 2012, Rolf Eike Beer <eike@sf-mail.de>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+# This file defines the following macros:
+#
+# PYTHON_INSTALL (SOURCE_FILE DESTINATION_DIR)
+#     Install the SOURCE_FILE, which is a Python .py file, into the
+#     destination directory during install. The file will be byte compiled
+#     and both the .py file and .pyc file will be installed.
+
+set(PYTHON_MACROS_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
+
+macro(PYTHON_INSTALL SOURCE_FILE DESTINATION_DIR)
+
+  find_file(_python_compile_py PythonCompile.py PATHS ${CMAKE_MODULE_PATH})
+
+  # Install the source file.
+  install(FILES ${SOURCE_FILE} DESTINATION ${DESTINATION_DIR})
+
+  # Byte compile and install the .pyc file, unless explicitly prevented by env..
+  if("$ENV{PYTHONDONTWRITEBYTECODE}" STREQUAL "")
+    get_filename_component(_absfilename ${SOURCE_FILE} ABSOLUTE)
+    get_filename_component(_filename ${SOURCE_FILE} NAME)
+    get_filename_component(_filenamebase ${SOURCE_FILE} NAME_WE)
+    get_filename_component(_basepath ${SOURCE_FILE} PATH)
+
+    if(WIN32)
+      # remove drive letter
+      string(REGEX REPLACE "^[a-zA-Z]:/" "/" _basepath "${_basepath}")
+    endif(WIN32)
+
+    set(_bin_py ${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/${_filename})
+
+    # Python 3.2 changed the pyc file location
+    if(PYTHON_VERSION_STRING VERSION_GREATER 3.1)
+      # To get the right version for suffix
+      set(_bin_pyc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/__pycache__/${_filenamebase}.cpython-${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}.pyc")
+      set(_py_install_dir "${DESTINATION_DIR}/__pycache__/")
+    else()
+      set(_bin_pyc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/${_filenamebase}.pyc")
+      set(_py_install_dir "${DESTINATION_DIR}")
+    endif()
+
+    file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${_basepath})
+
+    # Setting because it will be displayed later, in compile_python_files
+    set(_message "Byte-compiling ${_bin_py} to ${_bin_pyc}")
+
+    string(REPLACE "/" "_" _rule_name "${_basepath}/${_bin_pyc}")
+    add_custom_target("${_rule_name}" ALL)
+
+    get_filename_component(_abs_bin_py ${_bin_py} ABSOLUTE)
+    if(_abs_bin_py STREQUAL _absfilename)    # Don't copy the file onto itself.
+      add_custom_command(
+        TARGET "${_rule_name}"
+        COMMAND "${CMAKE_COMMAND}" -E echo "${_message}"
+        COMMAND "${PYTHON_EXECUTABLE}" "${_python_compile_py}" "${_bin_py}"
+        DEPENDS "${_absfilename}"
+      )
+    else()
+      add_custom_command(
+        TARGET "${_rule_name}"
+        COMMAND "${CMAKE_COMMAND}" -E echo "${_message}"
+        COMMAND "${CMAKE_COMMAND}" -E copy "${_absfilename}" "${_bin_py}"
+        COMMAND "${PYTHON_EXECUTABLE}" "${_python_compile_py}" "${_bin_py}"
+        DEPENDS "${_absfilename}"
+      )
+    endif()
+
+    install(FILES ${_bin_pyc} DESTINATION "${_py_install_dir}")
+    unset(_py_install_dir)
+    unset(_message)
+
+  endif("$ENV{PYTHONDONTWRITEBYTECODE}" STREQUAL "")
+
+endmacro(PYTHON_INSTALL)
+
diff --git a/cmake/SIPMacros.cmake b/cmake/SIPMacros.cmake
new file mode 100644 (file)
index 0000000..a3ba6a6
--- /dev/null
@@ -0,0 +1,125 @@
+# Macros for SIP
+# ~~~~~~~~~~~~~~
+# Copyright (c) 2007, Simon Edwards <simon@simonzone.com>
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+#
+# SIP website: http://www.riverbankcomputing.co.uk/sip/index.php
+#
+# This file defines the following macros:
+#
+# ADD_SIP_PYTHON_MODULE (MODULE_NAME MODULE_SIP [library1, libaray2, ...])
+#     Specifies a SIP file to be built into a Python module and installed.
+#     MODULE_NAME is the name of Python module including any path name. (e.g.
+#     os.sys, Foo.bar etc). MODULE_SIP the path and filename of the .sip file
+#     to process and compile. libraryN are libraries that the Python module,
+#     which is typically a shared library, should be linked to. The built
+#     module will also be install into Python's site-packages directory.
+#
+# The behaviour of the ADD_SIP_PYTHON_MODULE macro can be controlled by a
+# number of variables:
+#
+# SIP_INCLUDES - List of directories which SIP will scan through when looking
+#     for included .sip files. (Corresponds to the -I option for SIP.)
+#
+# SIP_TAGS - List of tags to define when running SIP. (Corresponds to the -t
+#     option for SIP.)
+#
+# SIP_CONCAT_PARTS - An integer which defines the number of parts the C++ code
+#     of each module should be split into. Defaults to 8. (Corresponds to the
+#     -j option for SIP.)
+#
+# SIP_DISABLE_FEATURES - List of feature names which should be disabled
+#     running SIP. (Corresponds to the -x option for SIP.)
+#
+# SIP_EXTRA_OPTIONS - Extra command line options which should be passed on to
+#     SIP.
+
+SET(SIP_INCLUDES)
+SET(SIP_TAGS)
+SET(SIP_CONCAT_PARTS 8)
+SET(SIP_DISABLE_FEATURES)
+SET(SIP_EXTRA_OPTIONS)
+
+MACRO(ADD_SIP_PYTHON_MODULE MODULE_NAME MODULE_SIP)
+
+    SET(EXTRA_LINK_LIBRARIES ${ARGN})
+
+    STRING(REPLACE "." "/" _x ${MODULE_NAME})
+    GET_FILENAME_COMPONENT(_parent_module_path ${_x}  PATH)
+    GET_FILENAME_COMPONENT(_child_module_name ${_x} NAME)
+
+    GET_FILENAME_COMPONENT(_module_path ${MODULE_SIP} PATH)
+
+    if(_module_path STREQUAL "")
+        set(CMAKE_CURRENT_SIP_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
+    else(_module_path STREQUAL "")
+        set(CMAKE_CURRENT_SIP_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_module_path}")
+    endif(_module_path STREQUAL "")
+
+    GET_FILENAME_COMPONENT(_abs_module_sip ${MODULE_SIP} ABSOLUTE)
+
+    # We give this target a long logical target name.
+    # (This is to avoid having the library name clash with any already
+    # install library names. If that happens then cmake dependancy
+    # tracking get confused.)
+    STRING(REPLACE "." "_" _logical_name ${MODULE_NAME})
+    SET(_logical_name "python_module_${_logical_name}")
+
+    FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_SIP_OUTPUT_DIR})    # Output goes in this dir.
+
+    SET(_sip_includes)
+    FOREACH (_inc ${SIP_INCLUDES})
+        GET_FILENAME_COMPONENT(_abs_inc ${_inc} ABSOLUTE)
+        LIST(APPEND _sip_includes -I ${_abs_inc})
+    ENDFOREACH (_inc )
+
+    SET(_sip_tags)
+    FOREACH (_tag ${SIP_TAGS})
+        LIST(APPEND _sip_tags -t ${_tag})
+    ENDFOREACH (_tag)
+
+    SET(_sip_x)
+    FOREACH (_x ${SIP_DISABLE_FEATURES})
+        LIST(APPEND _sip_x -x ${_x})
+    ENDFOREACH (_x ${SIP_DISABLE_FEATURES})
+
+    SET(_message "-DMESSAGE=Generating CPP code for module ${MODULE_NAME}")
+    SET(_sip_output_files)
+    FOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} )
+        IF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} )
+            SET(_sip_output_files ${_sip_output_files} ${CMAKE_CURRENT_SIP_OUTPUT_DIR}/sip${_child_module_name}part${CONCAT_NUM}.cpp )
+        ENDIF( ${CONCAT_NUM} LESS ${SIP_CONCAT_PARTS} )
+    ENDFOREACH(CONCAT_NUM RANGE 0 ${SIP_CONCAT_PARTS} )
+
+    IF(NOT WIN32)
+        SET(TOUCH_COMMAND touch)
+    ELSE(NOT WIN32)
+        SET(TOUCH_COMMAND echo)
+        # instead of a touch command, give out the name and append to the files
+        # this is basically what the touch command does.
+        FOREACH(filename ${_sip_output_files})
+            FILE(APPEND filename "")
+        ENDFOREACH(filename ${_sip_output_files})
+    ENDIF(NOT WIN32)
+    ADD_CUSTOM_COMMAND(
+        OUTPUT ${_sip_output_files}
+        COMMAND ${CMAKE_COMMAND} -E echo ${message}
+        COMMAND ${TOUCH_COMMAND} ${_sip_output_files}
+        COMMAND ${SIP_EXECUTABLE} ${_sip_tags} ${_sip_x} ${SIP_EXTRA_OPTIONS} -j ${SIP_CONCAT_PARTS} -c ${CMAKE_CURRENT_SIP_OUTPUT_DIR} ${_sip_includes} ${_abs_module_sip}
+        DEPENDS ${_abs_module_sip} ${SIP_EXTRA_FILES_DEPEND}
+    )
+    # not sure if type MODULE could be uses anywhere, limit to cygwin for now
+    IF (CYGWIN)
+        ADD_LIBRARY(${_logical_name} MODULE ${_sip_output_files} )
+    ELSE (CYGWIN)
+        ADD_LIBRARY(${_logical_name} SHARED ${_sip_output_files} )
+    ENDIF (CYGWIN)
+    TARGET_LINK_LIBRARIES(${_logical_name} ${PYTHON_LIBRARY})
+    TARGET_LINK_LIBRARIES(${_logical_name} ${EXTRA_LINK_LIBRARIES})
+    SET_TARGET_PROPERTIES(${_logical_name} PROPERTIES PREFIX "" OUTPUT_NAME ${_child_module_name})
+
+    INSTALL(TARGETS ${_logical_name} DESTINATION "${PYTHON_SITE_PACKAGES_INSTALL_DIR}/${_parent_module_path}")
+
+ENDMACRO(ADD_SIP_PYTHON_MODULE)
+
index a66a6897d0e0876f1dfa5b5190edd5f7c8283624..ce214fc4a38e6eac583e519366889f1e7536866b 100644 (file)
@@ -71,3 +71,7 @@ add_subdirectory(programs)
 if (NOT GMX_FAHCORE)
     add_subdirectory(contrib)
 endif()
+
+if (GMX_PYTHON_BINDINGS)
+    add_subdirectory(python)
+endif()
index 8553342b4c8f0b22a0bef92de628d33975ae70b4..d91b0daa3ca53926c5d72a2173c07164a2ef53f5 100644 (file)
@@ -388,6 +388,11 @@ class TrajectoryAnalysisModule
          */
         virtual void writeOutput() = 0;
 
+        typedef std::vector<TrajectoryAnalysisModule*> Batch;
+        virtual const Batch getBatch() { return Batch(); }
+
+        virtual const std::vector<char*> getArgv(int) { return std::vector<char*>(); }
+
         /*! \brief
          * Returns the name of the analysis module.
          *
index 056d3ac5ef858ea810dbebc759cc0d573b9f48cd..6a8ebfef9d4aab29d649babe48e225f999a72290 100644 (file)
@@ -81,7 +81,7 @@ class TrajectoryAnalysisCommandLineRunner::Impl
         void parseOptions(TrajectoryAnalysisSettings *settings,
                           TrajectoryAnalysisRunnerCommon *common,
                           SelectionCollection *selections,
-                          int *argc, char *argv[]);
+                          int *argc, char *argv[], bool full=true);
 
         TrajectoryAnalysisModule *module_;
         bool                      bUseDefaultGroups_;
@@ -106,7 +106,7 @@ TrajectoryAnalysisCommandLineRunner::Impl::parseOptions(
         TrajectoryAnalysisSettings *settings,
         TrajectoryAnalysisRunnerCommon *common,
         SelectionCollection *selections,
-        int *argc, char *argv[])
+        int *argc, char *argv[], bool full)
 {
     FileNameOptionManager  fileoptManager;
     SelectionOptionManager seloptManager(selections);
@@ -114,11 +114,15 @@ TrajectoryAnalysisCommandLineRunner::Impl::parseOptions(
 
     options.addManager(&fileoptManager);
     options.addManager(&seloptManager);
-    IOptionsContainer &commonOptions = options.addGroup();
+    if (full) {
+           IOptionsContainer &commonOptions = options.addGroup();
+    }
     IOptionsContainer &moduleOptions = options.addGroup();
 
     module_->initOptions(&moduleOptions, settings);
-    common->initOptions(&commonOptions);
+    if (full) {
+           common->initOptions(&commonOptions);
+    }
     selections->initOptions(&commonOptions);
 
     {
@@ -130,16 +134,19 @@ TrajectoryAnalysisCommandLineRunner::Impl::parseOptions(
         options.finish();
     }
 
-    common->optionsFinished();
+    if (full) {
+           common->optionsFinished();
+    }
     module_->optionsFinished(settings);
 
     common->initIndexGroups(selections, bUseDefaultGroups_);
 
     const bool bInteractive = StandardInputStream::instance().isInteractive();
     seloptManager.parseRequestedFromStdin(bInteractive);
-    common->doneIndexGroups(selections);
 
+    common->doneIndexGroups(selections);
     common->initTopology(selections);
+
     selections->compile();
 }
 
@@ -190,6 +197,20 @@ TrajectoryAnalysisCommandLineRunner::run(int argc, char *argv[])
     const TopologyInformation &topology = common.topologyInformation();
     module->initAnalysis(settings, topology);
 
+    TrajectoryAnalysisModule::Batch batch = module->getBatch();
+    std::vector<SelectionCollection*> batchSelections;
+    std::vector<Impl*> impls;
+    for (size_t i = 0; i < batch.size(); i++) {
+        TrajectoryAnalysisModule *bmodule = batch[i];
+        batchSelections.push_back(new SelectionCollection());
+        impls.push_back(new Impl(bmodule));
+        std::vector<char*> modArgv = module->getArgv(i);
+        int modArgc = modArgv.size();
+        impls.back()->parseOptions(&settings, &common, batchSelections.back(), &modArgc, modArgv.data(), false);
+
+        batch[i]->initAnalysis(settings, topology);
+    }
+
     // Load first frame.
     common.initFirstFrame();
     module->initAfterFirstFrame(settings, common.frame());
@@ -201,6 +222,17 @@ TrajectoryAnalysisCommandLineRunner::run(int argc, char *argv[])
     AnalysisDataParallelOptions         dataOptions;
     TrajectoryAnalysisModuleDataPointer pdata(
             module->startFrames(dataOptions, selections));
+
+    std::vector<AnalysisDataParallelOptions> batchOptions;
+    std::vector<TrajectoryAnalysisModuleDataPointer> batchDataPointers;
+    for (size_t i = 0; i < batch.size(); i++) {
+        batch[i]->initAfterFirstFrame(settings, common.frame());
+
+        batchOptions.push_back(AnalysisDataParallelOptions());
+        batchDataPointers.push_back(batch[i]->startFrames(
+            batchOptions.back(), *batchSelections[i]));
+    }
+
     do
     {
         common.initFrame();
@@ -210,6 +242,11 @@ TrajectoryAnalysisCommandLineRunner::run(int argc, char *argv[])
             set_pbc(ppbc, topology.ePBC(), frame.box);
         }
 
+        for (size_t i = 0; i < batch.size(); i++) {
+            batchSelections[i]->evaluate(&frame, ppbc);
+            batch[i]->analyzeFrame(nframes, frame, ppbc, batchDataPointers[i].get());
+            batch[i]->finishFrameSerial(nframes);
+        }
         selections.evaluate(&frame, ppbc);
         module->analyzeFrame(nframes, frame, ppbc, pdata.get());
         module->finishFrameSerial(nframes);
@@ -217,6 +254,14 @@ TrajectoryAnalysisCommandLineRunner::run(int argc, char *argv[])
         ++nframes;
     }
     while (common.readNextFrame());
+    for (size_t i = 0; i < batch.size(); i++) {
+        batch[i]->finishFrames(batchDataPointers[i].get());
+        if (batchDataPointers[i].get() != NULL) {
+            batchDataPointers[i]->finish();
+        }
+        batchDataPointers[i].reset();
+    }
+
     module->finishFrames(pdata.get());
     if (pdata.get() != NULL)
     {
@@ -235,6 +280,15 @@ TrajectoryAnalysisCommandLineRunner::run(int argc, char *argv[])
     }
 
     // Restore the maximal groups for dynamic selections.
+    for (size_t i = 0; i < batch.size(); i++) {
+        batchSelections[i]->evaluateFinal(nframes);
+        batch[i]->finishAnalysis(nframes);
+        batch[i]->writeOutput();
+
+        delete batchSelections[i];
+        delete impls[i];
+    }
+
     selections.evaluateFinal(nframes);
 
     module->finishAnalysis(nframes);
@@ -292,7 +346,16 @@ class TrajectoryAnalysisCommandLineRunner::Impl::RunnerCommandLineModule
          */
         RunnerCommandLineModule(const char *name, const char *description,
                                 ModuleFactoryMethod factory)
-            : name_(name), description_(description), factory_(factory)
+            : name_(name), description_(description), hasFunction_(true), factory_(factory), functor_(NULL)
+        {
+        }
+
+        /*! \brief
+         * Overloaded constructor accepting a functor instead of function pointer.
+         */
+        RunnerCommandLineModule(const char *name, const char *description,
+                                ModuleFactoryFunctor *factory)
+            : name_(name), description_(description), hasFunction_(false), factory_(NULL), functor_(factory)
         {
         }
 
@@ -304,9 +367,11 @@ class TrajectoryAnalysisCommandLineRunner::Impl::RunnerCommandLineModule
         virtual void writeHelp(const CommandLineHelpContext &context) const;
 
     private:
-        const char             *name_;
-        const char             *description_;
-        ModuleFactoryMethod     factory_;
+        const char            *name_;
+        const char            *description_;
+        bool                   hasFunction_;
+        ModuleFactoryMethod    factory_;
+        ModuleFactoryFunctor   *functor_;
 
         GMX_DISALLOW_COPY_AND_ASSIGN(RunnerCommandLineModule);
 };
@@ -319,7 +384,7 @@ void TrajectoryAnalysisCommandLineRunner::Impl::RunnerCommandLineModule::init(
 int TrajectoryAnalysisCommandLineRunner::Impl::RunnerCommandLineModule::run(
         int argc, char *argv[])
 {
-    TrajectoryAnalysisModulePointer     module(factory_());
+    TrajectoryAnalysisModulePointer     module(hasFunction_? factory_() : (*functor_)());
     TrajectoryAnalysisCommandLineRunner runner(module.get());
     return runner.run(argc, argv);
 }
@@ -327,7 +392,7 @@ int TrajectoryAnalysisCommandLineRunner::Impl::RunnerCommandLineModule::run(
 void TrajectoryAnalysisCommandLineRunner::Impl::RunnerCommandLineModule::writeHelp(
         const CommandLineHelpContext &context) const
 {
-    TrajectoryAnalysisModulePointer     module(factory_());
+    TrajectoryAnalysisModulePointer     module(hasFunction_? factory_() : (*functor_)());
     TrajectoryAnalysisCommandLineRunner runner(module.get());
     runner.writeHelp(context);
 }
@@ -341,6 +406,15 @@ TrajectoryAnalysisCommandLineRunner::runAsMain(
     return CommandLineModuleManager::runAsMainSingleModule(argc, argv, &module);
 }
 
+// static
+int
+TrajectoryAnalysisCommandLineRunner::runAsMain(
+        int argc, char *argv[], ModuleFactoryFunctor *factory)
+{
+    Impl::RunnerCommandLineModule module(NULL, NULL, factory);
+    return CommandLineModuleManager::runAsMainSingleModule(argc, argv, &module);
+}
+
 // static
 void
 TrajectoryAnalysisCommandLineRunner::registerModule(
index c99a0a80f076c78a99c99332085acf03439bd6bc..9bcc013418d1ee58b9f30c31d73e5820388bf2ab 100644 (file)
@@ -77,6 +77,25 @@ class TrajectoryAnalysisCommandLineRunner
          */
         typedef TrajectoryAnalysisModulePointer (*ModuleFactoryMethod)();
 
+        /*! \brief
+         * Factory functor class for creating a trajectory analysis module.
+         *
+         * Old compilers that still must be supported do not have std::function,
+         * so we have to implement runAsMain overload accepting a functor instead
+         * of a function pointer.
+         *
+         * This abstract class should be subclassed to be used. The main usage is for
+         * python bindings.
+         */
+        class ModuleFactoryFunctor {
+            public:
+                /*! \brief
+                 * operator() that returns a pointer to valid TrajectoryAnalysisModule
+                 */
+                virtual TrajectoryAnalysisModulePointer operator() () = 0;
+                virtual ~ModuleFactoryFunctor() {};
+        };
+
         /*! \brief
          * Implements a main() method that runs a given module.
          *
@@ -187,6 +206,12 @@ class TrajectoryAnalysisCommandLineRunner
          */
         void writeHelp(const CommandLineHelpContext &context);
 
+        //! Implements the template runAsMain() method.
+        static int runAsMain(int argc, char *argv[],
+                             ModuleFactoryMethod factory);
+        //! Overload of runAsMain accepting functor.
+        static int runAsMain(int argc, char *argv[],
+                             ModuleFactoryFunctor *factory);
     private:
         /*! \brief
          * Creates a trajectory analysis module of a given type.
@@ -199,9 +224,6 @@ class TrajectoryAnalysisCommandLineRunner
             return TrajectoryAnalysisModulePointer(new ModuleType());
         }
 
-        //! Implements the template runAsMain() method.
-        static int runAsMain(int argc, char *argv[],
-                             ModuleFactoryMethod factory);
 
         class Impl;
 
index 4483a2949d913e5a3712018764ed60be31b3c851..3543018b925b7f763698820b7c2f8fe9786924e7 100644 (file)
@@ -293,16 +293,9 @@ TrajectoryAnalysisRunnerCommon::doneIndexGroups(SelectionCollection *selections)
     }
 }
 
-
 void
 TrajectoryAnalysisRunnerCommon::initTopology(SelectionCollection *selections)
 {
-    // Return immediately if the topology has already been loaded.
-    if (impl_->topInfo_.hasTopology())
-    {
-        return;
-    }
-
     const TrajectoryAnalysisSettings &settings = impl_->settings_;
     const bool bRequireTop
         = settings.hasFlag(TrajectoryAnalysisSettings::efRequireTop)
@@ -313,7 +306,7 @@ TrajectoryAnalysisRunnerCommon::initTopology(SelectionCollection *selections)
     }
 
     // Load the topology if requested.
-    if (!impl_->topfile_.empty())
+    if (!impl_->topfile_.empty() && !impl_->topInfo_.hasTopology())
     {
         char  title[STRLEN];
 
diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt
new file mode 100644 (file)
index 0000000..d2f779e
--- /dev/null
@@ -0,0 +1,84 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2014, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and 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.
+#
+
+find_package(PythonLibrary REQUIRED)
+find_package(NumPy REQUIRED)
+find_package(SIP REQUIRED)
+
+include(SIPMacros)
+include(PythonMacros)
+
+include_directories(
+    ${PYTHON_INCLUDE_PATH}
+    ${SIP_INCLUDE_DIR}
+    ${GROMACS_INCLUDE_DIRS}
+    ${CMAKE_SOURCE_DIR}/src/python/include
+    ${NUMPY_INCLUDE_DIRS}
+)
+
+add_definitions(-DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION)
+
+set(SIP_INCLUDES ${CMAKE_BINARY_DIR} sip)
+set(SIP_EXTRA_OPTIONS ${SIP_EXTRA_OPTIONS} -e -o)
+
+file(GLOB common_files_sip sip/*.sip)
+
+file(GLOB options_files_sip sip/options/*.sip)
+set(SIP_EXTRA_FILES_DEPEND ${options_files_sip} ${common_files_sip})
+add_sip_python_module(gromacs.Options sip/options/Options.sip libgromacs)
+
+file(GLOB topology_files_sip sip/topology/*.sip)
+set(SIP_EXTRA_FILES_DEPEND ${topology_files_sip} ${common_files_sip})
+add_sip_python_module(gromacs.Topology
+    sip/topology/Topology.sip libgromacs)
+
+# This is needed for NumPy, which does not like code in many files
+set(SIP_CONCAT_PARTS 1)
+
+file(GLOB selection_files_sip sip/selection/*.sip)
+set(SIP_EXTRA_FILES_DEPEND ${selection_files_sip} ${common_files_sip})
+add_sip_python_module(gromacs.Selection
+    sip/selection/Selection.sip libgromacs)
+
+file(GLOB trajectoryanalysis_files_sip sip/trajectoryanalysis/*.sip)
+set(SIP_EXTRA_FILES_DEPEND ${trajectoryanalysis_files_sip} ${common_files_sip})
+add_sip_python_module(gromacs.TrajectoryAnalysis
+    sip/trajectoryanalysis/TrajectoryAnalysis.sip libgromacs)
+
+python_install(__init__.py ${PYTHON_SITE_PACKAGES_INSTALL_DIR}/gromacs)
+
+install(DIRECTORY runner DESTINATION ${PYTHON_SITE_PACKAGES_INSTALL_DIR}/gromacs)
+python_install(runner/__init__.py ${PYTHON_SITE_PACKAGES_INSTALL_DIR}/gromacs)
+python_install(runner/pipeline.py ${PYTHON_SITE_PACKAGES_INSTALL_DIR}/gromacs)
diff --git a/src/python/__init__.py b/src/python/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/python/include/numpy_conv.h b/src/python/include/numpy_conv.h
new file mode 100644 (file)
index 0000000..b810832
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 NUMPY_CONV_H
+#define NUMPY_CONV_H
+
+#include <Python.h>
+#include <numpy/ndarrayobject.h>
+
+PyObject* array2dToNumpy(int dim1, int dim2, const void *data) {
+    npy_intp dims[] = {dim1, dim2};
+    #ifdef GMX_DOUBLE
+        return PyArray_SimpleNewFromData(2, dims, NPY_DOUBLE, (double*) data);
+    #else
+        return PyArray_SimpleNewFromData(2, dims, NPY_FLOAT, (float*) data);
+    #endif
+}
+
+PyObject* array1dToNumpy(int dim, const void *data) {
+    npy_intp n_dim = dim;
+    #ifdef GMX_DOUBLE
+        return PyArray_SimpleNewFromData(1, &n_dim, NPY_DOUBLE, (double*) data);
+    #else
+        return PyArray_SimpleNewFromData(1, &n_dim, NPY_FLOAT, (float*) data);
+    #endif
+}
+
+PyObject* iarray1dToNumpy(int dim, const int *data) {
+    npy_intp n_dim = dim;
+    return PyArray_SimpleNewFromData(1, &n_dim, NPY_INT, (int*) data);
+}
+#endif
diff --git a/src/python/pipeline_test.py b/src/python/pipeline_test.py
new file mode 100644 (file)
index 0000000..8e21244
--- /dev/null
@@ -0,0 +1,40 @@
+
+from gromacs import TrajectoryAnalysis
+from runner.pipeline import GromacsPipeline, runPipeline
+
+class Test(TrajectoryAnalysis.TrajectoryAnalysisModule):
+
+    def __init__(self):
+        super(Test, self).__init__("test", "test")
+
+    def initOptions(self, options, settings):
+        settings.setHelpText(self.description())
+
+    def getBatch(self):
+        return self.modules
+
+    def getArgv(self, i):
+        return self.options[i]
+
+    def initAnalysis(self, settings, top):
+        pass
+
+    def analyzeFrame(self, frnr, frame, pbc, data):
+        print("Analyzing frame in Test module")
+
+    def finishAnalysis(self, nframes):
+        pass
+
+    def writeOutput(self):
+        pass
+
+modules = [
+    ("Angle", "-group1 System -oav angles.xvg"),
+    (Test(), ""),
+    (TrajectoryAnalysis.SasaInfo.create(), "-surface DNA"),
+]
+
+pipeline = runPipeline(name="Pipeline", modules=modules, keep_datasets=True)
+dataset = pipeline.modules[0].datasetFromIndex(1)
+for i in range(dataset.frameCount()):
+    print('frame =', i, ', columnCount =', dataset.columnCount(), ', y =', dataset.getDataFrame(i).y(0))
diff --git a/src/python/runner/__init__.py b/src/python/runner/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/python/runner/pipeline.py b/src/python/runner/pipeline.py
new file mode 100644 (file)
index 0000000..2ea912d
--- /dev/null
@@ -0,0 +1,68 @@
+
+from gromacs import Options, TrajectoryAnalysis
+import sys, shlex
+
+class GromacsPipeline(TrajectoryAnalysis.TrajectoryAnalysisModule):
+
+    def __init__(self,
+        name="PythonPipeline",
+        description="Pipeline of modules created with Python",
+        modules=[],
+        keep_datasets=False,
+    ):
+        super(GromacsPipeline, self).__init__(name, description)
+
+        self.optionsHolder = Options.PyOptionsHolder()
+
+        self.modules = []
+        self.options = []
+
+        for module, options in modules:
+            if not isinstance(module, TrajectoryAnalysis.TrajectoryAnalysisModule):
+                info_name = module + "Info"
+                if not hasattr(TrajectoryAnalysis, info_name):
+                    raise ValueError("There is no module named {}".format(name))
+
+                module = getattr(TrajectoryAnalysis, info_name).create()
+
+            options_list = [name] + shlex.split(options)
+
+            if keep_datasets:
+                for i in range(module.datasetCount()):
+                    module.datasetFromIndex(i).requestStorage(-1)
+
+            self.modules.append(module)
+            self.options.append(options_list)
+
+    def initOptions(self, options, settings):
+        settings.setHelpText(self.description())
+
+    def getBatch(self):
+        return self.modules
+
+    def getArgv(self, i):
+        return self.options[i]
+
+    def initAnalysis(self, settings, top):
+        pass
+
+    def analyzeFrame(self, frnr, frame, pbc, data):
+        pass
+
+    def finishAnalysis(self, nframes):
+        pass
+
+    def writeOutput(self):
+        pass
+
+    def run(self, argv):
+        if argv is None:
+            argv = sys.argv
+
+        TrajectoryAnalysis.runAsMain(self, argv)
+
+def runPipeline(argv=None, *args, **kwargs):
+    pipeline = GromacsPipeline(*args, **kwargs)
+    pipeline.run(argv)
+
+    return pipeline
diff --git a/src/python/sip/definitions.sip b/src/python/sip/definitions.sip
new file mode 100644 (file)
index 0000000..e06e1da
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%Exception std::out_of_range(SIP_IndexError) {
+
+%TypeHeaderCode
+#include <stdexcept>
+%End
+
+%RaiseCode
+    SIP_BLOCK_THREADS
+    PyErr_SetString(PyExc_IndexError, sipExceptionRef.what());
+    SIP_UNBLOCK_THREADS
+%End
+};
diff --git a/src/python/sip/options/Options.sip b/src/python/sip/options/Options.sip
new file mode 100644 (file)
index 0000000..348af77
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%Module gromacs.Options
+
+%DefaultEncoding "UTF-8"
+
+%Import selection/Selection.sip
+
+%Include options.sip
+%Include abstractoption.sip
+%Include pyoptionsholder.sip
+
+// This has to be here, instead of 'gromacs.Selection', because otherwise we'll get circular dependencies between sip modules
+%Include selectionoption.sip
+%Include basicoptions.sip
+%Include filenameoption.sip
diff --git a/src/python/sip/options/abstractoption.sip b/src/python/sip/options/abstractoption.sip
new file mode 100644 (file)
index 0000000..df74dfc
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+class AbstractOption /NoDefaultCtors/ {
+%TypeHeaderCode
+#include <gromacs/options/abstractoption.h>
+using gmx::AbstractOption;
+%End
+};
+
+template<T, U> class OptionTemplate : AbstractOption /NoDefaultCtors/ {
+%TypeHeaderCode
+#include <gromacs/options/abstractoption.h>
+using namespace gmx;
+%End
+public:
+    U& description(const char * /KeepReference/);
+    U& hidden(bool = true);
+    U& required(bool = true);
+    U& allowMultiple(bool = true);
+    // FIXME
+    // These function do not work, because they store pointer to argument, which then is garbage collected in python.
+    // Different combinations of Factory, KeepReference and Transfer annotations do not help.
+    // Use third argument of PyOptionsHolder's methods instead.
+    U& defaultValue(const T&);
+    U& defaultValueIfSet(const T&);
+};
diff --git a/src/python/sip/options/basicoptions.sip b/src/python/sip/options/basicoptions.sip
new file mode 100644 (file)
index 0000000..d69697b
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%ModuleHeaderCode
+typedef gmx::OptionTemplate<double, gmx::DoubleOption> DoubleOptionTemplate;
+typedef gmx::OptionTemplate<int, gmx::IntegerOption> IntegerOptionTemplate;
+typedef gmx::OptionTemplate<std::string, gmx::StringOption> StringOptionTemplate;
+typedef gmx::OptionTemplate<bool, gmx::BooleanOption> BooleanOptionTemplate;
+%End
+
+class std::string;
+typedef OptionTemplate<double, DoubleOption> DoubleOptionTemplate;
+typedef OptionTemplate<int, IntegerOption> IntegerOptionTemplate;
+typedef OptionTemplate<std::string, StringOption> StringOptionTemplate;
+typedef OptionTemplate<bool, BooleanOption> BooleanOptionTemplate;
+
+class DoubleOption : DoubleOptionTemplate /NoDefaultCtors/ {
+%TypeHeaderCode
+#include "gromacs/options/basicoptions.h"
+using gmx::DoubleOption;
+%End
+};
+class IntegerOption : IntegerOptionTemplate /NoDefaultCtors/ {
+%TypeHeaderCode
+#include "gromacs/options/basicoptions.h"
+using gmx::IntegerOption;
+%End
+};
+class StringOption : StringOptionTemplate /NoDefaultCtors/ {
+%TypeHeaderCode
+#include "gromacs/options/basicoptions.h"
+using gmx::StringOption;
+%End
+public:
+    StringOption& defaultValue(const char *);
+    %MethodCode
+        sipRes = &sipCpp->defaultValue(std::string(a0));
+    %End
+};
+class BooleanOption : BooleanOptionTemplate /NoDefaultCtors/ {
+%TypeHeaderCode
+#include "gromacs/options/basicoptions.h"
+using gmx::BooleanOption;
+%End
+};
diff --git a/src/python/sip/options/filenameoption.sip b/src/python/sip/options/filenameoption.sip
new file mode 100644 (file)
index 0000000..c3a76ab
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%ModuleHeaderCode
+#include "gromacs/options/filenameoption.h"
+#include "gromacs/fileio/filenm.h"
+typedef gmx::OptionTemplate<std::string, gmx::FileNameOption> FileNameOptionTemplate;
+using namespace gmx; // needed for compilation of enum
+%End
+
+typedef OptionTemplate<std::string, FileNameOption> FileNameOptionTemplate;
+
+enum OptionFileType {
+    eftUnknown, eftTopology, eftTrajectory, eftPDB,
+    eftIndex, eftPlot, eftGenericData, eftOptionFileType_NR
+};
+
+enum {
+    efMDP,
+    efTRX, efTRO, efTRN, efTRR, efCOMPRESSED, efXTC, efTNG,
+    efEDR,
+    efSTX, efSTO, efGRO, efG96, efPDB, efBRK, efENT, efESP, efPQR,
+    efCPT,
+    efLOG, efXVG, efOUT,
+    efNDX,
+    efTOP, efITP,
+    efTPS, efTPR,
+    efTEX, efRTP, efATP, efHDB,
+    efDAT, efDLG,
+    efMAP, efEPS, efMAT, efM2P,
+    efMTX,
+    efEDI,
+    efCUB,
+    efXPM,
+    efRND,
+    efNR
+};
+
+class FileNameOption : FileNameOptionTemplate /NoDefaultCtors/ {
+%TypeHeaderCode
+#include "gromacs/options/filenameoption.h"
+using gmx::FileNameOption;
+%End
+public:
+    FileNameOption& filetype(OptionFileType);
+    FileNameOption& legacyType(int);
+    FileNameOption& inputFile();
+    FileNameOption& outputFile();
+    FileNameOption& inputOutputFile();
+    FileNameOption& readWriteFlags(bool, bool);
+    FileNameOption& libraryFile(bool = true);
+    FileNameOption& defaultBasename(const char* /KeepReference/);
+    FileNameOption& defaultType(int);
+};
diff --git a/src/python/sip/options/options.sip b/src/python/sip/options/options.sip
new file mode 100644 (file)
index 0000000..077ac65
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+class IOptionManager /NoDefaultCtors/ {
+%TypeHeaderCode
+
+#include <gromacs/options/options.h>
+using gmx::IOptionManager;
+%End
+
+protected:
+    virtual ~IOptionManager();
+};
+
+class Options {
+%TypeHeaderCode
+
+#include <gromacs/options/options.h>
+using gmx::Options;
+%End
+
+public:
+    Options(const char *name, const char *title);
+    void addManager (IOptionManager *manager);
+    void addSubSection (Options *section);
+    void addOption(const AbstractOption &settings);
+
+    bool isSet(const char *name) const;
+    void finish();
+private:
+    Options(const Options &other);
+};
diff --git a/src/python/sip/options/pyoptionsholder.sip b/src/python/sip/options/pyoptionsholder.sip
new file mode 100644 (file)
index 0000000..0f77576
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%ModuleHeaderCode
+#include <exception>
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/filenameoption.h"
+#include "gromacs/selection/selectionoption.h"
+#include <map>
+#include <string>
+
+class PyOptionsHolder {
+public:
+    class DuplicateOption : public std::exception {
+    public:
+        virtual const char* what() const throw();
+    };
+    class StringList {
+    public:
+        StringList(const std::vector<std::string>*);
+        StringList(const std::string*, size_t);
+        const char* operator[] (size_t);
+    private:
+        const std::string *list;
+        size_t size;
+        const std::vector<std::string> *vector;
+    };
+    gmx::DoubleOption doubleOption(const char*, size_t = 1, double* = NULL);
+    gmx::IntegerOption integerOption(const char*, size_t = 1, int* = NULL);
+    gmx::StringOption stringOption(const char*, size_t = 1, const char* = NULL);
+    gmx::BooleanOption booleanOption(const char*, size_t = 1, bool = 0);
+    gmx::SelectionOption selectionOption(const char*, size_t = 1);
+    gmx::FileNameOption fileNameOption(const char*, size_t = 1);
+    PyObject* get_value(const char*);
+    ~PyOptionsHolder();
+private:
+    struct option_value {
+        void *value;
+        const char *type;
+        int *count;
+        bool vector;
+        const char *name;
+    };
+    std::map<std::string, option_value> storage;
+    template<typename T, typename U> U createStorage(const char*, const char*, int, const T* = 0);
+    template<typename T> PyObject* buildValue(const char*, const option_value&, const sipTypeDef* = NULL, size_t = 0);
+    template<typename T> void deleteStorage(const option_value&);
+};
+%End
+
+%ModuleCode
+#include "gromacs/utility/gmxassert.h"
+
+const char* PyOptionsHolder::DuplicateOption::what() const throw() {
+    return "This option is already defined";
+}
+
+PyOptionsHolder::StringList::StringList(const std::vector<std::string> *vector) :
+    list(NULL), size(vector->size()), vector(vector)
+{}
+
+PyOptionsHolder::StringList::StringList(const std::string *list, size_t size) :
+    list(list), size(size), vector(NULL)
+{}
+
+const char* PyOptionsHolder::StringList::operator[](size_t i) {
+    if (i >= size)
+        return NULL;
+    return vector ? (*vector)[i].data() : list[i].data();
+}
+
+template<typename T, typename U> U PyOptionsHolder::createStorage(const char *name, const char *type, int count, const T *def) {
+    if (storage.count(name))
+        throw DuplicateOption();
+
+    U option(name);
+
+    option_value value;
+    value.type = type;
+    value.count = new int;
+    value.name = name;
+
+    if (count == 0) { // std::vector of values
+        std::vector<T> *store = new std::vector<T>();
+        option.storeVector(store);
+        option.multiValue();
+        option.storeCount(value.count);
+
+        *value.count = 0;
+        if (def) {
+            store->push_back(*def);
+            *value.count = 1;
+        }
+
+        value.value = store;
+        value.vector = true;
+    } else { // exactly `count` values
+        T *store = new T[count];
+        if (def)
+            store[0] = *def;
+
+        option.store(store);
+        if (count > 1)
+            option.valueCount(count);
+
+        value.value = store;
+        value.vector = false;
+        *value.count = count;
+    }
+
+    storage[name] = value;
+    return option;
+}
+
+gmx::DoubleOption PyOptionsHolder::doubleOption(const char *name, size_t count, double *def) {
+    gmx::DoubleOption option = createStorage<double, gmx::DoubleOption>(name, "d", count, def);
+
+    return option;
+}
+
+gmx::IntegerOption PyOptionsHolder::integerOption(const char *name, size_t count, int *def) {
+    gmx::IntegerOption option = createStorage<int, gmx::IntegerOption>(name, "i", count, def);
+
+    return option;
+}
+
+gmx::StringOption PyOptionsHolder::stringOption(const char *name, size_t count, const char* def) {
+    std::string *s_def = NULL;
+    if (def)
+        s_def = new std::string(def);
+
+    gmx::StringOption option = createStorage<std::string, gmx::StringOption>(name, "A", count, s_def);
+    delete s_def;
+
+    return option;
+}
+
+// FIXME: Unify with the rest
+gmx::BooleanOption PyOptionsHolder::booleanOption(const char *name, size_t count, bool def) {
+    if (storage.count(name))
+        throw DuplicateOption();
+
+    bool *store = new bool;
+    *store = def;
+    gmx::BooleanOption option(name);
+    option.store(store);
+    option_value value = {store, "b"};
+    storage[name] = value;
+
+    return option;
+}
+
+gmx::SelectionOption PyOptionsHolder::selectionOption(const char *name, size_t count) {
+    gmx::SelectionOption option = createStorage<gmx::Selection, gmx::SelectionOption>(name, "S", count);
+
+    return option;
+}
+
+gmx::FileNameOption PyOptionsHolder::fileNameOption(const char *name, size_t count) {
+    gmx::FileNameOption option = createStorage<std::string, gmx::FileNameOption>(name, "f", count);
+
+    return option;
+}
+
+template<typename T> PyObject* PyOptionsHolder::buildValue(const char *sipType, const PyOptionsHolder::option_value &value, const sipTypeDef *td, size_t size) {
+    int count = *value.count;
+    T *store = !value.vector ? (T*) value.value : ((std::vector<T>*) value.value)->data();
+
+    if (count == 1 && !value.vector) {
+        if (td)
+            return sipConvertFromType(store, td, NULL);
+        else
+            return sipBuildResult(NULL, sipType, *store);
+    } else {
+        if (td)
+            return sipConvertToTypedArray(store, td, NULL, size, count, SIP_READ_ONLY);
+        else
+            return sipConvertToArray(store, sipType, count, SIP_READ_ONLY);
+    }
+}
+
+
+PyObject* PyOptionsHolder::get_value(const char *name) {
+    if (!storage.count(name))
+        return NULL;
+
+    option_value v = storage[name];
+    switch (*v.type) {
+    case 'd': // double
+        return buildValue<double>("d", v);
+        break;
+    case 'i': // int
+        return buildValue<int>("i", v);
+        break;
+    case 'A': // std::string
+    case 'f': // FileNameOption
+        if (v.vector)
+            return sipConvertFromType(new PyOptionsHolder::StringList(((std::vector<std::string>*) v.value)), sipType_PyOptionsHolder_StringList, Py_None);
+        else if (*v.count == 1)
+            return sipBuildResult(NULL, "A", ((std::string*) v.value)->data());
+        else
+            return sipConvertFromType(new PyOptionsHolder::StringList((std::string*) v.value, *v.count), sipType_PyOptionsHolder_StringList, Py_None);
+        break;
+    case 'b': // bool
+        // TODO: support vector bool options
+        return sipBuildResult(NULL, v.type, *((bool*) v.value));
+        break;
+    case 'S': // Selection
+        return buildValue<gmx::Selection>(NULL, v, sipType_Selection, sizeof(gmx::Selection));
+        break;
+    }
+
+    GMX_ASSERT(false, "Some type is not handled in PyOptionsHolder.get_value");
+    return NULL;
+}
+
+template<typename T> void PyOptionsHolder::deleteStorage(const PyOptionsHolder::option_value &value) {
+    if (value.vector)
+        delete (std::vector<T> *) value.value;
+    else
+        delete[] (T*) value.value;
+
+    delete value.count;
+}
+
+PyOptionsHolder::~PyOptionsHolder() {
+    for (std::map<std::string, option_value>::iterator it = storage.begin(); it != storage.end(); it++)
+        switch (*(it->second.type)) {
+            case 'd': // double
+                deleteStorage<double>(it->second);
+                break;
+            case 'i': // int
+                deleteStorage<int>(it->second);
+                break;
+            case 'A': // std::string
+            case 'f': // FileNameOption (the storage type is still std::string)
+                deleteStorage<std::string>(it->second);
+                break;
+            case 'b': // bool
+                delete (bool*) it->second.value;
+                break;
+            case 'S': // Selection
+                deleteStorage<gmx::Selection>(it->second);
+                break;
+        }
+}
+%End
+
+%Exception PyOptionsHolder::DuplicateOption {
+%RaiseCode
+        SIP_BLOCK_THREADS;
+        PyErr_SetString(PyExc_ValueError, sipExceptionRef.what());
+        SIP_UNBLOCK_THREADS;
+%End
+};
+
+class PyOptionsHolder {
+%TypeHeaderCode
+#include "gromacs/options/basicoptions.h"
+%End
+
+public:
+    class StringList /NoDefaultCtors/ {
+    public:
+        const char* operator[] (int);
+        %MethodCode
+            sipRes = (*sipCpp)[a0];
+
+            if (!sipRes) {
+                SIP_BLOCK_THREADS;
+                PyErr_SetString(PyExc_IndexError, "Index out of range");
+                SIP_UNBLOCK_THREADS;
+                sipIsErr = 1;
+            }
+        %End
+    };
+    // These methods are given twice to workaround sip setting 0 for when '*def = NULL' option is not given
+    DoubleOption doubleOption(const char *name /KeepReference/, int count = 1) throw (PyOptionsHolder::DuplicateOption);
+    DoubleOption doubleOption(const char *name /KeepReference/, int count, const double *def) throw (PyOptionsHolder::DuplicateOption);
+
+    IntegerOption integerOption(const char *name /KeepReference/, int count = 1) throw (PyOptionsHolder::DuplicateOption);
+    IntegerOption integerOption(const char *name /KeepReference/, int count, const int *def) throw (PyOptionsHolder::DuplicateOption);
+
+    StringOption stringOption(const char *name /KeepReference/, int count = 1) throw (PyOptionsHolder::DuplicateOption);
+    StringOption stringOption(const char *name /KeepReference/, int count, const char *def) throw (PyOptionsHolder::DuplicateOption);
+
+    BooleanOption booleanOption(const char *name /KeepReference/, int count = 1, bool def = 0) throw (PyOptionsHolder::DuplicateOption);
+
+    SelectionOption selectionOption(const char *name /KeepReference/, int count = 1) throw (PyOptionsHolder::DuplicateOption);
+
+    FileNameOption fileNameOption(const char *name /KeepReference/, int count = 1) throw (PyOptionsHolder::DuplicateOption);
+    SIP_PYOBJECT __getitem__(const char *name);
+    %MethodCode
+        sipRes = sipCpp->get_value(a0);
+
+        if (!sipRes) {
+            SIP_BLOCK_THREADS;
+            PyErr_SetString(PyExc_KeyError, "Invalid option name");
+            SIP_UNBLOCK_THREADS;
+            sipIsErr = 1;
+        }
+    %End
+};
diff --git a/src/python/sip/options/selectionoption.sip b/src/python/sip/options/selectionoption.sip
new file mode 100644 (file)
index 0000000..fad7254
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%ModuleHeaderCode
+#include "gromacs/options/abstractoption.h"
+#include "gromacs/selection/selectionoption.h"
+typedef gmx::OptionTemplate<gmx::Selection, gmx::SelectionOption> SelectionOptionTemplate;
+%End
+
+typedef OptionTemplate<Selection, SelectionOption> SelectionOptionTemplate;
+
+class SelectionOption : SelectionOptionTemplate /NoDefaultCtors/ {
+%TypeHeaderCode
+#include "gromacs/selection/selectionoption.h"
+using namespace gmx;
+%End
+
+public:
+    SelectionOption& evaluateVelocities();
+    SelectionOption& evaluateForces();
+    SelectionOption& onlyAtoms();
+    SelectionOption& onlyStatic();
+    SelectionOption& dynamicMask();
+    SelectionOption& allowEmpty();
+    SelectionOption& defaultSelectionText(const char*);
+};
diff --git a/src/python/sip/selection/Selection.sip b/src/python/sip/selection/Selection.sip
new file mode 100644 (file)
index 0000000..68592fb
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%Module gromacs.Selection
+
+%DefaultEncoding "UTF-8"
+
+%Include selection.sip
+
diff --git a/src/python/sip/selection/selection.sip b/src/python/sip/selection/selection.sip
new file mode 100644 (file)
index 0000000..cbcc95a
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%PostInitialisationCode
+import_array();
+%End
+
+enum e_index_t {
+    INDEX_UNKNOWN,
+    INDEX_ATOM,
+    INDEX_RES,
+    INDEX_MOL,
+    INDEX_ALL
+};
+
+class SelectionPosition /NoDefaultCtors/ {
+%TypeHeaderCode
+#include "gromacs/selection/selection.h"
+using namespace gmx;
+%End
+
+public:
+    e_index_t type();
+    SIP_PYOBJECT x();
+    %MethodCode
+        sipRes = array1dToNumpy(3, sipCpp->x());
+    %End
+    SIP_PYOBJECT v();
+    %MethodCode
+        sipRes = array1dToNumpy(3, sipCpp->v());
+    %End
+    SIP_PYOBJECT f();
+    %MethodCode
+        sipRes = array1dToNumpy(3, sipCpp->f());
+    %End
+    double mass();
+    double charge();
+    int atomCount();
+    SIP_PYOBJECT atomIndices();
+    %MethodCode
+        sipRes = iarray1dToNumpy(sipCpp->atomIndices().size(), sipCpp->atomIndices().data());
+    %End
+    bool selected();
+    int refId();
+    int mappedId();
+};
+
+enum e_coverfrac_t {
+    CFRAC_NONE,
+    CFRAC_SOLIDANGLE
+};
+
+class Selection {
+%TypeHeaderCode
+#include "gromacs/selection/selection.h"
+#include "numpy_conv.h"
+using namespace gmx;
+%End
+
+public:
+    bool isValid();
+    bool __eq__(const Selection&);
+    bool __ne__(const Selection&);
+    const char* name();
+    const char* selectionText();
+    bool isDynamic();
+    e_index_t type();
+    bool hasOnlyAtoms();
+    int atomCount();
+    SIP_PYOBJECT atomIndices();
+    %MethodCode
+        sipRes = iarray1dToNumpy(sipCpp->atomIndices().size(), sipCpp->atomIndices().data());
+    %End
+    int posCount();
+    SelectionPosition position(int);
+    SIP_PYOBJECT coordinates();
+    %MethodCode
+        sipRes = array2dToNumpy(sipCpp->coordinates().size(), 3, sipCpp->coordinates().data());
+    %End
+    bool hasVelocities();
+    SIP_PYOBJECT velocities();
+    %MethodCode
+        sipRes = array2dToNumpy(sipCpp->velocities().size(), 3, sipCpp->velocities().data());
+    %End
+    bool hasForces();
+    SIP_PYOBJECT forces();
+    %MethodCode
+        sipRes = array2dToNumpy(sipCpp->forces().size(), 3, sipCpp->forces().data());
+    %End
+    SIP_PYOBJECT masses();
+    %MethodCode
+        sipRes = array1dToNumpy(sipCpp->masses().size(), sipCpp->masses().data());
+    %End
+    SIP_PYOBJECT charges();
+    %MethodCode
+        sipRes = array1dToNumpy(sipCpp->charges().size(), sipCpp->charges().data());
+    %End
+    SIP_PYOBJECT refIds();
+    %MethodCode
+        sipRes = iarray1dToNumpy(sipCpp->refIds().size(), sipCpp->refIds().data());
+    %End
+    SIP_PYOBJECT mappedIds();
+    %MethodCode
+        sipRes = iarray1dToNumpy(sipCpp->mappedIds().size(), sipCpp->mappedIds().data());
+    %End
+    bool isCoveredFractionDynamic();
+    double coveredFraction();
+    bool initCoveredFraction(e_coverfrac_t);
+    void setEvaluateVelocities(bool);
+    void setEvaluateForces(bool);
+    void setOriginalId(int, int);
+};
diff --git a/src/python/sip/string.sip b/src/python/sip/string.sip
new file mode 100644 (file)
index 0000000..f9a0326
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%MappedType std::string
+{
+%TypeHeaderCode
+#include <string>
+%End
+
+%ConvertToTypeCode
+if (sipIsErr == NULL)
+    return PyBytes_Check(sipPy);
+
+    *sipCppPtr = new std::string(PyBytes_AsString(sipPy), PyBytes_Size(sipPy));
+
+    return sipGetState(sipTransferObj);
+%End
+
+%ConvertFromTypeCode
+return PyBytes_FromStringAndSize(sipCpp->data(),sipCpp->length());
+%End
+
+};
diff --git a/src/python/sip/topology/Topology.sip b/src/python/sip/topology/Topology.sip
new file mode 100644 (file)
index 0000000..9c57b4d
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%Module gromacs.Topology
+
+%DefaultEncoding "UTF-8"
+
+%Include pstringlistwrapper.sip
+
+%Include atoms.sip
+%Include topology.sip
diff --git a/src/python/sip/topology/atoms.sip b/src/python/sip/topology/atoms.sip
new file mode 100644 (file)
index 0000000..752ccb4
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+struct t_atom {
+
+%TypeHeaderCode
+#include <gromacs/topology/atoms.h>
+%End
+
+    double         m; double q;        /* Mass and charge                      */
+    double         mB; double qB;      /* Mass and charge for Free Energy calc */
+    unsigned short type;        /* Atom type                            */
+    unsigned short typeB;       /* Atom type for Free Energy calc       */
+    int            ptype;       /* Particle type                        */
+    int            resind;      /* Index into resinfo (in t_atoms)      */
+    int            atomnumber;  /* Atomic Number or NOTSET              */
+    char           *elem /NoSetter/;       /* Element name                         */
+};
+
+struct t_resinfo {
+
+%TypeHeaderCode
+#include <gromacs/topology/atoms.h>
+%End
+
+    SIP_PYOBJECT /* char** */      name /NoSetter/ {      /* Pointer to the residue name          */
+    %GetCode
+        sipPy = sipBuildResult(NULL, "A", (sipCpp->name) ? *(sipCpp->name) : NULL);
+    %End
+    };
+    int             nr;         /* Residue number                       */
+    unsigned char   ic;         /* Code for insertion of residues       */
+    int             chainnum;   /* Iincremented at TER or new chain id  */
+    char            chainid;    /* Chain identifier written/read to pdb */
+    SIP_PYOBJECT /* char** */      rtp /NoSetter/ {       /* rtp building block name (optional)   */
+    %GetCode
+        sipPy = sipBuildResult(NULL, "A", (sipCpp->rtp) ? *(sipCpp->rtp) : NULL);
+    %End
+    };
+};
+
+struct t_pdbinfo {
+
+%TypeHeaderCode
+#include <gromacs/topology/atoms.h>
+%End
+
+    int      type;              /* PDB record name                      */
+    int      atomnr;            /* PDB atom number                      */
+    char     altloc;            /* Alternate location indicator         */
+    char    *atomnm /NoSetter/; /* True atom name including leading spaces */
+    double   occup;             /* Occupancy                            */
+    double   bfac;              /* B-factor                             */
+    bool bAnisotropic;          /* (an)isotropic switch                 */
+    SIP_PYOBJECT /* int * */ uij /NoSetter/ {
+    %GetCode
+        sipPy = sipConvertToArray(sipCpp->uij, "i", 6, SIP_READ_ONLY);
+    %End
+    };
+};
+
+struct t_grps {
+
+%TypeHeaderCode
+#include <gromacs/topology/atoms.h>
+%End
+
+    int   nr;                   /* Number of different groups           */
+    SIP_PYOBJECT /* int* */ nm_ind /NoSetter/ {
+    %GetCode
+        sipPy = sipConvertToArray(sipCpp->nm_ind, "i", sipCpp->nr, SIP_READ_ONLY);
+    %End
+    };
+};
+
+
+struct t_atoms {
+
+%TypeHeaderCode
+#include <gromacs/topology/atoms.h>
+// Sip creates 'copy_[typename]' functions. In this case it coincides with function from atoms.h, so we need to rename it.
+#define copy_t_atoms copy_t_atoms_sip
+%End
+
+    int            nr;          /* Nr of atoms                          */
+    t_atom        *atom /NoSetter/ {
+    %GetCode
+        sipPy = sipConvertToTypedArray(sipCpp->atom, sipType_t_atom, NULL, sizeof(t_atom), sipCpp->nr, SIP_READ_ONLY);
+    %End
+    };
+    PStringListWrapper atomname /NoSetter/ {
+    %GetCode
+        PStringListWrapper *wrapper = new PStringListWrapper(sipCpp->atomname, sipCpp->nr);
+        sipPy = sipConvertFromType(wrapper, sipType_PStringListWrapper, Py_None);
+    %End
+    };
+    PStringListWrapper atomtype /NoSetter/ {
+    %GetCode
+        PStringListWrapper *wrapper = new PStringListWrapper(sipCpp->atomtype, sipCpp->nr);
+        sipPy = sipConvertFromType(wrapper, sipType_PStringListWrapper, Py_None);
+    %End
+    };
+    PStringListWrapper atomtypeB /NoSetter/ {
+    %GetCode
+        PStringListWrapper *wrapper = new PStringListWrapper(sipCpp->atomname, sipCpp->nr);
+        sipPy = sipConvertFromType(wrapper, sipType_PStringListWrapper, Py_None);
+    %End
+    };
+
+    int              nres;
+    t_resinfo       *resinfo /NoSetter/ {
+    %GetCode
+        sipPy = sipConvertToTypedArray(sipCpp->resinfo, sipType_t_resinfo, NULL, sizeof(t_resinfo), sipCpp->nres, SIP_READ_ONLY);
+    %End
+    };
+    // FIXME: how many pdbinfo's are there?
+    t_pdbinfo       *pdbinfo /NoSetter/ {
+    %GetCode
+        sipPy = sipConvertToTypedArray(sipCpp->pdbinfo, sipType_t_pdbinfo, NULL, sizeof(t_pdbinfo), sipCpp->nres, SIP_READ_ONLY);
+    %End
+    };
+};
diff --git a/src/python/sip/topology/pstringlistwrapper.sip b/src/python/sip/topology/pstringlistwrapper.sip
new file mode 100644 (file)
index 0000000..665fa3e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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 class is needed to transparently map 'atomname' and similar fields of struct t_atoms.
+// Avoids copying and mapping entire array to python.
+
+%ModuleHeaderCode
+class PStringListWrapper {
+public:
+    PStringListWrapper(char ***stringList, size_t size);
+    const char* operator[] (size_t i);
+private:
+    char ***stringList;
+    size_t size;
+};
+%End
+
+%ModuleCode
+PStringListWrapper::PStringListWrapper(char ***stringList, size_t size) :
+    stringList(stringList), size(size)
+    {}
+const char* PStringListWrapper::operator[] (size_t i) {
+    if (i >= size)
+        return NULL;
+    return *stringList[i];
+}
+%End
+
+class PStringListWrapper /NoDefaultCtors/ {
+public:
+    const char* operator[] (int i);
+    %MethodCode
+        sipRes = (*sipCpp)[a0];
+
+        if (!sipRes) {
+            SIP_BLOCK_THREADS;
+            PyErr_SetString(PyExc_IndexError, "Index out of range");
+            SIP_UNBLOCK_THREADS;
+            sipIsErr = 1;
+        }
+    %End
+};
diff --git a/src/python/sip/topology/topology.sip b/src/python/sip/topology/topology.sip
new file mode 100644 (file)
index 0000000..1ce94d4
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+struct t_topology
+{
+
+%TypeHeaderCode
+#include <gromacs/topology/topology.h>
+%End
+
+    SIP_PYOBJECT      name /NoSetter/ {       // Name of the topology
+    %GetCode
+        // name is stored as char**, when the outer pointer is null, let sip wrap it as None
+        sipPy = sipBuildResult(NULL, "A", (sipCpp->name) ? *(sipCpp->name) : NULL);
+    %End
+    };
+    //t_idef          idef;       [> The interaction function definition  <]
+    t_atoms         atoms;      /* The atoms                            */
+    //t_atomtypes     atomtypes;  [> Atomtype properties                  <]
+    //t_block         cgs;        [> The charge groups                    <]
+    //t_block         mols;       [> The molecules                        <]
+    //t_blocka        excls;      [> The exclusions                       <]
+    //t_symtab        symtab;     [> The symbol table                     <]
+};
diff --git a/src/python/sip/trajectoryanalysis/TrajectoryAnalysis.sip b/src/python/sip/trajectoryanalysis/TrajectoryAnalysis.sip
new file mode 100644 (file)
index 0000000..94c9a90
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%Module gromacs.TrajectoryAnalysis
+
+%DefaultEncoding "UTF-8"
+
+%Import options/Options.sip
+%Import topology/Topology.sip
+
+%Include definitions.sip
+
+%Include analysissettings.sip
+%Include analysisdata.sip
+%Include analysismodule.sip
+
+%Include modules.sip
+
+%ModuleCode
+#include "gromacs/trajectoryanalysis/analysismodule.h"
+#include "gromacs/trajectoryanalysis/cmdlinerunner.h"
+#include "gromacs/utility/exceptions.h"
+
+class PyFactory : public gmx::TrajectoryAnalysisCommandLineRunner::ModuleFactoryFunctor {
+public:
+    PyFactory(PyObject *mod) : mod(mod) {} ;
+    gmx::TrajectoryAnalysisModulePointer operator () () {
+        int iserr = 0;
+        int can = sipCanConvertToType(mod, sipType_TrajectoryAnalysisModule, 0);
+        // TODO: throw if can't
+        gmx::TrajectoryAnalysisModule *module = (gmx::TrajectoryAnalysisModule*) sipConvertToType(
+            mod, sipType_TrajectoryAnalysisModule, NULL, 0, NULL, &iserr);
+        return TrajectoryAnalysisModulePointer(module);
+    }
+private:
+    PyObject *mod;
+};
+
+void runAsMain(PyObject *mod, PyObject *py_argv) {
+    int argc = PyList_GET_SIZE(py_argv);
+
+    char **argv = new char *[argc + 1];
+    bool to_free[argc];
+    std::fill(to_free, to_free+argc, false);
+
+    // Convert the list.
+    // TODO: Use something better than AsLatin1String to avoid unicode errors
+    for (int a = 0; a < argc; ++a)
+    {
+        PyObject *arg_obj = PyList_GET_ITEM(py_argv, a);
+        const char *arg = sipString_AsLatin1String(&arg_obj);
+
+        if (arg)
+        {
+            arg = strdup(arg);
+            Py_DECREF(arg_obj);
+            to_free[a] = true;
+        }
+        else
+        {
+            arg = "unknown";
+        }
+
+        argv[a] = const_cast<char *>(arg);
+    }
+
+    argv[argc] = NULL;
+
+    PyFactory factory(mod);
+    TrajectoryAnalysisCommandLineRunner::runAsMain(argc, argv, &factory);
+
+    for (int i = 0; i < argc; i++)
+        if (to_free[i])
+            free(argv[i]);
+    delete[] argv;
+}
+
+%End
+
+void runAsMain(SIP_PYOBJECT mod, SIP_PYLIST argv);
diff --git a/src/python/sip/trajectoryanalysis/analysisdata.sip b/src/python/sip/trajectoryanalysis/analysisdata.sip
new file mode 100644 (file)
index 0000000..5eb1eff
--- /dev/null
@@ -0,0 +1,64 @@
+
+class AbstractAnalysisData /NoDefaultCtors/ {
+%TypeHeaderCode
+#include <gromacs/analysisdata/abstractdata.h>
+%End
+public:
+    bool isMultipoint() const;
+    int dataSetCount() const;
+    int columnCount(int dataSet) const;
+    int columnCount() const;
+    virtual int frameCount() const = 0;
+    AnalysisDataFrameRef tryGetDataFrame(int index) const;
+    AnalysisDataFrameRef getDataFrame(int index) const;
+    bool requestStorage(int nframes);
+};
+
+class AnalysisDataFrameRef /NoDefaultCtors/ {
+%TypeHeaderCode
+#include <gromacs/analysisdata/dataframe.h>
+%End
+public:
+    bool isValid() const;
+    //const AnalysidDataFrameHeader& header() const;
+    int frameIndex() const;
+    double x() const;
+    double dx() const;
+    int pointSetCount() const;
+    AnalysisDataPointSetRef pointSet(int index) const;
+    double y(int i) const;
+    double dy(int i) const;
+    bool present(int i) const;
+    bool allPresent() const;
+};
+
+class AnalysisDataFrameHeader /NoDefaultCtors/ {
+%TypeHeaderCode
+#include <gromacs/analysisdata/dataframe.h>
+%End
+public:
+    bool isValid() const;
+    int index() const;
+    double x() const;
+    double dx() const;
+};
+
+class AnalysisDataPointSetRef /NoDefaultCtors/ {
+%TypeHeaderCode
+#include <gromacs/analysisdata/dataframe.h>
+%End
+public:
+    const AnalysisDataFrameHeader& header() const;
+    int frameIndex() const;
+    double x() const;
+    double dx() const;
+    int dataSetIndex() const;
+    int firstColumn() const;
+    int columnCount() const;
+    int lastColumn() const;
+    //const std::vector<AnalysisDataValue>& values() const;
+    double y(int i) const;
+    double dy(int i) const;
+    bool present(int i) const;
+    bool allPresent() const;
+};
diff --git a/src/python/sip/trajectoryanalysis/analysismodule.sip b/src/python/sip/trajectoryanalysis/analysismodule.sip
new file mode 100644 (file)
index 0000000..a10caff
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+%PostInitialisationCode
+    import_array();
+%End
+
+struct t_trxframe {
+
+%TypeHeaderCode
+#include <gromacs/fileio/trx.h>
+#include "numpy_conv.h"
+%End
+
+    int flags;
+    int not_ok;
+    bool bDouble;
+    int natoms;
+    double t0;
+    double tf;
+    double tpf;
+    double tppf;
+    bool bTitle;
+    const char *title;
+    bool bStep;
+    int step;
+    bool bTime;
+    double time;
+    bool bLambda;
+    bool bFepState;
+    double lambda;
+    int fep_state;
+    bool bAtoms;
+    t_atoms *atoms;
+    bool bPrec;
+    double prec;
+    bool bX;
+    SIP_PYOBJECT x /NoSetter/ {
+    %GetCode
+        sipPy = array2dToNumpy(sipCpp->natoms, 3, sipCpp->x);
+    %End
+    };
+    bool bV;
+    SIP_PYOBJECT v /NoSetter/ {
+    %GetCode
+        sipPy = array2dToNumpy(sipCpp->natoms, 3, sipCpp->v);
+    %End
+    };
+    bool bF;
+    SIP_PYOBJECT f /NoSetter/ {
+    %GetCode
+        sipPy = array2dToNumpy(sipCpp->natoms, 3, sipCpp->f);
+    %End
+    };
+    bool bBox;
+    SIP_PYOBJECT box /NoSetter/ {
+    %GetCode
+        sipPy = array2dToNumpy(3, 3, sipCpp->box);
+    %End
+    };
+    bool bPBC;
+    int ePBC;
+    // TODO
+    /*t_gmxvmdplugin* *vmdplugin; */
+};
+
+struct t_pbc {
+
+%TypeHeaderCode
+#include <gromacs/pbcutil/pbc.h>
+#include "numpy_conv.h"
+%End
+    int ePBC;
+    int ndim_ePBC;
+    int ePBCDX;
+    int dim;
+    SIP_PYOBJECT box /NoSetter/ {
+    %GetCode
+        sipPy = array2dToNumpy(3, 3, sipCpp->box);
+    %End
+    };
+    SIP_PYOBJECT fbox_diag /NoSetter/ {
+    %GetCode
+        sipPy = array1dToNumpy(3, sipCpp->fbox_diag);
+    %End
+    };
+    SIP_PYOBJECT hbox_diag /NoSetter/ {
+    %GetCode
+        sipPy = array1dToNumpy(3, sipCpp->hbox_diag);
+    %End
+    };
+    SIP_PYOBJECT mhbox_diag /NoSetter/ {
+    %GetCode
+        sipPy = array1dToNumpy(3, sipCpp->mhbox_diag);
+    %End
+    };
+    double max_cutoff2;
+    bool bLimitDistance;
+    double limit_distance2;
+    int  ntric_vec;
+    /*ivec tric_shift[MAX_NTRICVEC];*/
+    /*rvec tric_vec[MAX_NTRICVEC];*/
+};
+
+class TrajectoryAnalysisModuleData /NoDefaultCtors/ {
+
+%TypeHeaderCode
+#include <gromacs/trajectoryanalysis/analysismodule.h>
+using namespace gmx;
+%End
+
+public:
+    virtual void finish() = 0;
+};
+
+%ModuleHeaderCode
+#include "gromacs/utility/exceptions.h"
+%End
+
+%VirtualErrorHandler vehandler
+    SIP_RELEASE_GIL(sipGILState);
+
+    GMX_THROW(gmx::InternalError("Python virtual overload raised an exception, see traceback"));
+%End
+
+%Include vector.sip
+
+class TrajectoryAnalysisModule /VirtualErrorHandler=vehandler/ {
+
+%TypeHeaderCode
+#include <gromacs/trajectoryanalysis/analysismodule.h>
+using namespace gmx;
+%End
+public:
+    virtual void initOptions(Options *options, TrajectoryAnalysisSettings *settings) = 0;
+    virtual void optionsFinished(Options *options, TrajectoryAnalysisSettings *settings);
+    virtual void initAnalysis(const TrajectoryAnalysisSettings &settings, const TopologyInformation &top) = 0;
+    virtual void initAfterFirstFrame(const TrajectoryAnalysisSettings &settings, const t_trxframe &fr);
+//    virtual TrajectoryAnalysisModuleDataPointer      startFrames (const AnalysisDataParallelOptions &opt, const SelectionCollection &selections);
+    virtual void analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc, TrajectoryAnalysisModuleData *pdata) = 0;
+    virtual void finishFrames(TrajectoryAnalysisModuleData *pdata);
+    virtual void finishAnalysis(int nframes) = 0;
+    virtual void writeOutput() = 0;
+    virtual const std::vector<TrajectoryAnalysisModule*> getBatch();
+    virtual const std::vector<char*> getArgv(int);
+    const char* name() const;
+    const char* description() const;
+    int datasetCount() const;
+//    const std::vector<std::string> datasetNames() const;
+    AbstractAnalysisData& datasetFromIndex(int index) const;
+    AbstractAnalysisData& datasetFromName(const char *name) const;
+protected:
+    TrajectoryAnalysisModule(const char *name, const char *description);
+private:
+    TrajectoryAnalysisModule(const TrajectoryAnalysisModule &other);
+};
+
+%Exception gmx::InconsistentInputError(SIP_Exception) {
+
+%TypeHeaderCode
+#include <gromacs/utility/exceptions.h>
+using namespace std;
+%End
+
+%RaiseCode
+    const char *detail = sipExceptionRef.what();
+
+    SIP_BLOCK_THREADS
+    PyErr_SetString(sipException_gmx_InconsistentInputError, detail);
+    SIP_UNBLOCK_THREADS
+%End
+};
diff --git a/src/python/sip/trajectoryanalysis/analysissettings.sip b/src/python/sip/trajectoryanalysis/analysissettings.sip
new file mode 100644 (file)
index 0000000..3e29c10
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and 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.
+ */
+
+class TrajectoryAnalysisSettings {
+%TypeHeaderCode
+#include <gromacs/trajectoryanalysis/analysissettings.h>
+using namespace gmx;
+%End
+
+public:
+    enum {
+        efRequireTop = 1,
+        efUseTopX = 2,
+        efNoUserPBC = 16,
+        efNoUserRmPBC = 32
+    };
+
+    TrajectoryAnalysisSettings();
+    /*
+    const TimeUnitManager& timeUnitManager() const;
+    TimeUnit timeUnit();
+    const AnalysisDataPlotSettings& plotSettings() const;
+    */
+    unsigned long flags() const;
+    bool hasFlag(unsigned long flag) const;
+    bool hasPBC() const;
+    bool hasRmPBC() const;
+    int frflags() const;
+    void setFlags(unsigned long flags);
+    void setFlag(unsigned long flag, bool bSet = true);
+    void setPBC(bool bPBC);
+    void setRmPBC(bool bRmPBC);
+    void setFrameFlags(int frflags);
+    void setHelpText(const char *helpText);
+    %MethodCode
+        const char *const helpText[] = {a0};
+        sipCpp->setHelpText(helpText);
+    %End
+private:
+    TrajectoryAnalysisSettings(const TrajectoryAnalysisSettings &other);
+};
+
+class TopologyInformation {
+%TypeHeaderCode
+#include <gromacs/trajectoryanalysis/analysissettings.h>
+using namespace gmx;
+%End
+public:
+    bool hasTopology() const;
+    bool hasFullTopology() const;
+    t_topology* topology() const;
+private:
+    TopologyInformation(const TopologyInformation &other);
+    ~TopologyInformation();
+};
diff --git a/src/python/sip/trajectoryanalysis/modules.sip b/src/python/sip/trajectoryanalysis/modules.sip
new file mode 100644 (file)
index 0000000..f724ef1
--- /dev/null
@@ -0,0 +1,117 @@
+
+template <T> class shared_ptr /NoDefaultCtors/ {
+%TypeHeaderCode
+#include <boost/shared_ptr.hpp>
+using namespace boost;
+%End
+};
+
+typedef shared_ptr<TrajectoryAnalysisModule> TrajectoryAnalysisModulePointer;
+
+template <TYPE>
+%MappedType py_shared_ptr<TYPE> /NoRelease/ {
+%TypeHeaderCode
+#include <boost/shared_ptr.hpp>
+template <typename T> using py_shared_ptr = boost::shared_ptr<T>;
+%End
+
+%ConvertFromTypeCode
+    PyObject *wrp = sipConvertFromType(sipCpp->get(), sipType_TYPE, NULL);
+    PyObject *ptr = sipConvertFromNewType(sipCpp, sipType_TYPEPointer, wrp);
+
+    return wrp;
+%End
+
+%ConvertToTypeCode
+    // Make it impossible to convert into this type
+    if (!sipIsErr)
+        return 0;
+
+    GMX_ASSERT(true, "Converting something into shared_ptr. This should not happen!");
+    return 0;
+%End
+};
+
+class AngleInfo {
+%TypeHeaderCode
+#include "gromacs/trajectoryanalysis/modules/angle.h"
+using namespace gmx::analysismodules;
+%End
+private:
+public:
+    static const char* name /NoSetter/;
+    static const char* shortDescription /NoSetter/;
+    static py_shared_ptr<TrajectoryAnalysisModule> create() /Factory/;
+};
+
+class DistanceInfo {
+%TypeHeaderCode
+#include "gromacs/trajectoryanalysis/modules/distance.h"
+using namespace gmx::analysismodules;
+%End
+private:
+public:
+    static const char* name /NoSetter/;
+    static const char* shortDescription /NoSetter/;
+    static py_shared_ptr<TrajectoryAnalysisModule> create() /Factory/;
+};
+
+class FreeVolumeInfo {
+%TypeHeaderCode
+#include "gromacs/trajectoryanalysis/modules/freevolume.h"
+using namespace gmx::analysismodules;
+%End
+private:
+public:
+    static const char* name /NoSetter/;
+    static const char* shortDescription /NoSetter/;
+    static py_shared_ptr<TrajectoryAnalysisModule> create() /Factory/;
+};
+
+class PairDistanceInfo {
+%TypeHeaderCode
+#include "gromacs/trajectoryanalysis/modules/pairdist.h"
+using namespace gmx::analysismodules;
+%End
+private:
+public:
+    static const char* name /NoSetter/;
+    static const char* shortDescription /NoSetter/;
+    static py_shared_ptr<TrajectoryAnalysisModule> create() /Factory/;
+};
+
+class RdfInfo {
+%TypeHeaderCode
+#include "gromacs/trajectoryanalysis/modules/rdf.h"
+using namespace gmx::analysismodules;
+%End
+private:
+public:
+    static const char* name /NoSetter/;
+    static const char* shortDescription /NoSetter/;
+    static py_shared_ptr<TrajectoryAnalysisModule> create() /Factory/;
+};
+
+class SasaInfo {
+%TypeHeaderCode
+#include "gromacs/trajectoryanalysis/modules/sasa.h"
+using namespace gmx::analysismodules;
+%End
+private:
+public:
+    static const char* name /NoSetter/;
+    static const char* shortDescription /NoSetter/;
+    static py_shared_ptr<TrajectoryAnalysisModule> create() /Factory/;
+};
+
+class SelectInfo {
+%TypeHeaderCode
+#include "gromacs/trajectoryanalysis/modules/select.h"
+using namespace gmx::analysismodules;
+%End
+private:
+public:
+    static const char* name /NoSetter/;
+    static const char* shortDescription /NoSetter/;
+    static py_shared_ptr<TrajectoryAnalysisModule> create() /Factory/;
+};
diff --git a/src/python/sip/vector.sip b/src/python/sip/vector.sip
new file mode 100644 (file)
index 0000000..f19846e
--- /dev/null
@@ -0,0 +1,423 @@
+// SIP support for std::vector
+// by Giovanni Bajo <rasky <at> develer.com>
+// Public domain
+
+// ****************************************************
+// SIP generic implementation for std::vector<>
+// ****************************************************
+// ALas, this template-based generic implementation is valid only
+// if the element type is a SIP-wrapped type. For basic types (int, double, etc.)
+// we are forced to cut & paste to provide a specialization.
+
+template<TYPE*>
+%MappedType std::vector<TYPE*>
+{
+%TypeHeaderCode
+#include <vector>
+%End
+
+%ConvertFromTypeCode
+    PyObject *l = PyList_New(sipCpp -> size());
+
+    // Create the Python list of the correct length.
+    if (!l)
+        return NULL;
+
+    // Go through each element in the C++ instance and convert it to a
+    // wrapped P2d.
+    for (int i = 0; i < (int)sipCpp->size(); ++i) {
+        TYPE *cpp = sipCpp->at(i);
+        PyObject *pobj = sipConvertFromInstance(cpp, sipClass_TYPE, sipTransferObj);
+
+        // Get the Python wrapper for the Type instance, creating a new
+        // one if necessary, and handle any ownership transfer.
+        if (!pobj) {
+            // There was an error so garbage collect the Python list.
+            Py_DECREF(l);
+            return NULL;
+        }
+
+        // Add the wrapper to the list.
+        PyList_SET_ITEM(l, i, pobj);
+    }
+
+    // Return the Python list.
+    return l;
+%End
+
+%ConvertToTypeCode
+    // Check if type is compatible
+    if (!sipIsErr) {
+        // Must be any iterable
+        PyObject *i = PyObject_GetIter(sipPy);
+        bool iterable = (i != NULL);
+        Py_XDECREF(i);
+        return iterable;
+    }
+
+    // Iterate over the object
+    PyObject *iterator = PyObject_GetIter(sipPy);
+    PyObject *item;
+
+    std::vector<TYPE*> *V = new std::vector<TYPE*>();
+
+    while ((item = PyIter_Next(iterator)))
+    {
+        if (!sipCanConvertToInstance(item, sipClass_TYPE, SIP_NOT_NONE)) {
+            PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to TYPE");
+            *sipIsErr = 1;
+            break;
+        }
+
+        int state;
+        TYPE* p = reinterpret_cast<TYPE*>(
+             sipConvertToInstance(item, sipClass_TYPE, 0, SIP_NOT_NONE, &state, sipIsErr));
+
+        if (!*sipIsErr)
+            V->push_back(p);
+
+        sipReleaseInstance(p, sipClass_TYPE, state);
+        Py_DECREF(item);
+    }
+
+    Py_DECREF(iterator);
+
+    if (*sipIsErr) {
+        delete V;
+        return 0;
+    }
+
+    *sipCppPtr = V;
+    return sipGetState(sipTransferObj);
+%End
+};
+
+// ****************************************************
+// Specialization for std::vector<char*>
+// ****************************************************
+
+%MappedType std::vector<char*>
+{
+%TypeHeaderCode
+#include <vector>
+%End
+
+%ConvertFromTypeCode
+    PyObject *l;
+
+    // Create the Python list of the correct length.
+    if ((l = PyList_New(sipCpp -> size())) == NULL)
+        return NULL;
+
+    // Go through each element in the C++ instance and convert it to a
+    // wrapped object.
+    for (int i = 0; i < (int)sipCpp -> size(); ++i)
+    {
+        // Add the wrapper to the list.
+        PyList_SET_ITEM(l, i, sipBuildResult(NULL, "A", sipCpp->at(i)));
+    }
+
+    // Return the Python list.
+    return l;
+%End
+
+%ConvertToTypeCode
+    // Check if type is compatible
+    if (sipIsErr == NULL)
+    {
+        // Must be any iterable
+        PyObject *i = PyObject_GetIter(sipPy);
+        bool iterable = (i != NULL);
+        Py_XDECREF(i);
+        return iterable;
+    }
+
+    // Iterate over the object
+    PyObject *iterator = PyObject_GetIter(sipPy);
+    PyObject *item;
+
+    // Maximum number of elements
+    int len = PyObject_Size(sipPy);
+    std::vector<char*> *V = new std::vector<char*>();
+    V->reserve(len);
+
+    if (len)
+    {
+        while ((item = PyIter_Next(iterator)))
+        {
+            if (!PyUnicode_Check(item))
+            {
+                PyErr_Format(PyExc_TypeError, "object in iterable is not a string");
+                *sipIsErr = 1;
+                break;
+            }
+            //FIXME: memory leak here
+            const char* str = strdup(sipString_AsLatin1String(&item));
+
+            V->push_back(const_cast<char*>(str));
+
+            Py_DECREF(item);
+        }
+
+        Py_DECREF(iterator);
+
+        if (*sipIsErr)
+        {
+            delete V;
+            return 0;
+        }
+    }
+
+    *sipCppPtr = V;
+    return sipGetState(sipTransferObj);
+%End
+};
+
+/*
+// ****************************************************
+// Specialization for std::vector<double>
+// ****************************************************
+
+%MappedType std::vector<double>
+{
+%TypeHeaderCode
+#include <vector>
+%End
+
+%ConvertFromTypeCode
+    PyObject *l;
+
+    // Create the Python list of the correct length.
+    if ((l = PyList_New(sipCpp -> size())) == NULL)
+        return NULL;
+
+    // Go through each element in the C++ instance and convert it to a
+    // wrapped object.
+    for (int i = 0; i < (int)sipCpp -> size(); ++i)
+    {
+        // Add the wrapper to the list.
+        PyList_SET_ITEM(l, i, PyFloat_FromDouble(sipCpp -> at(i)));
+    }
+
+    // Return the Python list.
+    return l;
+%End
+
+%ConvertToTypeCode
+    // Check if type is compatible
+    if (sipIsErr == NULL)
+    {
+        // Must be any iterable
+        PyObject *i = PyObject_GetIter(sipPy);
+        bool iterable = (i != NULL);
+        Py_XDECREF(i);
+        return iterable;
+    }
+
+    // Iterate over the object
+    PyObject *iterator = PyObject_GetIter(sipPy);
+    PyObject *item;
+
+    // Maximum number of elements
+    int len = PyObject_Size(sipPy);
+    std::vector<double> *V = new std::vector<double>();
+    V->reserve(len);
+
+    if (len)
+    {
+        while ((item = PyIter_Next(iterator)))
+        {
+            if (!PyNumber_Check(item))
+            {
+                PyErr_Format(PyExc_TypeError, "object in iterable is not a number");
+                *sipIsErr = 1;
+                break;
+            }
+
+            PyObject *f = PyNumber_Float(item);
+            V->push_back(PyFloat_AsDouble(f));
+
+            Py_DECREF(f);
+            Py_DECREF(item);
+        }
+
+        Py_DECREF(iterator);
+
+        if (*sipIsErr)
+        {
+            delete V;
+            return 0;
+        }
+    }
+
+    *sipCppPtr = V;
+    return sipGetState(sipTransferObj);
+%End
+};
+
+// ****************************************************
+// Specialization for std::vector<int>
+// ****************************************************
+
+%MappedType std::vector<int>
+{
+%TypeHeaderCode
+#include <vector>
+%End
+
+%ConvertFromTypeCode
+    PyObject *l;
+
+    // Create the Python list of the correct length.
+    if ((l = PyList_New((SIP_SSIZE_T)sipCpp -> size())) == NULL)
+        return NULL;
+
+    // Go through each element in the C++ instance and convert it to a
+    // wrapped object.
+    for (int i = 0; i < (int)sipCpp -> size(); ++i)
+    {
+        // Add the wrapper to the list.
+        PyList_SET_ITEM(l, i, PyInt_FromLong(sipCpp -> at(i)));
+    }
+
+    // Return the Python list.
+    return l;
+%End
+
+%ConvertToTypeCode
+    // Check if type is compatible
+    if (sipIsErr == NULL)
+    {
+        // Must be any iterable
+        PyObject *i = PyObject_GetIter(sipPy);
+        bool iterable = (i != NULL);
+        Py_XDECREF(i);
+        return iterable;
+    }
+
+    // Iterate over the object
+    PyObject *iterator = PyObject_GetIter(sipPy);
+    PyObject *item;
+
+    // Maximum number of elements
+    int len = PyObject_Size(sipPy);
+    std::vector<int> *V = new std::vector<int>();
+    V->reserve(len);
+
+    if (len)
+    {
+        while ((item = PyIter_Next(iterator)))
+        {
+            if (!PyInt_Check(item))
+            {
+                PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to float");
+                *sipIsErr = 1;
+                break;
+            }
+
+            int val = PyInt_AsLong(item);
+            V->push_back(val);
+
+            Py_DECREF(item);
+        }
+
+        Py_DECREF(iterator);
+
+        if (*sipIsErr)
+        {
+            delete V;
+            return 0;
+        }
+    }
+
+    *sipCppPtr = V;
+    return sipGetState(sipTransferObj);
+%End
+};
+
+
+// ****************************************************
+// Specialization for std::vector<unsigned int>
+// ****************************************************
+
+%MappedType std::vector<unsigned int>
+{
+%TypeHeaderCode
+#include <vector>
+%End
+
+%ConvertFromTypeCode
+    PyObject *l;
+
+    // Create the Python list of the correct length.
+    if ((l = PyList_New(sipCpp -> size())) == NULL)
+        return NULL;
+
+    // Go through each element in the C++ instance and convert it to a
+    // wrapped object.
+    for (int i = 0; i < (int)sipCpp -> size(); ++i)
+    {
+        // Add the wrapper to the list.
+        PyList_SET_ITEM(l, i, PyInt_FromLong(sipCpp -> at(i)));
+    }
+
+    // Return the Python list.
+    return l;
+%End
+
+%ConvertToTypeCode
+    // Check if type is compatible
+    if (sipIsErr == NULL)
+    {
+        // Must be any iterable
+        PyObject *i = PyObject_GetIter(sipPy);
+        bool iterable = (i != NULL);
+        Py_XDECREF(i);
+        return iterable;
+    }
+
+    // Iterate over the object
+    PyObject *iterator = PyObject_GetIter(sipPy);
+    PyObject *item;
+
+    // Maximum number of elements
+    Py_ssize_t size = PyObject_Size(sipPy);
+    if (size == -1) {
+        Py_DECREF(iterator);
+        return 0;
+    }
+
+    unsigned int len = size;
+    std::vector<unsigned int> *V = new std::vector<unsigned int>();
+    V->reserve(len);
+
+    if (len)
+    {
+        while ((item = PyIter_Next(iterator)))
+        {
+            if (!PyInt_Check(item))
+            {
+                PyErr_Format(PyExc_TypeError, "object in iterable cannot be converted to float");
+                *sipIsErr = 1;
+                break;
+            }
+
+            unsigned int val = PyInt_AsLong(item);
+            V->push_back(val);
+
+            Py_DECREF(item);
+        }
+
+        Py_DECREF(iterator);
+
+        if (*sipIsErr)
+        {
+            delete V;
+            return 0;
+        }
+    }
+
+    *sipCppPtr = V;
+    return sipGetState(sipTransferObj);
+%End
+};*/
diff --git a/src/python/test.py b/src/python/test.py
new file mode 100644 (file)
index 0000000..67e6ecc
--- /dev/null
@@ -0,0 +1,58 @@
+import sys
+from gromacs import Options, TrajectoryAnalysis
+
+class M(TrajectoryAnalysis.TrajectoryAnalysisModule):
+    def __init__(self):
+        super(M, self).__init__("a", "a")
+
+    def initOptions(self, options, settings):
+        print('python: initOptions')
+
+        settings.setHelpText('A stupid test module')
+
+        self.optionsHolder = Options.PyOptionsHolder()
+
+        options.addOption(self.optionsHolder.selectionOption('sel').required())
+        options.addOption(self.optionsHolder.fileNameOption('file').defaultBasename('test').description('filename from python to rule them all').outputFile().required().filetype(Options.eftGenericData))
+        settings.setFlag(TrajectoryAnalysis.TrajectoryAnalysisSettings.efRequireTop)
+
+        self.angle = TrajectoryAnalysis.AngleInfo.create()
+
+        print('python: inited')
+
+    def getBatch(self):
+        print('python: getBatch')
+        return [self.angle]
+
+    def getArgv(self, i):
+        print('python: getArgv')
+        if i == 0:
+            #First element of list should be module name -- gets discarded by parser anyway
+            return ["gangle", "-group1", "Backbone", "-oav", "angles.xvg"]
+
+    def initAnalysis(self, settings, top):
+        print('python: initAnalysis')
+        print('There are {} atoms'.format(top.topology().atoms.nr))
+        print('Topology name: {}'.format(top.topology().name))
+
+        #Tell GROMACS to keep last frame in storage, required in analyzeFrame()
+        self.angle.datasetFromIndex(1).requestStorage(1)
+
+    def analyzeFrame(self, frnr, frame, pbc, data):
+        sel = self.optionsHolder['sel']
+
+        dataset = self.angle.datasetFromIndex(1)
+
+        print('frame =', frnr, ', columnCount =', dataset.columnCount(), ', y =', dataset.getDataFrame(frnr).y(0))
+
+    def finishAnalysis(self, nframes):
+        print('python: Analyzed {} frames'.format(nframes))
+
+    def writeOutput(self):
+        print('python: writeOutput')
+        print('file = {}'.format(self.optionsHolder['file']))
+
+        fo = open(self.optionsHolder['file'], 'w')
+        fo.write('Test output\n')
+
+TrajectoryAnalysis.runAsMain(M(), sys.argv)