From ac927d997b952625053fbea400232a0495b4cae2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Fri, 8 Sep 2023 19:40:42 +0200 Subject: [PATCH] Added a get_dt() method Added a get_dt() to the opm.simulators.BlackOilSimulator Python module. This will return the size of the previous simulator time step. --- opm/simulators/flow/FlowMainEbos.hpp | 6 + .../flow/python/PyBlackOilSimulator.hpp | 11 +- python/simulators/CMakeLists.txt | 5 + python/simulators/PyBlackOilSimulator.cpp | 103 +++++++++++------- python/test/pytest_common.py | 12 ++ python/test/test_basic.py | 15 +-- python/test/test_schedule.py | 11 +- python/test/test_throw.py | 22 ++++ 8 files changed, 121 insertions(+), 64 deletions(-) create mode 100644 python/test/pytest_common.py create mode 100644 python/test/test_throw.py diff --git a/opm/simulators/flow/FlowMainEbos.hpp b/opm/simulators/flow/FlowMainEbos.hpp index 03e6f744c..41ad02874 100644 --- a/opm/simulators/flow/FlowMainEbos.hpp +++ b/opm/simulators/flow/FlowMainEbos.hpp @@ -321,6 +321,12 @@ void handleExtraConvergenceOutput(SimulatorReport& report, return simtimer_.get(); } + /// Get the size of the previous report step + double getPreviousReportStepSize() + { + return simtimer_->stepLengthTaken(); + } + private: // called by execute() or executeInitStep() int execute_(int (FlowMainEbos::* runOrInitFunc)(), bool cleanup) diff --git a/opm/simulators/flow/python/PyBlackOilSimulator.hpp b/opm/simulators/flow/python/PyBlackOilSimulator.hpp index 25d5710a8..534f0b668 100644 --- a/opm/simulators/flow/python/PyBlackOilSimulator.hpp +++ b/opm/simulators/flow/python/PyBlackOilSimulator.hpp @@ -43,20 +43,23 @@ public: std::shared_ptr state, std::shared_ptr schedule, std::shared_ptr summary_config); + void advance(int report_step); bool checkSimulationFinished(); + int currentStep(); py::array_t getCellVolumes(); + double getDT(); py::array_t getPorosity(); int run(); void setPorosity( py::array_t array); int step(); - void advance(int report_step); - int currentStep(); - int stepInit(); int stepCleanup(); - const Opm::FlowMainEbos& getFlowMainEbos() const; + int stepInit(); private: + Opm::FlowMainEbos& getFlowMainEbos() const; + PyMaterialState& getMaterialState() const; + const std::string deck_filename_; bool has_run_init_ = false; bool has_run_cleanup_ = false; diff --git a/python/simulators/CMakeLists.txt b/python/simulators/CMakeLists.txt index 1b773f5f5..67f16677c 100644 --- a/python/simulators/CMakeLists.txt +++ b/python/simulators/CMakeLists.txt @@ -54,6 +54,11 @@ if(OPM_ENABLE_PYTHON_TESTS) COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${PYTHON_PATH} ${PYTHON_EXECUTABLE} -m unittest test/test_schedule.py) + add_test(NAME python_throw + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/python + COMMAND ${CMAKE_COMMAND} + -E env PYTHONPATH=${PYTHON_PATH} ${PYTHON_EXECUTABLE} + -m unittest test/test_throw.py) endif() find_file(PYTHON_INSTALL_PY install.py diff --git a/python/simulators/PyBlackOilSimulator.cpp b/python/simulators/PyBlackOilSimulator.cpp index a339b11d3..3853d123a 100644 --- a/python/simulators/PyBlackOilSimulator.cpp +++ b/python/simulators/PyBlackOilSimulator.cpp @@ -55,33 +55,46 @@ PyBlackOilSimulator::PyBlackOilSimulator( { } -bool PyBlackOilSimulator::checkSimulationFinished() +// Public methods alphabetically sorted +// ------------------------------------ + +void PyBlackOilSimulator::advance(int report_step) { - return this->main_ebos_->getSimTimer()->done(); + while (currentStep() < report_step) { + step(); + } } -const Opm::FlowMainEbos& - PyBlackOilSimulator::getFlowMainEbos() const +bool PyBlackOilSimulator::checkSimulationFinished() { - if (this->main_ebos_) { - return *this->main_ebos_; - } - else { - throw std::runtime_error("BlackOilSimulator not initialized: " - "Cannot get reference to FlowMainEbos object" ); - } + return getFlowMainEbos().getSimTimer()->done(); +} + +// This returns the report step number that will be executed next time step() +// is called. +int PyBlackOilSimulator::currentStep() +{ + return getFlowMainEbos().getSimTimer()->currentStepNum(); + // NOTE: this->ebos_simulator_->episodeIndex() would also return the current + // report step number, but this number is always delayed by 1 step relative + // to this->main_ebos_->getSimTimer()->currentStepNum() + // See details in runStep() in file SimulatorFullyImplicitBlackoilEbos.hpp +} + +py::array_t PyBlackOilSimulator::getCellVolumes() { + std::size_t len; + auto array = getMaterialState().getCellVolumes(&len); + return py::array(len, array.get()); +} + +double PyBlackOilSimulator::getDT() { + return getFlowMainEbos().getPreviousReportStepSize(); } py::array_t PyBlackOilSimulator::getPorosity() { std::size_t len; - auto array = this->material_state_->getPorosity(&len); - return py::array(len, array.get()); -} - -py::array_t PyBlackOilSimulator::getCellVolumes() { - std::size_t len; - auto array = this->material_state_->getCellVolumes(&len); + auto array = getMaterialState().getPorosity(&len); return py::array(len, array.get()); } @@ -96,14 +109,7 @@ void PyBlackOilSimulator::setPorosity( py::array_tmaterial_state_->setPorosity(poro, size_); -} - -void PyBlackOilSimulator::advance(int report_step) -{ - while (currentStep() < report_step) { - step(); - } + getMaterialState().setPorosity(poro, size_); } int PyBlackOilSimulator::step() @@ -119,26 +125,14 @@ int PyBlackOilSimulator::step() } //if (this->debug_) // this->mainEbos_->getSimTimer()->report(std::cout); - auto result = this->main_ebos_->executeStep(); + auto result = getFlowMainEbos().executeStep(); return result; } -// This returns the report step number that will be executed next time step() -// is called. -int PyBlackOilSimulator::currentStep() -{ - return this->main_ebos_->getSimTimer()->currentStepNum(); - // NOTE: this->ebos_simulator_->episodeIndex() would also return the current - // report step number, but this number is always delayed by 1 step relative - // to this->main_ebos_->getSimTimer()->currentStepNum() - // See details in runStep() in file SimulatorFullyImplicitBlackoilEbos.hpp -} - - int PyBlackOilSimulator::stepCleanup() { this->has_run_cleanup_ = true; - return this->main_ebos_->executeStepsCleanup(); + return getFlowMainEbos().executeStepsCleanup(); } int PyBlackOilSimulator::stepInit() @@ -178,6 +172,34 @@ int PyBlackOilSimulator::stepInit() } } +// Private methods alphabetically sorted +// ------------------------------------ + +Opm::FlowMainEbos& + PyBlackOilSimulator::getFlowMainEbos() const +{ + if (this->main_ebos_) { + return *this->main_ebos_; + } + else { + throw std::runtime_error("BlackOilSimulator not initialized: " + "Cannot get reference to FlowMainEbos object" ); + } +} + +PyMaterialState& +PyBlackOilSimulator::getMaterialState() const +{ + if (this->material_state_) { + return *this->material_state_; + } + else { + throw std::runtime_error("BlackOilSimulator not initialized: " + "Cannot get reference to FlowMainEbos object" ); + } +} + +// Exported functions void export_PyBlackOilSimulator(py::module& m) { py::class_(m, "BlackOilSimulator") @@ -189,6 +211,7 @@ void export_PyBlackOilSimulator(py::module& m) std::shared_ptr >()) .def("get_cell_volumes", &PyBlackOilSimulator::getCellVolumes, py::return_value_policy::copy) + .def("get_dt", &PyBlackOilSimulator::getDT) .def("get_porosity", &PyBlackOilSimulator::getPorosity, py::return_value_policy::copy) .def("run", &PyBlackOilSimulator::run) diff --git a/python/test/pytest_common.py b/python/test/pytest_common.py new file mode 100644 index 000000000..3ae9c21ff --- /dev/null +++ b/python/test/pytest_common.py @@ -0,0 +1,12 @@ +import os +from contextlib import contextmanager + +@contextmanager +def pushd(path): + cwd = os.getcwd() + if not os.path.isdir(path): + os.makedirs(path) + os.chdir(path) + yield + os.chdir(cwd) + diff --git a/python/test/test_basic.py b/python/test/test_basic.py index d00fccbf4..b530b9c11 100755 --- a/python/test/test_basic.py +++ b/python/test/test_basic.py @@ -3,16 +3,7 @@ import unittest from contextlib import contextmanager from pathlib import Path from opm.simulators import BlackOilSimulator - -@contextmanager -def pushd(path): - cwd = os.getcwd() - if not os.path.isdir(path): - os.makedirs(path) - os.chdir(path) - yield - os.chdir(cwd) - +from .pytest_common import pushd class TestBasic(unittest.TestCase): @classmethod @@ -63,6 +54,10 @@ class TestBasic(unittest.TestCase): sim = BlackOilSimulator("SPE1CASE1.DATA") sim.step_init() sim.step() + dt = sim.get_dt() + # NOTE: The timestep should be 1 month = 31 days + # = 31 * 24 * 60 * 60 seconds = 2678400 seconds + self.assertAlmostEqual(dt, 2678400.0, places=7, msg='value of timestep') vol = sim.get_cell_volumes() self.assertEqual(len(vol), 300, 'length of volume vector') # NOTE: The volume should be 1000 ft x 1000 ft x 20 ft * 0.3 (porosity) diff --git a/python/test/test_schedule.py b/python/test/test_schedule.py index 058c942d8..0aa442f72 100755 --- a/python/test/test_schedule.py +++ b/python/test/test_schedule.py @@ -9,16 +9,7 @@ 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) - +from .pytest_common import pushd class TestBasic(unittest.TestCase): @classmethod diff --git a/python/test/test_throw.py b/python/test/test_throw.py new file mode 100644 index 000000000..ae0ddf78a --- /dev/null +++ b/python/test/test_throw.py @@ -0,0 +1,22 @@ +import os +import unittest +from pathlib import Path +from opm.simulators import BlackOilSimulator +from .pytest_common import pushd + +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/SPE1CASE1a") + + def test_all(self): + with pushd(self.data_dir): + sim = BlackOilSimulator("SPE1CASE1.DATA") + # NOTE: The following call should throw an exception since the simulation + # has not been initialized + with self.assertRaises(RuntimeError): + sim.get_dt()