Merge pull request #5242 from hakonhagland/python_doc

Add docstrings for Python bindings
This commit is contained in:
Arne Morten Kvarving 2024-03-05 11:33:46 +01:00 committed by GitHub
commit c94da66810
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 162 additions and 22 deletions

74
python/docstrings.json Normal file
View File

@ -0,0 +1,74 @@
{
"PyBlackOilSimulator_filename_constructor": {
"signature": "__init__(deck_filename: str) -> None",
"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"
},
"PyBlackOilSimulator_objects_constructor": {
"signature": "__init__(deck: Deck, state: EclipseState, schedule: Schedule, summary_config: SummaryConfig) -> None",
"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"
},
"advance": {
"signature": "advance(report_step: int) -> None",
"doc": "Advance 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": "check_simulation_finished() -> bool",
"doc": "Check if the simulation has finished.\n\n:return: True if the simulation is finished, False otherwise."
},
"currentStep": {
"signature": "current_step() -> int",
"doc": "Get the current simulation step.\n\n:return: The current step number."
},
"getCellVolumes": {
"signature": "get_cell_volumes() -> NDArray[float]",
"doc": "Retrieve the cell volumes of the simulation grid.\n\n:return: An array of cell volumes.\n:type return: NDArray[float]"
},
"getDT": {
"signature": "get_dt() -> float",
"doc": "Get the timestep size of the last completed step.\n\n:return: Timestep size in days.\n:type return: float"
},
"getFluidStateVariables": {
"signature": "get_fluid_state_variables(name: str) -> NDArray[float]",
"doc": "Retrieve a fluid state variable for the simulation grid.\n\n:para 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": "get_porosity() -> numpy.ndarray",
"doc": "Retrieve the porosity values of the simulation grid.\n\n:return: An array of porosity values.\n:type return: numpy.ndarray"
},
"getPrimaryVarMeaning": {
"signature": "get_primary_var_meaning(variable: str) -> NDArray[int]",
"doc": "Retrieve the primary variable meaning of the simulation grid.\n\n:para 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": "get_primary_var_meaning_map(variable: str) -> dict[str, int]",
"doc": "Retrieve the primary variable meaning map for each primary variable.\n\n:para 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": "get_primary_variable(variable: str) -> NDArray[float]",
"doc": "Retrieve the primary variable's values for the simulation grid.\n\n:para 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": "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": "set_porosity(array: NDArray[float]) -> None",
"doc": "Set 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": "set_primary_variable(variable: str, value: NDArray[float]) -> None",
"doc": "Set the primary variable's values for the simulation grid.\n\n:para variable: The name of the variable. Valid names are 'pressure', 'water', 'gas', and 'brine'.\n:type variable: str\n:para value: An array of primary variable values to be set. See ``get_primary_variable()`` for more information.\n:type value: NDArray[float]"
},
"step": {
"signature": "step() -> int",
"doc": "Execute the next simulation report step.\n\n:return: Result of the simulation step."
},
"stepCleanup": {
"signature": "step_cleanup() -> int",
"doc": "Perform cleanup after the last simulation step.\n\n:return: EXIT_SUCCESS if cleanup is successful."
},
"stepInit": {
"signature": "step_init() -> int",
"doc": "Initialize 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."
}
}

View File

@ -0,0 +1,41 @@
import json
import sys
def generate_hpp_from_json(json_path: str, output_hpp_path: str):
with open(json_path, 'r', encoding='utf-8') as file:
docstrings = json.load(file)
hpp_content = """\
#ifndef PYBLACKOILSIMULATORDOC_HPP
#define PYBLACKOILSIMULATORDOC_HPP
// Generated docstrings for PyBlackOilSimulator
namespace Opm::Pybind::DocStrings {
"""
for func_name, info in docstrings.items():
signature = info['signature']
doc = info['doc'].replace('\n', '\n ')
hpp_content += f"""
static constexpr char {func_name}_docstring[] = R\"doc(
{doc}
)doc\";\n"""
hpp_content += """\
} // namespace Opm::Pybind::DocStrings
#endif // PYBLACKOILSIMULATORDOC_HPP
"""
with open(output_hpp_path, 'w', encoding='utf-8') as file:
file.write(hpp_content)
if __name__ == "__main__":
# Check that exactly two command line arguments are provided
if len(sys.argv) != 3:
print("Usage: python generate_docstring_hpp.py <json_path> <output_hpp_path>")
sys.exit(1)
# Extract json_path and output_hpp_path from command line arguments
json_path = sys.argv[1]
output_hpp_path = sys.argv[2]
generate_hpp_from_json(json_path, output_hpp_path)

View File

