diff --git a/python/sunbeam/__init__.py b/python/sunbeam/__init__.py index c717ea304..c269c04e9 100644 --- a/python/sunbeam/__init__.py +++ b/python/sunbeam/__init__.py @@ -2,10 +2,10 @@ """ -from .schedule import Well +from .schedule import Well, Completion from .libsunbeam import action from .config import EclipseConfig from .parser import parse_deck, parse -__version__ = '0.0.1' +__version__ = '0.0.3' __license__ = 'GNU General Public License version 3' diff --git a/python/sunbeam/schedule.py b/python/sunbeam/schedule.py index bb48b4028..04806fc77 100644 --- a/python/sunbeam/schedule.py +++ b/python/sunbeam/schedule.py @@ -31,6 +31,9 @@ class Well(object): def __repr__(self): return 'Well(name = "%s")' % self.name + def completions(self, timestep): + return map(Completion, self._completions(timestep)) + @staticmethod def defined(timestep): def fn(well): return well.isdefined(timestep) @@ -66,6 +69,36 @@ class Well(object): return fn +@delegate(lib.Completion) +class Completion(object): + + @property + def pos(self): + return self.I, self.J, self.K + + def __repr__(self): + return 'Completion(number = {})'.format(self.number) + + # using the names flowing and closed for functions that test if a well is + # opened or closed at some point, because we might want to use the more + # imperative words 'open' and 'close' (or 'shut') for *changing* the status + # later + @staticmethod + def flowing(): + def fn(completion): return completion.state == 'OPEN' + return fn + + @staticmethod + def closed(): + def fn(completion): return completion.state == 'SHUT' + return fn + + @staticmethod + def auto(): + def fn(completion): return completion.state == 'AUTO' + return fn + + @delegate(lib.Group) class Group(object): def __init__(self, _, schedule, timestep): diff --git a/sunbeam/completion.cpp b/sunbeam/completion.cpp index f6a6488a1..584ea582c 100644 --- a/sunbeam/completion.cpp +++ b/sunbeam/completion.cpp @@ -2,12 +2,36 @@ #include "sunbeam.hpp" +namespace { + +std::string state( const Completion& c ) { + return WellCompletion::StateEnum2String( c.getState() ); +} + +std::string direction( const Completion& c ) { + return WellCompletion::DirectionEnum2String( c.getDirection() ); +} + +} + + void sunbeam::export_Completion() { py::class_< Completion >( "Completion", py::no_init ) - .def( "getI", &Completion::getI ) - .def( "getJ", &Completion::getJ ) - .def( "getK", &Completion::getK ) + .add_property( "direction", &direction ) + .add_property( "state", &state ) + .def_readonly( "I", &Completion::getI ) + .def_readonly( "J", &Completion::getJ ) + .def_readonly( "K", &Completion::getK ) + .def_readonly( "attached_to_segment", &Completion::attachedToSegment ) + .def_readonly( "center_depth", &Completion::getCenterDepth ) + .def_readonly( "diameter", &Completion::getDiameter ) + .def_readonly( "number", &Completion::complnum) + .def_readonly( "sat_table_id", &Completion::getSatTableId ) + .def_readonly( "segment_number", &Completion::getSegmentNumber ) + .def_readonly( "skin_factor", &Completion::getSkinFactor ) + .def_readonly( "transmissibility", &Completion::getConnectionTransmissibilityFactor ) + .def_readonly( "well_pi", &Completion::getWellPi ) ; } diff --git a/sunbeam/well.cpp b/sunbeam/well.cpp index 3f8896137..8c4b49a5d 100644 --- a/sunbeam/well.cpp +++ b/sunbeam/well.cpp @@ -7,8 +7,8 @@ namespace { - py::list completions( const Well& w) { - return iterable_to_pylist( w.getCompletions() ); + py::list completions( const Well& w, size_t timestep ) { + return iterable_to_pylist( w.getCompletions( timestep ) ); } std::string status( const Well& w, size_t timestep ) { @@ -39,21 +39,21 @@ void sunbeam::export_Well() { py::class_< Well >( "Well", py::no_init ) .add_property( "name", mkcopy( &Well::name ) ) .add_property( "preferred_phase", &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( "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 ) + .def( "__eq__", &Well::operator== ) + .def( "_completions", &completions ) ; py::class_< std::vector< Well > >( "WellList", py::no_init ) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0c09f80a9..1794321c6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,6 +3,6 @@ configure_file(data/CORNERPOINT_ACTNUM.DATA data/CORNERPOINT_ACTNUM.DATA COPYONL configure_file(data/JFUNC.DATA data/JFUNC.DATA COPYONLY) -foreach(prog deck group_tree parse_deck parse state props schedule wells) +foreach(prog completions deck group_tree parse_deck parse state props schedule wells) add_python_test(${prog} ${prog}.py) endforeach() diff --git a/tests/completions.py b/tests/completions.py new file mode 100644 index 000000000..e566c8c75 --- /dev/null +++ b/tests/completions.py @@ -0,0 +1,46 @@ +import unittest +import sunbeam + +class TestWells(unittest.TestCase): + spe3 = None + + def setUp(self): + if self.spe3 is None: + self.spe3 = sunbeam.parse('spe3/SPE3CASE1.DATA') + self.timesteps = self.spe3.schedule.timesteps + self.wells = self.spe3.schedule.wells + + def test_completion_pos(self): + p00 = self.wells[0].completions(0)[0].pos + p01 = self.wells[0].completions(0)[1].pos + p10 = self.wells[1].completions(0)[0].pos + p11 = self.wells[1].completions(0)[1].pos + self.assertEqual(p00, (6,6,2)) + self.assertEqual(p01, (6,6,3)) + self.assertEqual(p10, (0,0,0)) + self.assertEqual(p11, (0,0,1)) + + def test_completion_state(self): + for well in self.wells: + for timestep,_ in enumerate(self.timesteps): + for completion in well.completions(timestep): + self.assertEqual("OPEN", completion.state) + + def test_filters(self): + flowing = sunbeam.Completion.flowing() + closed = sunbeam.Completion.closed() + completions = self.wells[0].completions(0) + self.assertEqual(len(filter(flowing, completions)), 2) + self.assertEqual(len(filter(closed, completions)), 0) + + def test_direction(self): + for well in self.wells: + for timestep,_ in enumerate(self.timesteps): + for completion in well.completions(timestep): + self.assertEqual(completion.direction, 'Z') + + def test_attached_to_segment(self): + for well in self.wells: + for timestep,_ in enumerate(self.timesteps): + for completion in well.completions(timestep): + self.assertFalse(completion.attached_to_segment) diff --git a/tests/wells.py b/tests/wells.py index 097843e77..a7b313f1e 100644 --- a/tests/wells.py +++ b/tests/wells.py @@ -7,6 +7,7 @@ class TestWells(unittest.TestCase): def setUp(self): if self.spe3 is None: self.spe3 = sunbeam.parse('spe3/SPE3CASE1.DATA') + self.timesteps = self.spe3.schedule.timesteps self.wells = self.spe3.schedule.wells def inje(self): @@ -90,6 +91,6 @@ class TestWells(unittest.TestCase): def testCompletions(self): w0 = self.wells[0] - c0,c1 = w0.completions() - self.assertEqual((6,6,2), (c0.getI(), c0.getJ(), c0.getK())) - self.assertEqual((6,6,3), (c1.getI(), c1.getJ(), c1.getK())) + c0,c1 = w0.completions(len(self.timesteps) - 1) + self.assertEqual((6,6,2), c0.pos) + self.assertEqual((6,6,3), c1.pos)