From 5ad65c70ee67c6bb2ce1c7b8fcc93090ec1e340c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Tue, 21 Sep 2021 01:13:39 +0200 Subject: [PATCH] Initialize blackoil simulator from schedule shared with Python. Adds a new constructor to Main.hpp that takes shared pointers to Deck, EclipseState, Schedule, and SummaryConfig. This makes it possible to share these variables with Python without worrying about lifetime issues of the underlying C++ objects. For example, a Python script can first create an opm.io.schedule.Schedule object which is modified from Python. Then, assume the same Python script creates an opm.simulators.BlackOilSimulator which is initialized with the same schedule object. Since the underlying C++ object is a shared pointer, the Schedule object in Python may go out of scope (get deleted by Python) without having the C++ schedule object being deleted. And the Python BlackOilSimulator may continue to be used after the Python Schedule object has been deleted since it still has a valid C++ schedule object. --- ebos/eclgenericvanguard.cc | 33 +- ebos/eclgenericvanguard.hh | 24 +- flow/flow_ebos_blackoil.cpp | 16 +- flow/flow_ebos_blackoil.hpp | 8 +- flow/flow_ebos_brine.cpp | 16 +- flow/flow_ebos_brine.hpp | 8 +- flow/flow_ebos_energy.cpp | 16 +- flow/flow_ebos_energy.hpp | 8 +- flow/flow_ebos_extbo.cpp | 16 +- flow/flow_ebos_extbo.hpp | 8 +- flow/flow_ebos_foam.cpp | 16 +- flow/flow_ebos_foam.hpp | 8 +- flow/flow_ebos_gasoil.cpp | 16 +- flow/flow_ebos_gasoil.hpp | 8 +- flow/flow_ebos_gaswater.cpp | 16 +- flow/flow_ebos_gaswater.hpp | 8 +- flow/flow_ebos_oilwater.cpp | 16 +- flow/flow_ebos_oilwater.hpp | 8 +- flow/flow_ebos_oilwater_brine.cpp | 16 +- flow/flow_ebos_oilwater_brine.hpp | 8 +- flow/flow_ebos_oilwater_polymer.cpp | 16 +- flow/flow_ebos_oilwater_polymer.hpp | 8 +- flow/flow_ebos_polymer.cpp | 16 +- flow/flow_ebos_polymer.hpp | 8 +- flow/flow_ebos_solvent.cpp | 16 +- flow/flow_ebos_solvent.hpp | 8 +- opm/simulators/flow/Main.hpp | 151 +++--- .../flow/python/PyBlackOilSimulator.hpp | 76 +++ .../flow/python/Pybind11Exporter.hpp | 15 + opm/simulators/utils/readDeck.cpp | 4 +- opm/simulators/utils/readDeck.hpp | 4 +- python/simulators/CMakeLists.txt | 35 +- python/simulators/PyBlackOilSimulator.cpp | 162 +++++++ python/simulators/Pybind11Exporter.cpp | 11 + python/test/test_basic.py | 2 +- python/test/test_schedule.py | 52 +++ .../{SPE1CASE1 => SPE1CASE1a}/SPE1CASE1.DATA | 0 python/test_data/SPE1CASE1b/SPE1CASE1.DATA | 439 ++++++++++++++++++ 38 files changed, 1048 insertions(+), 248 deletions(-) create mode 100644 opm/simulators/flow/python/PyBlackOilSimulator.hpp create mode 100644 opm/simulators/flow/python/Pybind11Exporter.hpp create mode 100644 python/simulators/PyBlackOilSimulator.cpp create mode 100644 python/simulators/Pybind11Exporter.cpp create mode 100755 python/test/test_schedule.py rename python/test_data/{SPE1CASE1 => SPE1CASE1a}/SPE1CASE1.DATA (100%) create mode 100644 python/test_data/SPE1CASE1b/SPE1CASE1.DATA diff --git a/ebos/eclgenericvanguard.cc b/ebos/eclgenericvanguard.cc index c86fa62c7..ef4031693 100644 --- a/ebos/eclgenericvanguard.cc +++ b/ebos/eclgenericvanguard.cc @@ -55,11 +55,11 @@ namespace Opm { double EclGenericVanguard::externalSetupTime_ = 0.0; std::unique_ptr EclGenericVanguard::externalParseContext_; std::unique_ptr EclGenericVanguard::externalErrorGuard_; -std::unique_ptr EclGenericVanguard::externalDeck_; +std::shared_ptr EclGenericVanguard::externalDeck_; bool EclGenericVanguard::externalDeckSet_ = false; -std::unique_ptr EclGenericVanguard::externalEclState_; -std::unique_ptr EclGenericVanguard::externalEclSchedule_; -std::unique_ptr EclGenericVanguard::externalEclSummaryConfig_; +std::shared_ptr EclGenericVanguard::externalEclState_; +std::shared_ptr EclGenericVanguard::externalEclSchedule_; +std::shared_ptr EclGenericVanguard::externalEclSummaryConfig_; std::unique_ptr EclGenericVanguard::externalUDQState_; std::unique_ptr EclGenericVanguard::externalActionState_; std::unique_ptr EclGenericVanguard::comm_; @@ -81,22 +81,45 @@ void EclGenericVanguard::setExternalErrorGuard(std::unique_ptr error externalErrorGuard_ = std::move(errorGuard); } +void EclGenericVanguard::setExternalSchedule(std::shared_ptr& schedule) +{ + externalEclSchedule_ = schedule; +} + void EclGenericVanguard::setExternalSchedule(std::unique_ptr schedule) { externalEclSchedule_ = std::move(schedule); } -void EclGenericVanguard::setExternalSummaryConfig(std::unique_ptr summaryConfig) +void EclGenericVanguard::setExternalSummaryConfig( + std::shared_ptr& summaryConfig) +{ + externalEclSummaryConfig_ = summaryConfig; +} + +void EclGenericVanguard::setExternalSummaryConfig( + std::unique_ptr summaryConfig) { externalEclSummaryConfig_ = std::move(summaryConfig); } +void EclGenericVanguard::setExternalDeck(std::shared_ptr& deck) +{ + externalDeck_ = deck; + externalDeckSet_ = true; +} + void EclGenericVanguard::setExternalDeck(std::unique_ptr deck) { externalDeck_ = std::move(deck); externalDeckSet_ = true; } +void EclGenericVanguard::setExternalEclState(std::shared_ptr& eclState) +{ + externalEclState_ = eclState; +} + void EclGenericVanguard::setExternalEclState(std::unique_ptr eclState) { externalEclState_ = std::move(eclState); diff --git a/ebos/eclgenericvanguard.hh b/ebos/eclgenericvanguard.hh index 9fc79a368..04a7b341d 100644 --- a/ebos/eclgenericvanguard.hh +++ b/ebos/eclgenericvanguard.hh @@ -128,12 +128,14 @@ public: * management of these two objects, i.e., they are not allowed to be deleted as long * as the simulator vanguard object is alive. */ + static void setExternalDeck(std::shared_ptr& deck); static void setExternalDeck(std::unique_ptr deck); /*! * \brief Set the Opm::EclipseState object which ought to be used when the simulator * vanguard is instantiated. */ + static void setExternalEclState(std::shared_ptr& eclState); static void setExternalEclState(std::unique_ptr eclState); /*! @@ -142,6 +144,7 @@ public: * The lifetime of this object is not managed by the vanguard, i.e., the object must * stay valid until after the vanguard gets destroyed. */ + static void setExternalSchedule(std::shared_ptr& schedule); static void setExternalSchedule(std::unique_ptr schedule); /*! @@ -150,6 +153,7 @@ public: * The lifetime of this object is not managed by the vanguard, i.e., the object must * stay valid until after the vanguard gets destroyed. */ + static void setExternalSummaryConfig(std::shared_ptr& summaryConfig); static void setExternalSummaryConfig(std::unique_ptr summaryConfig); static void setExternalUDQState(std::unique_ptr udqState); @@ -296,11 +300,14 @@ protected: static double externalSetupTime_; static std::unique_ptr externalParseContext_; static std::unique_ptr externalErrorGuard_; - static std::unique_ptr externalDeck_; + + // These variables may be owned by both Python and the simulator + static std::shared_ptr externalDeck_; + static std::shared_ptr externalEclState_; + static std::shared_ptr externalEclSchedule_; + static std::shared_ptr externalEclSummaryConfig_; + static bool externalDeckSet_; - static std::unique_ptr externalEclState_; - static std::unique_ptr externalEclSchedule_; - static std::unique_ptr externalEclSummaryConfig_; static std::unique_ptr externalUDQState_; static std::unique_ptr externalActionState_; static std::unique_ptr comm_; @@ -326,11 +333,12 @@ protected: // parser objects. std::unique_ptr parseContext_; std::unique_ptr errorGuard_; - std::unique_ptr deck_; - std::unique_ptr eclState_; - std::unique_ptr eclSchedule_; - std::unique_ptr eclSummaryConfig_; std::shared_ptr python; + // These variables may be owned by both Python and the simulator + std::shared_ptr deck_; + std::shared_ptr eclState_; + std::shared_ptr eclSchedule_; + std::shared_ptr eclSummaryConfig_; /*! \brief Information about wells in parallel * diff --git a/flow/flow_ebos_blackoil.cpp b/flow/flow_ebos_blackoil.cpp index b90da267d..ad1216292 100644 --- a/flow/flow_ebos_blackoil.cpp +++ b/flow/flow_ebos_blackoil.cpp @@ -30,21 +30,21 @@ namespace Opm { -void flowEbosBlackoilSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, +void flowEbosBlackoilSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, std::unique_ptr udqState, - std::unique_ptr summaryConfig) + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); Vanguard::setExternalUDQState(std::move(udqState)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalSummaryConfig(summaryConfig); } std::unique_ptr> diff --git a/flow/flow_ebos_blackoil.hpp b/flow/flow_ebos_blackoil.hpp index 9331ec415..cdf9c8782 100644 --- a/flow/flow_ebos_blackoil.hpp +++ b/flow/flow_ebos_blackoil.hpp @@ -29,11 +29,11 @@ class SummaryConfig; class UDQState; namespace Properties { namespace TTag { struct EclFlowProblem; } } -void flowEbosBlackoilSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, +void flowEbosBlackoilSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, std::unique_ptr udqState, - std::unique_ptr summaryConfig); + std::shared_ptr& summaryConfig); int flowEbosBlackoilMain(int argc, char** argv, bool outputCout, bool outputFiles); diff --git a/flow/flow_ebos_brine.cpp b/flow/flow_ebos_brine.cpp index 9ffc85b47..6df9f86f7 100644 --- a/flow/flow_ebos_brine.cpp +++ b/flow/flow_ebos_brine.cpp @@ -43,19 +43,19 @@ struct EnableBrine { }} namespace Opm { -void flowEbosBrineSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) +void flowEbosBrineSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowBrineProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } diff --git a/flow/flow_ebos_brine.hpp b/flow/flow_ebos_brine.hpp index a117ba341..4dd2c1f4c 100644 --- a/flow/flow_ebos_brine.hpp +++ b/flow/flow_ebos_brine.hpp @@ -26,10 +26,10 @@ class EclipseState; class Schedule; class SummaryConfig; -void flowEbosBrineSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig); +void flowEbosBrineSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig); int flowEbosBrineMain(int argc, char** argv, bool outputCout, bool outputFiles); } diff --git a/flow/flow_ebos_energy.cpp b/flow/flow_ebos_energy.cpp index 13f41eda5..ec88c161e 100644 --- a/flow/flow_ebos_energy.cpp +++ b/flow/flow_ebos_energy.cpp @@ -43,19 +43,19 @@ struct EnableEnergy { }} namespace Opm { -void flowEbosEnergySetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) +void flowEbosEnergySetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowEnergyProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } // ----------------- Main program ----------------- diff --git a/flow/flow_ebos_energy.hpp b/flow/flow_ebos_energy.hpp index bbd05f20b..c916f202c 100644 --- a/flow/flow_ebos_energy.hpp +++ b/flow/flow_ebos_energy.hpp @@ -26,10 +26,10 @@ class EclipseState; class Schedule; class SummaryConfig; -void flowEbosEnergySetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig); +void flowEbosEnergySetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig); int flowEbosEnergyMain(int argc, char** argv, bool outputCout, bool outputFiles); } diff --git a/flow/flow_ebos_extbo.cpp b/flow/flow_ebos_extbo.cpp index a759c6929..f1330f948 100644 --- a/flow/flow_ebos_extbo.cpp +++ b/flow/flow_ebos_extbo.cpp @@ -43,19 +43,19 @@ struct EnableExtbo { }} namespace Opm { -void flowEbosExtboSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) +void flowEbosExtboSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowExtboProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } // ----------------- Main program ----------------- diff --git a/flow/flow_ebos_extbo.hpp b/flow/flow_ebos_extbo.hpp index a36189285..508d742c5 100644 --- a/flow/flow_ebos_extbo.hpp +++ b/flow/flow_ebos_extbo.hpp @@ -26,10 +26,10 @@ class EclipseState; class Schedule; class SummaryConfig; -void flowEbosExtboSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig); +void flowEbosExtboSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig); int flowEbosExtboMain(int argc, char** argv, bool outputCout, bool outputFiles); } diff --git a/flow/flow_ebos_foam.cpp b/flow/flow_ebos_foam.cpp index 6d40ca6da..ba4209731 100644 --- a/flow/flow_ebos_foam.cpp +++ b/flow/flow_ebos_foam.cpp @@ -43,19 +43,19 @@ struct EnableFoam { }} namespace Opm { -void flowEbosFoamSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) +void flowEbosFoamSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowFoamProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } diff --git a/flow/flow_ebos_foam.hpp b/flow/flow_ebos_foam.hpp index 33b036b59..453d1bfc9 100644 --- a/flow/flow_ebos_foam.hpp +++ b/flow/flow_ebos_foam.hpp @@ -26,10 +26,10 @@ class EclipseState; class Schedule; class SummaryConfig; -void flowEbosFoamSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig); +void flowEbosFoamSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig); int flowEbosFoamMain(int argc, char** argv, bool outputCout, bool outputFiles); } diff --git a/flow/flow_ebos_gasoil.cpp b/flow/flow_ebos_gasoil.cpp index 69f4e9c37..d649d1960 100644 --- a/flow/flow_ebos_gasoil.cpp +++ b/flow/flow_ebos_gasoil.cpp @@ -63,19 +63,19 @@ public: }} namespace Opm { -void flowEbosGasOilSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) +void flowEbosGasOilSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowGasOilProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } diff --git a/flow/flow_ebos_gasoil.hpp b/flow/flow_ebos_gasoil.hpp index a30b94f0b..f05fcda59 100644 --- a/flow/flow_ebos_gasoil.hpp +++ b/flow/flow_ebos_gasoil.hpp @@ -26,10 +26,10 @@ class EclipseState; class Schedule; class SummaryConfig; -void flowEbosGasOilSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig); +void flowEbosGasOilSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig); int flowEbosGasOilMain(int argc, char** argv, bool outputCout, bool outputFiles); } diff --git a/flow/flow_ebos_gaswater.cpp b/flow/flow_ebos_gaswater.cpp index c76500db8..4a3c61982 100644 --- a/flow/flow_ebos_gaswater.cpp +++ b/flow/flow_ebos_gaswater.cpp @@ -66,19 +66,19 @@ public: }} namespace Opm { -void flowEbosGasWaterSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) +void flowEbosGasWaterSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowGasWaterProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } diff --git a/flow/flow_ebos_gaswater.hpp b/flow/flow_ebos_gaswater.hpp index 1db517a1e..22960c487 100644 --- a/flow/flow_ebos_gaswater.hpp +++ b/flow/flow_ebos_gaswater.hpp @@ -26,10 +26,10 @@ class EclipseState; class Schedule; class SummaryConfig; -void flowEbosGasWaterSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig); +void flowEbosGasWaterSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig); int flowEbosGasWaterMain(int argc, char** argv, bool outputCout, bool outputFiles); } diff --git a/flow/flow_ebos_oilwater.cpp b/flow/flow_ebos_oilwater.cpp index 557601a43..f7cfcde30 100644 --- a/flow/flow_ebos_oilwater.cpp +++ b/flow/flow_ebos_oilwater.cpp @@ -63,19 +63,19 @@ public: }} namespace Opm { -void flowEbosOilWaterSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) +void flowEbosOilWaterSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowOilWaterProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } // ----------------- Main program ----------------- diff --git a/flow/flow_ebos_oilwater.hpp b/flow/flow_ebos_oilwater.hpp index ea4c940b2..b81176377 100644 --- a/flow/flow_ebos_oilwater.hpp +++ b/flow/flow_ebos_oilwater.hpp @@ -26,10 +26,10 @@ class EclipseState; class Schedule; class SummaryConfig; -void flowEbosOilWaterSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig); +void flowEbosOilWaterSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig); int flowEbosOilWaterMain(int argc, char** argv, bool outputCout, bool outputFiles); } diff --git a/flow/flow_ebos_oilwater_brine.cpp b/flow/flow_ebos_oilwater_brine.cpp index 759a0f610..da21c804b 100644 --- a/flow/flow_ebos_oilwater_brine.cpp +++ b/flow/flow_ebos_oilwater_brine.cpp @@ -66,19 +66,19 @@ public: }} namespace Opm { -void flowEbosOilWaterBrineSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) +void flowEbosOilWaterBrineSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowOilWaterBrineProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } // ----------------- Main program ----------------- diff --git a/flow/flow_ebos_oilwater_brine.hpp b/flow/flow_ebos_oilwater_brine.hpp index 7a6c919af..56f358cbf 100644 --- a/flow/flow_ebos_oilwater_brine.hpp +++ b/flow/flow_ebos_oilwater_brine.hpp @@ -26,10 +26,10 @@ class EclipseState; class Schedule; class SummaryConfig; -void flowEbosOilWaterBrineSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig); +void flowEbosOilWaterBrineSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig); int flowEbosOilWaterBrineMain(int argc, char** argv, bool outputCout, bool outputFiles); } diff --git a/flow/flow_ebos_oilwater_polymer.cpp b/flow/flow_ebos_oilwater_polymer.cpp index e25508776..e2d07bc20 100644 --- a/flow/flow_ebos_oilwater_polymer.cpp +++ b/flow/flow_ebos_oilwater_polymer.cpp @@ -66,19 +66,19 @@ public: }} namespace Opm { -void flowEbosOilWaterPolymerSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) +void flowEbosOilWaterPolymerSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowOilWaterPolymerProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } // ----------------- Main program ----------------- diff --git a/flow/flow_ebos_oilwater_polymer.hpp b/flow/flow_ebos_oilwater_polymer.hpp index d82dc4df3..778ab27c7 100644 --- a/flow/flow_ebos_oilwater_polymer.hpp +++ b/flow/flow_ebos_oilwater_polymer.hpp @@ -26,10 +26,10 @@ class EclipseState; class Schedule; class SummaryConfig; -void flowEbosOilWaterPolymerSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig); +void flowEbosOilWaterPolymerSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig); int flowEbosOilWaterPolymerMain(int argc, char** argv, bool outputCout, bool outputFiles); } diff --git a/flow/flow_ebos_polymer.cpp b/flow/flow_ebos_polymer.cpp index ef4eab9b7..c03c7f873 100644 --- a/flow/flow_ebos_polymer.cpp +++ b/flow/flow_ebos_polymer.cpp @@ -43,19 +43,19 @@ struct EnablePolymer { }} namespace Opm { -void flowEbosPolymerSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) +void flowEbosPolymerSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowPolymerProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } // ----------------- Main program ----------------- diff --git a/flow/flow_ebos_polymer.hpp b/flow/flow_ebos_polymer.hpp index a007c6569..9709edb28 100644 --- a/flow/flow_ebos_polymer.hpp +++ b/flow/flow_ebos_polymer.hpp @@ -26,10 +26,10 @@ class EclipseState; class Schedule; class SummaryConfig; -void flowEbosPolymerSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig); +void flowEbosPolymerSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig); int flowEbosPolymerMain(int argc, char** argv, bool outputCout, bool outputFiles); } diff --git a/flow/flow_ebos_solvent.cpp b/flow/flow_ebos_solvent.cpp index 329d3a87b..7f4ebd5bf 100644 --- a/flow/flow_ebos_solvent.cpp +++ b/flow/flow_ebos_solvent.cpp @@ -43,19 +43,19 @@ struct EnableSolvent { }} namespace Opm { -void flowEbosSolventSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) +void flowEbosSolventSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) { using TypeTag = Properties::TTag::EclFlowSolventProblem; using Vanguard = GetPropType; Vanguard::setExternalSetupTime(setupTime); - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } diff --git a/flow/flow_ebos_solvent.hpp b/flow/flow_ebos_solvent.hpp index 9662e774e..7290d49de 100644 --- a/flow/flow_ebos_solvent.hpp +++ b/flow/flow_ebos_solvent.hpp @@ -26,10 +26,10 @@ class EclipseState; class Schedule; class SummaryConfig; -void flowEbosSolventSetDeck(double setupTime, std::unique_ptr deck, - std::unique_ptr eclState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig); +void flowEbosSolventSetDeck(double setupTime, std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig); int flowEbosSolventMain(int argc, char** argv, bool outoutCout, bool outputFiles); } diff --git a/opm/simulators/flow/Main.hpp b/opm/simulators/flow/Main.hpp index 01ab24fd0..cea6a1df5 100644 --- a/opm/simulators/flow/Main.hpp +++ b/opm/simulators/flow/Main.hpp @@ -82,13 +82,16 @@ struct FlowEarlyBird { namespace Opm { template - void flowEbosSetDeck(std::unique_ptr deck, std::unique_ptr eclState, std::unique_ptr schedule, std::unique_ptr summaryConfig) + void flowEbosSetDeck(std::shared_ptr& deck, + std::shared_ptr& eclState, + std::shared_ptr& schedule, + std::shared_ptr summaryConfig) { using Vanguard = GetPropType; - Vanguard::setExternalDeck(std::move(deck)); - Vanguard::setExternalEclState(std::move(eclState)); - Vanguard::setExternalSchedule(std::move(schedule)); - Vanguard::setExternalSummaryConfig(std::move(summaryConfig)); + Vanguard::setExternalDeck(deck); + Vanguard::setExternalEclState(eclState); + Vanguard::setExternalSchedule(schedule); + Vanguard::setExternalSummaryConfig(summaryConfig); } // ----------------- Main program ----------------- @@ -123,31 +126,27 @@ namespace Opm public: Main(int argc, char** argv) : argc_(argc), argv_(argv) { initMPI(); } + // This constructor can be called from Python Main(const std::string &filename) { - deckFilename_.assign(filename); - flowProgName_.assign("flow"); - argc_ = 2; - saveArgs_[0] = const_cast(flowProgName_.c_str()); - saveArgs_[1] = const_cast(deckFilename_.c_str()); - argv_ = saveArgs_; + setArgvArgc_(filename); initMPI(); } - Main(int argc, - char** argv, - std::unique_ptr deck, - std::unique_ptr eclipseState, - std::unique_ptr schedule, - std::unique_ptr summaryConfig) - : argc_(argc) - , argv_(argv) - , deck_(std::move(deck)) - , eclipseState_(std::move(eclipseState)) - , schedule_(std::move(schedule)) - , summaryConfig_(std::move(summaryConfig)) + // This constructor can be called from Python when Python has already + // parsed a deck + Main( + std::shared_ptr& deck, + std::shared_ptr& eclipseState, + std::shared_ptr& schedule, + std::shared_ptr& summaryConfig) + : deck_{deck} + , eclipseState_{eclipseState} + , schedule_{schedule} + , summaryConfig_{summaryConfig} { - initMPI(); + setArgvArgc_(deck->getDataFile()); + initMPI(); } ~Main() @@ -159,6 +158,16 @@ namespace Opm #endif } + void setArgvArgc_(const std::string& filename) + { + deckFilename_.assign(filename); + flowProgName_.assign("flow"); + argc_ = 2; + saveArgs_[0] = const_cast(flowProgName_.c_str()); + saveArgs_[1] = const_cast(deckFilename_.c_str()); + argv_ = saveArgs_; + } + void initMPI() { #if HAVE_DUNE_FEM @@ -202,11 +211,11 @@ namespace Opm // case. E.g. check that number of phases == 3 flowEbosBlackoilSetDeck( setupTime_, - std::move(deck_), - std::move(eclipseState_), - std::move(schedule_), + deck_, + eclipseState_, + schedule_, std::move(udqState_), - std::move(summaryConfig_)); + summaryConfig_); return flowEbosBlackoilMainInit( argc_, argv_, outputCout_, outputFiles_); } else { @@ -230,18 +239,20 @@ namespace Opm else if( phases.size() == 2 ) { // oil-gas if (phases.active( Phase::OIL ) && phases.active( Phase::GAS )) { - flowEbosGasOilSetDeck(setupTime_, std::move(deck_), std::move(eclipseState_), - std::move(schedule_), std::move(summaryConfig_)); + flowEbosGasOilSetDeck( + setupTime_, deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosGasOilMain(argc_, argv_, outputCout_, outputFiles_); } // oil-water else if ( phases.active( Phase::OIL ) && phases.active( Phase::WATER ) ) { - flowEbosOilWaterSetDeck(setupTime_, std::move(deck_), std::move(eclipseState_), std::move(schedule_), std::move(summaryConfig_)); + flowEbosOilWaterSetDeck( + setupTime_, deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosOilWaterMain(argc_, argv_, outputCout_, outputFiles_); } // gas-water else if ( phases.active( Phase::GAS ) && phases.active( Phase::WATER ) ) { - flowEbosGasWaterSetDeck(setupTime_, std::move(deck_), std::move(eclipseState_), std::move(schedule_), std::move(summaryConfig_)); + flowEbosGasWaterSetDeck( + setupTime_, deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosGasWaterMain(argc_, argv_, outputCout_, outputFiles_); } else { @@ -268,25 +279,19 @@ namespace Opm } if ( phases.size() == 3 ) { // oil water polymer case - flowEbosOilWaterPolymerSetDeck(setupTime_, std::move(deck_), - std::move(eclipseState_), - std::move(schedule_), - std::move(summaryConfig_)); + flowEbosOilWaterPolymerSetDeck( + setupTime_, deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosOilWaterPolymerMain(argc_, argv_, outputCout_, outputFiles_); } else { - flowEbosPolymerSetDeck(setupTime_, std::move(deck_), - std::move(eclipseState_), - std::move(schedule_), - std::move(summaryConfig_)); + flowEbosPolymerSetDeck( + setupTime_, deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosPolymerMain(argc_, argv_, outputCout_, outputFiles_); } } // Foam case else if ( phases.active( Phase::FOAM ) ) { - flowEbosFoamSetDeck(setupTime_, std::move(deck_), - std::move(eclipseState_), - std::move(schedule_), - std::move(summaryConfig_)); + flowEbosFoamSetDeck( + setupTime_, deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosFoamMain(argc_, argv_, outputCout_, outputFiles_); } // Brine case @@ -298,51 +303,43 @@ namespace Opm return EXIT_FAILURE; } if ( phases.size() == 3 ) { // oil water brine case - flowEbosOilWaterBrineSetDeck(setupTime_, std::move(deck_), - std::move(eclipseState_), - std::move(schedule_), - std::move(summaryConfig_)); + flowEbosOilWaterBrineSetDeck( + setupTime_, deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosOilWaterBrineMain(argc_, argv_, outputCout_, outputFiles_); } else { - flowEbosBrineSetDeck(setupTime_, std::move(deck_), - std::move(eclipseState_), - std::move(schedule_), - std::move(summaryConfig_)); + flowEbosBrineSetDeck( + setupTime_, deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosBrineMain(argc_, argv_, outputCout_, outputFiles_); } } // Solvent case else if ( phases.active( Phase::SOLVENT ) ) { - flowEbosSolventSetDeck(setupTime_, std::move(deck_), - std::move(eclipseState_), - std::move(schedule_), - std::move(summaryConfig_)); + flowEbosSolventSetDeck( + setupTime_, deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosSolventMain(argc_, argv_, outputCout_, outputFiles_); } // Extended BO case else if ( phases.active( Phase::ZFRACTION ) ) { - flowEbosExtboSetDeck(setupTime_, std::move(deck_), - std::move(eclipseState_), - std::move(schedule_), - std::move(summaryConfig_)); + flowEbosExtboSetDeck( + setupTime_, deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosExtboMain(argc_, argv_, outputCout_, outputFiles_); } // Energy case else if (eclipseState_->getSimulationConfig().isThermal()) { - flowEbosEnergySetDeck(setupTime_, std::move(deck_), - std::move(eclipseState_), - std::move(schedule_), - std::move(summaryConfig_)); + flowEbosEnergySetDeck( + setupTime_, deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosEnergyMain(argc_, argv_, outputCout_, outputFiles_); } #endif // FLOW_BLACKOIL_ONLY // Blackoil case else if( phases.size() == 3 ) { - flowEbosBlackoilSetDeck(setupTime_, std::move(deck_), - std::move(eclipseState_), - std::move(schedule_), - std::move(udqState_), - std::move(summaryConfig_)); + flowEbosBlackoilSetDeck( + setupTime_, + deck_, + eclipseState_, + schedule_, + std::move(udqState_), + summaryConfig_); return flowEbosBlackoilMain(argc_, argv_, outputCout_, outputFiles_); } else { @@ -355,10 +352,8 @@ namespace Opm template int dispatchStatic_() { - flowEbosSetDeck(std::move(deck_), - std::move(eclipseState_), - std::move(schedule_), - std::move(summaryConfig_)); + flowEbosSetDeck( + deck_, eclipseState_, schedule_, summaryConfig_); return flowEbosMain(argc_, argv_, outputCout_, outputFiles_); } @@ -549,12 +544,14 @@ namespace Opm std::string deckFilename_; std::string flowProgName_; char *saveArgs_[2]; - std::unique_ptr deck_; - std::unique_ptr eclipseState_; - std::unique_ptr schedule_; std::unique_ptr udqState_; std::unique_ptr actionState_; - std::unique_ptr summaryConfig_; + + // These variables may be owned by both Python and the simulator + std::shared_ptr deck_; + std::shared_ptr eclipseState_; + std::shared_ptr schedule_; + std::shared_ptr summaryConfig_; }; } // namespace Opm diff --git a/opm/simulators/flow/python/PyBlackOilSimulator.hpp b/opm/simulators/flow/python/PyBlackOilSimulator.hpp new file mode 100644 index 000000000..0c7ffd6bc --- /dev/null +++ b/opm/simulators/flow/python/PyBlackOilSimulator.hpp @@ -0,0 +1,76 @@ +/* + Copyright 2020 Equinor ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ + +#ifndef OPM_PY_BLACKOIL_SIMULATOR_HEADER_INCLUDED +#define OPM_PY_BLACKOIL_SIMULATOR_HEADER_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Opm::Pybind { +class PyBlackOilSimulator +{ + using TypeTag = Opm::Properties::TTag::EclFlowProblem; +private: + using Simulator = Opm::GetPropType; + +public: + PyBlackOilSimulator( const std::string& deckFilename); + PyBlackOilSimulator( + std::shared_ptr& deck, + std::shared_ptr& state, + std::shared_ptr& schedule, + std::shared_ptr& summary_config); + py::array_t getPorosity(); + int run(); + void setPorosity( + py::array_t array); + int step(); + int stepInit(); + int stepCleanup(); + const Opm::FlowMainEbos& getFlowMainEbos() const; + +private: + const std::string deckFilename_; + bool hasRunInit_ = false; + bool hasRunCleanup_ = false; + + // This *must* be declared before other pointers + // to simulator objects. This in order to deinitialize + // MPI at the correct time (ie after the other objects). + std::unique_ptr main_; + + std::unique_ptr> mainEbos_; + Simulator *ebosSimulator_; + std::unique_ptr> materialState_; + std::shared_ptr deck_; + std::shared_ptr eclipse_state_; + std::shared_ptr schedule_; + std::shared_ptr summary_config_; +}; + +} // namespace Opm::Pybind +#endif // OPM_PY_BLACKOIL_SIMULATOR_HEADER_INCLUDED diff --git a/opm/simulators/flow/python/Pybind11Exporter.hpp b/opm/simulators/flow/python/Pybind11Exporter.hpp new file mode 100644 index 000000000..1feedd305 --- /dev/null +++ b/opm/simulators/flow/python/Pybind11Exporter.hpp @@ -0,0 +1,15 @@ +#ifndef OPM_PYBIND11_EXPORTER_HEADER_INCLUDED +#define OPM_PYBIND11_EXPORTER_HEADER_INCLUDED + +#include +#include +//#include + +namespace py = pybind11; + +namespace Opm::Pybind { + void export_all(py::module& m); + void export_PyBlackOilSimulator(py::module& m); +} + +#endif //OPM_PYBIND11_EXPORTER_HEADER_INCLUDED diff --git a/opm/simulators/utils/readDeck.cpp b/opm/simulators/utils/readDeck.cpp index 476936f25..958c0e31b 100644 --- a/opm/simulators/utils/readDeck.cpp +++ b/opm/simulators/utils/readDeck.cpp @@ -191,8 +191,8 @@ void setupMessageLimiter(const Opm::MessageLimits msgLimits, const std::string& } -void readDeck(int rank, std::string& deckFilename, std::unique_ptr& deck, std::unique_ptr& eclipseState, - std::unique_ptr& schedule, std::unique_ptr& udqState, std::unique_ptr& actionState, std::unique_ptr& summaryConfig, +void readDeck(int rank, std::string& deckFilename, std::shared_ptr& deck, std::shared_ptr& eclipseState, + std::shared_ptr& schedule, std::unique_ptr& udqState, std::unique_ptr& actionState, std::shared_ptr& summaryConfig, std::unique_ptr errorGuard, std::shared_ptr& python, std::unique_ptr parseContext, bool initFromRestart, bool checkDeck, const std::optional& outputInterval) { diff --git a/opm/simulators/utils/readDeck.hpp b/opm/simulators/utils/readDeck.hpp index be200431a..2e0acbe06 100644 --- a/opm/simulators/utils/readDeck.hpp +++ b/opm/simulators/utils/readDeck.hpp @@ -57,8 +57,8 @@ FileOutputMode setupLogging(int mpi_rank_, const std::string& deck_filename, con /// \brief Reads the deck and creates all necessary objects if needed /// /// If pointers already contains objects then they are used otherwise they are created and can be used outside later. -void readDeck(int rank, std::string& deckFilename, std::unique_ptr& deck, std::unique_ptr& eclipseState, - std::unique_ptr& schedule, std::unique_ptr& udqState, std::unique_ptr& actionState, std::unique_ptr& summaryConfig, +void readDeck(int rank, std::string& deckFilename, std::shared_ptr& deck, std::shared_ptr& eclipseState, + std::shared_ptr& schedule, std::unique_ptr& udqState, std::unique_ptr& actionState, std::shared_ptr& summaryConfig, std::unique_ptr errorGuard, std::shared_ptr& python, std::unique_ptr parseContext, bool initFromRestart, bool checkDeck, const std::optional& outputInterval); } // end namespace Opm diff --git a/python/simulators/CMakeLists.txt b/python/simulators/CMakeLists.txt index 40237a4e6..7a3545d05 100644 --- a/python/simulators/CMakeLists.txt +++ b/python/simulators/CMakeLists.txt @@ -1,11 +1,18 @@ # NOTE: we assume that add_subdirectory( pybind11 ) is called from the -# parent folder's CMakeLists.txt before this CMakeLists.txt is loaded. -# Therefore, pybind11's CMakeLists.txt has already run -# find_package(PYTHON) to define variables like -# ${PYTHON_EXECUTABLE} +# parent folder's CMakeLists.txt before this CMakeLists.txt is loaded. +# Therefore, pybind11's CMakeLists.txt has already run +# find_package(PYTHON) to define variables like ${PYTHON_EXECUTABLE} # - -pybind11_add_module(simulators simulators.cpp ${PYBIND11_SYSTEM}) +# NOTE: The variable ${PYBIND11_SYSTEM} is set in python/CMakeLists.txt +# to the value "SYSTEM" or unset, depending on the current version of Pybind11. +# The value is then forwarded to target_include_directories(), see +# +# https://cmake.org/cmake/help/latest/command/target_include_directories.html +# https://pybind11.readthedocs.io/en/stable/compiling.html +# +pybind11_add_module(simulators ${PYBIND11_SYSTEM} + PyBlackOilSimulator.cpp + Pybind11Exporter.cpp) set_target_properties( simulators PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/python/opm2 ) @@ -30,9 +37,19 @@ if(OPM_ENABLE_PYTHON_TESTS) if(Python3_EXECUTABLE AND NOT PYTHON_EXECUTABLE) set(PYTHON_EXECUTABLE ${Python3_EXECUTABLE}) endif() - add_test(NAME python_tests + set(PYTHON_PATH ${PROJECT_BINARY_DIR}/python:${opm-common_DIR}/python:$ENV{PYTHONPATH}) + # NOTE: See comment in test_basic.py for the reason why we are + # splitting the python tests into multiple add_test() tests instead + # of having a single "python -m unittest" test call that will run all + # the tests in the "test" sub directory. + add_test(NAME python_basic WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/python COMMAND ${CMAKE_COMMAND} - -E env PYTHONPATH=${PROJECT_BINARY_DIR}/python:$ENV{PYTHONPATH} - ${PYTHON_EXECUTABLE} -m unittest ) + -E env PYTHONPATH=${PYTHON_PATH} ${PYTHON_EXECUTABLE} + -m unittest test/test_basic.py) + add_test(NAME python_schedule + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/python + COMMAND ${CMAKE_COMMAND} + -E env PYTHONPATH=${PYTHON_PATH} ${PYTHON_EXECUTABLE} + -m unittest test/test_schedule.py) endif() diff --git a/python/simulators/PyBlackOilSimulator.cpp b/python/simulators/PyBlackOilSimulator.cpp new file mode 100644 index 000000000..e44b6ca51 --- /dev/null +++ b/python/simulators/PyBlackOilSimulator.cpp @@ -0,0 +1,162 @@ +/* + Copyright 2020 Equinor ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ + +#include "config.h" +#include +#include +#include +#include +#define FLOW_BLACKOIL_ONLY +#include +#include +// NOTE: EXIT_SUCCESS, EXIT_FAILURE is defined in cstdlib +#include +#include +#include +#include + +namespace py = pybind11; + +namespace Opm::Pybind { +PyBlackOilSimulator::PyBlackOilSimulator( const std::string &deckFilename) + : deckFilename_{deckFilename} +{ +} + +PyBlackOilSimulator::PyBlackOilSimulator( + std::shared_ptr& deck, + std::shared_ptr& state, + std::shared_ptr& schedule, + std::shared_ptr& summary_config +) + : deck_{deck} + , eclipse_state_{state} + , schedule_{schedule} + , summary_config_{summary_config} +{ +} + +const Opm::FlowMainEbos& + PyBlackOilSimulator::getFlowMainEbos() const +{ + if (this->mainEbos_) { + return *(this->mainEbos_.get()); + } + else { + throw std::runtime_error("BlackOilSimulator not initialized: " + "Cannot get reference to FlowMainEbos object" ); + } +} + +py::array_t PyBlackOilSimulator::getPorosity() +{ + std::size_t len; + auto array = materialState_->getPorosity(&len); + return py::array(len, array.get()); +} + +int PyBlackOilSimulator::run() +{ + auto mainObject = Opm::Main( deckFilename_ ); + return mainObject.runDynamic(); +} + +void PyBlackOilSimulator::setPorosity( py::array_t array) +{ + std::size_t size_ = array.size(); + const double *poro = array.data(); + materialState_->setPorosity(poro, size_); +} + +int PyBlackOilSimulator::step() +{ + if (!hasRunInit_) { + throw std::logic_error("step() called before step_init()"); + } + if (hasRunCleanup_) { + throw std::logic_error("step() called after step_cleanup()"); + } + return mainEbos_->executeStep(); +} + +int PyBlackOilSimulator::stepCleanup() +{ + hasRunCleanup_ = true; + return mainEbos_->executeStepsCleanup(); +} + +int PyBlackOilSimulator::stepInit() +{ + + if (hasRunInit_) { + // Running step_init() multiple times is not implemented yet, + if (hasRunCleanup_) { + throw std::logic_error("step_init() called again"); + } + else { + return EXIT_SUCCESS; + } + } + if (this->deck_) { + main_ = std::make_unique( + this->deck_, + this->eclipse_state_, + this->schedule_, + this->summary_config_ + ); + } + else { + main_ = std::make_unique( deckFilename_ ); + } + int exitCode = EXIT_SUCCESS; + mainEbos_ = main_->initFlowEbosBlackoil(exitCode); + if (mainEbos_) { + int result = mainEbos_->executeInitStep(); + hasRunInit_ = true; + ebosSimulator_ = mainEbos_->getSimulatorPtr(); + materialState_ = std::make_unique>( + ebosSimulator_); + return result; + } + else { + return exitCode; + } +} + +void export_PyBlackOilSimulator(py::module& m) +{ + py::class_(m, "BlackOilSimulator") + .def(py::init< const std::string& >()) + .def(py::init< + std::shared_ptr&, + std::shared_ptr&, + std::shared_ptr&, + std::shared_ptr& >()) + .def("get_porosity", &PyBlackOilSimulator::getPorosity, + py::return_value_policy::copy) + .def("run", &PyBlackOilSimulator::run) + .def("set_porosity", &PyBlackOilSimulator::setPorosity) + .def("step", &PyBlackOilSimulator::step) + .def("step_init", &PyBlackOilSimulator::stepInit) + .def("step_cleanup", &PyBlackOilSimulator::stepCleanup); +} + +} // namespace Opm::Pybind + diff --git a/python/simulators/Pybind11Exporter.cpp b/python/simulators/Pybind11Exporter.cpp new file mode 100644 index 000000000..6f0db977b --- /dev/null +++ b/python/simulators/Pybind11Exporter.cpp @@ -0,0 +1,11 @@ +#include +#include + +void Opm::Pybind::export_all(py::module& m) { + export_PyBlackOilSimulator(m); +} + +PYBIND11_MODULE(simulators, m) +{ + Opm::Pybind::export_all(m); +} diff --git a/python/test/test_basic.py b/python/test/test_basic.py index 933377b76..d769f0456 100755 --- a/python/test/test_basic.py +++ b/python/test/test_basic.py @@ -55,7 +55,7 @@ class TestBasic(unittest.TestCase): # However, as noted above this is not currently possible. # test_dir = Path(os.path.dirname(__file__)) - cls.data_dir = test_dir.parent.joinpath("test_data/SPE1CASE1") + cls.data_dir = test_dir.parent.joinpath("test_data/SPE1CASE1a") def test_all(self): diff --git a/python/test/test_schedule.py b/python/test/test_schedule.py new file mode 100755 index 000000000..99aa1c262 --- /dev/null +++ b/python/test/test_schedule.py @@ -0,0 +1,52 @@ +import os +import unittest +from contextlib import contextmanager +import datetime as dt +from pathlib import Path +from opm2.simulators import BlackOilSimulator +from opm.io.parser import Parser +from opm.io.ecl_state import EclipseState +from opm.io.schedule import Schedule +from opm.io.summary import SummaryConfig + +@contextmanager +def pushd(path): + cwd = os.getcwd() + if not os.path.isdir(path): + os.makedirs(path) + os.chdir(path) + yield + os.chdir(cwd) + + +class TestBasic(unittest.TestCase): + @classmethod + def setUpClass(cls): + # NOTE: See comment in test_basic.py for the reason why we are + # only using a single test_all() function instead of splitting + # it up in multiple test functions + test_dir = Path(os.path.dirname(__file__)) + cls.data_dir = test_dir.parent.joinpath("test_data/SPE1CASE1b") + + + def test_all(self): + with pushd(self.data_dir): + deck = Parser().parse('SPE1CASE1.DATA') + state = EclipseState(deck) + schedule = Schedule( deck, state ) + summary_config = SummaryConfig(deck, state, schedule) + self.assertTrue('PROD' in schedule) + self.assertTrue('INJ' in schedule) + self.assertEqual(dt.datetime(2015, 1, 1), schedule.start) + self.assertEqual(dt.datetime(2016, 1, 1), schedule.end) + sim = BlackOilSimulator( deck, state, schedule, summary_config ) + sim.step_init() + sim.step() + prod = schedule.get_well("PROD", 2) + self.assertEqual(prod.status(), "OPEN") + #schedule.shut_well("PROD", 3) + #prod = schedule.get_well("PROD", 3) + #self.assertEqual(prod.status(), "SHUT") + sim.step() + sim.step() + diff --git a/python/test_data/SPE1CASE1/SPE1CASE1.DATA b/python/test_data/SPE1CASE1a/SPE1CASE1.DATA similarity index 100% rename from python/test_data/SPE1CASE1/SPE1CASE1.DATA rename to python/test_data/SPE1CASE1a/SPE1CASE1.DATA diff --git a/python/test_data/SPE1CASE1b/SPE1CASE1.DATA b/python/test_data/SPE1CASE1b/SPE1CASE1.DATA new file mode 100644 index 000000000..19b65bd6c --- /dev/null +++ b/python/test_data/SPE1CASE1b/SPE1CASE1.DATA @@ -0,0 +1,439 @@ +-- This reservoir simulation deck is made available under the Open Database +-- License: http://opendatacommons.org/licenses/odbl/1.0/. Any rights in +-- individual contents of the database are licensed under the Database Contents +-- License: http://opendatacommons.org/licenses/dbcl/1.0/ + +-- Copyright (C) 2015 Statoil + +-- This simulation is based on the data given in +-- 'Comparison of Solutions to a Three-Dimensional +-- Black-Oil Reservoir Simulation Problem' by Aziz S. Odeh, +-- Journal of Petroleum Technology, January 1981 + +-- NOTE: This deck is currently not supported by the OPM +-- simulator flow due to lack of support for DRSDT. + +--------------------------------------------------------------------------- +------------------------ SPE1 - CASE 1 ------------------------------------ +--------------------------------------------------------------------------- + +RUNSPEC +-- ------------------------------------------------------------------------- + +TITLE + SPE1 - CASE 1 + +DIMENS + 10 10 3 / + +-- The number of equilibration regions is inferred from the EQLDIMS +-- keyword. +EQLDIMS +/ + +-- The number of PVTW tables is inferred from the TABDIMS keyword; +-- when no data is included in the keyword the default values are used. +TABDIMS +/ + +OIL +GAS +WATER +DISGAS +-- As seen from figure 4 in Odeh, GOR is increasing with time, +-- which means that dissolved gas is present + +FIELD + +START + 1 'JAN' 2015 / + +WELLDIMS +-- Item 1: maximum number of wells in the model +-- - there are two wells in the problem; injector and producer +-- Item 2: maximum number of grid blocks connected to any one well +-- - must be one as the wells are located at specific grid blocks +-- Item 3: maximum number of groups in the model +-- - we are dealing with only one 'group' +-- Item 4: maximum number of wells in any one group +-- - there must be two wells in a group as there are two wells in total + 2 1 1 2 / + +UNIFOUT + +GRID + +-- The INIT keyword is used to request an .INIT file. The .INIT file +-- is written before the simulation actually starts, and contains grid +-- properties and saturation tables as inferred from the input +-- deck. There are no other keywords which can be used to configure +-- exactly what is written to the .INIT file. +INIT + + +-- ------------------------------------------------------------------------- +NOECHO + +DX +-- There are in total 300 cells with length 1000ft in x-direction + 300*1000 / +DY +-- There are in total 300 cells with length 1000ft in y-direction + 300*1000 / +DZ +-- The layers are 20, 30 and 50 ft thick, in each layer there are 100 cells + 100*20 100*30 100*50 / + +TOPS +-- The depth of the top of each grid block + 100*8325 / + +PORO +-- Constant porosity of 0.3 throughout all 300 grid cells + 300*0.3 / + +PERMX +-- The layers have perm. 500mD, 50mD and 200mD, respectively. + 100*500 100*50 100*200 / + +PERMY +-- Equal to PERMX + 100*500 100*50 100*200 / + +PERMZ +-- Cannot find perm. in z-direction in Odeh's paper +-- For the time being, we will assume PERMZ equal to PERMX and PERMY: + 100*500 100*50 100*200 / +ECHO + +PROPS +-- ------------------------------------------------------------------------- + +PVTW +-- Item 1: pressure reference (psia) +-- Item 2: water FVF (rb per bbl or rb per stb) +-- Item 3: water compressibility (psi^{-1}) +-- Item 4: water viscosity (cp) +-- Item 5: water 'viscosibility' (psi^{-1}) + +-- Using values from Norne: +-- In METRIC units: +-- 277.0 1.038 4.67E-5 0.318 0.0 / +-- In FIELD units: + 4017.55 1.038 3.22E-6 0.318 0.0 / + +ROCK +-- Item 1: reference pressure (psia) +-- Item 2: rock compressibility (psi^{-1}) + +-- Using values from table 1 in Odeh: + 14.7 3E-6 / + +SWOF +-- Column 1: water saturation +-- - this has been set to (almost) equally spaced values from 0.12 to 1 +-- Column 2: water relative permeability +-- - generated from the Corey-type approx. formula +-- the coeffisient is set to 10e-5, S_{orw}=0 and S_{wi}=0.12 +-- Column 3: oil relative permeability when only oil and water are present +-- - we will use the same values as in column 3 in SGOF. +-- This is not really correct, but since only the first +-- two values are of importance, this does not really matter +-- Column 4: water-oil capillary pressure (psi) + +0.12 0 1 0 +0.18 4.64876033057851E-008 1 0 +0.24 0.000000186 0.997 0 +0.3 4.18388429752066E-007 0.98 0 +0.36 7.43801652892562E-007 0.7 0 +0.42 1.16219008264463E-006 0.35 0 +0.48 1.67355371900826E-006 0.2 0 +0.54 2.27789256198347E-006 0.09 0 +0.6 2.97520661157025E-006 0.021 0 +0.66 3.7654958677686E-006 0.01 0 +0.72 4.64876033057851E-006 0.001 0 +0.78 0.000005625 0.0001 0 +0.84 6.69421487603306E-006 0 0 +0.91 8.05914256198347E-006 0 0 +1 0.00001 0 0 / + + +SGOF +-- Column 1: gas saturation +-- Column 2: gas relative permeability +-- Column 3: oil relative permeability when oil, gas and connate water are present +-- Column 4: oil-gas capillary pressure (psi) +-- - stated to be zero in Odeh's paper + +-- Values in column 1-3 are taken from table 3 in Odeh's paper: +0 0 1 0 +0.001 0 1 0 +0.02 0 0.997 0 +0.05 0.005 0.980 0 +0.12 0.025 0.700 0 +0.2 0.075 0.350 0 +0.25 0.125 0.200 0 +0.3 0.190 0.090 0 +0.4 0.410 0.021 0 +0.45 0.60 0.010 0 +0.5 0.72 0.001 0 +0.6 0.87 0.0001 0 +0.7 0.94 0.000 0 +0.85 0.98 0.000 0 +0.88 0.984 0.000 0 / +--1.00 1.0 0.000 0 / +-- Warning from Eclipse: first sat. value in SWOF + last sat. value in SGOF +-- must not be greater than 1, but Eclipse still runs +-- Flow needs the sum to be excactly 1 so I added a row with gas sat. = 0.88 +-- The corresponding krg value was estimated by assuming linear rel. between +-- gas sat. and krw. between gas sat. 0.85 and 1.00 (the last two values given) + +DENSITY +-- Density (lb per ft³) at surface cond. of +-- oil, water and gas, respectively (in that order) + +-- Using values from Norne: +-- In METRIC units: +-- 859.5 1033.0 0.854 / +-- In FIELD units: + 53.66 64.49 0.0533 / + +PVDG +-- Column 1: gas phase pressure (psia) +-- Column 2: gas formation volume factor (rb per Mscf) +-- - in Odeh's paper the units are said to be given in rb per bbl, +-- but this is assumed to be a mistake: FVF-values in Odeh's paper +-- are given in rb per scf, not rb per bbl. This will be in +-- agreement with conventions +-- Column 3: gas viscosity (cP) + +-- Using values from lower right table in Odeh's table 2: +14.700 166.666 0.008000 +264.70 12.0930 0.009600 +514.70 6.27400 0.011200 +1014.7 3.19700 0.014000 +2014.7 1.61400 0.018900 +2514.7 1.29400 0.020800 +3014.7 1.08000 0.022800 +4014.7 0.81100 0.026800 +5014.7 0.64900 0.030900 +9014.7 0.38600 0.047000 / + +PVTO +-- Column 1: dissolved gas-oil ratio (Mscf per stb) +-- Column 2: bubble point pressure (psia) +-- Column 3: oil FVF for saturated oil (rb per stb) +-- Column 4: oil viscosity for saturated oil (cP) + +-- Use values from top left table in Odeh's table 2: +0.0010 14.7 1.0620 1.0400 / +0.0905 264.7 1.1500 0.9750 / +0.1800 514.7 1.2070 0.9100 / +0.3710 1014.7 1.2950 0.8300 / +0.6360 2014.7 1.4350 0.6950 / +0.7750 2514.7 1.5000 0.6410 / +0.9300 3014.7 1.5650 0.5940 / +1.2700 4014.7 1.6950 0.5100 + 9014.7 1.5790 0.7400 / +1.6180 5014.7 1.8270 0.4490 + 9014.7 1.7370 0.6310 / +-- It is required to enter data for undersaturated oil for the highest GOR +-- (i.e. the last row) in the PVTO table. +-- In order to fulfill this requirement, values for oil FVF and viscosity +-- at 9014.7psia and GOR=1.618 for undersaturated oil have been approximated: +-- It has been assumed that there is a linear relation between the GOR +-- and the FVF when keeping the pressure constant at 9014.7psia. +-- From Odeh we know that (at 9014.7psia) the FVF is 2.357 at GOR=2.984 +-- for saturated oil and that the FVF is 1.579 at GOR=1.27 for undersaturated oil, +-- so it is possible to use the assumption described above. +-- An equivalent approximation for the viscosity has been used. +/ + +SOLUTION +-- ------------------------------------------------------------------------- + +EQUIL +-- Item 1: datum depth (ft) +-- Item 2: pressure at datum depth (psia) +-- - Odeh's table 1 says that initial reservoir pressure is +-- 4800 psi at 8400ft, which explains choice of item 1 and 2 +-- Item 3: depth of water-oil contact (ft) +-- - chosen to be directly under the reservoir +-- Item 4: oil-water capillary pressure at the water oil contact (psi) +-- - given to be 0 in Odeh's paper +-- Item 5: depth of gas-oil contact (ft) +-- - chosen to be directly above the reservoir +-- Item 6: gas-oil capillary pressure at gas-oil contact (psi) +-- - given to be 0 in Odeh's paper +-- Item 7: RSVD-table +-- Item 8: RVVD-table +-- Item 9: Set to 0 as this is the only value supported by OPM + +-- Item #: 1 2 3 4 5 6 7 8 9 + 8400 4800 8450 0 8300 0 1 0 0 / + +RSVD +-- Dissolved GOR is initially constant with depth through the reservoir. +-- The reason is that the initial reservoir pressure given is higher +---than the bubble point presssure of 4014.7psia, meaning that there is no +-- free gas initially present. +8300 1.270 +8450 1.270 / + +SUMMARY +-- ------------------------------------------------------------------------- + +-- 1a) Oil rate vs time +FOPR +-- Field Oil Production Rate + +-- 1b) GOR vs time +WGOR +-- Well Gas-Oil Ratio + 'PROD' +/ +-- Using FGOR instead of WGOR:PROD results in the same graph +FGOR + +-- 2a) Pressures of the cell where the injector and producer are located +BPR +1 1 1 / +10 10 3 / +/ + +-- 2b) Gas saturation at grid points given in Odeh's paper +BGSAT +1 1 1 / +1 1 2 / +1 1 3 / +10 1 1 / +10 1 2 / +10 1 3 / +10 10 1 / +10 10 2 / +10 10 3 / +/ + +-- In order to compare Eclipse with Flow: +WBHP + 'INJ' + 'PROD' +/ +WGIR + 'INJ' + 'PROD' +/ +WGIT + 'INJ' + 'PROD' +/ +WGPR + 'INJ' + 'PROD' +/ +WGPT + 'INJ' + 'PROD' +/ +WOIR + 'INJ' + 'PROD' +/ +WOIT + 'INJ' + 'PROD' +/ +WOPR + 'INJ' + 'PROD' +/ +WOPT + 'INJ' + 'PROD' +/ +WWIR + 'INJ' + 'PROD' +/ +WWIT + 'INJ' + 'PROD' +/ +WWPR + 'INJ' + 'PROD' +/ +WWPT + 'INJ' + 'PROD' +/ +SCHEDULE +-- ------------------------------------------------------------------------- +RPTSCHED + 'PRES' 'SGAS' 'RS' 'WELLS' / + +RPTRST + 'BASIC=1' / + + +-- If no resolution (i.e. case 1), the two following lines must be added: +DRSDT + 0 / +-- if DRSDT is set to 0, GOR cannot rise and free gas does not +-- dissolve in undersaturated oil -> constant bubble point pressure + +WELSPECS +-- WELNAME GRPNAME III JJJ DEPTH PREFERRED_PHASE + 'PROD' 'G1' 10 10 8400 'OIL' / + 'INJ' 'G1' 1 1 8335 'GAS' / +/ +-- Coordinates in item 3-4 are retrieved from Odeh's figure 1 and 2 +-- Note that the depth at the midpoint of the well grid blocks +-- has been used as reference depth for bottom hole pressure in item 5 + +COMPDAT +-- WELNAME III JJJ KUP KLOW OPEN/SHUT SATTAB TRANS DIAM + 'PROD' 10 10 3 3 'OPEN' 1* 1* 0.5 / + 'INJ' 1 1 1 1 'OPEN' 1* 1* 0.5 / +/ +-- Coordinates in item 2-5 are retreived from Odeh's figure 1 and 2 +-- Item 9 is the well bore internal diameter, +-- the radius is given to be 0.25ft in Odeh's paper + + +WCONPROD +-- WELLNAME OPEN/SHUT CTRLMODE OILRATE_UPLIM BHP_LOWLIM + 'PROD' 'OPEN' 'ORAT' 20000 4* 1000 / +/ + +-- It is stated in Odeh's paper that the maximum oil prod. rate +-- is 20 000stb per day which explains the choice of value in item 4. +-- The items > 4 are defaulted with the exception of item 9, +-- the BHP lower limit, which is given to be 1000psia in Odeh's paper + +WCONINJE +-- WELLNAME INJECTORTYP OPEN/SHUT CTRLMODE SURFTGTRATE 6 BHPUPLIMIT + 'INJ' 'GAS' 'OPEN' 'RATE' 100000 1* 9014 / +/ + +-- Stated in Odeh that gas inj. rate (item 5) is 100MMscf per day +-- BHP upper limit (item 7) should not be exceeding the highest +-- pressure in the PVT table=9014.7psia (default is 100 000psia) + +TSTEP +--Advance the simulater once a month for TEN years: +31 28 31 30 31 30 31 31 30 31 30 31 / +--31 28 31 30 31 30 31 31 30 31 30 31 +--31 28 31 30 31 30 31 31 30 31 30 31 +--31 28 31 30 31 30 31 31 30 31 30 31 +--31 28 31 30 31 30 31 31 30 31 30 31 +--31 28 31 30 31 30 31 31 30 31 30 31 +--31 28 31 30 31 30 31 31 30 31 30 31 +--31 28 31 30 31 30 31 31 30 31 30 31 +--31 28 31 30 31 30 31 31 30 31 30 31 +--31 28 31 30 31 30 31 31 30 31 30 31 / + +--Advance the simulator once a year for TEN years: +--10*365 / + +END