@ -1,6 +1,20 @@
set(PYTHON_OPM_SIMULATORS_PACKAGE_PATH ${PROJECT_BINARY_DIR}/python/opm/simulators)
# Set the path to the input docstrings.json file and the output .hpp file
set(PYTHON_DOCSTRINGS_FILE "${PROJECT_SOURCE_DIR}/python/docstrings.json")
set(PYTHON_DOCSTRINGS_GENERATED_HPP "${PROJECT_BINARY_DIR}/python/PyBlackOilSimulatorDoc.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}
#
# Command to run the Python script
add_custom_command(
OUTPUT ${PYTHON_DOCSTRINGS_GENERATED_HPP}
COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${CMAKE_SOURCE_DIR}
${PYTHON_EXECUTABLE} ${PROJECT_SOURCE_DIR}/python/generate_docstring_hpp.py
${PYTHON_DOCSTRINGS_FILE} ${PYTHON_DOCSTRINGS_GENERATED_HPP}
DEPENDS ${PYTHON_DOCSTRINGS_FILE}
COMMENT "Generating PyBlackOilSimulatorDoc.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
@ -12,12 +26,17 @@ pybind11_add_module(simulators ${PYBIND11_SYSTEM}
$<TARGET_OBJECTS:moduleVersion>
Pybind11Exporter.cpp
PyBlackOilSimulator.cpp
${PYTHON_DOCSTRINGS_GENERATED_HPP} # Include the generated .hpp as a source file
)
set(PYTHON_OPM_SIMULATORS_PACKAGE_PATH ${PROJECT_BINARY_DIR}/python/opm/simulators)
set_target_properties( simulators PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PYTHON_OPM_SIMULATORS_PACKAGE_PATH} )
target_link_libraries( simulators PRIVATE opmsimulators )
# Add the binary (build) directory to the include directories for the target
# Add the build directory where the generated hpp file will be
# to the include directories for the target
target_include_directories(simulators PRIVATE ${PROJECT_BINARY_DIR}/python)
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "
import site, sys

View File

@ -27,6 +27,9 @@
//#include <opm/simulators/flow/python/PyFluidState.hpp>
#include <opm/simulators/flow/python/PyMaterialState.hpp>
#include <opm/simulators/flow/python/PyBlackOilSimulator.hpp>
// 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 <PyBlackOilSimulatorDoc.hpp>
// NOTE: EXIT_SUCCESS, EXIT_FAILURE is defined in cstdlib
#include <cstdlib>
#include <stdexcept>
@ -158,14 +161,14 @@ void PyBlackOilSimulator::setPorosity( py::array_t<double,
void
PyBlackOilSimulator::
setPrimaryVariable(
const std::string &idx_name,
const std::string &variable,
py::array_t<double,
py::array::c_style | py::array::forcecast> array
)
{
std::size_t size_ = array.size();
const double *data = array.data();
getFluidState().setPrimaryVariable(idx_name, data, size_);
getFluidState().setPrimaryVariable(variable, data, size_);
}
int PyBlackOilSimulator::step()
@ -272,36 +275,39 @@ PyBlackOilSimulator::getMaterialState() const
// Exported functions
void export_PyBlackOilSimulator(py::module& m)
{
using namespace Opm::Pybind::DocStrings;
py::class_<PyBlackOilSimulator>(m, "BlackOilSimulator")
.def(py::init< const std::string& >())
.def(py::init<const std::string&>(),
PyBlackOilSimulator_filename_constructor_docstring)
.def(py::init<
std::shared_ptr<Opm::Deck>,
std::shared_ptr<Opm::EclipseState>,
std::shared_ptr<Opm::Schedule>,
std::shared_ptr<Opm::SummaryConfig> >())
.def("advance", &PyBlackOilSimulator::advance, py::arg("report_step"))
.def("current_step", &PyBlackOilSimulator::currentStep)
.def("get_cell_volumes", &PyBlackOilSimulator::getCellVolumes,
py::return_value_policy::copy)
.def("get_dt", &PyBlackOilSimulator::getDT)
std::shared_ptr<Opm::Deck>,
std::shared_ptr<Opm::EclipseState>,
std::shared_ptr<Opm::Schedule>,
std::shared_ptr<Opm::SummaryConfig>>(),
PyBlackOilSimulator_objects_constructor_docstring)
.def("advance", &PyBlackOilSimulator::advance, advance_docstring, py::arg("report_step"))
.def("check_simulation_finished", &PyBlackOilSimulator::checkSimulationFinished,
checkSimulationFinished_docstring)
.def("current_step", &PyBlackOilSimulator::currentStep, currentStep_docstring)
.def("get_cell_volumes", &PyBlackOilSimulator::getCellVolumes, getCellVolumes_docstring)
.def("get_dt", &PyBlackOilSimulator::getDT, getDT_docstring)
.def("get_fluidstate_variable", &PyBlackOilSimulator::getFluidStateVariable,
py::return_value_policy::copy, py::arg("name"))
.def("get_porosity", &PyBlackOilSimulator::getPorosity,
py::return_value_policy::copy)
.def("get_porosity", &PyBlackOilSimulator::getPorosity, getPorosity_docstring)
.def("get_primary_variable_meaning", &PyBlackOilSimulator::getPrimaryVarMeaning,
py::return_value_policy::copy, py::arg("variable"))
.def("get_primary_variable_meaning_map", &PyBlackOilSimulator::getPrimaryVarMeaningMap,
py::return_value_policy::copy, py::arg("variable"))
.def("get_primary_variable", &PyBlackOilSimulator::getPrimaryVariable,
py::return_value_policy::copy, py::arg("variable"))
.def("run", &PyBlackOilSimulator::run)
.def("set_porosity", &PyBlackOilSimulator::setPorosity)
.def("run", &PyBlackOilSimulator::run, run_docstring)
.def("set_porosity", &PyBlackOilSimulator::setPorosity, setPorosity_docstring, py::arg("array"))
.def("set_primary_variable", &PyBlackOilSimulator::setPrimaryVariable,
py::arg("idx_name"), py::arg("value"))
.def("current_step", &PyBlackOilSimulator::currentStep)
.def("step", &PyBlackOilSimulator::step)
.def("step_cleanup", &PyBlackOilSimulator::stepCleanup)
.def("step_init", &PyBlackOilSimulator::stepInit);
py::arg("variable"), py::arg("value"))
.def("step", &PyBlackOilSimulator::step, step_docstring)
.def("step_cleanup", &PyBlackOilSimulator::stepCleanup, stepCleanup_docstring)
.def("step_init", &PyBlackOilSimulator::stepInit, stepInit_docstring);
}
} // namespace Opm::Pybind