Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/pyAction: Separate classes for python bindings and opm embedded #4017

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 14 additions & 34 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -404,34 +404,15 @@ if (OPM_ENABLE_PYTHON)

target_link_libraries(opmcommon_python PRIVATE
opmcommon)
if(OPM_ENABLE_EMBEDDED_PYTHON)
pybind11_add_module(opm_embedded
${PYTHON_CXX_SOURCE_FILES}
${PROJECT_BINARY_DIR}/python/cxx/builtin_pybind11.cpp)
target_link_libraries(opm_embedded PRIVATE
opmcommon)
endif()
if(TARGET pybind11::pybind11)
target_link_libraries(opmcommon_python PRIVATE
pybind11::pybind11)
if(OPM_ENABLE_EMBEDDED_PYTHON)
target_link_libraries(opm_embedded PRIVATE
pybind11::pybind11)
endif()
else()
target_include_directories(opmcommon_python SYSTEM PRIVATE ${pybind11_INCLUDE_DIRS})
if(OPM_ENABLE_EMBEDDED_PYTHON)
target_include_directories(opm_embedded SYSTEM PRIVATE ${pybind11_INCLUDE_DIRS})
endif()
endif()
set_target_properties(opmcommon_python PROPERTIES
LIBRARY_OUTPUT_DIRECTORY python/opm)
add_dependencies(opmcommon_python copy_python)
if(OPM_ENABLE_EMBEDDED_PYTHON)
set_target_properties(opm_embedded PROPERTIES
LIBRARY_OUTPUT_DIRECTORY python)
add_dependencies(opm_embedded copy_python)
endif()

