From d0c08c43822cd4e2da44117e738786c3da2ecc71 Mon Sep 17 00:00:00 2001 From: Svenn Tveit Date: Wed, 13 Aug 2025 14:36:06 +0200 Subject: [PATCH 1/7] Python wrapper of single phase (water) simulator --- CMakeLists_files.cmake | 1 + .../flow/TTagFlowProblemOnePhase.hpp | 39 +++++ .../flow/python/PyOnePhaseSimulator.hpp | 53 +++++++ .../flow/python/Pybind11Exporter.hpp | 1 + python/docstrings_op_simulators.json | 83 +++++++++++ python/opm/simulators/__init__.py | 1 + python/setup.py.in | 3 +- python/simulators/CMakeLists.txt | 18 ++- python/simulators/PyOnePhaseSimulator.cpp | 135 ++++++++++++++++++ 9 files changed, 332 insertions(+), 2 deletions(-) create mode 100644 opm/simulators/flow/TTagFlowProblemOnePhase.hpp create mode 100644 opm/simulators/flow/python/PyOnePhaseSimulator.hpp create mode 100644 python/docstrings_op_simulators.json create mode 100644 python/simulators/PyOnePhaseSimulator.cpp diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 3671844003d..823b67bc517 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -959,6 +959,7 @@ list (APPEND PUBLIC_HEADER_FILES opm/simulators/flow/SubDomain.hpp opm/simulators/flow/TTagFlowProblemTPFA.hpp opm/simulators/flow/TTagFlowProblemGasWater.hpp + opm/simulators/flow/TTagFlowProblemOnePhase.hpp opm/simulators/flow/TracerContainer.hpp opm/simulators/flow/TracerModel.hpp opm/simulators/flow/Transmissibility.hpp diff --git a/opm/simulators/flow/TTagFlowProblemOnePhase.hpp b/opm/simulators/flow/TTagFlowProblemOnePhase.hpp new file mode 100644 index 00000000000..41dfefae26a --- /dev/null +++ b/opm/simulators/flow/TTagFlowProblemOnePhase.hpp @@ -0,0 +1,39 @@ +/* + Copyright 2025 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 TTAG_FLOW_PROBLEM_ONE_PHASE_HPP +#define TTAG_FLOW_PROBLEM_ONE_PHASE_HPP + +#include + +namespace Opm { +namespace Properties { +namespace TTag { + + struct FlowProblem; + + struct FlowOnePhaseProblem { + using InheritsFrom = std::tuple; + }; +} + + +} // namespace Opm::Properties::TTag +} +#endif // TTAG_FLOW_ONE_PHASE_HPP diff --git a/opm/simulators/flow/python/PyOnePhaseSimulator.hpp b/opm/simulators/flow/python/PyOnePhaseSimulator.hpp new file mode 100644 index 00000000000..7f665eee5e5 --- /dev/null +++ b/opm/simulators/flow/python/PyOnePhaseSimulator.hpp @@ -0,0 +1,53 @@ +/* + 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_ONE_PHASE_SIMULATOR_HEADER_INCLUDED +#define OPM_PY_ONE_PHASE_SIMULATOR_HEADER_INCLUDED + +#include +#include + +#include + +namespace Opm::Pybind { + +class PyOnePhaseSimulator : public PyBaseSimulator +{ +private: + using BaseType = PyBaseSimulator; + using TypeTag = Opm::Properties::TTag::FlowOnePhaseProblem; + +public: + PyOnePhaseSimulator(const std::string& deck_filename, + const std::vector& args) + : BaseType(deck_filename, args) + {} + + PyOnePhaseSimulator(std::shared_ptr deck, + std::shared_ptr state, + std::shared_ptr schedule, + std::shared_ptr summary_config, + const std::vector& args) + : BaseType(deck, state, schedule, summary_config, args) + {} + +}; + +} // namespace Opm::Pybind +#endif // OPM_PY_GASWATER_SIMULATOR_HEADER_INCLUDED diff --git a/opm/simulators/flow/python/Pybind11Exporter.hpp b/opm/simulators/flow/python/Pybind11Exporter.hpp index 101abe2ea32..f399d9f0fed 100644 --- a/opm/simulators/flow/python/Pybind11Exporter.hpp +++ b/opm/simulators/flow/python/Pybind11Exporter.hpp @@ -11,6 +11,7 @@ namespace py = pybind11; namespace Opm::Pybind { void export_PyBlackOilSimulator(py::module& m); void export_PyGasWaterSimulator(py::module& m); + void export_PyOnePhaseSimulator(py::module& m); } #endif //OPM_PYBIND11_EXPORTER_HEADER_INCLUDED diff --git a/python/docstrings_op_simulators.json b/python/docstrings_op_simulators.json new file mode 100644 index 00000000000..47ff41befdb --- /dev/null +++ b/python/docstrings_op_simulators.json @@ -0,0 +1,83 @@ +{ + "PyOnePhaseSimulator":{ + "type": "class", + "signature": "opm.simulators.OnePhaseSimulator", + "doc": "The OnePhaseSimulator class to run simulations using a given Deck." + }, + "PyOnePhaseSimulator_filename_constructor": { + "signature": "opm.simulators.OnePhaseSimulator.__init__(deck_filename: str, args: list[str] = []) -> OnePhaseSimulator", + "doc": "Constructor using a deck file name.\n\n:param deck_filename: The file name of the deck to be used for the simulation.\n:type deck_filename: str\n:param args: Simulator options.\n:type args: list[str]\n:return: The OnePhaseSimulator.\n:type return: OnePhaseSimulator" + }, + "PyOnePhaseSimulator_objects_constructor": { + "signature": "opm.simulators.OnePhaseSimulator.__init__(deck: Deck, state: EclipseState, schedule: Schedule, summary_config: SummaryConfig, args: list[str] = []) -> OnePhaseSimulator", + "doc": "Constructor using Deck, EclipseState, Schedule, and SummaryConfig objects.\n\n:param deck: Deck object.\n:type deck: Deck\n:param state: EclipseState object.\n:type state: EclipseState\n:param schedule: Schedule object.\n:type schedule: Schedule\n:param summary_config: SummaryConfig object.\n:type summary_config: SummaryConfig\n:param args: Simulator options.\n:type args: list[str]\n:return: The OnePhaseSimulator.\n:type return: OnePhaseSimulator" + }, + "advance": { + "signature": "opm.simulators.OnePhaseSimulator.advance(report_step: int) -> None", + "doc": "Advances the simulation to a specific report step.\n\n:param report_step: Target report step to advance to.\n:type report_step: int" + }, + "checkSimulationFinished": { + "signature": "opm.simulators.OnePhaseSimulator.check_simulation_finished() -> bool", + "doc": "Checks if the simulation has finished.\n\n:return: True if the simulation is finished, False otherwise.\n:type return: bool" + }, + "currentStep": { + "signature": "opm.simulators.OnePhaseSimulator.current_step() -> int", + "doc": "Gets the current simulation step.\n\n:return: The current step number." + }, + "getCellVolumes": { + "signature": "opm.simulators.OnePhaseSimulator.get_cell_volumes() -> NDArray[float]", + "doc": "Retrieves the cell volumes of the simulation grid.\n\n:return: An array of cell volumes.\n:type return: NDArray[float]" + }, + "getDT": { + "signature": "opm.simulators.OnePhaseSimulator.get_dt() -> float", + "doc": "Gets the timestep size of the last completed step.\n\n:return: Timestep size in days.\n:type return: float" + }, + "getFluidStateVariable": { + "signature": "opm.simulators.OnePhaseSimulator.get_fluid_state_variable(name: str) -> NDArray[float]", + "doc": "Retrieves a fluid state variable for the simulation grid.\n\n:param name: The name of the variable. Valid names are 'pw' (pressure water), 'pg' (pressure gas), 'po' (pressure oil), 'rho_w' (density water), 'rho_g' (density gas), 'rho_o' (density oil)'Rs' (soultion gas-oil ratio), 'Rv' (volatile gas-oil ratio), 'Sw' (water saturation), 'Sg' (gas saturation), 'So' (oil saturation), and 'T' (temperature).\n:type name: str\n\n:return: An array of fluid state variables.\n:type return: NDArray[float]" + }, + "getPorosity": { + "signature": "opm.simulators.OnePhaseSimulator.get_porosity() -> NDArray[float]", + "doc": "Retrieves the porosity values of the simulation grid.\n\n:return: An array of porosity values.\n:type return: numpy.ndarray" + }, + "getPrimaryVarMeaning": { + "signature": "opm.simulators.OnePhaseSimulator.get_primary_var_meaning(variable: str) -> NDArray[int]", + "doc": "Retrieves the primary variable meaning of the simulation grid.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n\n:return: An array of primary variable meanings. See ``get_primary_variable_meaning_map()`` for more information.\n:type return: NDArray[int]" + }, + "getPrimaryVarMeaningMap": { + "signature": "opm.simulators.OnePhaseSimulator.get_primary_var_meaning_map(variable: str) -> dict[str, int]", + "doc": "Retrieves the primary variable meaning map for each primary variable.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n\n:return: A dictionary of primary variable meanings. The keys are the primary variable meanings and the values are the corresponding integer codes. The integer codes are used to represent the primary variable meanings in the simulation grid. For variable name 'pressure', the valid keys are: 'Po', 'Pg', and 'Pw', for variable name 'water', the valid keys are: 'Sw', 'Rvw', 'Rsw', and 'Disabled', for variable name 'gas', the valid keys are: 'Sg', 'Rs', 'Rv', and 'Disabled', for variable name 'brine', the valid keys are: 'Cs', 'Sp', and 'Disabled'.\n:type return: dict[str, int]" + }, + "getPrimaryVariable": { + "signature": "opm.simulators.OnePhaseSimulator.get_primary_variable(variable: str) -> NDArray[float]", + "doc": "Retrieves the primary variable's values for the simulation grid.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n\n:return: An array of primary variable values. See ``get_primary_variable_meaning()`` for more information.\n:type return: NDArray[float]" + }, + "run": { + "signature": "opm.simulators.OnePhaseSimulator.run() -> int", + "doc": "Runs the simulation to completion with the provided deck file or previously set deck.\n\n:return: EXIT_SUCCESS if the simulation completes successfully." + }, + "setPorosity": { + "signature": "opm.simulators.OnePhaseSimulator.set_porosity(array: NDArray[float]) -> None", + "doc": "Sets the porosity values for the simulation grid.\n\n:param array: An array of porosity values to be set.\n:type array: NDArray[float]" + }, + "setPrimaryVariable": { + "signature": "opm.simulators.OnePhaseSimulator.set_primary_variable(variable: str, value: NDArray[float]) -> None", + "doc": "Sets the primary variable's values for the simulation grid.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n:param value: An array of primary variable values to be set. See ``get_primary_variable()`` for more information.\n:type value: NDArray[float]" + }, + "setupMpi": { + "signature": "opm.simulators.OnePhaseSimulator.mpi_init(init: bool, finalize: bool) -> None", + "doc": "Sets MPI up for parallel simulation. This method should be called before any other method.\n\n:param init: Whether to call ``MPI_Init()`` or not.\n:param finalize: Whether to call ``MPI_Finalize()```when the simulator object goes out of scope.\n\n:return: None" + }, + "step": { + "signature": "opm.simulators.OnePhaseSimulator.step() -> int", + "doc": "Executes the next simulation report step.\n\n:return: Result of the simulation step." + }, + "stepCleanup": { + "signature": "opm.simulators.OnePhaseSimulator.step_cleanup() -> int", + "doc": "Performs cleanup after the last simulation step.\n\n:return: EXIT_SUCCESS if cleanup is successful." + }, + "stepInit": { + "signature": "opm.simulators.OnePhaseSimulator.step_init() -> int", + "doc": "Initializes the simulation before taking the first report step. This method should be called before the first call to ``step()``\n\n:return: EXIT_SUCCESS if the initialization is successful." + } +} diff --git a/python/opm/simulators/__init__.py b/python/opm/simulators/__init__.py index c869f579bb3..6c47420bf83 100644 --- a/python/opm/simulators/__init__.py +++ b/python/opm/simulators/__init__.py @@ -11,3 +11,4 @@ # from .BlackOil import BlackOilSimulator from .GasWater import GasWaterSimulator +from .OnePhase import OnePhaseSimulator diff --git a/python/setup.py.in b/python/setup.py.in index aa1583bcd7c..7cc6c5a619a 100644 --- a/python/setup.py.in +++ b/python/setup.py.in @@ -36,7 +36,8 @@ setup( package_data={ 'opm': [ '$', - '$' + '$', + '$', ] }, include_package_data=True, diff --git a/python/simulators/CMakeLists.txt b/python/simulators/CMakeLists.txt index 283c62f4799..e378e237d4e 100644 --- a/python/simulators/CMakeLists.txt +++ b/python/simulators/CMakeLists.txt @@ -4,6 +4,8 @@ set(PYTHON_OPM_SIMULATORS_PACKAGE_PATH ${PROJECT_BINARY_DIR}/python/opm/simulato set(PYTHON_DOCSTRINGS_FILE "${PROJECT_SOURCE_DIR}/python/docstrings_simulators.json") set(PYTHON_DOCSTRINGS_GENERATED_HPP "${PROJECT_BINARY_DIR}/python/PyBlackOilSimulatorDoc.hpp") set(PYTHON_GW_DOCSTRINGS_GENERATED_HPP "${PROJECT_BINARY_DIR}/python/PyGasWaterSimulatorDoc.hpp") +set(PYTHON_OP_DOCSTRINGS_FILE "${PROJECT_SOURCE_DIR}/python/docstrings_op_simulators.json") +set(PYTHON_OP_DOCSTRINGS_GENERATED_HPP "${PROJECT_BINARY_DIR}/python/PyOnePhaseSimulatorDoc.hpp") # Note: If the new find_package(Python3) is used in the top level CMakeLists.txt, the variable # ${PYTHON_EXECUTABLE} is set there to ${Python3_EXECUTABLE} # @@ -29,6 +31,14 @@ add_custom_command( DEPENDS ${PYTHON_DOCSTRINGS_FILE} COMMENT "Generating PyGasWaterSimulatorDoc.hpp from JSON file" ) +add_custom_command( + OUTPUT ${PYTHON_OP_DOCSTRINGS_GENERATED_HPP} + COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${CMAKE_SOURCE_DIR} + ${PYTHON_EXECUTABLE} ${PYTHON_GENERATE_DOCSTRINGS_PY} + ${PYTHON_OP_DOCSTRINGS_FILE} ${PYTHON_OP_DOCSTRINGS_GENERATED_HPP} PYONEPHASESIMULATORDOC_HPP "Opm::Pybind::DocStrings" + DEPENDS ${PYTHON_OP_DOCSTRINGS_FILE} + COMMENT "Generating PyOnePhaseSimulatorDoc.hpp from JSON file" +) # 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 @@ -48,6 +58,12 @@ pybind11_add_module(GasWater ${PYBIND11_SYSTEM} ${PYTHON_GW_DOCSTRINGS_GENERATED_HPP} # Include the generated .hpp as a source file ) +pybind11_add_module(OnePhase ${PYBIND11_SYSTEM} + $ + PyOnePhaseSimulator.cpp + ${PYTHON_OP_DOCSTRINGS_GENERATED_HPP} # Include the generated .hpp as a source file + ) + # Create a convenience target to build all Python simulator modules add_custom_target(python_simulator_modules DEPENDS BlackOil GasWater @@ -71,7 +87,7 @@ add_custom_target(copy_python ALL ${PROJECT_SOURCE_DIR}/python/test_data ${PROJECT_BINARY_DIR}/python 0 ) -foreach(target_name IN ITEMS BlackOil GasWater) +foreach(target_name IN ITEMS BlackOil GasWater OnePhase) set_target_properties( ${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PYTHON_OPM_SIMULATORS_PACKAGE_PATH} ) diff --git a/python/simulators/PyOnePhaseSimulator.cpp b/python/simulators/PyOnePhaseSimulator.cpp new file mode 100644 index 00000000000..57b8f48e868 --- /dev/null +++ b/python/simulators/PyOnePhaseSimulator.cpp @@ -0,0 +1,135 @@ +/* + 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 +// NOTE: This file will be generated at compile time and placed in the build directory +// See python/generate_docstring_hpp.py, and python/simulators/CMakeLists.txt for details +#include +// NOTE: EXIT_SUCCESS, EXIT_FAILURE is defined in cstdlib +#include +#include +#include + +namespace Opm::Properties { + + //! The indices required by the model + template + struct Indices + { + private: + // it is unfortunately not possible to simply use 'TypeTag' here because this leads + // to cyclic definitions of some properties. if this happens the compiler error + // messages unfortunately are *really* confusing and not really helpful. + using BaseTypeTag = TTag::FlowProblem; + using FluidSystem = GetPropType; + + public: + using type = BlackOilOnePhaseIndices(), + getPropValue(), + getPropValue(), + getPropValue(), + getPropValue(), + getPropValue(), + /*PVOffset=*/0, + /*enabledCompIdx=*/FluidSystem::waterCompIdx, + getPropValue()>; + }; // struct Indices + +} // namespace Opm::Properties + +// NOTE: We need the below explicit instantiations or else the symbols +// will not be available in the shared library and we will get +// undefined symbol errors when trying to import the module in Python. +namespace Opm::Pybind { + +template class PyBaseSimulator; + +} // namespace Opm::Pybind + +// Define main function +namespace Opm { + +template class PyMain; +template std::unique_ptr> + flowMainInit( + int argc, char** argv, bool outputCout, bool outputFiles); + +} // namespace Opm + +namespace py = pybind11; + +namespace Opm::Pybind { + +// Exported functions +void export_PyOnePhaseSimulator(py::module& m) +{ + using namespace Opm::Pybind::DocStrings; + using TypeTag = Opm::Properties::TTag::FlowOnePhaseProblem; + + py::class_>( + m, + "_BaseSimulatorOP", + py::module_local() + ); + py::class_ >(m, "OnePhaseSimulator") + .def(py::init&>(), + PyOnePhaseSimulator_filename_constructor_docstring, + py::arg("filename"), py::arg("args") = std::vector{}) + .def(py::init< + std::shared_ptr, + std::shared_ptr, + std::shared_ptr, + std::shared_ptr, + const std::vector&>(), + PyOnePhaseSimulator_objects_constructor_docstring, + py::arg("Deck"), py::arg("EclipseState"), py::arg("Schedule"), py::arg("SummaryConfig"), + py::arg("args") = std::vector{}) + .def("advance", &PyBaseSimulator::advance, advance_docstring, py::arg("report_step")) + .def("check_simulation_finished", &PyBaseSimulator::checkSimulationFinished, + checkSimulationFinished_docstring) + .def("current_step", &PyBaseSimulator::currentStep, currentStep_docstring) + .def("get_cell_volumes", &PyBaseSimulator::getCellVolumes, getCellVolumes_docstring) + .def("get_dt", &PyBaseSimulator::getDT, getDT_docstring) + .def("get_fluidstate_variable", &PyBaseSimulator::getFluidStateVariable, + py::return_value_policy::copy, getFluidStateVariable_docstring, py::arg("name")) + .def("get_porosity", &PyBaseSimulator::getPorosity, getPorosity_docstring) + .def("get_primary_variable_meaning", &PyBaseSimulator::getPrimaryVarMeaning, + py::return_value_policy::copy, getPrimaryVarMeaning_docstring, py::arg("variable")) + .def("get_primary_variable_meaning_map", &PyBaseSimulator::getPrimaryVarMeaningMap, + py::return_value_policy::copy, getPrimaryVarMeaningMap_docstring, py::arg("variable")) + .def("get_primary_variable", &PyBaseSimulator::getPrimaryVariable, + py::return_value_policy::copy, getPrimaryVariable_docstring, py::arg("variable")) + .def("run", &PyBaseSimulator::run, run_docstring) + .def("set_porosity", &PyBaseSimulator::setPorosity, setPorosity_docstring, py::arg("array")) + .def("set_primary_variable", &PyBaseSimulator::setPrimaryVariable, + py::arg("variable"), setPrimaryVariable_docstring, py::arg("value")) + .def("setup_mpi", &PyBaseSimulator::setupMpi, setupMpi_docstring, py::arg("init"), py::arg("finalize")) + .def("step", &PyBaseSimulator::step, step_docstring) + .def("step_cleanup", &PyBaseSimulator::stepCleanup, stepCleanup_docstring) + .def("step_init", &PyBaseSimulator::stepInit, stepInit_docstring); +} + +PYBIND11_MODULE(OnePhase, m) +{ + export_PyOnePhaseSimulator(m); +} + +} // namespace Opm::Pybind \ No newline at end of file From 5153cd6fc0db1cc87c9e1f50ab8f7a2309f68510 Mon Sep 17 00:00:00 2001 From: Svenn Tveit Date: Wed, 17 Sep 2025 15:24:06 +0200 Subject: [PATCH 2/7] Add OnePhaseSimulator to custom Python target --- python/simulators/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/simulators/CMakeLists.txt b/python/simulators/CMakeLists.txt index e378e237d4e..54a34c4dabf 100644 --- a/python/simulators/CMakeLists.txt +++ b/python/simulators/CMakeLists.txt @@ -66,7 +66,7 @@ pybind11_add_module(OnePhase ${PYBIND11_SYSTEM} # Create a convenience target to build all Python simulator modules add_custom_target(python_simulator_modules - DEPENDS BlackOil GasWater + DEPENDS BlackOil GasWater OnePhase COMMENT "Building all Python simulator modules (BlackOil, GasWater, etc.)" ) From fc3e1bb73fcb88ddc87c2b21f6a30cdf8abf8520 Mon Sep 17 00:00:00 2001 From: Svenn Tveit Date: Thu, 18 Sep 2025 11:21:03 +0200 Subject: [PATCH 3/7] Tests for OnePhaseSimulator --- python/test/test_basic.py | 21 ++ python/test/test_fluidstate_variables.py | 14 ++ python/test/test_primary_variables.py | 25 +++ .../test_data/SPE1CASE1/SPE1CASE1_WATER.DATA | 203 ++++++++++++++++++ 4 files changed, 263 insertions(+) create mode 100644 python/test_data/SPE1CASE1/SPE1CASE1_WATER.DATA diff --git a/python/test/test_basic.py b/python/test/test_basic.py index 865a6514f9d..5d439984c99 100755 --- a/python/test/test_basic.py +++ b/python/test/test_basic.py @@ -8,6 +8,7 @@ class TestBasic(unittest.TestCase): def setUpClass(cls): test_dir = Path(os.path.dirname(__file__)) cls.data_dir_bo = test_dir.parent.joinpath("test_data/SPE1CASE1a") + cls.data_dir_op = test_dir.parent.joinpath("test_data/SPE1CASE1") cls.data_dir_gw = test_dir.parent.joinpath("test_data/SPE1CASE2") # IMPORTANT: Since all the python unittests run in the same process we must be @@ -43,6 +44,26 @@ def test_01_blackoil(self): sim.step() poro2 = sim.get_porosity() self.assertAlmostEqual(poro2[0], 0.285, places=7, msg='value of porosity 2') + + def test_02_onephase(self): + with pushd(self.data_dir_op): + sim = OnePhaseSimulator(args=['--linear-solver=ilu0'], filename="SPE1CASE1_WATER.DATA") + sim.setup_mpi(init=False, finalize=False) + sim.step_init() + sim.step() + dt = sim.get_dt() # 31 days = 31 * 24 * 60 * 60 = 2678400 seconds + self.assertAlmostEqual(dt, 2678400., places=7, msg='value of timestep') + vol = sim.get_cell_volumes() + self.assertEqual(len(vol), 300, 'length of volume vector') + self.assertAlmostEqual(vol[0], 566336.93, places=2, msg='value of volume') + poro = sim.get_porosity() + self.assertEqual(len(poro), 300, 'length of porosity vector') + self.assertAlmostEqual(poro[0], 0.3, places=7, msg='value of porosity') + poro = poro *.95 + sim.set_porosity(poro) + sim.step() + poro2 = sim.get_porosity() + self.assertAlmostEqual(poro2[0], 0.285, places=7, msg='value of porosity 2') # IMPORTANT: This test must be run last since it calls MPI_Finalize() def test_99_gaswater(self): diff --git a/python/test/test_fluidstate_variables.py b/python/test/test_fluidstate_variables.py index 0f36498a712..8e47b88fbfc 100644 --- a/python/test/test_fluidstate_variables.py +++ b/python/test/test_fluidstate_variables.py @@ -8,6 +8,7 @@ class TestBasic(unittest.TestCase): def setUpClass(cls): test_dir = Path(os.path.dirname(__file__)) cls.data_dir_bo = test_dir.parent.joinpath("test_data/SPE1CASE1a") + cls.data_dir_op = test_dir.parent.joinpath("test_data/SPE1CASE1") cls.data_dir_gw = test_dir.parent.joinpath("test_data/SPE1CASE2") # IMPORTANT: Since all the python unittests run in the same process we must be @@ -49,6 +50,19 @@ def test_01_blackoil(self): T = sim.get_fluidstate_variable(name='T') self.assertAlmostEqual(T[0], 288.705, places=3, msg='value of temperature') + def test_02_onephase(self): + with pushd(self.data_dir_op): + sim = OnePhaseSimulator("SPE1CASE1_WATER.DATA") + sim.setup_mpi(False, False) + sim.step_init() + sim.step() + water_pressure = sim.get_fluidstate_variable(name='pw') + self.assertAlmostEqual(water_pressure[0], 44780102.277570, delta=1e4, msg='value of water pressure') + rho_w = sim.get_fluidstate_variable(name='rho_w') + self.assertAlmostEqual(rho_w[0], 1003.182858, places=3, msg='value of water density') + Sw = sim.get_fluidstate_variable(name='Sw') + self.assertAlmostEqual(Sw[0], 1.0, places=5, msg='value of water saturation') + # IMPORTANT: This test must be run last since it calls MPI_Finalize() def test_99_gaswater(self): with pushd(self.data_dir_gw): diff --git a/python/test/test_primary_variables.py b/python/test/test_primary_variables.py index 60558ed8b7b..955ee797f6b 100644 --- a/python/test/test_primary_variables.py +++ b/python/test/test_primary_variables.py @@ -11,6 +11,7 @@ def setUpClass(cls): # it up in multiple test functions test_dir = Path(os.path.dirname(__file__)) cls.data_dir_bo = test_dir.parent.joinpath("test_data/SPE1CASE1a") + cls.data_dir_op = test_dir.parent.joinpath("test_data/SPE1CASE1") cls.data_dir_gw = test_dir.parent.joinpath("test_data/SPE1CASE2") # IMPORTANT: Since all the python unittests run in the same process we must be @@ -50,6 +51,30 @@ def test_01_blackoil(self): variable='brine') self.assertEqual(brine_meaning[0], brine_meaning_map["Disabled"]) + def test_02_onephase(self): + with pushd(self.data_dir_op): + sim = OnePhaseSimulator("SPE1CASE1_WATER.DATA") + sim.setup_mpi(False, False) + sim.step_init() + sim.step() + pressure = sim.get_primary_variable(variable='pressure') + self.assertAlmostEqual(pressure[0], 44780102.277570, delta=1e4, msg='value of pressure') + pressure_meaning = sim.get_primary_variable_meaning( + variable='pressure') + pressure_meaning_map = sim.get_primary_variable_meaning_map( + variable='pressure') + self.assertEqual(pressure_meaning[0], pressure_meaning_map["Pw"]) + water_meaning = sim.get_primary_variable_meaning( + variable='water') + water_meaning_map = sim.get_primary_variable_meaning_map( + variable='water') + self.assertEqual(water_meaning[0], water_meaning_map["Disabled"]) + brine_meaning = sim.get_primary_variable_meaning( + variable='brine') + brine_meaning_map = sim.get_primary_variable_meaning_map( + variable='brine') + self.assertEqual(brine_meaning[0], brine_meaning_map["Disabled"]) + # IMPORTANT: This test must be run last since it calls MPI_Finalize() def test_99_gaswater(self): with pushd(self.data_dir_gw): diff --git a/python/test_data/SPE1CASE1/SPE1CASE1_WATER.DATA b/python/test_data/SPE1CASE1/SPE1CASE1_WATER.DATA new file mode 100644 index 00000000000..d8fcc70b971 --- /dev/null +++ b/python/test_data/SPE1CASE1/SPE1CASE1_WATER.DATA @@ -0,0 +1,203 @@ +-- 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) 2019 SINTEF +-- Copyright (C) 2020 Equinor + +-- This simulation deck is for flow_onephase +-- to simulate water injection/production +-- in a water single-phase system + +--------------------------------------------------------------------------- +------------------------ 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 +/ + +WATER + + +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 / + +UNIFIN +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 + 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 / + +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 / + +SOLUTION +-- ------------------------------------------------------------------------- +PRESSURE +300*4800 +/ + +SUMMARY +-- ------------------------------------------------------------------------- +WBHP + 'INJ' + 'PROD' +/ +WWIR + 'INJ' +/ +WWIT + 'INJ' +/ +WWPR + 'PROD' +/ +WWPT + 'PROD' +/ +SCHEDULE +-- ------------------------------------------------------------------------- +RPTSCHED + 'PRES' / + +RPTRST + 'BASIC=1' / + +WELSPECS +-- Item #: 1 2 3 4 5 6 + 'PROD' 'G1' 10 10 8400 'WATER' / + 'INJ' 'G1' 1 1 8335 'WATER' / +/ +-- 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 +-- Item #: 1 2 3 4 5 6 7 8 9 + '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 +-- Item #:1 2 3 4 5 9 + 'PROD' 'OPEN' 'BHP' 1* 1* 1* 1* 1* 1000 / +/ + + +WCONINJE +-- Item #:1 2 3 4 5 6 7 + 'INJ' 'WATER' '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 ONE years: +31 28 31 30 31 30 31 31 30 31 30 31 / + +END From 883b385520082a769aa8c3dd6176994bed872a6f Mon Sep 17 00:00:00 2001 From: Svenn Tveit Date: Thu, 18 Sep 2025 13:31:59 +0200 Subject: [PATCH 4/7] Cleaned up formatting --- opm/simulators/flow/TTagFlowProblemOnePhase.hpp | 13 ++++++------- opm/simulators/flow/python/PyOnePhaseSimulator.hpp | 8 ++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/opm/simulators/flow/TTagFlowProblemOnePhase.hpp b/opm/simulators/flow/TTagFlowProblemOnePhase.hpp index 41dfefae26a..52f9b772016 100644 --- a/opm/simulators/flow/TTagFlowProblemOnePhase.hpp +++ b/opm/simulators/flow/TTagFlowProblemOnePhase.hpp @@ -22,18 +22,17 @@ #include -namespace Opm { -namespace Properties { -namespace TTag { - +namespace Opm::Properties::TTag { struct FlowProblem; + /// Specialized type tag for one phase (water) simulations. + /// + /// All properties are otherwise the same as for the regular + /// FlowProblem. struct FlowOnePhaseProblem { using InheritsFrom = std::tuple; }; -} +} // namespace Opm::Properties::TTag -} // namespace Opm::Properties::TTag -} #endif // TTAG_FLOW_ONE_PHASE_HPP diff --git a/opm/simulators/flow/python/PyOnePhaseSimulator.hpp b/opm/simulators/flow/python/PyOnePhaseSimulator.hpp index 7f665eee5e5..81447d407ab 100644 --- a/opm/simulators/flow/python/PyOnePhaseSimulator.hpp +++ b/opm/simulators/flow/python/PyOnePhaseSimulator.hpp @@ -36,7 +36,7 @@ class PyOnePhaseSimulator : public PyBaseSimulator& args) - : BaseType(deck_filename, args) + : BaseType(deck_filename, args) {} PyOnePhaseSimulator(std::shared_ptr deck, @@ -44,10 +44,10 @@ class PyOnePhaseSimulator : public PyBaseSimulator schedule, std::shared_ptr summary_config, const std::vector& args) - : BaseType(deck, state, schedule, summary_config, args) + : BaseType(deck, state, schedule, summary_config, args) {} - }; } // namespace Opm::Pybind -#endif // OPM_PY_GASWATER_SIMULATOR_HEADER_INCLUDED + +#endif // OPM_PY_ONEPHASE_SIMULATOR_HEADER_INCLUDED From 46559c532ff9c743caa6633a60f4984ca31324d1 Mon Sep 17 00:00:00 2001 From: Svenn Tveit Date: Fri, 19 Sep 2025 11:14:14 +0200 Subject: [PATCH 5/7] Adressed review comments --- opm/simulators/flow/python/PyOnePhaseSimulator.hpp | 2 +- python/simulators/PyOnePhaseSimulator.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/opm/simulators/flow/python/PyOnePhaseSimulator.hpp b/opm/simulators/flow/python/PyOnePhaseSimulator.hpp index 81447d407ab..a1e8304015a 100644 --- a/opm/simulators/flow/python/PyOnePhaseSimulator.hpp +++ b/opm/simulators/flow/python/PyOnePhaseSimulator.hpp @@ -1,5 +1,5 @@ /* - Copyright 2020 Equinor ASA. + Copyright 2025 Equinor ASA. This file is part of the Open Porous Media project (OPM). diff --git a/python/simulators/PyOnePhaseSimulator.cpp b/python/simulators/PyOnePhaseSimulator.cpp index 57b8f48e868..51c09bacb72 100644 --- a/python/simulators/PyOnePhaseSimulator.cpp +++ b/python/simulators/PyOnePhaseSimulator.cpp @@ -1,5 +1,5 @@ /* - Copyright 2020 Equinor ASA. + Copyright 2025 Equinor ASA. This file is part of the Open Porous Media project (OPM). @@ -49,7 +49,7 @@ namespace Opm::Properties { getPropValue(), /*PVOffset=*/0, /*enabledCompIdx=*/FluidSystem::waterCompIdx, - getPropValue()>; + getPropValue()>; }; // struct Indices } // namespace Opm::Properties @@ -132,4 +132,4 @@ PYBIND11_MODULE(OnePhase, m) export_PyOnePhaseSimulator(m); } -} // namespace Opm::Pybind \ No newline at end of file +} // namespace Opm::Pybind From 116e22e58c6c908c6a6e73c33daef1a19cd727c0 Mon Sep 17 00:00:00 2001 From: Svenn Tveit Date: Tue, 23 Sep 2025 13:20:10 +0200 Subject: [PATCH 6/7] Safe creation of OnePhaseSimulator object in tests --- python/test/pytest_common.py | 16 ++++++++++++++++ python/test/test_basic.py | 4 ++-- python/test/test_fluidstate_variables.py | 4 ++-- python/test/test_primary_variables.py | 4 ++-- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/python/test/pytest_common.py b/python/test/pytest_common.py index b190e4f3502..7a8f14be7dd 100644 --- a/python/test/pytest_common.py +++ b/python/test/pytest_common.py @@ -61,3 +61,19 @@ def create_gas_water_simulator(*args, **kwargs): return GasWaterSimulator(*args, **kwargs) +def create_onephase_simulator(*args, **kwargs): + """Create OnePhaseSimulator with test-safe default arguments. + + Automatically disables async ECL output to prevent race conditions + with pushd context manager in tests. + """ + from opm.simulators import OnePhaseSimulator + + flag_to_add = ENABLE_ASYNC_ECL_OUTPUT_FLAG + # Add our flag to args + kwargs['args'] = kwargs.get('args', []) + if flag_to_add not in kwargs['args']: + kwargs['args'].append(flag_to_add) + + return OnePhaseSimulator(*args, **kwargs) + diff --git a/python/test/test_basic.py b/python/test/test_basic.py index 5d439984c99..aa13c098af7 100755 --- a/python/test/test_basic.py +++ b/python/test/test_basic.py @@ -1,7 +1,7 @@ import os import unittest from pathlib import Path -from .pytest_common import pushd, create_black_oil_simulator, create_gas_water_simulator +from .pytest_common import pushd, create_black_oil_simulator, create_gas_water_simulator, create_onephase_simulator class TestBasic(unittest.TestCase): @classmethod @@ -47,7 +47,7 @@ def test_01_blackoil(self): def test_02_onephase(self): with pushd(self.data_dir_op): - sim = OnePhaseSimulator(args=['--linear-solver=ilu0'], filename="SPE1CASE1_WATER.DATA") + sim = create_onephase_simulator(args=['--linear-solver=ilu0'], filename="SPE1CASE1_WATER.DATA") sim.setup_mpi(init=False, finalize=False) sim.step_init() sim.step() diff --git a/python/test/test_fluidstate_variables.py b/python/test/test_fluidstate_variables.py index 8e47b88fbfc..98f28c9375c 100644 --- a/python/test/test_fluidstate_variables.py +++ b/python/test/test_fluidstate_variables.py @@ -1,7 +1,7 @@ import os import unittest from pathlib import Path -from .pytest_common import pushd, create_black_oil_simulator, create_gas_water_simulator +from .pytest_common import pushd, create_black_oil_simulator, create_gas_water_simulator, create_onephase_simulator class TestBasic(unittest.TestCase): @classmethod @@ -52,7 +52,7 @@ def test_01_blackoil(self): def test_02_onephase(self): with pushd(self.data_dir_op): - sim = OnePhaseSimulator("SPE1CASE1_WATER.DATA") + sim = create_onephase_simulator("SPE1CASE1_WATER.DATA") sim.setup_mpi(False, False) sim.step_init() sim.step() diff --git a/python/test/test_primary_variables.py b/python/test/test_primary_variables.py index 955ee797f6b..b8f9b747e19 100644 --- a/python/test/test_primary_variables.py +++ b/python/test/test_primary_variables.py @@ -1,7 +1,7 @@ import os import unittest from pathlib import Path -from .pytest_common import pushd, create_black_oil_simulator, create_gas_water_simulator +from .pytest_common import pushd, create_black_oil_simulator, create_gas_water_simulator, create_onephase_simulator class TestBasic(unittest.TestCase): @classmethod @@ -53,7 +53,7 @@ def test_01_blackoil(self): def test_02_onephase(self): with pushd(self.data_dir_op): - sim = OnePhaseSimulator("SPE1CASE1_WATER.DATA") + sim = create_onephase_simulator("SPE1CASE1_WATER.DATA") sim.setup_mpi(False, False) sim.step_init() sim.step() From 8eaa56885de57c6af8c5309b8fd38de234f30e16 Mon Sep 17 00:00:00 2001 From: Svenn Tveit Date: Tue, 23 Sep 2025 13:20:42 +0200 Subject: [PATCH 7/7] Use docstring template for OnePhaseSimulator documentation --- python/docstrings_op_simulators.json | 83 ---------------------------- python/docstrings_simulators.json | 5 ++ python/simulators/CMakeLists.txt | 5 +- 3 files changed, 7 insertions(+), 86 deletions(-) delete mode 100644 python/docstrings_op_simulators.json diff --git a/python/docstrings_op_simulators.json b/python/docstrings_op_simulators.json deleted file mode 100644 index 47ff41befdb..00000000000 --- a/python/docstrings_op_simulators.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "PyOnePhaseSimulator":{ - "type": "class", - "signature": "opm.simulators.OnePhaseSimulator", - "doc": "The OnePhaseSimulator class to run simulations using a given Deck." - }, - "PyOnePhaseSimulator_filename_constructor": { - "signature": "opm.simulators.OnePhaseSimulator.__init__(deck_filename: str, args: list[str] = []) -> OnePhaseSimulator", - "doc": "Constructor using a deck file name.\n\n:param deck_filename: The file name of the deck to be used for the simulation.\n:type deck_filename: str\n:param args: Simulator options.\n:type args: list[str]\n:return: The OnePhaseSimulator.\n:type return: OnePhaseSimulator" - }, - "PyOnePhaseSimulator_objects_constructor": { - "signature": "opm.simulators.OnePhaseSimulator.__init__(deck: Deck, state: EclipseState, schedule: Schedule, summary_config: SummaryConfig, args: list[str] = []) -> OnePhaseSimulator", - "doc": "Constructor using Deck, EclipseState, Schedule, and SummaryConfig objects.\n\n:param deck: Deck object.\n:type deck: Deck\n:param state: EclipseState object.\n:type state: EclipseState\n:param schedule: Schedule object.\n:type schedule: Schedule\n:param summary_config: SummaryConfig object.\n:type summary_config: SummaryConfig\n:param args: Simulator options.\n:type args: list[str]\n:return: The OnePhaseSimulator.\n:type return: OnePhaseSimulator" - }, - "advance": { - "signature": "opm.simulators.OnePhaseSimulator.advance(report_step: int) -> None", - "doc": "Advances the simulation to a specific report step.\n\n:param report_step: Target report step to advance to.\n:type report_step: int" - }, - "checkSimulationFinished": { - "signature": "opm.simulators.OnePhaseSimulator.check_simulation_finished() -> bool", - "doc": "Checks if the simulation has finished.\n\n:return: True if the simulation is finished, False otherwise.\n:type return: bool" - }, - "currentStep": { - "signature": "opm.simulators.OnePhaseSimulator.current_step() -> int", - "doc": "Gets the current simulation step.\n\n:return: The current step number." - }, - "getCellVolumes": { - "signature": "opm.simulators.OnePhaseSimulator.get_cell_volumes() -> NDArray[float]", - "doc": "Retrieves the cell volumes of the simulation grid.\n\n:return: An array of cell volumes.\n:type return: NDArray[float]" - }, - "getDT": { - "signature": "opm.simulators.OnePhaseSimulator.get_dt() -> float", - "doc": "Gets the timestep size of the last completed step.\n\n:return: Timestep size in days.\n:type return: float" - }, - "getFluidStateVariable": { - "signature": "opm.simulators.OnePhaseSimulator.get_fluid_state_variable(name: str) -> NDArray[float]", - "doc": "Retrieves a fluid state variable for the simulation grid.\n\n:param name: The name of the variable. Valid names are 'pw' (pressure water), 'pg' (pressure gas), 'po' (pressure oil), 'rho_w' (density water), 'rho_g' (density gas), 'rho_o' (density oil)'Rs' (soultion gas-oil ratio), 'Rv' (volatile gas-oil ratio), 'Sw' (water saturation), 'Sg' (gas saturation), 'So' (oil saturation), and 'T' (temperature).\n:type name: str\n\n:return: An array of fluid state variables.\n:type return: NDArray[float]" - }, - "getPorosity": { - "signature": "opm.simulators.OnePhaseSimulator.get_porosity() -> NDArray[float]", - "doc": "Retrieves the porosity values of the simulation grid.\n\n:return: An array of porosity values.\n:type return: numpy.ndarray" - }, - "getPrimaryVarMeaning": { - "signature": "opm.simulators.OnePhaseSimulator.get_primary_var_meaning(variable: str) -> NDArray[int]", - "doc": "Retrieves the primary variable meaning of the simulation grid.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n\n:return: An array of primary variable meanings. See ``get_primary_variable_meaning_map()`` for more information.\n:type return: NDArray[int]" - }, - "getPrimaryVarMeaningMap": { - "signature": "opm.simulators.OnePhaseSimulator.get_primary_var_meaning_map(variable: str) -> dict[str, int]", - "doc": "Retrieves the primary variable meaning map for each primary variable.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n\n:return: A dictionary of primary variable meanings. The keys are the primary variable meanings and the values are the corresponding integer codes. The integer codes are used to represent the primary variable meanings in the simulation grid. For variable name 'pressure', the valid keys are: 'Po', 'Pg', and 'Pw', for variable name 'water', the valid keys are: 'Sw', 'Rvw', 'Rsw', and 'Disabled', for variable name 'gas', the valid keys are: 'Sg', 'Rs', 'Rv', and 'Disabled', for variable name 'brine', the valid keys are: 'Cs', 'Sp', and 'Disabled'.\n:type return: dict[str, int]" - }, - "getPrimaryVariable": { - "signature": "opm.simulators.OnePhaseSimulator.get_primary_variable(variable: str) -> NDArray[float]", - "doc": "Retrieves the primary variable's values for the simulation grid.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n\n:return: An array of primary variable values. See ``get_primary_variable_meaning()`` for more information.\n:type return: NDArray[float]" - }, - "run": { - "signature": "opm.simulators.OnePhaseSimulator.run() -> int", - "doc": "Runs the simulation to completion with the provided deck file or previously set deck.\n\n:return: EXIT_SUCCESS if the simulation completes successfully." - }, - "setPorosity": { - "signature": "opm.simulators.OnePhaseSimulator.set_porosity(array: NDArray[float]) -> None", - "doc": "Sets the porosity values for the simulation grid.\n\n:param array: An array of porosity values to be set.\n:type array: NDArray[float]" - }, - "setPrimaryVariable": { - "signature": "opm.simulators.OnePhaseSimulator.set_primary_variable(variable: str, value: NDArray[float]) -> None", - "doc": "Sets the primary variable's values for the simulation grid.\n\n:param variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n:param value: An array of primary variable values to be set. See ``get_primary_variable()`` for more information.\n:type value: NDArray[float]" - }, - "setupMpi": { - "signature": "opm.simulators.OnePhaseSimulator.mpi_init(init: bool, finalize: bool) -> None", - "doc": "Sets MPI up for parallel simulation. This method should be called before any other method.\n\n:param init: Whether to call ``MPI_Init()`` or not.\n:param finalize: Whether to call ``MPI_Finalize()```when the simulator object goes out of scope.\n\n:return: None" - }, - "step": { - "signature": "opm.simulators.OnePhaseSimulator.step() -> int", - "doc": "Executes the next simulation report step.\n\n:return: Result of the simulation step." - }, - "stepCleanup": { - "signature": "opm.simulators.OnePhaseSimulator.step_cleanup() -> int", - "doc": "Performs cleanup after the last simulation step.\n\n:return: EXIT_SUCCESS if cleanup is successful." - }, - "stepInit": { - "signature": "opm.simulators.OnePhaseSimulator.step_init() -> int", - "doc": "Initializes the simulation before taking the first report step. This method should be called before the first call to ``step()``\n\n:return: EXIT_SUCCESS if the initialization is successful." - } -} diff --git a/python/docstrings_simulators.json b/python/docstrings_simulators.json index c5c7207172f..152cc611feb 100644 --- a/python/docstrings_simulators.json +++ b/python/docstrings_simulators.json @@ -10,6 +10,11 @@ "class": "PyGasWaterSimulator", "name": "GasWaterSimulator", "doc": "The GasWaterSimulator class to run simulations using a given Deck." + }, + "OnePhase": { + "class": "PyOnePhaseSimulator", + "name": "OnePhaseSimulator", + "doc": "The OnePhaseSimulator class to run simulations using a given Deck." } }, "constructors": { diff --git a/python/simulators/CMakeLists.txt b/python/simulators/CMakeLists.txt index 54a34c4dabf..937d6dcda5a 100644 --- a/python/simulators/CMakeLists.txt +++ b/python/simulators/CMakeLists.txt @@ -4,7 +4,6 @@ set(PYTHON_OPM_SIMULATORS_PACKAGE_PATH ${PROJECT_BINARY_DIR}/python/opm/simulato set(PYTHON_DOCSTRINGS_FILE "${PROJECT_SOURCE_DIR}/python/docstrings_simulators.json") set(PYTHON_DOCSTRINGS_GENERATED_HPP "${PROJECT_BINARY_DIR}/python/PyBlackOilSimulatorDoc.hpp") set(PYTHON_GW_DOCSTRINGS_GENERATED_HPP "${PROJECT_BINARY_DIR}/python/PyGasWaterSimulatorDoc.hpp") -set(PYTHON_OP_DOCSTRINGS_FILE "${PROJECT_SOURCE_DIR}/python/docstrings_op_simulators.json") set(PYTHON_OP_DOCSTRINGS_GENERATED_HPP "${PROJECT_BINARY_DIR}/python/PyOnePhaseSimulatorDoc.hpp") # Note: If the new find_package(Python3) is used in the top level CMakeLists.txt, the variable # ${PYTHON_EXECUTABLE} is set there to ${Python3_EXECUTABLE} @@ -35,8 +34,8 @@ add_custom_command( OUTPUT ${PYTHON_OP_DOCSTRINGS_GENERATED_HPP} COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${CMAKE_SOURCE_DIR} ${PYTHON_EXECUTABLE} ${PYTHON_GENERATE_DOCSTRINGS_PY} - ${PYTHON_OP_DOCSTRINGS_FILE} ${PYTHON_OP_DOCSTRINGS_GENERATED_HPP} PYONEPHASESIMULATORDOC_HPP "Opm::Pybind::DocStrings" - DEPENDS ${PYTHON_OP_DOCSTRINGS_FILE} + ${PYTHON_DOCSTRINGS_FILE} ${PYTHON_OP_DOCSTRINGS_GENERATED_HPP} PYONEPHASESIMULATORDOC_HPP "Opm::Pybind::DocStrings" "OnePhase" + DEPENDS ${PYTHON_DOCSTRINGS_FILE} COMMENT "Generating PyOnePhaseSimulatorDoc.hpp from JSON file" ) # NOTE: The variable ${PYBIND11_SYSTEM} is set in python/CMakeLists.txt