diff --git a/CMakeLists.txt b/CMakeLists.txt
index d81da8c60..aa224cb8a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,6 +9,8 @@ option(ENABLE_ECL_INPUT "Enable eclipse input support?" ON)
option(ENABLE_ECL_OUTPUT "Enable eclipse output support?" ON)
option(ENABLE_MOCKSIM "Build the mock simulator for io testing" ON)
option(OPM_ENABLE_PYTHON "Enable python bindings?" OFF)
+option(OPM_ENABLE_EMBEDDED_PYTHON "Enable python bindings?" OFF)
+
# Output implies input
if(ENABLE_ECL_OUTPUT)
@@ -211,7 +213,8 @@ install(DIRECTORY cmake DESTINATION share/opm)
install(FILES etc/opm_bash_completion.sh.in DESTINATION share/opm/etc)
if (OPM_ENABLE_PYTHON)
-
+ # -------------------------------------------------------------------------
+ # 1: Wrap C++ functionality in Python
find_package(PythonInterp REQUIRED)
include(FindPythonInterp)
@@ -272,6 +275,9 @@ if (OPM_ENABLE_PYTHON)
set_target_properties(opmcommon PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${CMAKE_BINARY_DIR}/python/python)
+ # -------------------------------------------------------------------------
+ # Let cmake configure some small shell scripts which can be used to simplify
+ # building and testing of the Python extensions.
configure_file(python/setup-build.sh.in tmp/setup-build.sh)
file( COPY ${PROJECT_BINARY_DIR}/tmp/setup-build.sh
DESTINATION ${PROJECT_BINARY_DIR}
@@ -283,6 +289,15 @@ if (OPM_ENABLE_PYTHON)
FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE )
configure_file(python/enable-python.sh.in enable-python.sh)
+
+ # -------------------------------------------------------------------------
+ # 2: Embed the Python interpreter for keywords like PYACTION and PYINPUT
+ if (OPM_ENABLE_EMBEDDED_PYTHON)
+ add_subdirectory(python/pybind11)
+ #target_link_libraries(opmcommon PRIVATE pybind11::embed)
+ include_directories("python/pybind11/include;${PYTHON_INCLUDE_DIRS}")
+ target_link_libraries(opmcommon PRIVATE ${PYTHON_LIBRARY})
+
+ add_definitions(-DEMBEDDED_PYTHON)
+ endif()
endif()
-
-
diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake
index d593a2c80..709bfffca 100644
--- a/CMakeLists_files.cmake
+++ b/CMakeLists_files.cmake
@@ -46,6 +46,8 @@ if(ENABLE_ECL_INPUT)
src/opm/parser/eclipse/Deck/DeckOutput.cpp
src/opm/parser/eclipse/Deck/Section.cpp
src/opm/parser/eclipse/Deck/UDAValue.cpp
+ src/opm/parser/eclipse/Python/Python.cpp
+ src/opm/parser/eclipse/Python/PythonInterp.cpp
src/opm/parser/eclipse/EclipseState/AquiferCT.cpp
src/opm/parser/eclipse/EclipseState/Aquifetp.cpp
src/opm/parser/eclipse/EclipseState/Aquancon.cpp
@@ -234,6 +236,7 @@ if(ENABLE_ECL_INPUT)
tests/parser/DynamicVectorTests.cpp
tests/parser/Eclipse3DPropertiesTests.cpp
tests/parser/EclipseGridTests.cpp
+ tests/parser/EmbeddedPython.cpp
tests/parser/EqualRegTests.cpp
tests/parser/EventTests.cpp
tests/parser/FaceDirTests.cpp
@@ -591,7 +594,8 @@ if(ENABLE_ECL_INPUT)
opm/parser/eclipse/Deck/DeckOutput.hpp
opm/parser/eclipse/Deck/DeckKeyword.hpp
opm/parser/eclipse/Deck/DeckRecord.hpp
- opm/parser/eclipse/Deck/UDAValue.hpp)
+ opm/parser/eclipse/Deck/UDAValue.hpp
+ opm/parser/eclipse/Python/Python.hpp)
endif()
if(ENABLE_ECL_OUTPUT)
list(APPEND PUBLIC_HEADER_FILES
diff --git a/opm/parser/eclipse/Python/Python.hpp b/opm/parser/eclipse/Python/Python.hpp
new file mode 100644
index 000000000..3f6545389
--- /dev/null
+++ b/opm/parser/eclipse/Python/Python.hpp
@@ -0,0 +1,65 @@
+/*
+ Copyright 2019 Equinor ASA.
+
+ This file is part of the Open Porous Media project (OPM).
+
+ OPM 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.
+
+ OPM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OPM. If not, see .
+*/
+
+#ifndef OPM_EMBEDDED_PYTHON
+#define OPM_EMBEDDED_PYTHON
+
+#include
+#include
+
+
+namespace Opm {
+class PythonInterp;
+
+
+
+/*
+ This class is a thin wrapper around the PythonInterp class. The Python class
+ can always be safely instantiated, but the actual PythonInterp implementation
+ depends on whether Python support was enabled when this library instance was
+ compiled.
+
+ If one the methods actually invoking the Python interpreter is invoked without
+ proper Python support a dummy PythinInterp instance will be used; and that
+ will just throw std::logic_error. The operator bool can be used to check if
+ this Python manager indeed has a valid Python runtime:
+
+
+ Python python;
+
+ if (python)
+ python.exec("print('Hello world')")
+ else
+ OpmLog::Error("This version of opmcommon has been built with support for embedded Python");
+
+*/
+
+class Python {
+public:
+ Python();
+ bool exec(const std::string& python_code);
+ explicit operator bool() const;
+private:
+ std::shared_ptr interp;
+};
+}
+
+
+#endif
+
diff --git a/src/opm/parser/eclipse/Python/Python.cpp b/src/opm/parser/eclipse/Python/Python.cpp
new file mode 100644
index 000000000..2e2a3d73c
--- /dev/null
+++ b/src/opm/parser/eclipse/Python/Python.cpp
@@ -0,0 +1,45 @@
+/*
+ Copyright 2019 Equinor ASA.
+
+ This file is part of the Open Porous Media project (OPM).
+
+ OPM 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.
+
+ OPM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OPM. If not, see .
+*/
+
+
+#include
+#include "PythonInterp.hpp"
+
+namespace Opm {
+
+Python::Python():
+ interp(std::make_shared())
+{
+}
+
+
+bool Python::exec(const std::string& python_code) {
+ this->interp->exec(python_code);
+ return true;
+}
+
+
+Python::operator bool() const {
+ if (this->interp)
+ return bool( *this->interp );
+ else
+ return false;
+}
+
+}
diff --git a/src/opm/parser/eclipse/Python/PythonInterp.cpp b/src/opm/parser/eclipse/Python/PythonInterp.cpp
new file mode 100644
index 000000000..1f9bfdaa9
--- /dev/null
+++ b/src/opm/parser/eclipse/Python/PythonInterp.cpp
@@ -0,0 +1,38 @@
+/*
+ Copyright 2019 Equinor ASA.
+
+ This file is part of the Open Porous Media project (OPM).
+
+ OPM 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.
+
+ OPM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OPM. If not, see .
+*/
+
+#include "PythonInterp.hpp"
+
+#ifdef EMBEDDED_PYTHON
+
+#include
+namespace py = pybind11;
+
+namespace Opm {
+
+
+bool PythonInterp::exec(const std::string& python_code) {
+ py::object scope = py::module::import("__main__").attr("__dict__");
+ py::exec(python_code, scope);
+ return true;
+}
+
+}
+
+#endif
diff --git a/src/opm/parser/eclipse/Python/PythonInterp.hpp b/src/opm/parser/eclipse/Python/PythonInterp.hpp
new file mode 100644
index 000000000..3ce2d4d78
--- /dev/null
+++ b/src/opm/parser/eclipse/Python/PythonInterp.hpp
@@ -0,0 +1,66 @@
+/*
+ Copyright 2019 Equinor ASA.
+
+ This file is part of the Open Porous Media project (OPM).
+
+ OPM 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.
+
+ OPM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OPM. If not, see .
+*/
+
+
+#ifndef EMBEDDED_PYTHON_INTERP
+#define EMBEDDED_PYTHON_INTERP
+
+#include
+#include
+
+#ifdef EMBEDDED_PYTHON
+
+#include
+namespace py = pybind11;
+
+#endif
+
+
+
+namespace Opm {
+
+#ifdef EMBEDDED_PYTHON
+
+class PythonInterp {
+public:
+ bool exec(const std::string& python_code);
+ explicit operator bool() const { return true; }
+private:
+ py::scoped_interpreter guard = {};
+};
+
+
+#else
+
+class PythonInterp {
+public:
+ bool exec(const std::string&) {
+ return this->fail();
+ };
+
+ explicit operator bool() const { return false; }
+private:
+ bool fail() { throw std::logic_error("The current opm code has been built without Python support;"); }
+};
+
+#endif
+
+}
+
+#endif
diff --git a/tests/parser/EmbeddedPython.cpp b/tests/parser/EmbeddedPython.cpp
new file mode 100644
index 000000000..e7e31a58a
--- /dev/null
+++ b/tests/parser/EmbeddedPython.cpp
@@ -0,0 +1,47 @@
+/*
+ Copyright 2019 Equinor ASA.
+
+ This file is part of the Open Porous Media project (OPM).
+
+ OPM 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.
+
+ OPM is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OPM. If not, see .
+ */
+
+#include
+#include
+#include
+
+#define BOOST_TEST_MODULE EMBEDDED_PYTHON
+
+#include
+
+#include
+
+#ifndef EMBEDDED_PYTHON
+
+BOOST_AUTO_TEST_CASE(INSTANTIATE) {
+ Opm::Python python;
+ BOOST_CHECK(!python);
+ BOOST_CHECK_THROW(python.exec("print('Hello world')"), std::logic_error);
+}
+
+#else
+
+BOOST_AUTO_TEST_CASE(INSTANTIATE) {
+ Opm::Python python;
+ BOOST_CHECK(python);
+ BOOST_CHECK_NO_THROW(python.exec("print('Hello world')"));
+}
+
+#endif
+