From 6e8b4a6c1237e16c80f0bd38ed98eec717438363 Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Tue, 3 Mar 2020 08:47:44 +0100 Subject: [PATCH] Add WellType class for ecl interop --- .../EclipseState/Schedule/ScheduleTypes.hpp | 43 ++++ .../EclipseState/Schedule/ScheduleTypes.cpp | 198 ++++++++++++++++++ tests/parser/WellTests.cpp | 44 ++++ 3 files changed, 285 insertions(+) diff --git a/opm/parser/eclipse/EclipseState/Schedule/ScheduleTypes.hpp b/opm/parser/eclipse/EclipseState/Schedule/ScheduleTypes.hpp index df5f9076f..5bdaeb302 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/ScheduleTypes.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/ScheduleTypes.hpp @@ -21,6 +21,7 @@ #define OPM_SCHEDULE_TYPES_HPP #include +#include namespace Opm { @@ -33,6 +34,48 @@ enum class InjectorType { const std::string InjectorType2String( InjectorType enumValue ); InjectorType InjectorTypeFromString( const std::string& stringValue ); + +class WellType { +public: + WellType(int ecl_wtype, int welspecs_phase); + WellType(bool producer, Phase welspecs_phase); + explicit WellType(Phase welspecs_phase); + WellType() = default; + + bool injector() const; + bool producer() const; + bool update(InjectorType injector_type); + bool update(bool producer); + + static bool oil_injector(int ecl_wtype); + static bool gas_injector(int ecl_wtype); + static bool water_injector(int ecl_wtype); + static bool producer(int ecl_wtype); + + int ecl_wtype() const; + int ecl_phase() const; + Phase preferred_phase() const; + InjectorType injector_type() const; + bool operator==(const WellType& other) const; +private: + bool m_producer; + /* + The injection_phase member is updated during the course of the simulation; + following each WCONINJE keyword the injection phase is updated. If an + producer is specified in the constructor the injection_phase is + initialzied to the welspecs phase. This is not wildly random - but the + injection_phase will not be meaningfull before an update(Phase) call has been + issued. + + The welspecs_phase is the preferred phase specified when the well is + defined with the WELSPECS keyword. This member is immutable, and it is only + used when initializing the well equations for a producer. + */ + + Phase injection_phase; + Phase m_welspecs_phase; +}; + } diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/ScheduleTypes.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/ScheduleTypes.cpp index 35167a339..6ddbb172c 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/ScheduleTypes.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/ScheduleTypes.cpp @@ -22,6 +22,204 @@ namespace Opm { +namespace ecl { + +static constexpr int producer = 1; +static constexpr int oil_injector = 2; +static constexpr int water_injector = 3; +static constexpr int gas_injector = 4; + + +static constexpr int oil_phase = 1; +static constexpr int water_phase = 2; +static constexpr int gas_phase = 3; +static constexpr int liquid_phase = 4; + + +Phase from_ecl_phase(int ecl_phase) { + switch(ecl_phase) { + case ecl::oil_phase: + return Phase::OIL; + case ecl::water_phase: + return Phase::WATER; + case ecl::gas_phase: + return Phase::GAS; + case ecl::liquid_phase: + throw std::logic_error("Sorry wells with preferred phase:LIQUID is not supported"); + default: + throw std::invalid_argument("Invalid integer well phase"); + } +} +} + + +namespace { + +Phase from_injector_type(InjectorType injector_type) { + switch (injector_type) { + case InjectorType::WATER: + return Phase::WATER; + case InjectorType::GAS: + return Phase::GAS; + case InjectorType::OIL: + return Phase::OIL; + default: + throw std::logic_error("Unhandled injector type"); + } +} + +} + + +bool WellType::producer(int ecl_wtype) { + return ecl_wtype == ecl::producer; +} + +bool WellType::oil_injector(int ecl_wtype) { + return ecl_wtype == ecl::oil_injector; +} + +bool WellType::water_injector(int ecl_wtype) { + return ecl_wtype == ecl::water_injector; +} + +bool WellType::gas_injector(int ecl_wtype) { + return ecl_wtype == ecl::gas_injector; +} + + +WellType::WellType(int ecl_wtype, int ecl_phase) : + injection_phase(ecl::from_ecl_phase(ecl_phase)), + m_welspecs_phase(ecl::from_ecl_phase(ecl_phase)) +{ + this->m_producer = false; + switch (ecl_wtype) { + case ecl::producer: + this->m_producer = true; + break; + case ecl::oil_injector: + this->injection_phase = Phase::OIL; + break; + case ecl::water_injector: + this->injection_phase = Phase::WATER; + break; + case ecl::gas_injector: + this->injection_phase = Phase::GAS; + break; + default: + throw std::invalid_argument("Invalid integer well type ID"); + } + +} + +WellType::WellType(bool producer, Phase phase) : + m_producer(producer), + injection_phase(phase), + m_welspecs_phase(phase) +{} + +WellType::WellType(Phase phase) : + WellType(true, phase) +{} + +bool WellType::update(bool producer_arg) { + if (this->m_producer != producer_arg) { + this->m_producer = producer_arg; + return true; + } else + return false; +} + +bool WellType::update(InjectorType injector_type) { + bool ret_value = false; + if (this->m_producer) { + this->m_producer = false; + ret_value = true; + } + + auto inj_phase = from_injector_type(injector_type); + if (this->injection_phase != inj_phase) { + this->injection_phase = inj_phase; + ret_value = true; + } + + return ret_value; +} + +bool WellType::producer() const { + return this->m_producer; +} + +bool WellType::injector() const { + return !this->m_producer; +} + +int WellType::ecl_wtype() const { + if (this->m_producer) + return ecl::producer; + + switch (this->injection_phase) { + case Phase::OIL: + return ecl::oil_injector; + case Phase::WATER: + return ecl::water_injector; + case Phase::GAS: + return ecl::gas_injector; + default: + throw std::logic_error("Internal error - should not be here"); + } +} + +/* + The enum Runspec::Phase is maybe not very well suited; it has lots of 'extra' + phases like ENERGY and BRINE, and at the same time it is missing the phase + LIQUID which should map to ecl value 4. +*/ + +int WellType::ecl_phase() const { + switch (this->m_welspecs_phase) { + case Phase::OIL: + return ecl::oil_phase; + case Phase::WATER: + return ecl::water_phase; + case Phase::GAS: + return ecl::gas_phase; + default: + throw std::logic_error("Member has invalid phase"); + } +} + + +Phase WellType::preferred_phase() const { + return this->m_welspecs_phase; +} + + +bool WellType::operator==(const WellType& other) const { + return this->m_welspecs_phase == other.m_welspecs_phase && + this->injection_phase == other.injection_phase && + this->m_producer == other.m_producer; +} + + +InjectorType WellType::injector_type() const { + if (this->producer()) + throw std::invalid_argument("Asked for injector type for a well which is a producer"); + + switch (this->injection_phase) { + case Phase::OIL: + return InjectorType::OIL; + case Phase::WATER: + return InjectorType::WATER; + case Phase::GAS: + return InjectorType::GAS; + default: + throw std::logic_error("Member has invalid phase"); + } + +} + + const std::string InjectorType2String( InjectorType enumValue ) { switch( enumValue ) { case InjectorType::OIL: diff --git a/tests/parser/WellTests.cpp b/tests/parser/WellTests.cpp index 6a17bf1d4..a561ae7b0 100644 --- a/tests/parser/WellTests.cpp +++ b/tests/parser/WellTests.cpp @@ -863,3 +863,47 @@ BOOST_AUTO_TEST_CASE(WELOPEN) { } +BOOST_AUTO_TEST_CASE(WellTypeTest) { + BOOST_CHECK_THROW(Opm::WellType(0, 3), std::invalid_argument); + BOOST_CHECK_THROW(Opm::WellType(5, 3), std::invalid_argument); + BOOST_CHECK_THROW(Opm::WellType(3, 0), std::invalid_argument); + BOOST_CHECK_THROW(Opm::WellType(3, 5), std::invalid_argument); + + Opm::WellType wt1(1,1); + BOOST_CHECK(wt1.producer()); + BOOST_CHECK(!wt1.injector()); + BOOST_CHECK_EQUAL(wt1.ecl_wtype(), 1); + BOOST_CHECK_EQUAL(wt1.ecl_phase(), 1); + BOOST_CHECK(wt1.preferred_phase() == Phase::OIL); + BOOST_CHECK_THROW(wt1.injector_type(), std::invalid_argument); + + Opm::WellType wt4(4,3); + BOOST_CHECK(!wt4.producer()); + BOOST_CHECK(wt4.injector()); + BOOST_CHECK_EQUAL(wt4.ecl_wtype(), 4); + BOOST_CHECK_EQUAL(wt4.ecl_phase(), 3); + BOOST_CHECK(wt4.preferred_phase() == Phase::GAS); + BOOST_CHECK(wt4.injector_type() == InjectorType::GAS); + + BOOST_CHECK(wt4.update(true)); + BOOST_CHECK(!wt4.update(true)); + BOOST_CHECK(wt4.producer()); + BOOST_CHECK(!wt4.injector()); + BOOST_CHECK_EQUAL(wt4.ecl_wtype(), 1); + BOOST_CHECK_EQUAL(wt4.ecl_phase(), 3); + BOOST_CHECK(wt4.preferred_phase() == Phase::GAS); + + Opm::WellType wtp(false, Phase::WATER); + BOOST_CHECK(!wtp.producer()); + BOOST_CHECK(wtp.injector()); + BOOST_CHECK_EQUAL(wtp.ecl_wtype(), 3); + BOOST_CHECK_EQUAL(wtp.ecl_phase(), 2); + BOOST_CHECK(wtp.preferred_phase() == Phase::WATER); + BOOST_CHECK(wtp.injector_type() == InjectorType::WATER); + + wtp.update( InjectorType::GAS ); + BOOST_CHECK_EQUAL(wtp.ecl_wtype(), 4); + BOOST_CHECK_EQUAL(wtp.ecl_phase(), 2); + BOOST_CHECK(wtp.preferred_phase() == Phase::WATER); + BOOST_CHECK(wtp.injector_type() == InjectorType::GAS); +}