From: Alexey Shvetsov Date: Mon, 27 Jul 2015 18:53:14 +0000 (+0300) Subject: Merge branch 'master' into pygromacs X-Git-Url: http://biod.pnpi.spb.ru/gitweb/?a=commitdiff_plain;h=87823c5ebe2ecab05a07cfdfd5165e53cb07c30d;hp=ac65de032cce28672cb4e14cd9d83d853855a43a;p=alexxy%2Fgromacs.git Merge branch 'master' into pygromacs --- diff --git a/.gitattributes b/.gitattributes index 1f069f1777..86fb3cf8ea 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt index c6a2cf3e38..014b349800 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 index 0000000000..f14142f186 --- /dev/null +++ b/cmake/FindNumPy.cmake @@ -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 index 0000000000..975cb8e31b --- /dev/null +++ b/cmake/FindPythonLibrary.cmake @@ -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 +# Copyright (c) 2012, Luca Beltrame +# 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 index 0000000000..d6090a3d1d --- /dev/null +++ b/cmake/FindSIP.cmake @@ -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 +# 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 index 0000000000..5e35d9f087 --- /dev/null +++ b/cmake/FindSIP.py @@ -0,0 +1,16 @@ +# FindSIP.py +# +# Copyright (c) 2007, Simon Edwards +# 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 index 0000000000..e7cc17ee6f --- /dev/null +++ b/cmake/PythonCompile.py @@ -0,0 +1,5 @@ +# By Simon Edwards +# 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 index 0000000000..3a40095245 --- /dev/null +++ b/cmake/PythonMacros.cmake @@ -0,0 +1,83 @@ +# Python macros +# ~~~~~~~~~~~~~ +# Copyright (c) 2007, Simon Edwards +# Copyright (c) 2012, Luca Beltrame +# Copyright (c) 2012, Rolf Eike Beer +# +# 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 index 0000000000..a3ba6a60b5 --- /dev/null +++ b/cmake/SIPMacros.cmake @@ -0,0 +1,125 @@ +# Macros for SIP +# ~~~~~~~~~~~~~~ +# Copyright (c) 2007, Simon Edwards +# 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) + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a66a6897d0..ce214fc4a3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -71,3 +71,7 @@ add_subdirectory(programs) if (NOT GMX_FAHCORE) add_subdirectory(contrib) endif() + +if (GMX_PYTHON_BINDINGS) + add_subdirectory(python) +endif() diff --git a/src/gromacs/trajectoryanalysis/analysismodule.h b/src/gromacs/trajectoryanalysis/analysismodule.h index 8553342b4c..d91b0daa3c 100644 --- a/src/gromacs/trajectoryanalysis/analysismodule.h +++ b/src/gromacs/trajectoryanalysis/analysismodule.h @@ -388,6 +388,11 @@ class TrajectoryAnalysisModule */ virtual void writeOutput() = 0; + typedef std::vector Batch; + virtual const Batch getBatch() { return Batch(); } + + virtual const std::vector getArgv(int) { return std::vector(); } + /*! \brief * Returns the name of the analysis module. * diff --git a/src/gromacs/trajectoryanalysis/cmdlinerunner.cpp b/src/gromacs/trajectoryanalysis/cmdlinerunner.cpp index 056d3ac5ef..6a8ebfef9d 100644 --- a/src/gromacs/trajectoryanalysis/cmdlinerunner.cpp +++ b/src/gromacs/trajectoryanalysis/cmdlinerunner.cpp @@ -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 batchSelections; + std::vector 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 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 batchOptions; + std::vector 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( diff --git a/src/gromacs/trajectoryanalysis/cmdlinerunner.h b/src/gromacs/trajectoryanalysis/cmdlinerunner.h index c99a0a80f0..9bcc013418 100644 --- a/src/gromacs/trajectoryanalysis/cmdlinerunner.h +++ b/src/gromacs/trajectoryanalysis/cmdlinerunner.h @@ -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; diff --git a/src/gromacs/trajectoryanalysis/runnercommon.cpp b/src/gromacs/trajectoryanalysis/runnercommon.cpp index 4483a2949d..3543018b92 100644 --- a/src/gromacs/trajectoryanalysis/runnercommon.cpp +++ b/src/gromacs/trajectoryanalysis/runnercommon.cpp @@ -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 index 0000000000..d2f779eb45 --- /dev/null +++ b/src/python/CMakeLists.txt @@ -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 index 0000000000..e69de29bb2 diff --git a/src/python/include/numpy_conv.h b/src/python/include/numpy_conv.h new file mode 100644 index 0000000000..b810832b05 --- /dev/null +++ b/src/python/include/numpy_conv.h @@ -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 +#include + +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 index 0000000000..8e2124453b --- /dev/null +++ b/src/python/pipeline_test.py @@ -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 index 0000000000..e69de29bb2 diff --git a/src/python/runner/pipeline.py b/src/python/runner/pipeline.py new file mode 100644 index 0000000000..2ea912df68 --- /dev/null +++ b/src/python/runner/pipeline.py @@ -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 index 0000000000..e06e1da296 --- /dev/null +++ b/src/python/sip/definitions.sip @@ -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 +%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 index 0000000000..348af77f8a --- /dev/null +++ b/src/python/sip/options/Options.sip @@ -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 index 0000000000..df74dfcbe2 --- /dev/null +++ b/src/python/sip/options/abstractoption.sip @@ -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 +using gmx::AbstractOption; +%End +}; + +template class OptionTemplate : AbstractOption /NoDefaultCtors/ { +%TypeHeaderCode +#include +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 index 0000000000..d69697b5d3 --- /dev/null +++ b/src/python/sip/options/basicoptions.sip @@ -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 DoubleOptionTemplate; +typedef gmx::OptionTemplate IntegerOptionTemplate; +typedef gmx::OptionTemplate StringOptionTemplate; +typedef gmx::OptionTemplate BooleanOptionTemplate; +%End + +class std::string; +typedef OptionTemplate DoubleOptionTemplate; +typedef OptionTemplate IntegerOptionTemplate; +typedef OptionTemplate StringOptionTemplate; +typedef OptionTemplate 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 index 0000000000..c3a76ab8d0 --- /dev/null +++ b/src/python/sip/options/filenameoption.sip @@ -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 FileNameOptionTemplate; +using namespace gmx; // needed for compilation of enum +%End + +typedef OptionTemplate 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 index 0000000000..077ac6536c --- /dev/null +++ b/src/python/sip/options/options.sip @@ -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 +using gmx::IOptionManager; +%End + +protected: + virtual ~IOptionManager(); +}; + +class Options { +%TypeHeaderCode + +#include +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 index 0000000000..0f775761d2 --- /dev/null +++ b/src/python/sip/options/pyoptionsholder.sip @@ -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 +#include "gromacs/options/basicoptions.h" +#include "gromacs/options/filenameoption.h" +#include "gromacs/selection/selectionoption.h" +#include +#include + +class PyOptionsHolder { +public: + class DuplicateOption : public std::exception { + public: + virtual const char* what() const throw(); + }; + class StringList { + public: + StringList(const std::vector*); + StringList(const std::string*, size_t); + const char* operator[] (size_t); + private: + const std::string *list; + size_t size; + const std::vector *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 storage; + template U createStorage(const char*, const char*, int, const T* = 0); + template PyObject* buildValue(const char*, const option_value&, const sipTypeDef* = NULL, size_t = 0); + template 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 *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 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 *store = new std::vector(); + 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(name, "d", count, def); + + return option; +} + +gmx::IntegerOption PyOptionsHolder::integerOption(const char *name, size_t count, int *def) { + gmx::IntegerOption option = createStorage(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(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(name, "S", count); + + return option; +} + +gmx::FileNameOption PyOptionsHolder::fileNameOption(const char *name, size_t count) { + gmx::FileNameOption option = createStorage(name, "f", count); + + return option; +} + +template 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*) 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("d", v); + break; + case 'i': // int + return buildValue("i", v); + break; + case 'A': // std::string + case 'f': // FileNameOption + if (v.vector) + return sipConvertFromType(new PyOptionsHolder::StringList(((std::vector*) 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(NULL, v, sipType_Selection, sizeof(gmx::Selection)); + break; + } + + GMX_ASSERT(false, "Some type is not handled in PyOptionsHolder.get_value"); + return NULL; +} + +template void PyOptionsHolder::deleteStorage(const PyOptionsHolder::option_value &value) { + if (value.vector) + delete (std::vector *) value.value; + else + delete[] (T*) value.value; + + delete value.count; +} + +PyOptionsHolder::~PyOptionsHolder() { + for (std::map::iterator it = storage.begin(); it != storage.end(); it++) + switch (*(it->second.type)) { + case 'd': // double + deleteStorage(it->second); + break; + case 'i': // int + deleteStorage(it->second); + break; + case 'A': // std::string + case 'f': // FileNameOption (the storage type is still std::string) + deleteStorage(it->second); + break; + case 'b': // bool + delete (bool*) it->second.value; + break; + case 'S': // Selection + deleteStorage(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 index 0000000000..fad72544e2 --- /dev/null +++ b/src/python/sip/options/selectionoption.sip @@ -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 SelectionOptionTemplate; +%End + +typedef OptionTemplate 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 index 0000000000..68592fbc49 --- /dev/null +++ b/src/python/sip/selection/Selection.sip @@ -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 index 0000000000..cbcc95aebc --- /dev/null +++ b/src/python/sip/selection/selection.sip @@ -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 index 0000000000..f9a0326001 --- /dev/null +++ b/src/python/sip/string.sip @@ -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 +%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 index 0000000000..9c57b4d44d --- /dev/null +++ b/src/python/sip/topology/Topology.sip @@ -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 index 0000000000..752ccb48a7 --- /dev/null +++ b/src/python/sip/topology/atoms.sip @@ -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 +%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 +%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 +%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 +%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 +// 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 index 0000000000..665fa3eb41 --- /dev/null +++ b/src/python/sip/topology/pstringlistwrapper.sip @@ -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 index 0000000000..1ce94d4f33 --- /dev/null +++ b/src/python/sip/topology/topology.sip @@ -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 +%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 index 0000000000..94c9a901e2 --- /dev/null +++ b/src/python/sip/trajectoryanalysis/TrajectoryAnalysis.sip @@ -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(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 index 0000000000..5eb1effcba --- /dev/null +++ b/src/python/sip/trajectoryanalysis/analysisdata.sip @@ -0,0 +1,64 @@ + +class AbstractAnalysisData /NoDefaultCtors/ { +%TypeHeaderCode +#include +%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 +%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 +%End +public: + bool isValid() const; + int index() const; + double x() const; + double dx() const; +}; + +class AnalysisDataPointSetRef /NoDefaultCtors/ { +%TypeHeaderCode +#include +%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& 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 index 0000000000..a10cafface --- /dev/null +++ b/src/python/sip/trajectoryanalysis/analysismodule.sip @@ -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 +#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 +#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 +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 +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 getBatch(); + virtual const std::vector getArgv(int); + const char* name() const; + const char* description() const; + int datasetCount() const; +// const std::vector 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 +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 index 0000000000..3e29c100c1 --- /dev/null +++ b/src/python/sip/trajectoryanalysis/analysissettings.sip @@ -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 +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 +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 index 0000000000..f724ef1f20 --- /dev/null +++ b/src/python/sip/trajectoryanalysis/modules.sip @@ -0,0 +1,117 @@ + +template class shared_ptr /NoDefaultCtors/ { +%TypeHeaderCode +#include +using namespace boost; +%End +}; + +typedef shared_ptr TrajectoryAnalysisModulePointer; + +template +%MappedType py_shared_ptr /NoRelease/ { +%TypeHeaderCode +#include +template using py_shared_ptr = boost::shared_ptr; +%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 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 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 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 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 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 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 create() /Factory/; +}; diff --git a/src/python/sip/vector.sip b/src/python/sip/vector.sip new file mode 100644 index 0000000000..f19846e88b --- /dev/null +++ b/src/python/sip/vector.sip @@ -0,0 +1,423 @@ +// SIP support for std::vector +// by Giovanni Bajo 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 +%MappedType std::vector +{ +%TypeHeaderCode +#include +%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 *V = new std::vector(); + + 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( + 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 +// **************************************************** + +%MappedType std::vector +{ +%TypeHeaderCode +#include +%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 *V = new std::vector(); + 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(str)); + + Py_DECREF(item); + } + + Py_DECREF(iterator); + + if (*sipIsErr) + { + delete V; + return 0; + } + } + + *sipCppPtr = V; + return sipGetState(sipTransferObj); +%End +}; + +/* +// **************************************************** +// Specialization for std::vector +// **************************************************** + +%MappedType std::vector +{ +%TypeHeaderCode +#include +%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 *V = new std::vector(); + 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 +// **************************************************** + +%MappedType std::vector +{ +%TypeHeaderCode +#include +%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 *V = new std::vector(); + 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 +// **************************************************** + +%MappedType std::vector +{ +%TypeHeaderCode +#include +%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 *V = new std::vector(); + 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 index 0000000000..67e6ecc48a --- /dev/null +++ b/src/python/test.py @@ -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)