Add docstrings for Python bindings

This commit is contained in:
Håkon Hægland 2024-03-04 23:37:12 +01:00
parent 67bcc491ff
commit e20faa255c
4 changed files with 169 additions and 21 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

@ -18,6 +18,33 @@ set(PYTHON_OPM_SIMULATORS_PACKAGE_PATH ${PROJECT_BINARY_DIR}/python/opm/simulato
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
# 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")
# 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"
)
# Create a custom target that depends on the generated .hpp file
add_custom_target(
GenerateDocHPP
DEPENDS ${PYTHON_DOCSTRINGS_GENERATED_HPP}
)
# Ensure that the simulator target depends on the custom target
add_dependencies(simulators GenerateDocHPP)
# Add the build directory where the generated hpp file will be
# to the include directories for the target
message(STATUS "Include directory: ${PROJECT_BINARY_DIR}/python")
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