# Generate versioned setup.py
configure_file(${PROJECT_SOURCE_DIR}/python/setup.py.in
Expand All @@ -443,23 +424,22 @@ if (OPM_ENABLE_PYTHON)
# extra cmake switch, OPM_INSTALL_PYTHON. If you prefer you can still invoke
# setup.py install manually - optionally with the generated script
# setup-install.sh - and completely bypass cmake in the installation phase.
if (OPM_INSTALL_PYTHON)
# If OPM_ENABLE_EMBEDDED_PYTHON is enabled, we also install opmcommon_python,
# to make it available in a Python console.
if (OPM_INSTALL_PYTHON OR OPM_ENABLE_EMBEDDED_PYTHON)
include(PyInstallPrefix)
install(TARGETS opmcommon_python DESTINATION ${DEST_PREFIX}${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX}/opm)
install(
CODE "execute_process(
COMMAND ${PYTHON_EXECUTABLE}
python/install.py
${PROJECT_BINARY_DIR}/python/opm
${DEST_PREFIX}${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX} 1)")

## Need to install this Python script such that it can be used by opm-simulators when building against an installed
## opm-common
install( PROGRAMS "python/install.py" DESTINATION "${OPM_PYTHON_COMMON_DIR}" )

# Install the convenience library for PYACTION script development
if (OPM_ENABLE_EMBEDDED_PYTHON)
install(TARGETS opm_embedded DESTINATION ${DEST_PREFIX}${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX})
if (OPM_INSTALL_PYTHON)
install(
CODE "execute_process(
COMMAND ${PYTHON_EXECUTABLE}
python/install.py
${PROJECT_BINARY_DIR}/python/opm
${DEST_PREFIX}${CMAKE_INSTALL_PREFIX}/${PYTHON_INSTALL_PREFIX} 1)")

## Need to install this Python script such that it can be used by opm-simulators when building against an installed
## opm-common
install( PROGRAMS "python/install.py" DESTINATION "${OPM_PYTHON_COMMON_DIR}" )
endif()
endif()

Expand Down
4 changes: 4 additions & 0 deletions CMakeLists_files.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ if(ENABLE_ECL_INPUT)
python/cxx/parsecontext.cpp
python/cxx/parser.cpp
python/cxx/schedule.cpp
python/cxx/schedule_state.cpp
python/cxx/simulation_config.cpp
python/cxx/summary_state.cpp
python/cxx/table_manager.cpp
python/cxx/unit_system.cpp
Expand Down Expand Up @@ -704,13 +706,15 @@ if(ENABLE_ECL_OUTPUT)
tests/ACTIONX_M1.X0010
tests/wclose.py
tests/msim/MSIM_PYACTION.DATA
tests/msim/MSIM_PYACTION_RETRIEVE_INFO.DATA
tests/msim/MSIM_PYACTION_CHANGING_SCHEDULE.DATA
tests/msim/MSIM_PYACTION_CHANGING_SCHEDULE_ACTIONX_CALLBACK.DATA
tests/msim/MSIM_PYACTION_INSERT_KEYWORD.DATA
tests/msim/MSIM_PYACTION_INSERT_INVALID_KEYWORD.DATA
tests/msim/MSIM_PYACTION_NO_RUN_FUNCTION.DATA
tests/msim/MSIM_PYACTION_OPEN_WELL_AT_PAST_REPORT_STEP.DATA
tests/msim/MSIM_PYACTION_OPEN_WELL_AT_TOO_LATE_REPORT_STEP.DATA
tests/msim/retrieve_info.py
tests/msim/action1.py
tests/msim/action2.py
tests/msim/action2_no_run_function.py
Expand Down
2 changes: 1 addition & 1 deletion opm/input/eclipse/Python/PythonInterp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ namespace Opm {
*/

OPM_EMBEDDED_MODULE(opm_embedded, module) {
python::common::export_all_opm_embedded(module);
python::common::export_all(module);
}


Expand Down
13 changes: 12 additions & 1 deletion python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,15 @@ This folder contains the Python bindings and code required for embedding python

For the Python bindings, see the [Python bindings of opm-simulators](https://github.com/OPM/opm-simulators/blob/master/python/README.md).

For embedding python, see the [documentation](https://opm-project.org/?page_id=1454).
For embedding python, see the [documentation](https://opm-project.org/?page_id=1454).

To enable tooltips for opm_embedded on VSCode (embedded python code):
- Install opm-common
- Copy the file "<opm-common-folder>/python/opm_embedded/__init__.pyi" into the folder at "python.analysis.stubPath" of VS Code and rename it to "opm_embedded.pyi"
You can recreate this stub file by executing "stubgen -m opmcommon_python" in "<opm-common-build-folder>/python/opm", renaming the resuling stub file from "opmcommon_python.pyi" to "opm_embedded.pyi" and adding the lines
```python
current_ecl_state: EclipseState
current_report_step: int
current_schedule: Schedule
current_summary_state: SummaryState
```
2 changes: 1 addition & 1 deletion python/cxx/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ void python::common::export_Connection(py::module& module) {
.def_property_readonly("state", &state )
.def_property_readonly( "i", &Connection::getI )
.def_property_readonly( "j", &Connection::getJ )
.def_property_readonly( "j", &Connection::getK )
.def_property_readonly( "k", &Connection::getK )
.def_property_readonly( "pos", &get_pos )
.def_property_readonly( "attached_to_segment", &Connection::attachedToSegment )
.def_property_readonly( "center_depth", &Connection::depth)
Expand Down
9 changes: 0 additions & 9 deletions python/cxx/eclipse_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,5 @@ void python::common::export_EclipseConfig(py::module& module)
.def( "getRestartStep" , &InitConfig::getRestartStep );

py::class_< IOConfig >( module, "IOConfig");

py::class_< SimulationConfig >( module, "SimulationConfig")
.def("hasThresholdPressure", &SimulationConfig::useThresholdPressure )
.def("useCPR", &SimulationConfig::useCPR )
.def("useNONNC", &SimulationConfig::useNONNC )
.def("hasDISGAS", &SimulationConfig::hasDISGAS )
.def("hasDISGASW", &SimulationConfig::hasDISGASW )
.def("hasVAPOIL", &SimulationConfig::hasVAPOIL )
.def("hasVAPWAT", &SimulationConfig::hasVAPWAT );
}

27 changes: 10 additions & 17 deletions python/cxx/export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ void python::common::export_all(py::module& module) {
export_Deck(module);
export_DeckKeyword(module);
export_Schedule(module);
export_ScheduleState(module);
export_Well(module);
export_Group(module);
export_Connection(module);
export_EclipseConfig(module);
export_SimulationConfig(module);
export_FieldProperties(module);
export_EclipseState(module);
export_TableManager(module);
Expand All @@ -30,22 +32,13 @@ void python::common::export_all(py::module& module) {

PYBIND11_MODULE(opmcommon_python, module) {
python::common::export_all(module);
}

void python::common::export_all_opm_embedded(py::module& module) {
python::common::export_all(module);
module.attr("current_ecl_state") = std::make_shared<EclipseState>();
module.attr("current_summary_state") = std::make_shared<SummaryState>();
module.attr("current_schedule") = std::make_shared<Schedule>();
module.attr("current_report_step") = 0;
module.doc() = R"pbdoc(This is the opm_embedded module for embedding python code in PYACTION.)pbdoc";
}
pybind11::module submodule = module.def_submodule("embedded");

/*
PYBIND11_MODULE create a Python of all the Python/C++ classes which are
generated in the python::common::export_all_opm_embedded() function in the wrapping code.
The same module is created as an embedded python module in PythonInterp.cpp
*/
PYBIND11_MODULE(opm_embedded, module) {
python::common::export_all_opm_embedded(module);
}
// These attributes are placeholders, they get set to the actual EclipseState, Schedule and SummaryState in PyRunModule.cpp
// If you change anything here, please recreate and update the python stub file for opm_embedded as described in python/README.md
submodule.attr("current_ecl_state") = std::make_shared<EclipseState>();
lisajulia marked this conversation as resolved.
Show resolved Hide resolved
submodule.attr("current_summary_state") = std::make_shared<SummaryState>();
submodule.attr("current_schedule") = std::make_shared<Schedule>();
submodule.attr("current_report_step") = 0;
}
3 changes: 2 additions & 1 deletion python/cxx/export.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ const py::return_value_policy move = py::return_value_policy::move;

namespace python::common {
void export_all(py::module& module);
void export_all_opm_embedded(py::module& module);
void export_UnitSystem(py::module& module);
void export_Connection(py::module& module);
void export_Deck(py::module& module);
Expand All @@ -26,7 +25,9 @@ void export_EclipseState(py::module& module);
void export_Group(py::module& module);
void export_ParseContext(py::module& module);
void export_Parser(py::module& module);
void export_SimulationConfig(py::module& module);
void export_Schedule(py::module& module);
void export_ScheduleState(py::module& module);
void export_TableManager(py::module& module);
void export_Well(py::module& module);
void export_Log(py::module& module);
Expand Down
19 changes: 11 additions & 8 deletions python/cxx/log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,15 @@ void note(const std::string& msg) {

void python::common::export_Log(py::module& module)
{
py::class_<OpmLog>(module, "OpmLog")
.def_static("info", info )
.def_static("warning", warning)
.def_static("error", error)
.def_static("problem", problem)
.def_static("bug", bug)
.def_static("debug", debug)
.def_static("note", note);
py::class_<OpmLog, std::shared_ptr<OpmLog> >( module, "OpmLog", R"(
The Opm::OpmLog class - this is a fully static class which manages a proper
Logger instance.
)")
.def_static("info", info, "Add an info message to the opm log.")
.def_static("warning", warning, "Add a warning message to the opm log.")
.def_static("error", error, "Add an error message to the opm log.")
.def_static("problem", problem, "Add a problem message to the opm log.")
.def_static("bug", bug, "Add a bug message to the opm log.")
.def_static("debug", debug, "Add a debug message to the opm log.")
.def_static("note", note, "Add a note to the opm log.");
}
11 changes: 0 additions & 11 deletions python/cxx/schedule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,11 +139,6 @@ namespace {
return sch.hasWell( wellName );
}

const Group& get_group(const ScheduleState& st, const std::string& group_name) {
return st.groups.get(group_name);
}


const ScheduleState& getitem(const Schedule& sch, std::size_t report_step) {
return sch[report_step];
}
Expand Down Expand Up @@ -197,12 +192,6 @@ namespace {

void python::common::export_Schedule(py::module& module) {


py::class_<ScheduleState>(module, "ScheduleState")
.def_property_readonly("nupcol", py::overload_cast<>(&ScheduleState::nupcol, py::const_))
.def("group", &get_group, ref_internal);


// Note: In the below class we use std::shared_ptr as the holder type, see:
//
// https://pybind11.readthedocs.io/en/stable/advanced/smart_ptrs.html
Expand Down
25 changes: 25 additions & 0 deletions python/cxx/schedule_state.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <opm/input/eclipse/Schedule/ScheduleState.hpp>

#include "export.hpp"

namespace {
const Group& get_group(const ScheduleState& st, const std::string& group_name) {
return st.groups.get(group_name);
}
}

/**
* @brief Function to export the ScheduleState class and some methods to Python.
*
* In the below class we use std::shared_ptr as the holder type, see https://pybind11.readthedocs.io/en/stable/advanced/smart_ptrs.html
* this makes it possible to share the ScheduleState (which is created only once per simulation) with e.g. the opm.simulators.BlackOilSimulator Python object.
*
* @param module Reference to the python module.
*/
void python::common::export_ScheduleState(py::module& module) {

py::class_<ScheduleState>(module, "ScheduleState")
.def_property_readonly("nupcol", py::overload_cast<>(&ScheduleState::nupcol, py::const_))
.def("group", &get_group, ref_internal)
;
}
23 changes: 23 additions & 0 deletions python/cxx/simulation_config.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <opm/input/eclipse/EclipseState/SimulationConfig/SimulationConfig.hpp>

#include "export.hpp"

/**
* @brief Function to export the SimulationConfig class and some methods to Python.
*
* In the below class we use std::shared_ptr as the holder type, see https://pybind11.readthedocs.io/en/stable/advanced/smart_ptrs.html
* this makes it possible to share the SimulationConfig (which is created only once per simulation) with e.g. the opm.simulators.BlackOilSimulator Python object.
*
* @param module Reference to the python module.
*/
void python::common::export_SimulationConfig(py::module& module)
{
py::class_< SimulationConfig , std::shared_ptr<SimulationConfig>>( module, "SimulationConfig")
.def("hasThresholdPressure", &SimulationConfig::useThresholdPressure )
.def("useCPR", &SimulationConfig::useCPR )
.def("useNONNC", &SimulationConfig::useNONNC )
.def("hasDISGAS", &SimulationConfig::hasDISGAS )
.def("hasDISGASW", &SimulationConfig::hasDISGASW )
.def("hasVAPOIL", &SimulationConfig::hasVAPOIL )
.def("hasVAPWAT", &SimulationConfig::hasVAPWAT );
}
8 changes: 8 additions & 0 deletions python/opm_embedded/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""
This is the opm_embedded module for embedding python code in PYACTION.
"""

# If you change anything here, please recreate and update the python stub file for opm_embedded as described in python/README.md
from opm.opmcommon_python.embedded import current_ecl_state, current_summary_state, current_schedule, current_report_step
from opm.opmcommon_python import OpmLog
from opm.opmcommon_python import DeckKeyword # Needed for PYINPUT