Sunbeam will be compiled with setuptools.
setup.py moved to python/python. moved python tests to python/python. added __init__.py under python/tests. added 'test_' before all python test names. test_ prefix added to tests. setup.py and python tests moved back to python base. setuptools executes from root python. python: tests run from root python w/ setup.py. python tests: temp reduced to test_deck only. python setup.py: manually linked opmcommon. setup.py: linked ecl. setup.py linked boost_filesystem. setup.py: linked boost_regex. python all tests run. removec usr/local from setup.py ext_module. cmake make copies entire python dir to build. setup.py can execute from build. setup.py executes from build/python. python tests run under setup.py. setup.py library_dirs and include-dirs set by cmake command. removed cmake files from sunbeam. sunbeam: added code for install. setup.py: removed 'import ecl'. python/src -> python->src_sunbeam. setup.py: discontinued use of glob, all files listed instead. build-opm_module.sh: added prefix_path to opm. build-opm-module.sh: changed spell error for EXTRA_MODULE_FLAGS[opm-common]. setup.py: infer include directories from cmake target CMakeLists.txt: under python: align install statement. CMakeLists build python: removed find_package. src_sunbeam -> cxx. setup.py: test_suite as string. setup.py: tests_suite -> test_suite. setup.py: added exception if 'build_ext' not used. temporarily moved files to python/sunbeam.
This commit is contained in:
parent
b55e073182
commit
c208a59597
4
.gitignore
vendored
4
.gitignore
vendored
@ -69,3 +69,7 @@ install
|
||||
|
||||
# emacs directory setting:
|
||||
.dir-locals.el
|
||||
|
||||
*.pyc
|
||||
*.eggs
|
||||
*.egg-info
|
||||
|
@ -211,8 +211,46 @@ install(DIRECTORY cmake DESTINATION share/opm)
|
||||
install(FILES etc/opm_bash_completion.sh.in DESTINATION share/opm/etc)
|
||||
|
||||
if (OPM_ENABLE_PYTHON)
|
||||
|
||||
if (EXISTS "/etc/debian_version")
|
||||
set( PYTHON_PACKAGE_PATH "dist-packages")
|
||||
else()
|
||||
set( PYTHON_PACKAGE_PATH "site-packages")
|
||||
endif()
|
||||
set(PYTHON_INSTALL_PREFIX "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/${PYTHON_PACKAGE_PATH}/sunbeam" CACHE STRING "Subdirectory to install Python modules in")
|
||||
|
||||
add_custom_target(sunbeam ALL)
|
||||
add_dependencies(sunbeam opmcommon)
|
||||
add_custom_command(TARGET sunbeam PRE_BUILD COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/python/ ${CMAKE_BINARY_DIR}/python)
|
||||
|
||||
get_target_property(_ecl_include_dirs ecl INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_target_property(_opmcommon_include_dirs opmcommon INCLUDE_DIRECTORIES)
|
||||
list(APPEND _opmcommon_include_dirs ${_ecl_include_dirs})
|
||||
string(REPLACE ";" ":" _setup_include_dirs "${_opmcommon_include_dirs}")
|
||||
|
||||
get_target_property(_ecl_lib ecl LOCATION)
|
||||
get_filename_component(_ecl_lib_dir ${_ecl_lib} DIRECTORY)
|
||||
set(_opmcommon_lib_dirs ${_ecl_lib_dir} ${CMAKE_BINARY_DIR}/lib ${CMAKE_PREFIX_PATH}/lib)
|
||||
string(REPLACE ";" ":" _setup_lib_dirs "${_opmcommon_lib_dirs}")
|
||||
|
||||
|
||||
add_custom_command(TARGET sunbeam PRE_BUILD COMMAND python ${CMAKE_BINARY_DIR}/python/setup.py
|
||||
build
|
||||
build_ext
|
||||
--build-lib=${CMAKE_BINARY_DIR}/python/python/sunbeam
|
||||
--library-dirs=${_setup_lib_dirs}
|
||||
--include-dirs=${_setup_include_dirs}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/python
|
||||
)
|
||||
|
||||
INSTALL( DIRECTORY ${CMAKE_BINARY_DIR}/python/python/sunbeam/ DESTINATION ${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX})
|
||||
|
||||
add_test(NAME python_tests
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/python
|
||||
COMMAND python setup.py build_ext --dry-run --build-lib ${CMAKE_BINARY_DIR}/python/python/sunbeam test
|
||||
)
|
||||
|
||||
set_target_properties(opmcommon PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
add_subdirectory(python)
|
||||
endif()
|
||||
|
||||
|
||||
|
@ -4,7 +4,7 @@ declare -A configurations
|
||||
|
||||
declare -A EXTRA_MODULE_FLAGS
|
||||
EXTRA_MODULE_FLAGS[opm-simulators]="-DBUILD_EBOS_EXTENSIONS=ON -DBUILD_EBOS_DEBUG_EXTENSIONS=ON"
|
||||
EXTRA_MODULE_FLAGS[opm-common]="-DOPM_ENABLE_PYTHON=ON"
|
||||
EXTRA_MODULE_FLAGS[opm-common]="-DOPM_ENABLE_PYTHON=ON -DOPM_PREFIX_PATH=$WORKSPACE/$configuration/install"
|
||||
EXTRA_MODULE_FLAGS[libecl]="-DCMAKE_POSITION_INDEPENDENT_CODE=1"
|
||||
|
||||
# Parse revisions from trigger comment and setup arrays
|
||||
|
@ -1,20 +0,0 @@
|
||||
|
||||
find_package(PythonInterp REQUIRED)
|
||||
|
||||
set( CMAKE_CXX_FLAGS "-std=c++11" )
|
||||
|
||||
set( PYTHON_DIR ${CMAKE_SOURCE_DIR}/python )
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/python/pycmake)
|
||||
|
||||
option( USE_RPATH "Embed RPATH in libraries and binaries" OFF)
|
||||
if (USE_RPATH)
|
||||
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
endif ()
|
||||
|
||||
add_subdirectory( pybind11 )
|
||||
add_subdirectory( python )
|
||||
add_subdirectory( sunbeam )
|
||||
add_subdirectory( tests )
|
||||
|
24
python/cxx/group.cpp
Normal file
24
python/cxx/group.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Group/Group.hpp>
|
||||
#include <pybind11/stl.h>
|
||||
#include "sunbeam.hpp"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
const std::set<std::string> wellnames( const Group& g, size_t timestep ) {
|
||||
return g.getWells( timestep );
|
||||
}
|
||||
|
||||
int get_vfp_table_nr( const Group& g, size_t timestep ) {
|
||||
return g.getGroupNetVFPTable(timestep);
|
||||
}
|
||||
}
|
||||
|
||||
void sunbeam::export_Group(py::module& module) {
|
||||
|
||||
py::class_< Group >( module, "Group")
|
||||
.def_property_readonly( "name", &Group::name)
|
||||
.def( "_vfp_table_nr", &get_vfp_table_nr )
|
||||
.def( "_wellnames", &wellnames );
|
||||
|
||||
}
|
26
python/cxx/group_tree.cpp
Normal file
26
python/cxx/group_tree.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Group/GroupTree.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
|
||||
#include "sunbeam.hpp"
|
||||
#include "converters.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
std::string parent( const GroupTree& gt, const std::string& name ) {
|
||||
return gt.parent(name);
|
||||
}
|
||||
|
||||
py::list children( const GroupTree& gt, const std::string& name ) {
|
||||
return iterable_to_pylist(gt.children(name)) ;
|
||||
}
|
||||
}
|
||||
|
||||
void sunbeam::export_GroupTree(py::module& module) {
|
||||
|
||||
py::class_< GroupTree >(module, "GroupTree")
|
||||
|
||||
.def( "_parent", &parent, "parent function returning parent of a group")
|
||||
.def( "_children", &children, "children function returning python"
|
||||
" list containing children of a group")
|
||||
;
|
||||
}
|
106
python/cxx/schedule.cpp
Normal file
106
python/cxx/schedule.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
|
||||
|
||||
#include <pybind11/stl.h>
|
||||
#include <pybind11/chrono.h>
|
||||
#include "sunbeam.hpp"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
using system_clock = std::chrono::system_clock;
|
||||
|
||||
|
||||
/*
|
||||
timezones - the stuff that make you wonder why didn't do social science in
|
||||
university. The situation here is as follows:
|
||||
|
||||
1. In the C++ code Eclipse style string literals like "20. NOV 2017" are
|
||||
converted to time_t values using the utc based function timegm() which
|
||||
does not take timezones into account.
|
||||
|
||||
2. Here we use the function gmtime( ) to convert back from a time_t value
|
||||
to a broken down struct tm representation.
|
||||
|
||||
3. The broken down representation is then converted to a time_t value
|
||||
using the timezone aware function mktime().
|
||||
|
||||
4. The time_t value is converted to a std::chrono::system_clock value.
|
||||
|
||||
Finally std::chrono::system_clock value is automatically converted to a
|
||||
python datetime object as part of the pybind11 process. This latter
|
||||
conversion *is* timezone aware, that is the reason we must go through
|
||||
these hoops.
|
||||
*/
|
||||
system_clock::time_point datetime( std::time_t utc_time) {
|
||||
struct tm utc_tm;
|
||||
time_t local_time;
|
||||
|
||||
gmtime_r(&utc_time, &utc_tm);
|
||||
local_time = mktime(&utc_tm);
|
||||
|
||||
return system_clock::from_time_t(local_time);
|
||||
}
|
||||
|
||||
const Well2& get_well( const Schedule& sch, const std::string& name, const size_t& timestep ) try {
|
||||
return sch.getWell2( name, timestep );
|
||||
} catch( const std::invalid_argument& e ) {
|
||||
throw py::key_error( name );
|
||||
}
|
||||
|
||||
const GroupTree& get_grouptree ( const Schedule& sch, const size_t& timestep) {
|
||||
return sch.getGroupTree(timestep);
|
||||
}
|
||||
system_clock::time_point get_start_time( const Schedule& s ) {
|
||||
return datetime(s.posixStartTime());
|
||||
}
|
||||
|
||||
system_clock::time_point get_end_time( const Schedule& s ) {
|
||||
return datetime(s.posixEndTime());
|
||||
}
|
||||
|
||||
std::vector<system_clock::time_point> get_timesteps( const Schedule& s ) {
|
||||
const auto& tm = s.getTimeMap();
|
||||
std::vector< system_clock::time_point > v;
|
||||
v.reserve( tm.size() );
|
||||
|
||||
for( size_t i = 0; i < tm.size(); ++i )
|
||||
v.push_back( datetime( tm[ i ] ));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
std::vector<Group> get_groups( const Schedule& sch ) {
|
||||
std::vector< Group > groups;
|
||||
for( const auto& group_name : sch.groupNames())
|
||||
groups.push_back( sch.getGroup(group_name) );
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
bool has_well( const Schedule& sch, const std::string& wellName) {
|
||||
return sch.hasWell( wellName );
|
||||
}
|
||||
|
||||
const Group& get_group(const Schedule& sch, const std::string group_name) {
|
||||
return sch.getGroup(group_name);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void sunbeam::export_Schedule(py::module& module) {
|
||||
|
||||
py::class_< Schedule >( module, "Schedule")
|
||||
.def_property_readonly( "_groups", &get_groups )
|
||||
.def_property_readonly( "start", &get_start_time )
|
||||
.def_property_readonly( "end", &get_end_time )
|
||||
.def_property_readonly( "timesteps", &get_timesteps )
|
||||
.def( "_get_wells", &Schedule::getWells2)
|
||||
.def("_getwell", &get_well)
|
||||
.def( "__contains__", &has_well )
|
||||
.def( "_group", &get_group, ref_internal)
|
||||
.def( "_group_tree", &get_grouptree, ref_internal);
|
||||
|
||||
}
|
@ -1,168 +0,0 @@
|
||||
# Copyright (C) 2016 Statoil ASA, Norway.
|
||||
#
|
||||
# This file is part of ERT - Ensemble based Reservoir Tool.
|
||||
#
|
||||
# ERT is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# ERT is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details
|
||||
|
||||
|
||||
|
||||
# The basic assumption of this package is PEP 396 -- Module Version Numbers as
|
||||
# layed out in https://www.python.org/dev/peps/pep-0396/
|
||||
|
||||
# Unfortunately, not all Python modules expose a version number, like inspect.
|
||||
# Other Python modules expose several version numbers, e.g. one for the
|
||||
# underlying software and one for the python packaging, like SQLite and PyQt.
|
||||
|
||||
cmake_minimum_required (VERSION 2.8.1)
|
||||
|
||||
|
||||
|
||||
# try import python module, if success, check its version, store as PY_module.
|
||||
# the module is imported as-is, hence the case (e.g. PyQt4) must be correct.
|
||||
#
|
||||
# if given a second argument, the accessor, we call accessor on the module
|
||||
# instead of the default __version__.
|
||||
#
|
||||
# (Yes, accessor could potentially be a function like "os.delete_everything()".)
|
||||
macro(python_module_version module)
|
||||
set(PY_VERSION_ACCESSOR "__version__")
|
||||
set(PY_module_name ${module})
|
||||
|
||||
if(${PY_module_name} STREQUAL "PyQt4")
|
||||
set(PY_module_name "PyQt4.Qt")
|
||||
endif()
|
||||
if(${PY_module_name} STREQUAL "PyQt4.Qt")
|
||||
set(PY_VERSION_ACCESSOR "PYQT_VERSION_STR")
|
||||
endif()
|
||||
|
||||
if(${PY_module_name} STREQUAL "serial")
|
||||
set(PY_VERSION_ACCESSOR "VERSION")
|
||||
endif()
|
||||
|
||||
if(${PY_module_name} STREQUAL "sqlite")
|
||||
set(PY_VERSION_ACCESSOR "version")
|
||||
endif()
|
||||
|
||||
|
||||
# ARGUMENTS: module accessor
|
||||
set (extra_macro_args ${ARGN})
|
||||
list(LENGTH extra_macro_args num_extra_args)
|
||||
if (${num_extra_args} GREATER 0)
|
||||
list(GET extra_macro_args 0 accessor)
|
||||
set(PY_VERSION_ACCESSOR ${accessor})
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c"
|
||||
"# set module's version to py_mv and print it
|
||||
import ${PY_module_name} as py_m
|
||||
py_mv = '0.0.0' # output if no accessor is found
|
||||
if hasattr(py_m, '${PY_VERSION_ACCESSOR}'):
|
||||
py_mv = py_m.${PY_VERSION_ACCESSOR}
|
||||
print(py_mv)
|
||||
"
|
||||
RESULT_VARIABLE _${module}_fail # error code 0 if module is importable
|
||||
OUTPUT_VARIABLE _${module}_version # module.accessor or "0.0.0" if no such
|
||||
ERROR_VARIABLE stderr_output
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT _${module}_fail)
|
||||
set(PY_${module} ${_${module}_version})
|
||||
endif()
|
||||
|
||||
# clean up
|
||||
unset(PY_VERSION_ACCESSOR)
|
||||
unset(PY_module_name)
|
||||
unset(extra_macro_args)
|
||||
endmacro()
|
||||
|
||||
|
||||
|
||||
# If we find the correct module and new enough version, set PY_package, where
|
||||
# "package" is the given argument to the version we found else, display warning
|
||||
# and do not set any variables.
|
||||
macro(python_module package)
|
||||
|
||||
# ARGUMENTS: package package_req module_version version_req accessor
|
||||
set (extra_macro_args ${ARGN})
|
||||
# Did we get any optional args?
|
||||
list(LENGTH extra_macro_args num_extra_args)
|
||||
if (${num_extra_args} GREATER 0)
|
||||
list(GET extra_macro_args 0 package_req)
|
||||
else()
|
||||
set(package_req "REQUIRED") # requirement not set, is required
|
||||
endif ()
|
||||
if (${num_extra_args} GREATER 1)
|
||||
list(GET extra_macro_args 1 module_version)
|
||||
else()
|
||||
set(module_version "0.0.0") # module_version not set, 0.0.0 is ok
|
||||
endif ()
|
||||
if (${num_extra_args} GREATER 2)
|
||||
list(GET extra_macro_args 2 version_req)
|
||||
else()
|
||||
set(version_req "MINIMUM") # version requirement not set, is minimum
|
||||
endif ()
|
||||
if (${num_extra_args} GREATER 3)
|
||||
list(GET extra_macro_args 3 accessor)
|
||||
endif ()
|
||||
|
||||
# Setting warning/error output level
|
||||
set(PY_MSG_ERR SEND_ERROR)
|
||||
set(PY_MSG_WARN WARNING)
|
||||
if(${package_req} STREQUAL "QUIET")
|
||||
set(PY_MSG_ERR STATUS)
|
||||
set(PY_MSG_WARN STATUS)
|
||||
endif()
|
||||
|
||||
# We are done expanding the optional arguments
|
||||
|
||||
python_module_version(${package} ${accessor})
|
||||
|
||||
# package not found in system
|
||||
if(NOT DEFINED PY_${package})
|
||||
if(${package_req} STREQUAL "OPTIONAL")
|
||||
message(${PY_MSG_WARN} "Could not find Python module " ${package})
|
||||
else()
|
||||
message(${PY_MSG_ERR} "Could not find Python module " ${package})
|
||||
endif()
|
||||
|
||||
else()
|
||||
# package found in system
|
||||
|
||||
if (${version_req} STREQUAL "EXACT" AND NOT ${PY_${package}} VERSION_EQUAL ${module_version})
|
||||
message(${PY_MSG_ERR} "Python module ${package} not exact. "
|
||||
"Wanted EXACT ${module_version}, found ${PY_${package}}")
|
||||
elseif (${version_req} STREQUAL "OPTIONAL" AND ${PY_${package}} VERSION_LESS ${module_version})
|
||||
message(${PY_MSG_WARN} "Python module ${package} too old. "
|
||||
"Wanted ${module_version}, found ${PY_${package}}")
|
||||
elseif (${version_req} STREQUAL "MINIMUM" AND ${PY_${package}} VERSION_LESS ${module_version})
|
||||
message(${PY_MSG_ERR} "Python module ${package} too old. "
|
||||
"Wanted MINIMUM ${module_version}, found ${PY_${package}}")
|
||||
else()
|
||||
if(NOT DEFINED accessor)
|
||||
message(STATUS "Found ${package}. "
|
||||
"${PY_${package}} >= ${module_version}")
|
||||
else()
|
||||
message(STATUS "Found ${package}. "
|
||||
"${PY_${package}} >= ${module_version} (" ${accessor} ")")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# clean up
|
||||
unset(package_req)
|
||||
unset(module_version)
|
||||
unset(version_req)
|
||||
unset(accessor)
|
||||
unset(extra_macro_args)
|
||||
set(PY_MSG_ERR)
|
||||
set(PY_MSG_WARN)
|
||||
endmacro()
|
@ -1,93 +0,0 @@
|
||||
# Copyright (C) 2016 Statoil ASA, Norway.
|
||||
#
|
||||
# pymake is free software: you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation, either version 3 of the License, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# pymake is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
# A PARTICULAR PURPOSE.
|
||||
#
|
||||
# See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||
# for more details
|
||||
|
||||
# This module exports the following functions:
|
||||
# * to_path_list(var path)
|
||||
# which takes a list of paths and constructs a valid PYTHONPATH string,
|
||||
# regardless of platform (path1:path2 for unix, path1;path2 for windows)
|
||||
#
|
||||
# * add_python_package(package_name package_path python_files) where
|
||||
# which takes a package name, a path and the series of python files that
|
||||
# makes that package. It exports the cmake target package_${package_name}
|
||||
# in copies all ${python_files} sources to python/${package_path}, and
|
||||
# sets up so you can install with `make install`.
|
||||
#
|
||||
# * add_python_test(testname python_test_file)
|
||||
# which sets up a test target (using pycmake_test_runner.py, distributed
|
||||
# with this module) and registeres it with ctest.
|
||||
#
|
||||
# * add_python_example(example testname test_file [args...])
|
||||
# which sets up an example program which will be run with the arguments
|
||||
# [args...] (can be empty) Useful to make sure some program runs
|
||||
# correctly with the given arguments, and which will report as a unit
|
||||
# test failure.
|
||||
|
||||
configure_file(${CMAKE_CURRENT_LIST_DIR}/pycmake_test_runner.py ${CMAKE_BINARY_DIR}/python/tests/pycmake_test_runner.py COPYONLY)
|
||||
|
||||
function(to_path_list var path1)
|
||||
if("${CMAKE_HOST_SYSTEM}" MATCHES ".*Windows.*")
|
||||
set(sep "\\;")
|
||||
else()
|
||||
set(sep ":")
|
||||
endif()
|
||||
set(result "${path1}") # First element doesn't require separator at all...
|
||||
foreach(path ${ARGN})
|
||||
set(result "${result}${sep}${path}") # .. but other elements do.
|
||||
endforeach()
|
||||
set(${var} "${result}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
if (EXISTS "/etc/debian_version")
|
||||
set( PYTHON_PACKAGE_PATH "dist-packages")
|
||||
else()
|
||||
set( PYTHON_PACKAGE_PATH "site-packages")
|
||||
endif()
|
||||
set(PYTHON_INSTALL_PREFIX "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/${PYTHON_PACKAGE_PATH}" CACHE STRING "Subdirectory to install Python modules in")
|
||||
|
||||
function(add_python_package PACKAGE_NAME PACKAGE_PATH PYTHON_FILES)
|
||||
add_custom_target(package_${PACKAGE_NAME} ALL)
|
||||
|
||||
foreach (file ${PYTHON_FILES})
|
||||
add_custom_command(TARGET package_${PACKAGE_NAME}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/python/${PACKAGE_PATH}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${file} ${CMAKE_BINARY_DIR}/python/${PACKAGE_PATH}
|
||||
)
|
||||
endforeach ()
|
||||
set_target_properties(package_${PACKAGE_NAME} PROPERTIES PACKAGE_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX}/${PACKAGE_PATH})
|
||||
install(FILES ${PYTHON_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX}/${PACKAGE_PATH})
|
||||
endfunction()
|
||||
|
||||
function(add_python_test TESTNAME PYTHON_TEST_FILE arg)
|
||||
configure_file(${PYTHON_TEST_FILE} ${PYTHON_TEST_FILE} COPYONLY)
|
||||
|
||||
add_test(NAME ${TESTNAME}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/python/tests
|
||||
COMMAND python pycmake_test_runner.py ${PYTHON_TEST_FILE} ${arg}
|
||||
)
|
||||
|
||||
to_path_list(pythonpath "${CMAKE_BINARY_DIR}/python" "$ENV{PYTHONPATH}")
|
||||
set_tests_properties(${TESTNAME} PROPERTIES ENVIRONMENT "PYTHONPATH=${pythonpath}")
|
||||
endfunction()
|
||||
|
||||
function(add_python_example TESTNAME PYTHON_TEST_FILE)
|
||||
configure_file(${PYTHON_TEST_FILE} ${PYTHON_TEST_FILE} COPYONLY)
|
||||
|
||||
add_test(NAME ${TESTNAME}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/examples
|
||||
COMMAND python ${PYTHON_TEST_FILE} ${ARGN}
|
||||
)
|
||||
to_path_list(pythonpath "${CMAKE_BINARY_DIR}/python" "$ENV{PYTHONPATH}")
|
||||
set_tests_properties(${TESTNAME} PROPERTIES ENVIRONMENT "PYTHONPATH=${pythonpath}")
|
||||
endfunction()
|
||||
|
@ -1,48 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
import inspect
|
||||
import os
|
||||
import sys
|
||||
|
||||
import imp
|
||||
|
||||
try:
|
||||
from unittest2 import TextTestRunner, TestLoader, TestCase
|
||||
except ImportError:
|
||||
from unittest import TextTestRunner, TestLoader, TestCase
|
||||
|
||||
|
||||
def runTestCase(tests, verbosity=0):
|
||||
test_result = TextTestRunner(verbosity=verbosity).run(tests)
|
||||
|
||||
if len(test_result.errors) or len(test_result.failures):
|
||||
test_result.printErrors()
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def getTestClassFromModule(module_path):
|
||||
test_module = imp.load_source('test', module_path)
|
||||
for name, obj in inspect.getmembers(test_module):
|
||||
if inspect.isclass(obj) and issubclass(obj, TestCase) and not obj == TestCase:
|
||||
return obj
|
||||
|
||||
def getTestsFromModule(module_path):
|
||||
klass = getTestClassFromModule(module_path)
|
||||
if klass is None:
|
||||
raise UserWarning("No tests classes found in: '%s'" % module_path)
|
||||
|
||||
loader = TestLoader()
|
||||
return loader.loadTestsFromTestCase(klass)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_module = sys.argv[1]
|
||||
argv = []
|
||||
|
||||
tests = getTestsFromModule(test_module)
|
||||
|
||||
# Set verbosity to 2 to see which test method in a class that fails.
|
||||
if runTestCase(tests, verbosity=0):
|
||||
sys.exit(0)
|
||||
else:
|
||||
sys.exit(1)
|
@ -1,11 +0,0 @@
|
||||
include( FindPythonModule )
|
||||
include( PythonPackage )
|
||||
|
||||
python_module( inspect OPTIONAL )
|
||||
if (DEFINED PY_inspect)
|
||||
message(STATUS "We have inspect.")
|
||||
else()
|
||||
message(STATUS "We do not have inspect, ignoring ...")
|
||||
endif()
|
||||
|
||||
add_subdirectory( sunbeam )
|
@ -1,12 +0,0 @@
|
||||
set(PYTHON_SOURCES
|
||||
__init__.py
|
||||
sunbeam.py
|
||||
config.py
|
||||
parser.py
|
||||
properties.py
|
||||
schedule.py)
|
||||
|
||||
add_python_package(sunbeam sunbeam "${PYTHON_SOURCES}")
|
||||
|
||||
add_subdirectory(deck)
|
||||
add_subdirectory(tools)
|
@ -1,4 +0,0 @@
|
||||
set(PYTHON_SOURCES
|
||||
__init__.py)
|
||||
|
||||
add_python_package(sunbeam.deck "sunbeam/deck" "${PYTHON_SOURCES}")
|
@ -1,5 +0,0 @@
|
||||
set(PYTHON_SOURCES
|
||||
__init__.py
|
||||
time_vector.py)
|
||||
|
||||
add_python_package("sunbeam.tools" "sunbeam/tools" "${PYTHON_SOURCES}")
|
@ -1,5 +0,0 @@
|
||||
set(PYTHON_SOURCES
|
||||
__init__.py
|
||||
time_vector.py)
|
||||
|
||||
add_python_package("sunbeam.tools" "sunbeam/tools" "${PYTHON_SOURCES}")
|
55
python/setup.py
Normal file
55
python/setup.py
Normal file
@ -0,0 +1,55 @@
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
from setuptools import Extension
|
||||
from setuptools.command.build_ext import build_ext
|
||||
import sys
|
||||
import setuptools
|
||||
|
||||
import glob
|
||||
import os
|
||||
|
||||
if 'build' in sys.argv:
|
||||
if not 'build_ext' in sys.argv:
|
||||
raise TypeError("Missing option 'build_ext'.")
|
||||
|
||||
ext_modules = [
|
||||
Extension(
|
||||
'libsunbeam',
|
||||
[
|
||||
'cxx/connection.cpp',
|
||||
'cxx/deck.cpp',
|
||||
'cxx/deck_keyword.cpp',
|
||||
'cxx/eclipse_3d_properties.cpp',
|
||||
'cxx/eclipse_config.cpp',
|
||||
'cxx/eclipse_grid.cpp',
|
||||
'cxx/eclipse_state.cpp',
|
||||
'cxx/group.cpp',
|
||||
'cxx/group_tree.cpp',
|
||||
'cxx/parser.cpp',
|
||||
'cxx/schedule.cpp',
|
||||
'cxx/sunbeam_state.cpp',
|
||||
'cxx/table_manager.cpp',
|
||||
'cxx/well.cpp',
|
||||
'cxx/sunbeam.cpp'
|
||||
],
|
||||
libraries=['opmcommon', 'boost_filesystem', 'boost_regex', 'ecl'],
|
||||
language='c++',
|
||||
undef_macros=["NDEBUG"],
|
||||
include_dirs=["pybind11/include"]
|
||||
),
|
||||
]
|
||||
|
||||
setup(
|
||||
name='Sunbeam',
|
||||
package_dir = {'': 'python'},
|
||||
packages=[
|
||||
'sunbeam',
|
||||
'sunbeam.tools',
|
||||
'sunbeam.deck',
|
||||
],
|
||||
ext_modules=ext_modules,
|
||||
license='Open Source',
|
||||
zip_safe=False,
|
||||
test_suite='tests',
|
||||
setup_requires=["pytest-runner", 'setuptools_scm'],
|
||||
)
|
@ -1,50 +0,0 @@
|
||||
pybind11_add_module(libsunbeam sunbeam.cpp
|
||||
eclipse_state.cpp
|
||||
deck_keyword.cpp
|
||||
deck.cpp
|
||||
well.cpp
|
||||
sunbeam_state.cpp
|
||||
schedule.cpp
|
||||
connection.cpp
|
||||
eclipse_config.cpp
|
||||
table_manager.cpp
|
||||
eclipse_grid.cpp
|
||||
group.cpp
|
||||
group_tree.cpp
|
||||
eclipse_3d_properties.cpp
|
||||
parser.cpp)
|
||||
|
||||
set_target_properties( libsunbeam PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/python/sunbeam )
|
||||
|
||||
# The cmake config files generated by opm-common are generated in a non standard
|
||||
# way and they are not fully relocatable. This creates problems when we are
|
||||
# building sunbeam towards a opm-common distribution which has been installed
|
||||
# using the DESTDIR option in make install.
|
||||
#
|
||||
# If we subsequently configure sunbeam as:
|
||||
#
|
||||
# bash% cmake .. -DDEST_PREFIX=/path/to/DESTDIR
|
||||
#
|
||||
# There is an extreme scotch-tape-and-chewing-gum solution which just barely
|
||||
# works:
|
||||
#
|
||||
# 1. When evaluating opm-common-config.cmake the DEST_PREFIX variable is
|
||||
# detected and the paths are manually prefixed with DEST_PREFIX.
|
||||
#
|
||||
# 2. Here we link explicitly to the dependenencies of opm-common; i.e. ecl and
|
||||
# three boost libraries insteady linking transitively through the
|
||||
# ${opm-common_LIBRARIES} variable.
|
||||
#
|
||||
# See also the file cmake/Templates/opm-project-config.cmake.in in the
|
||||
# opm-common distribution which this hack depends on.
|
||||
|
||||
if (DEST_PREFIX)
|
||||
find_package(ecl)
|
||||
find_package(Boost REQUIRED COMPONENTS filesystem regex)
|
||||
target_link_libraries(libsunbeam PRIVATE ecl)
|
||||
target_link_libraries(libsunbeam PRIVATE ${Boost_LIBRARIES})
|
||||
target_link_libraries(libsunbeam PRIVATE opmcommon)
|
||||
else()
|
||||
target_link_libraries( libsunbeam PRIVATE opmcommon )
|
||||
endif()
|
||||
install(TARGETS libsunbeam DESTINATION ${PYTHON_INSTALL_PREFIX}/sunbeam)
|
@ -1,14 +0,0 @@
|
||||
configure_file(spe3/SPE3CASE1.DATA spe3/SPE3CASE1.DATA COPYONLY)
|
||||
configure_file(data/CORNERPOINT_ACTNUM.DATA data/CORNERPOINT_ACTNUM.DATA COPYONLY)
|
||||
configure_file(data/JFUNC.DATA data/JFUNC.DATA COPYONLY)
|
||||
configure_file(data/schedule/part1.sch data/schedule/part1.sch COPYONLY)
|
||||
configure_file(data/schedule/part2.sch data/schedule/part2.sch COPYONLY)
|
||||
configure_file(data/schedule/part3.sch data/schedule/part3.sch COPYONLY)
|
||||
configure_file(data/schedule/fragment.sch data/schedule/fragment.sch COPYONLY)
|
||||
configure_file(data/schedule/fragment_dates.sch data/schedule/fragment_dates.sch COPYONLY)
|
||||
configure_file(data/schedule/TEMPLATE.SCH data/schedule/TEMPLATE.SCH COPYONLY)
|
||||
configure_file(utils.py utils.py COPYONLY)
|
||||
|
||||
foreach(prog time_vector connection deck group_tree grupnet parse_deck parse state props schedule wells)
|
||||
add_python_test(${prog} ${prog}.py ${PYTHON_DIR})
|
||||
endforeach()
|
0
python/tests/__init__.py
Normal file
0
python/tests/__init__.py
Normal file
@ -5,7 +5,7 @@ class TestWells(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.sch = sunbeam.parse('spe3/SPE3CASE1.DATA').schedule
|
||||
cls.sch = sunbeam.parse('tests/spe3/SPE3CASE1.DATA').schedule
|
||||
cls.timesteps = cls.sch.timesteps
|
||||
|
||||
def test_connection_pos(self):
|
@ -3,11 +3,9 @@ import unittest
|
||||
|
||||
import sunbeam
|
||||
|
||||
python_dir = sys.argv[2]
|
||||
|
||||
class TestGroupTree(unittest.TestCase):
|
||||
def setUp(self):
|
||||
norne = python_dir + '/examples/data/norne/NORNE_ATW2013.DATA'
|
||||
norne = 'examples/data/norne/NORNE_ATW2013.DATA'
|
||||
self.sch = sunbeam.parse(norne, [('PARSE_RANDOM_SLASH', sunbeam.action.ignore)]).schedule
|
||||
|
||||
def test_group(self):
|
@ -3,12 +3,10 @@ import unittest
|
||||
|
||||
import sunbeam
|
||||
|
||||
python_dir = sys.argv[2]
|
||||
|
||||
class TestGrupnet(unittest.TestCase):
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
norne = python_dir + '/examples/data/norne/NORNE_ATW2013.DATA'
|
||||
norne = 'examples/data/norne/NORNE_ATW2013.DATA'
|
||||
cls.sch = sunbeam.parse(norne, [('PARSE_RANDOM_SLASH', sunbeam.action.ignore)]).schedule
|
||||
|
||||
def test_vfp_table(self):
|
@ -3,8 +3,6 @@ import sunbeam
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
python_dir = sys.argv[2]
|
||||
|
||||
class TestParse(unittest.TestCase):
|
||||
|
||||
REGIONDATA = """
|
||||
@ -31,8 +29,8 @@ FIPNUM
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.spe3fn = 'spe3/SPE3CASE1.DATA'
|
||||
self.norne_fname = os.path.abspath(python_dir + '/examples/data/norne/NORNE_ATW2013.DATA')
|
||||
self.spe3fn = 'tests/spe3/SPE3CASE1.DATA'
|
||||
self.norne_fname = os.path.abspath('examples/data/norne/NORNE_ATW2013.DATA')
|
||||
|
||||
def test_parse(self):
|
||||
spe3 = sunbeam.parse(self.spe3fn)
|
@ -9,7 +9,7 @@ class TestProps(unittest.TestCase):
|
||||
self.assertTrue(diff <= epsilon, msg=err_msg)
|
||||
|
||||
def setUp(self):
|
||||
self.spe3 = sunbeam.parse('spe3/SPE3CASE1.DATA').state
|
||||
self.spe3 = sunbeam.parse('tests/spe3/SPE3CASE1.DATA').state
|
||||
self.props = self.spe3.props()
|
||||
|
||||
def test_repr(self):
|
@ -7,7 +7,7 @@ class TestSchedule(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.sch = sunbeam.parse('spe3/SPE3CASE1.DATA').schedule
|
||||
cls.sch = sunbeam.parse('tests/spe3/SPE3CASE1.DATA').schedule
|
||||
|
||||
def testWells(self):
|
||||
self.assertEqual(2, len(self.sch.get_wells(0)))
|
@ -49,8 +49,8 @@ SATNUM
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.spe3 = sunbeam.parse('spe3/SPE3CASE1.DATA')
|
||||
cpa = sunbeam.parse('data/CORNERPOINT_ACTNUM.DATA')
|
||||
cls.spe3 = sunbeam.parse('tests/spe3/SPE3CASE1.DATA')
|
||||
cpa = sunbeam.parse('tests/data/CORNERPOINT_ACTNUM.DATA')
|
||||
cls.state = cls.spe3.state
|
||||
cls.cp_state = cpa.state
|
||||
|
||||
@ -139,7 +139,7 @@ SATNUM
|
||||
# jf["OIL_WATER"] = 21.0 # set in deck
|
||||
# jf["GAS_OIL"] = -1.0 # N/A
|
||||
|
||||
js = sunbeam.parse('data/JFUNC.DATA').state
|
||||
js = sunbeam.parse('tests/data/JFUNC.DATA').state
|
||||
self.assertEqual('JFUNC TEST', js.title)
|
||||
jf = js.jfunc()
|
||||
print(jf)
|
@ -56,10 +56,10 @@ class TestTimeVector(unittest.TestCase):
|
||||
|
||||
|
||||
def test_load(self):
|
||||
tv = TimeVector(datetime.date(1997, 11, 6), base_file = "data/schedule/part1.sch")
|
||||
tv.load("data/schedule/part3.sch")
|
||||
tv.load("data/schedule/fragment_dates.sch")
|
||||
tv.load("data/schedule/part2.sch")
|
||||
tv = TimeVector(datetime.date(1997, 11, 6), base_file = "tests/data/schedule/part1.sch")
|
||||
tv.load("tests/data/schedule/part3.sch")
|
||||
tv.load("tests/data/schedule/fragment_dates.sch")
|
||||
tv.load("tests/data/schedule/part2.sch")
|
||||
|
||||
self.assertEqual(tv.dates, [datetime.datetime(1997, 11, 6),
|
||||
datetime.datetime(1997, 11, 14),
|
||||
@ -79,9 +79,9 @@ class TestTimeVector(unittest.TestCase):
|
||||
datetime.datetime(1998, 8, 1)])
|
||||
|
||||
def test_str(self):
|
||||
tv = TimeVector(datetime.date(1997, 11, 6), base_string = open("data/schedule/part1.sch").read())
|
||||
tv.load("data/schedule/part3.sch")
|
||||
tv.load("data/schedule/part2.sch")
|
||||
tv = TimeVector(datetime.date(1997, 11, 6), base_string = open("tests/data/schedule/part1.sch").read())
|
||||
tv.load("tests/data/schedule/part3.sch")
|
||||
tv.load("tests/data/schedule/part2.sch")
|
||||
|
||||
s = str(tv)
|
||||
tv2 = TimeVector(datetime.date(1997, 11, 6))
|
||||
@ -92,17 +92,17 @@ class TestTimeVector(unittest.TestCase):
|
||||
|
||||
|
||||
def test_optional(self):
|
||||
tv = TimeVector(datetime.date(1997, 11, 6), base_file = "data/schedule/part1.sch")
|
||||
tv = TimeVector(datetime.date(1997, 11, 6), base_file = "tests/data/schedule/part1.sch")
|
||||
|
||||
# Must have a starting date, either as first keyword in loaded file,
|
||||
# or alternatively as the optional date argument.
|
||||
with self.assertRaises(ValueError):
|
||||
tv.load("data/schedule/fragment.sch")
|
||||
tv.load("tests/data/schedule/fragment.sch")
|
||||
|
||||
with self.assertRaises(ValueError):
|
||||
tv.load("data/schedule/fragment_dates.sch", date = datetime.datetime(1998, 1,1))
|
||||
tv.load("tests/data/schedule/fragment_dates.sch", date = datetime.datetime(1998, 1,1))
|
||||
|
||||
tv.load("data/schedule/fragment.sch", date = datetime.datetime(1998, 1, 10))
|
||||
tv.load("tests/data/schedule/fragment.sch", date = datetime.datetime(1998, 1, 10))
|
||||
ts = tv[-1]
|
||||
self.assertEqual(ts.dt, datetime.datetime(1998, 1 , 10))
|
||||
self.assertEqual(ts.keywords[0].name, "WCONINJE")
|
||||
@ -111,14 +111,14 @@ class TestTimeVector(unittest.TestCase):
|
||||
|
||||
def test_user_test(self):
|
||||
tv=TimeVector(datetime.date(1999,12,31))
|
||||
tv.load('data/schedule/TEMPLATE.SCH', date=datetime.datetime(1999,12,31))
|
||||
tv.load('tests/data/schedule/TEMPLATE.SCH', date=datetime.datetime(1999,12,31))
|
||||
self.assertListEqual(tv.dates, [datetime.datetime(1999,12,31),
|
||||
datetime.datetime(2000,1,1),
|
||||
datetime.datetime(2000,2,1),
|
||||
datetime.datetime(2000,3,1)])
|
||||
|
||||
def test_no_leading_DATES(self):
|
||||
tv = TimeVector(datetime.date(1997, 11, 6), base_file="data/schedule/part1.sch")
|
||||
tv = TimeVector(datetime.date(1997, 11, 6), base_file="tests/data/schedule/part1.sch")
|
||||
s = str(tv)
|
||||
d = sunbeam.deck.parse_string(s)
|
||||
kw0 = d[0]
|
||||
@ -128,7 +128,7 @@ class TestTimeVector(unittest.TestCase):
|
||||
self.assertEqual("", str(tv2))
|
||||
|
||||
def test_drop_dates(self):
|
||||
tv = TimeVector(datetime.date(1997, 11, 6), base_file="data/schedule/part1.sch")
|
||||
tv = TimeVector(datetime.date(1997, 11, 6), base_file="tests/data/schedule/part1.sch")
|
||||
with self.assertRaises(KeyError):
|
||||
tv.delete(datetime.datetime(2019,1,1))
|
||||
|
@ -5,7 +5,7 @@ class TestWells(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.sch = sunbeam.parse('spe3/SPE3CASE1.DATA').schedule
|
||||
cls.sch = sunbeam.parse('tests/spe3/SPE3CASE1.DATA').schedule
|
||||
cls.timesteps = cls.sch.timesteps
|
||||
# cls.wells = cls.sch.wells
|
||||
|
Loading…
Reference in New Issue
Block a user