diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 6f38adf2a..3a49cd8c0 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -190,6 +190,7 @@ if(ENABLE_ECL_INPUT) python/cxx/deck_keyword.cpp python/cxx/eclipse_io.cpp python/cxx/eclipse_3d_properties.cpp + python/cxx/field_props.cpp python/cxx/eclipse_config.cpp python/cxx/eclipse_grid.cpp python/cxx/eclipse_state.cpp diff --git a/opm/parser/eclipse/EclipseState/EclipseState.hpp b/opm/parser/eclipse/EclipseState/EclipseState.hpp index 3b1f4a740..42928033d 100644 --- a/opm/parser/eclipse/EclipseState/EclipseState.hpp +++ b/opm/parser/eclipse/EclipseState/EclipseState.hpp @@ -39,6 +39,8 @@ namespace Opm { + bool enable3DPropsTesting(); + template< typename > class GridProperty; template< typename > class GridProperties; diff --git a/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp b/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp index 0a2981aa8..2f1808bf4 100644 --- a/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp +++ b/opm/parser/eclipse/EclipseState/Grid/FieldPropsManager.hpp @@ -20,6 +20,7 @@ #define FIELDPROPS_MANAGER_HPP #include +#include namespace Opm { diff --git a/python/cxx/eclipse_state.cpp b/python/cxx/eclipse_state.cpp index 232b48d12..57dc5c6df 100644 --- a/python/cxx/eclipse_state.cpp +++ b/python/cxx/eclipse_state.cpp @@ -85,14 +85,24 @@ namespace { return l; } + const FieldPropsManager& get_field_props(const EclipseState& state) { + if (enable3DPropsTesting()) + return state.fieldProps(); + else + throw std::logic_error("Field properties not implemented for this compilation."); + } + } void python::common::export_EclipseState(py::module& module) { + module.def("test_field_props", &enable3DPropsTesting); + py::class_< EclipseState >( module, "EclipseState" ) .def(py::init()) .def_property_readonly( "title", &EclipseState::getTitle ) - .def( "props", &EclipseState::get3DProperties, ref_internal) + .def( "ecl3d_props", &EclipseState::get3DProperties, ref_internal) + .def( "field_props", &get_field_props, ref_internal) .def( "grid", &EclipseState::getInputGrid, ref_internal) .def( "config", &EclipseState::cfg, ref_internal) .def( "tables", &EclipseState::getTableManager, ref_internal) diff --git a/python/cxx/export.cpp b/python/cxx/export.cpp index 46054e227..858f48912 100644 --- a/python/cxx/export.cpp +++ b/python/cxx/export.cpp @@ -13,6 +13,7 @@ void python::common::export_all(py::module& module) { export_Connection(module); export_EclipseConfig(module); export_Eclipse3DProperties(module); + export_FieldProperties(module); export_EclipseState(module); export_TableManager(module); export_EclipseGrid(module); diff --git a/python/cxx/export.hpp b/python/cxx/export.hpp index 0dc60a142..d89288655 100644 --- a/python/cxx/export.hpp +++ b/python/cxx/export.hpp @@ -19,6 +19,7 @@ void export_Connection(py::module& module); void export_Deck(py::module& module); void export_DeckKeyword(py::module& module); void export_Eclipse3DProperties(py::module& module); +void export_FieldProperties(py::module& module); void export_EclipseConfig(py::module& module); void export_EclipseGrid(py::module& module); void export_EclipseState(py::module& module); diff --git a/python/cxx/field_props.cpp b/python/cxx/field_props.cpp new file mode 100644 index 000000000..418690507 --- /dev/null +++ b/python/cxx/field_props.cpp @@ -0,0 +1,39 @@ +#include + +#include + +#include + +#include "export.hpp" +#include "converters.hpp" + +namespace { + + py::list getitem( const FieldPropsManager& m, const std::string& kw) { + if (m.has(kw)) + return iterable_to_pylist( m.get(kw) ); + if (m.has(kw)) + return iterable_to_pylist( m.get(kw) ); + + throw py::key_error( "no such grid property " + kw ); + } + + bool contains( const FieldPropsManager& manager, const std::string& kw) { + if (manager.has(kw)) + return true; + if (manager.has(kw)) + return true; + + return false; + } +} + + +void python::common::export_FieldProperties(py::module& module) { + + py::class_< FieldPropsManager >( module, "FieldProperties") + .def( "__contains__", &contains ) + .def( "__getitem__", &getitem ) + ; + +} diff --git a/python/python/opm/_common.py b/python/python/opm/_common.py index df593dfb3..892bdf7dd 100644 --- a/python/python/opm/_common.py +++ b/python/python/opm/_common.py @@ -15,6 +15,8 @@ from .libopmcommon_python import Parser, ParseContext from .libopmcommon_python import DeckKeyword from .libopmcommon_python import EclipseState +from .libopmcommon_python import test_field_props +from .libopmcommon_python import FieldProperties from .libopmcommon_python import Schedule from .libopmcommon_python import OpmLog from .libopmcommon_python import SummaryConfig diff --git a/python/python/opm/io/ecl_state/__init__.py b/python/python/opm/io/ecl_state/__init__.py index 1629610f3..27a809011 100644 --- a/python/python/opm/io/ecl_state/__init__.py +++ b/python/python/opm/io/ecl_state/__init__.py @@ -1 +1 @@ -from opm._common import EclipseState +from opm._common import EclipseState, test_field_props diff --git a/python/setup.py b/python/setup.py index e651b5a35..9d73122d6 100644 --- a/python/setup.py +++ b/python/setup.py @@ -41,6 +41,7 @@ ext_modules = [ 'cxx/deck_keyword.cpp', 'cxx/eclipse_io.cpp', 'cxx/eclipse_3d_properties.cpp', + 'cxx/field_props.cpp', 'cxx/eclipse_config.cpp', 'cxx/eclipse_grid.cpp', 'cxx/eclipse_state.cpp', diff --git a/python/tests/test_field_props.py b/python/tests/test_field_props.py new file mode 100644 index 000000000..18eb2a391 --- /dev/null +++ b/python/tests/test_field_props.py @@ -0,0 +1,73 @@ +import unittest +import opm.io + +from opm.io.parser import Parser +from opm.io.ecl_state import EclipseState, test_field_props +try: + from tests.utils import test_path +except ImportError: + from utils import test_path + + +if (test_field_props()): + + class TestFieldProps(unittest.TestCase): + + def assertClose(self, expected, observed, epsilon=1e-08): + diff = abs(expected - observed) + err_msg = '|%g - %g| = %g > %g' % (expected, observed, diff, epsilon) + self.assertTrue(diff <= epsilon, msg=err_msg) + + def setUp(self): + parser = Parser() + deck = parser.parse(test_path('spe3/SPE3CASE1.DATA')) + self.spe3 = EclipseState(deck) + self.props = self.spe3.field_props() + + def test_contains(self): + p = self.props + self.assertTrue('PORO' in p) + self.assertFalse('NONO' in p) + self.assertTrue('PORV' in p) + + def test_getitem(self): + p = self.props + poro = p['PORO'] + self.assertEqual(324, len(poro)) + self.assertEqual(0.13, poro[0]) + self.assertTrue( 'PERMX' in p ) + px = p['PERMX'] + print(len(px)) + self.assertEqual(324, len(px)) + + def test_permx_values(self): + def md2si(md): + #millidarcy->SI + return md * 1e-3 * 9.869233e-13 + field_props = self.props + + grid = self.spe3.grid() + permx = field_props['PERMX'] + print('set(PERMX) = %s' % set(permx)) + # 130mD, 40mD, 20mD, and 150mD, respectively, top to bottom + darcys = {0:md2si(130), 1:md2si(40), 2:md2si(20), 3:md2si(150)} + for i in range(grid.nx): + for j in range(grid.ny): + for k in range(grid.nz): + g_idx = grid.globalIndex(i,j,k) + perm = permx[g_idx] + darcy = darcys[k] + self.assertClose(darcy, perm) + + def test_volume(self): + grid = self.spe3.grid() + for i in range(grid.nx): + for j in range(grid.ny): + for k in range(grid.nz): + g_idx = grid.globalIndex(i,j,k) + exp = 293.3 * 293.3 * 30 # cubicfeet = 73 078.6084 cubic meter + exp *= (12*0.0254)**3 # cubic feet to cubic meter + if k == 0: + self.assertClose(exp, grid.getCellVolume(g_idx)) + self.assertEqual(grid.getCellVolume(g_idx), grid.getCellVolume(i, j, k)) + diff --git a/python/tests/test_props.py b/python/tests/test_props.py index d130068a8..6d270e8b5 100644 --- a/python/tests/test_props.py +++ b/python/tests/test_props.py @@ -2,7 +2,7 @@ import unittest import opm.io from opm.io.parser import Parser -from opm.io.ecl_state import EclipseState +from opm.io.ecl_state import EclipseState, test_field_props try: from tests.utils import test_path except ImportError: @@ -20,7 +20,10 @@ class TestProps(unittest.TestCase): parser = Parser() deck = parser.parse(test_path('spe3/SPE3CASE1.DATA')) self.spe3 = EclipseState(deck) - self.props = self.spe3.props() + self.props = self.spe3.ecl3d_props() + if (not test_field_props()): + with self.assertRaises(RuntimeError): + self.field = self.spe3.field_props() def test_contains(self): p = self.props @@ -58,7 +61,6 @@ class TestProps(unittest.TestCase): self.assertClose(darcy, perm) def test_volume(self): - e3dp = self.props grid = self.spe3.grid() for i in range(grid.nx): for j in range(grid.ny): diff --git a/src/opm/parser/eclipse/EclipseState/EclipseState.cpp b/src/opm/parser/eclipse/EclipseState/EclipseState.cpp index 752788a55..1cf069d63 100644 --- a/src/opm/parser/eclipse/EclipseState/EclipseState.cpp +++ b/src/opm/parser/eclipse/EclipseState/EclipseState.cpp @@ -48,6 +48,19 @@ namespace Opm { +/* +This Function is used in Python to check if the +ENABBLE_3DPROPS_TESTING macro has been set. +*/ +#ifdef ENABLE_3DPROPS_TESTING +bool enable3DPropsTesting() { + return true; +} +#else +bool enable3DPropsTesting() { + return false; +} +#endif namespace {