diff --git a/sunbeam/CMakeLists.txt b/sunbeam/CMakeLists.txt index 449190a71..fd3996f91 100644 --- a/sunbeam/CMakeLists.txt +++ b/sunbeam/CMakeLists.txt @@ -5,7 +5,17 @@ include_directories(SYSTEM ${PYTHON_INCLUDE_DIRS} ${Boost_INCLUDE_DIR} ${opm-parser_INCLUDE_DIRS}) -add_library( sunbeam SHARED sunbeam.cpp ) +add_library( sunbeam SHARED eclipse_state.cpp + completion.cpp + eclipse_3d_properties.cpp + eclipse_config.cpp + eclipse_grid.cpp + eclipse_state.cpp + group.cpp + schedule.cpp + sunbeam.cpp + table_manager.cpp + well.cpp ) set_target_properties( sunbeam PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/python/sunbeam ) target_link_libraries( sunbeam ${Boost_LIBRARIES} ${opm-parser_LIBRARIES} ) diff --git a/sunbeam/completion.cpp b/sunbeam/completion.cpp new file mode 100644 index 000000000..e5a9daab7 --- /dev/null +++ b/sunbeam/completion.cpp @@ -0,0 +1,21 @@ +#include + +#include "completion.hpp" + +namespace py = boost::python; +using namespace Opm; + + +namespace completion { + + void export_Completion() { + + py::class_< Completion >( "Completion", py::no_init ) + .def( "getI", &Completion::getI ) + .def( "getJ", &Completion::getJ ) + .def( "getK", &Completion::getK ) + ; + + } + +} diff --git a/sunbeam/completion.hpp b/sunbeam/completion.hpp new file mode 100644 index 000000000..15dc5e182 --- /dev/null +++ b/sunbeam/completion.hpp @@ -0,0 +1,14 @@ +#ifndef SUNBEAM_COMPLETION_HPP +#define SUNBEAM_COMPLETION_HPP + +#include + + +namespace completion { + namespace py = boost::python; + + void export_Completion(); + +} + +#endif //SUNBEAM_COMPLETION_HPP \ No newline at end of file diff --git a/sunbeam/converters.hpp b/sunbeam/converters.hpp index 199de1744..92bb528f4 100644 --- a/sunbeam/converters.hpp +++ b/sunbeam/converters.hpp @@ -5,11 +5,12 @@ #include #include +#include #include namespace py = boost::python; -using namespace Opm; + /* * boost.python lacks converters for a lot of types we use, or we need to diff --git a/sunbeam/eclipse_3d_properties.cpp b/sunbeam/eclipse_3d_properties.cpp new file mode 100644 index 000000000..cf768d8fc --- /dev/null +++ b/sunbeam/eclipse_3d_properties.cpp @@ -0,0 +1,50 @@ +#include + +#include "eclipse_3d_properties.hpp" + +namespace py = boost::python; +using namespace Opm; + +using ref = py::return_internal_reference<>; +using copy = py::return_value_policy< py::copy_const_reference >; + + +namespace eclipse_3d_properties { + + py::list getitem( const Eclipse3DProperties& p, const std::string& kw) { + const auto& ip = p.getIntProperties(); + if (ip.supportsKeyword(kw) && ip.hasKeyword(kw)) + return iterable_to_pylist(p.getIntGridProperty(kw).getData()); + + const auto& dp = p.getDoubleProperties(); + if (dp.supportsKeyword(kw) && dp.hasKeyword(kw)) + return iterable_to_pylist(p.getDoubleGridProperty(kw).getData()); + throw key_error( "no such grid property " + kw ); + } + + bool contains( const Eclipse3DProperties& p, const std::string& kw) { + return + (p.getIntProperties().supportsKeyword(kw) && + p.getIntProperties().hasKeyword(kw)) + || + (p.getDoubleProperties().supportsKeyword(kw) && + p.getDoubleProperties().hasKeyword(kw)) + ; + } + py::list regions( const Eclipse3DProperties& p, const std::string& kw) { + return iterable_to_pylist( p.getRegions(kw) ); + } + + + void export_Eclipse3DProperties() { + + + py::class_< Eclipse3DProperties >( "Eclipse3DProperties", py::no_init ) + .def( "getRegions", ®ions ) + .def( "__contains__", &contains ) + .def( "__getitem__", &getitem ) + ; + + } + +} diff --git a/sunbeam/eclipse_3d_properties.hpp b/sunbeam/eclipse_3d_properties.hpp new file mode 100644 index 000000000..3cb77a4e7 --- /dev/null +++ b/sunbeam/eclipse_3d_properties.hpp @@ -0,0 +1,21 @@ +#ifndef SUNBEAM_ESCLIPSE_3D_PROPERTIES_HPP +#define SUNBEAM_ESCLIPSE_3D_PROPERTIES_HPP + +#include +#include "converters.hpp" + +namespace Opm { + class Eclipse3DProperties; +} + +namespace eclipse_3d_properties { + namespace py = boost::python; + using namespace Opm; + + py::list getitem( const Eclipse3DProperties& p, const std::string& kw); + bool contains( const Eclipse3DProperties& p, const std::string& kw); + void export_Eclipse3DProperties(); + +} + +#endif //SUNBEAM_ESCLIPSE_3D_PROPERTIES_HPP diff --git a/sunbeam/eclipse_config.cpp b/sunbeam/eclipse_config.cpp new file mode 100644 index 000000000..8cd5f589a --- /dev/null +++ b/sunbeam/eclipse_config.cpp @@ -0,0 +1,52 @@ +#include +#include +#include +#include +#include + +#include "eclipse_config.hpp" + +namespace py = boost::python; +using namespace Opm; + +using ref = py::return_internal_reference<>; +using copy = py::return_value_policy< py::copy_const_reference >; + + +namespace eclipse_config { + + void export_EclipseConfig() + { + + py::class_< EclipseConfig >( "EclipseConfig", py::no_init ) + .def( "summary", &EclipseConfig::summary, ref()) + .def( "init", &EclipseConfig::init, ref()) + .def( "restart", &EclipseConfig::restart, ref()) + .def( "simulation", &EclipseConfig::simulation, ref()) + ; + + py::class_< SummaryConfig >( "SummaryConfig", py::no_init ) + .def( "__contains__", &SummaryConfig::hasKeyword ) + ; + + py::class_< InitConfig >( "InitConfig", py::no_init ) + .def( "hasEquil", &InitConfig::hasEquil ) + .def( "restartRequested", &InitConfig::restartRequested ) + .def( "getRestartStep" , &InitConfig::getRestartStep ) + ; + + py::class_< RestartConfig >( "RestartConfig", py::no_init ) + .def( "getKeyword", &RestartConfig::getKeyword ) + .def( "getFirstRestartStep", &RestartConfig::getFirstRestartStep ) + .def( "getWriteRestartFile", &RestartConfig::getWriteRestartFile ) + ; + + py::class_< SimulationConfig >( "SimulationConfig", py::no_init ) + .def("hasThresholdPressure", &SimulationConfig::hasThresholdPressure ) + .def("useCPR", &SimulationConfig::useCPR ) + .def("hasDISGAS", &SimulationConfig::hasDISGAS ) + .def("hasVAPOIL", &SimulationConfig::hasVAPOIL ) + ; + } + +} diff --git a/sunbeam/eclipse_config.hpp b/sunbeam/eclipse_config.hpp new file mode 100644 index 000000000..2ed908c15 --- /dev/null +++ b/sunbeam/eclipse_config.hpp @@ -0,0 +1,18 @@ +#ifndef SUNBEAM_ECLIPSE_CONFIG_HPP +#define SUNBEAM_ECLIPSE_CONFIG_HPP + +#include + + +namespace Opm { +} + +namespace eclipse_config { + namespace py = boost::python; + using namespace Opm; + + void export_EclipseConfig(); + +} + +#endif //SUNBEAM_ECLIPSE_CONFIG_HPP diff --git a/sunbeam/eclipse_grid.cpp b/sunbeam/eclipse_grid.cpp new file mode 100644 index 000000000..5494a6e43 --- /dev/null +++ b/sunbeam/eclipse_grid.cpp @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include + +#include "eclipse_grid.hpp" + +namespace py = boost::python; +using namespace Opm; + +using ref = py::return_internal_reference<>; +using copy = py::return_value_policy< py::copy_const_reference >; + +namespace eclipse_grid { + py::tuple getXYZ( const EclipseGrid& grid ) { + return py::make_tuple( grid.getNX(), + grid.getNY(), + grid.getNZ()); + } + int getNumActive( const EclipseGrid& grid ) { + return grid.getNumActive(); + } + int getCartesianSize( const EclipseGrid& grid ) { + return grid.getCartesianSize(); + } + int getGlobalIndex( const EclipseGrid& grid, int i, int j, int k ) { + return grid.getGlobalIndex(i, j, k); + } + py::tuple getIJK( const EclipseGrid& grid, int g ) { + const auto& ijk = grid.getIJK(g); + return py::make_tuple(ijk[0], ijk[1], ijk[2]); + } + double cellVolume1G( const EclipseGrid& grid, size_t glob_idx) { + return grid.getCellVolume(glob_idx); + } + double cellVolume3( const EclipseGrid& grid, size_t i_idx, size_t j_idx, size_t k_idx) { + return grid.getCellVolume(i_idx, j_idx, k_idx); + } + + + void export_EclipseGrid() { + + py::class_< EclipseGrid >( "EclipseGrid", py::no_init ) + .def( "_getXYZ", &getXYZ ) + .def( "nactive", &getNumActive ) + .def( "cartesianSize", &getCartesianSize ) + .def( "globalIndex", &getGlobalIndex ) + .def( "getIJK", &getIJK ) + .def( "_cellVolume1G", &cellVolume1G) + .def( "_cellVolume3", &cellVolume3) + ; + + } +} diff --git a/sunbeam/eclipse_grid.hpp b/sunbeam/eclipse_grid.hpp new file mode 100644 index 000000000..040aaaed1 --- /dev/null +++ b/sunbeam/eclipse_grid.hpp @@ -0,0 +1,20 @@ +#ifndef SUNBEAM_ECLIPSE_GRID_HPP +#define SUNBEAM_ECLIPSE_GRID_HPP + +#include + + +namespace Opm { + class EclipseGrid; +} + +namespace eclipse_grid { + namespace py = boost::python; + using namespace Opm; + + py::tuple getXYZ( const EclipseGrid& grid ); + void export_EclipseGrid(); + +} + +#endif //SUNBEAM_ECLIPSE_GRID_HPP diff --git a/sunbeam/eclipse_state.cpp b/sunbeam/eclipse_state.cpp new file mode 100644 index 000000000..049bc0e36 --- /dev/null +++ b/sunbeam/eclipse_state.cpp @@ -0,0 +1,132 @@ +#include +#include +#include + +#include "eclipse_state.hpp" + +namespace py = boost::python; +using namespace Opm; + +using ref = py::return_internal_reference<>; +using copy = py::return_value_policy< py::copy_const_reference >; + + +namespace eclipse_state { + + py::list getNNC( const EclipseState& state ) { + py::list l; + for( const auto& x : state.getInputNNC().nncdata() ) + l.append( py::make_tuple( x.cell1, x.cell2, x.trans ) ); + return l; + } + py::list faultNames( const EclipseState& state ) { + py::list l; + const auto& fc = state.getFaults(); + for (size_t i = 0; i < fc.size(); i++) { + const auto& f = fc.getFault(i); + l.append(f.getName()); + } + return l; + } + py::dict jfunc( const EclipseState& s) { + const auto& tm = s.getTableManager(); + if (!tm.useJFunc()) + return py::dict(); + const auto& j = tm.getJFunc(); + std::string flag = "BOTH"; + std::string dir = "XY"; + if (j.flag() == JFunc::Flag::WATER) + flag = "WATER"; + else if (j.flag() == JFunc::Flag::GAS) + flag = "GAS"; + + if (j.direction() == JFunc::Direction::X) + dir = "X"; + else if (j.direction() == JFunc::Direction::Y) + dir = "Y"; + else if (j.direction() == JFunc::Direction::Z) + dir = "Z"; + + py::dict ret; + ret["FLAG"] = flag; + ret["DIRECTION"] = dir; + ret["ALPHA_FACTOR"] = j.alphaFactor(); + ret["BETA_FACTOR"] = j.betaFactor(); + if (j.flag() == JFunc::Flag::WATER || j.flag() == JFunc::Flag::BOTH) + ret["OIL_WATER"] = j.owSurfaceTension(); + if (j.flag() == JFunc::Flag::GAS || j.flag() == JFunc::Flag::BOTH) + ret["GAS_OIL"] = j.goSurfaceTension(); + return ret; + } + + + const std::string faceDir( FaceDir::DirEnum dir ) { + switch (dir) { + case FaceDir::DirEnum::XPlus: return "X+"; + case FaceDir::DirEnum::XMinus: return "X-"; + case FaceDir::DirEnum::YPlus: return "Y+"; + case FaceDir::DirEnum::YMinus: return "Y-"; + case FaceDir::DirEnum::ZPlus: return "Z+"; + case FaceDir::DirEnum::ZMinus: return "Z-"; + } + return "Unknown direction"; + } + + py::list faultFaces( const EclipseState& state, const std::string& name ) { + py::list l; + const auto& gr = state.getInputGrid(); // used for global -> IJK + const auto& fc = state.getFaults(); + const Fault& f = fc.getFault(name); + for (const auto& ff : f) { + // for each fault face + for (size_t g : ff) { + // for global index g in ff + const auto ijk = gr.getIJK(g); + l.append(py::make_tuple(ijk[0], ijk[1], ijk[2], faceDir(ff.getDir()))); + } + } + return l; + } + + EclipseState (*parse)( const std::string&, const ParseContext& ) = &Parser::parse; + EclipseState (*parseData) (const std::string &data, const ParseContext& context) = &Parser::parseData; + void (ParseContext::*ctx_update)(const std::string&, InputError::Action) = &ParseContext::update; + + + void export_EclipseState() { + + py::def( "parse", parse ); + py::def( "parseData", parseData ); + + py::class_< EclipseState >( "EclipseState", py::no_init ) + .add_property( "title", &EclipseState::getTitle ) + .def( "_schedule", &EclipseState::getSchedule, ref() ) + .def( "_props", &EclipseState::get3DProperties, ref() ) + .def( "_grid", &EclipseState::getInputGrid, ref() ) + .def( "_cfg", &EclipseState::cfg, ref() ) + .def( "_tables", &EclipseState::getTableManager, ref() ) + .def( "has_input_nnc", &EclipseState::hasInputNNC ) + .def( "input_nnc", &getNNC ) + .def( "faultNames", &faultNames ) + .def( "faultFaces", &faultFaces ) + .def( "jfunc", &jfunc ) + ; + + + /* + * Temporarily + */ + py::class_< ParseContext >( "ParseContext" ) + .def( "update", ctx_update ) + ; + + py::enum_< InputError::Action >( "action" ) + .value( "throw", InputError::Action::THROW_EXCEPTION ) + .value( "warn", InputError::Action::WARN ) + .value( "ignore", InputError::Action::IGNORE ) + ; + + } +} + + diff --git a/sunbeam/eclipse_state.hpp b/sunbeam/eclipse_state.hpp new file mode 100644 index 000000000..425384e5c --- /dev/null +++ b/sunbeam/eclipse_state.hpp @@ -0,0 +1,26 @@ +#ifndef ECLIPSE_STATE_HPP +#define ECLIPSE_STATE_HPP + +#include +#include + + +namespace Opm { + class EclipseState; +} + +namespace eclipse_state { + namespace py = boost::python; + using namespace Opm; + + py::list getNNC( const EclipseState& state ); + py::list faultNames( const EclipseState& state ); + py::dict jfunc( const EclipseState& s); + const std::string faceDir( FaceDir::DirEnum dir ); + py::list faultFaces( const EclipseState& state, const std::string& name ); + + void export_EclipseState(); + +} + +#endif //ECLIPSE_STATE_HPP diff --git a/sunbeam/group.cpp b/sunbeam/group.cpp new file mode 100644 index 000000000..c05cdf51d --- /dev/null +++ b/sunbeam/group.cpp @@ -0,0 +1,23 @@ +#include + +#include "group.hpp" + +namespace py = boost::python; +using namespace Opm; + + +namespace group { + + py::list wellnames( const Group& g, size_t timestep ) { + return iterable_to_pylist( g.getWells( timestep ) ); + } + + void export_Group() { + + py::class_< Group >( "Group", py::no_init ) + .add_property( "name", mkcopy( &Group::name ) ) + .def( "_wellnames", &wellnames ) + ; + + } +} diff --git a/sunbeam/group.hpp b/sunbeam/group.hpp new file mode 100644 index 000000000..bf1b3a8f9 --- /dev/null +++ b/sunbeam/group.hpp @@ -0,0 +1,22 @@ +#ifndef SUNBEAM_GROUP_HPP +#define SUNBEAM_GROUP_HPP + +#include +#include "converters.hpp" + + +namespace Opm { + class Group; +} + +namespace group { + + namespace py = boost::python; + using namespace Opm; + + py::list wellnames( const Group& g, size_t timestep ); + void export_Group(); + +} + +#endif //SUNBEAM_GROUP_HPP diff --git a/sunbeam/schedule.cpp b/sunbeam/schedule.cpp new file mode 100644 index 000000000..d8f65265a --- /dev/null +++ b/sunbeam/schedule.cpp @@ -0,0 +1,73 @@ +#include +#include "converters.hpp" + +#include "schedule.hpp" + +namespace py = boost::python; +using namespace Opm; + +using ref = py::return_internal_reference<>; +using copy = py::return_value_policy< py::copy_const_reference >; + + +namespace schedule { + + std::vector< Well > get_wells( const Schedule& sch ) { + std::vector< Well > wells; + for( const auto& w : sch.getWells() ) + wells.push_back( *w ); + + return wells; + } + + const Well& get_well( const Schedule& sch, const std::string& name ) try { + return *sch.getWell( name ); + } catch( const std::invalid_argument& e ) { + throw key_error( name ); + } + + + boost::posix_time::ptime get_start_time( const Schedule& s ) { + return boost::posix_time::from_time_t( s.posixStartTime() ); + } + + boost::posix_time::ptime get_end_time( const Schedule& s ) { + return boost::posix_time::from_time_t( s.posixEndTime() ); + } + + py::list get_timesteps( const Schedule& s ) { + namespace time = boost::posix_time; + const auto& tm = s.getTimeMap(); + std::vector< time::ptime > v; + v.reserve( tm.size() ); + + for( size_t i = 0; i < tm.size(); ++i ) + v.push_back( time::from_time_t(tm[ i ]) ); + + return iterable_to_pylist( v ); + } + + py::list get_groups( const Schedule& sch ) { + std::vector< Group > groups; + for( const auto& g : sch.getGroups() ) + groups.push_back( *g ); + + return iterable_to_pylist( groups ); + } + + void export_Schedule() { + + py::class_< Schedule >( "Schedule", py::no_init ) + .add_property( "_wells", &schedule::get_wells ) + .add_property( "_groups", &get_groups ) + .add_property( "start", &get_start_time ) + .add_property( "end", &get_end_time ) + .add_property( "timesteps", &schedule::get_timesteps ) + .def( "__contains__", &Schedule::hasWell ) + .def( "__getitem__", &get_well, ref() ) + .def( "_group", &Schedule::getGroup, ref() ) + ; + + } + +} \ No newline at end of file diff --git a/sunbeam/schedule.hpp b/sunbeam/schedule.hpp new file mode 100644 index 000000000..68b23549a --- /dev/null +++ b/sunbeam/schedule.hpp @@ -0,0 +1,28 @@ +#ifndef SUNBEAM_SCHEDULE_HPP +#define SUNBEAM_SCHEDULE_HPP + +#include + + +namespace Opm { + class Schedule; + class Well; +} + +namespace schedule { + namespace py = boost::python; + using namespace Opm; + + + std::vector< Well > get_wells( const Schedule& sch ); + const Well& get_well( const Schedule& sch, const std::string& name ); + boost::posix_time::ptime get_start_time( const Schedule& s ); + boost::posix_time::ptime get_end_time( const Schedule& s ); + py::list get_timesteps( const Schedule& s ); + py::list get_groups( const Schedule& sch ); + + void export_Schedule(); + +} + +#endif //SUNBEAM_SCHEDULE_HPP diff --git a/sunbeam/sunbeam.cpp b/sunbeam/sunbeam.cpp index b836d4c71..f562103d3 100644 --- a/sunbeam/sunbeam.cpp +++ b/sunbeam/sunbeam.cpp @@ -1,413 +1,42 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include "converters.hpp" +#include "completion.hpp" +#include "eclipse_3d_properties.hpp" +#include "eclipse_config.hpp" +#include "eclipse_grid.hpp" +#include "eclipse_state.hpp" +#include "group.hpp" +#include "schedule.hpp" +#include "table_manager.hpp" +#include "well.hpp" -namespace py = boost::python; -using namespace Opm; - -namespace { - -namespace state { -py::list getNNC( const EclipseState& state ) { - py::list l; - for( const auto& x : state.getInputNNC().nncdata() ) - l.append( py::make_tuple( x.cell1, x.cell2, x.trans ) ); - return l; -} -py::list faultNames( const EclipseState& state ) { - py::list l; - const auto& fc = state.getFaults(); - for (size_t i = 0; i < fc.size(); i++) { - const auto& f = fc.getFault(i); - l.append(f.getName()); - } - return l; -} -py::dict jfunc( const EclipseState& s) { - const auto& tm = s.getTableManager(); - if (!tm.useJFunc()) - return py::dict(); - const auto& j = tm.getJFunc(); - std::string flag = "BOTH"; - std::string dir = "XY"; - if (j.flag() == JFunc::Flag::WATER) - flag = "WATER"; - else if (j.flag() == JFunc::Flag::GAS) - flag = "GAS"; - - if (j.direction() == JFunc::Direction::X) - dir = "X"; - else if (j.direction() == JFunc::Direction::Y) - dir = "Y"; - else if (j.direction() == JFunc::Direction::Z) - dir = "Z"; - - py::dict ret; - ret["FLAG"] = flag; - ret["DIRECTION"] = dir; - ret["ALPHA_FACTOR"] = j.alphaFactor(); - ret["BETA_FACTOR"] = j.betaFactor(); - if (j.flag() == JFunc::Flag::WATER || j.flag() == JFunc::Flag::BOTH) - ret["OIL_WATER"] = j.owSurfaceTension(); - if (j.flag() == JFunc::Flag::GAS || j.flag() == JFunc::Flag::BOTH) - ret["GAS_OIL"] = j.goSurfaceTension(); - return ret; -} - - -const std::string faceDir( FaceDir::DirEnum dir ) { - switch (dir) { - case FaceDir::DirEnum::XPlus: return "X+"; - case FaceDir::DirEnum::XMinus: return "X-"; - case FaceDir::DirEnum::YPlus: return "Y+"; - case FaceDir::DirEnum::YMinus: return "Y-"; - case FaceDir::DirEnum::ZPlus: return "Z+"; - case FaceDir::DirEnum::ZMinus: return "Z-"; - } - return "Unknown direction"; -} - -py::list faultFaces( const EclipseState& state, const std::string& name ) { - py::list l; - const auto& gr = state.getInputGrid(); // used for global -> IJK - const auto& fc = state.getFaults(); - const Fault& f = fc.getFault(name); - for (const auto& ff : f) { - // for each fault face - for (size_t g : ff) { - // for global index g in ff - const auto ijk = gr.getIJK(g); - l.append(py::make_tuple(ijk[0], ijk[1], ijk[2], faceDir(ff.getDir()))); - } - } - return l; -} -} - -namespace cfg { -} - -namespace grid { -py::tuple getXYZ( const EclipseGrid& grid ) { - return py::make_tuple( grid.getNX(), - grid.getNY(), - grid.getNZ()); -} -int getNumActive( const EclipseGrid& grid ) { - return grid.getNumActive(); -} -int getCartesianSize( const EclipseGrid& grid ) { - return grid.getCartesianSize(); -} -int getGlobalIndex( const EclipseGrid& grid, int i, int j, int k ) { - return grid.getGlobalIndex(i, j, k); -} -py::tuple getIJK( const EclipseGrid& grid, int g ) { - const auto& ijk = grid.getIJK(g); - return py::make_tuple(ijk[0], ijk[1], ijk[2]); -} -double cellVolume1G( const EclipseGrid& grid, size_t glob_idx) { - return grid.getCellVolume(glob_idx); -} -double cellVolume3( const EclipseGrid& grid, size_t i_idx, size_t j_idx, size_t k_idx) { - return grid.getCellVolume(i_idx, j_idx, k_idx); -} -} - -namespace props { -py::list getitem( const Eclipse3DProperties& p, const std::string& kw) { - const auto& ip = p.getIntProperties(); - if (ip.supportsKeyword(kw) && ip.hasKeyword(kw)) - return iterable_to_pylist(p.getIntGridProperty(kw).getData()); - - const auto& dp = p.getDoubleProperties(); - if (dp.supportsKeyword(kw) && dp.hasKeyword(kw)) - return iterable_to_pylist(p.getDoubleGridProperty(kw).getData()); - throw key_error( "no such grid property " + kw ); -} - -bool contains( const Eclipse3DProperties& p, const std::string& kw) { - return - (p.getIntProperties().supportsKeyword(kw) && - p.getIntProperties().hasKeyword(kw)) - || - (p.getDoubleProperties().supportsKeyword(kw) && - p.getDoubleProperties().hasKeyword(kw)) - ; -} -py::list regions( const Eclipse3DProperties& p, const std::string& kw) { - return iterable_to_pylist( p.getRegions(kw) ); -} -} - -namespace group { -py::list wellnames( const Group& g, size_t timestep ) { - return iterable_to_pylist( g.getWells( timestep ) ); -} - -} - -namespace well { -py::list completions( const Well& w) { - return iterable_to_pylist( w.getCompletions() ); -} - -std::string status( const Well& w, size_t timestep ) { - return WellCommon::Status2String( w.getStatus( timestep ) ); -} - -std::string preferred_phase( const Well& w ) { - switch( w.getPreferredPhase() ) { - case Phase::OIL: return "OIL"; - case Phase::GAS: return "GAS"; - case Phase::WATER: return "WATER"; - default: throw std::logic_error( "Unhandled enum value" ); - } -} - -int (Well::*headI)() const = &Well::getHeadI; -int (Well::*headJ)() const = &Well::getHeadI; -double (Well::*refD)() const = &Well::getRefDepth; - -int (Well::*headI_at)(size_t) const = &Well::getHeadI; -int (Well::*headJ_at)(size_t) const = &Well::getHeadI; -double (Well::*refD_at)(size_t) const = &Well::getRefDepth; - -} - -namespace schedule { - -std::vector< Well > get_wells( const Schedule& sch ) { - std::vector< Well > wells; - for( const auto& w : sch.getWells() ) - wells.push_back( *w ); - - return wells; -} - -const Well& get_well( const Schedule& sch, const std::string& name ) try { - return *sch.getWell( name ); -} catch( const std::invalid_argument& e ) { - throw key_error( name ); -} - - -boost::posix_time::ptime get_start_time( const Schedule& s ) { - return boost::posix_time::from_time_t( s.posixStartTime() ); -} - -boost::posix_time::ptime get_end_time( const Schedule& s ) { - return boost::posix_time::from_time_t( s.posixEndTime() ); -} - -py::list get_timesteps( const Schedule& s ) { - namespace time = boost::posix_time; - const auto& tm = s.getTimeMap(); - std::vector< time::ptime > v; - v.reserve( tm.size() ); - - for( size_t i = 0; i < tm.size(); ++i ) - v.push_back( time::from_time_t(tm[ i ]) ); - - return iterable_to_pylist( v ); -} - -py::list get_groups( const Schedule& sch ) { - std::vector< Group > groups; - for( const auto& g : sch.getGroups() ) - groups.push_back( *g ); - - return iterable_to_pylist( groups ); -} - -} - -namespace tables { -double evaluate( const TableManager& tab, - std::string tab_name, - int tab_idx, - std::string col_name, double x ) try { - return tab[tab_name].getTable(tab_idx).evaluate(col_name, x); -} catch( std::invalid_argument& e ) { - throw key_error( e.what() ); -} -} - -EclipseState (*parse)( const std::string&, const ParseContext& ) = &Parser::parse; -EclipseState (*parseData) (const std::string &data, const ParseContext& context) = &Parser::parseData; -void (ParseContext::*ctx_update)(const std::string&, InputError::Action) = &ParseContext::update; - -} BOOST_PYTHON_MODULE(libsunbeam) { -/* - * Python C-API requires this macro to be invoked before anything from - * datetime.h is used. - */ -PyDateTime_IMPORT; -/* register all converters */ -py::to_python_converter< const boost::posix_time::ptime, - ptime_to_python_datetime >(); + /* + * Python C-API requires this macro to be invoked before anything from + * datetime.h is used. + */ + PyDateTime_IMPORT; -py::register_exception_translator< key_error >( &key_error::translate ); + /* register all converters */ + py::to_python_converter< const boost::posix_time::ptime, + ptime_to_python_datetime >(); -py::def( "parse", parse ); -py::def( "parseData", parseData ); + py::register_exception_translator< key_error >( &key_error::translate ); + eclipse_state::export_EclipseState(); + eclipse_config::export_EclipseConfig(); + completion::export_Completion(); + eclipse_3d_properties::export_Eclipse3DProperties(); + eclipse_grid::export_EclipseGrid(); + group::export_Group(); + schedule::export_Schedule(); + table_manager::export_TableManager(); + well::export_Well(); -/* - * state, grid, properties - */ -py::class_< EclipseState >( "EclipseState", py::no_init ) - .add_property( "title", &EclipseState::getTitle ) - .def( "_schedule", &EclipseState::getSchedule, ref() ) - .def( "_props", &EclipseState::get3DProperties, ref() ) - .def( "_grid", &EclipseState::getInputGrid, ref() ) - .def( "_cfg", &EclipseState::cfg, ref() ) - .def( "_tables", &EclipseState::getTableManager, ref() ) - .def( "has_input_nnc", &EclipseState::hasInputNNC ) - .def( "input_nnc", state::getNNC ) - .def( "faultNames", state::faultNames ) - .def( "faultFaces", state::faultFaces ) - .def( "jfunc", state::jfunc ) - ; + // parser::export_Parser(); + // deck::export_Deck(); + // deck_keyword::export_DeckKeyword(); -py::class_< EclipseGrid >( "EclipseGrid", py::no_init ) - .def( "_getXYZ", grid::getXYZ ) - .def( "nactive", grid::getNumActive ) - .def( "cartesianSize", grid::getCartesianSize ) - .def( "globalIndex", grid::getGlobalIndex ) - .def( "getIJK", grid::getIJK ) - .def( "_cellVolume1G", grid::cellVolume1G) - .def( "_cellVolume3", grid::cellVolume3) - ; - -py::class_< Eclipse3DProperties >( "Eclipse3DProperties", py::no_init ) - .def( "getRegions", props::regions ) - .def( "__contains__", props::contains ) - .def( "__getitem__", props::getitem ) - ; - -py::class_< TableManager >( "Tables", py::no_init ) - .def( "__contains__", &TableManager::hasTables ) - .def("_evaluate", tables::evaluate ) - ; - -/* - * config - */ -py::class_< EclipseConfig >( "EclipseConfig", py::no_init ) - .def( "summary", &EclipseConfig::summary, ref()) - .def( "init", &EclipseConfig::init, ref()) - .def( "restart", &EclipseConfig::restart, ref()) - .def( "simulation", &EclipseConfig::simulation, ref()) - ; - -py::class_< SummaryConfig >( "SummaryConfig", py::no_init ) - .def( "__contains__", &SummaryConfig::hasKeyword ) - ; - -py::class_< InitConfig >( "InitConfig", py::no_init ) - .def( "hasEquil", &InitConfig::hasEquil ) - .def( "restartRequested", &InitConfig::restartRequested ) - .def( "getRestartStep" , &InitConfig::getRestartStep ) - ; - -py::class_< RestartConfig >( "RestartConfig", py::no_init ) - .def( "getKeyword", &RestartConfig::getKeyword ) - .def( "getFirstRestartStep", &RestartConfig::getFirstRestartStep ) - .def( "getWriteRestartFile", &RestartConfig::getWriteRestartFile ) - ; - -py::class_< SimulationConfig >( "SimulationConfig", py::no_init ) - .def("hasThresholdPressure", &SimulationConfig::hasThresholdPressure ) - .def("useCPR", &SimulationConfig::useCPR ) - .def("hasDISGAS", &SimulationConfig::hasDISGAS ) - .def("hasVAPOIL", &SimulationConfig::hasVAPOIL ) - ; - - - - -/* - * schedule, well, completion, group - */ -py::class_< Well >( "Well", py::no_init ) - .add_property( "name", mkcopy( &Well::name ) ) - .add_property( "preferred_phase", &well::preferred_phase ) - .def( "I", well::headI ) - .def( "I", well::headI_at ) - .def( "J", well::headJ ) - .def( "J", well::headJ_at ) - .def( "ref", well::refD ) - .def( "ref", well::refD_at ) - .def( "status", &well::status ) - .def( "isdefined", &Well::hasBeenDefined ) - .def( "isinjector", &Well::isInjector ) - .def( "isproducer", &Well::isProducer ) - .def( "group", &Well::getGroupName ) - .def( "guide_rate", &Well::getGuideRate ) - .def( "available_gctrl", &Well::isAvailableForGroupControl ) - .def( "__eq__", &Well::operator== ) - .def( "completions", well::completions ) - ; - -py::class_< Completion >( "Completion", py::no_init ) - .def( "getI", &Completion::getI ) - .def( "getJ", &Completion::getJ ) - .def( "getK", &Completion::getK ) - ; - - -py::class_< std::vector< Well > >( "WellList", py::no_init ) - .def( py::vector_indexing_suite< std::vector< Well > >() ) - ; - -py::class_< Group >( "Group", py::no_init ) - .add_property( "name", mkcopy( &Group::name ) ) - .def( "_wellnames", group::wellnames ) - ; - -py::class_< Schedule >( "Schedule", py::no_init ) - .add_property( "_wells", schedule::get_wells ) - .add_property( "_groups", schedule::get_groups ) - .add_property( "start", schedule::get_start_time ) - .add_property( "end", schedule::get_end_time ) - .add_property( "timesteps", schedule::get_timesteps ) - .def( "__contains__", &Schedule::hasWell ) - .def( "__getitem__", schedule::get_well, ref() ) - .def( "_group", &Schedule::getGroup, ref() ) - ; - - - -/* - * misc - */ -py::class_< ParseContext >( "ParseContext" ) - .def( "update", ctx_update ) - ; - -py::enum_< InputError::Action >( "action" ) - .value( "throw", InputError::Action::THROW_EXCEPTION ) - .value( "warn", InputError::Action::WARN ) - .value( "ignore", InputError::Action::IGNORE ) - ; } diff --git a/sunbeam/table_manager.cpp b/sunbeam/table_manager.cpp new file mode 100644 index 000000000..d81dc010c --- /dev/null +++ b/sunbeam/table_manager.cpp @@ -0,0 +1,29 @@ +#include + +#include "table_manager.hpp" + +namespace py = boost::python; +using namespace Opm; + + +namespace table_manager { + + double evaluate( const TableManager& tab, + std::string tab_name, + int tab_idx, + std::string col_name, double x ) try { + return tab[tab_name].getTable(tab_idx).evaluate(col_name, x); + } catch( std::invalid_argument& e ) { + throw key_error( e.what() ); + } + + void export_TableManager() { + + py::class_< TableManager >( "Tables", py::no_init ) + .def( "__contains__", &TableManager::hasTables ) + .def("_evaluate", &evaluate ) + ; + + } + +} diff --git a/sunbeam/table_manager.hpp b/sunbeam/table_manager.hpp new file mode 100644 index 000000000..dea277de8 --- /dev/null +++ b/sunbeam/table_manager.hpp @@ -0,0 +1,26 @@ +#ifndef SUNBEAM_TABLE_MANAGER_HPP +#define SUNBEAM_TABLE_MANAGER_HPP + +#include +#include "converters.hpp" + + +namespace Opm { + class TableManager; +} + +namespace table_manager { + namespace py = boost::python; + using namespace Opm; + + + double evaluate( const TableManager& tab, + std::string tab_name, + int tab_idx, + std::string col_name, double x ); + + void export_TableManager(); + +} + +#endif //SUNBEAM_TABLE_MANAGER_HPP diff --git a/sunbeam/well.cpp b/sunbeam/well.cpp new file mode 100644 index 000000000..68341cdb1 --- /dev/null +++ b/sunbeam/well.cpp @@ -0,0 +1,68 @@ +#include + +#include "well.hpp" + +namespace py = boost::python; +using namespace Opm; + +using ref = py::return_internal_reference<>; +using copy = py::return_value_policy< py::copy_const_reference >; + + +namespace well { + + py::list completions( const Well& w) { + return iterable_to_pylist( w.getCompletions() ); + } + + std::string status( const Well& w, size_t timestep ) { + return WellCommon::Status2String( w.getStatus( timestep ) ); + } + + std::string preferred_phase( const Well& w ) { + switch( w.getPreferredPhase() ) { + case Phase::OIL: return "OIL"; + case Phase::GAS: return "GAS"; + case Phase::WATER: return "WATER"; + default: throw std::logic_error( "Unhandled enum value" ); + } + } + + int (Well::*headI)() const = &Well::getHeadI; + int (Well::*headJ)() const = &Well::getHeadI; + double (Well::*refD)() const = &Well::getRefDepth; + + int (Well::*headI_at)(size_t) const = &Well::getHeadI; + int (Well::*headJ_at)(size_t) const = &Well::getHeadI; + double (Well::*refD_at)(size_t) const = &Well::getRefDepth; + + + void export_Well() { + + py::class_< Well >( "Well", py::no_init ) + .add_property( "name", mkcopy( &Well::name ) ) + .add_property( "preferred_phase", &well::preferred_phase ) + .def( "I", headI ) + .def( "I", headI_at ) + .def( "J", headJ ) + .def( "J", headJ_at ) + .def( "ref", refD ) + .def( "ref", refD_at ) + .def( "status", &status ) + .def( "isdefined", &Well::hasBeenDefined ) + .def( "isinjector", &Well::isInjector ) + .def( "isproducer", &Well::isProducer ) + .def( "group", &Well::getGroupName ) + .def( "guide_rate", &Well::getGuideRate ) + .def( "available_gctrl", &Well::isAvailableForGroupControl ) + .def( "__eq__", &Well::operator== ) + .def( "completions", &completions ) + ; + + py::class_< std::vector< Well > >( "WellList", py::no_init ) + .def( py::vector_indexing_suite< std::vector< Well > >() ) + ; + + } + +} diff --git a/sunbeam/well.hpp b/sunbeam/well.hpp new file mode 100644 index 000000000..c7d0714ac --- /dev/null +++ b/sunbeam/well.hpp @@ -0,0 +1,25 @@ +#ifndef SUNBEAM_WELL_HPP +#define SUNBEAM_WELL_HPP + +#include +#include +#include "converters.hpp" + + +namespace Opm { + class Well; +} + +namespace well { + namespace py = boost::python; + using namespace Opm; + + py::list completions( const Well& w) ; + std::string status( const Well& w, size_t timestep ); + std::string preferred_phase( const Well& w ); + + void export_Well(); + +} + +#endif //SUNBEAM_WELL_HPP