Use pybind11 for smspec_node - #1258
Conversation
746afed to
943e29b
Compare
There was a problem hiding this comment.
Pull request overview
This PR migrates smspec_node to a pybind11-based Python binding, fixes a null-pointer handling bug in smspec_node::valid_type, and updates both C++ and Python call sites/tests to use the modernized API and Python comparison semantics.
Changes:
- Introduces a new pybind11 module for
ResdataSMSPECNodeand removes the legacy Python cwrap wrapper. - Fixes
smspec_node::valid_typeto ensurenullptr/dummy-well checks are performed safely and consistently. - Updates C++ call sites away from the removed “old API” free functions and adds targeted unit/property tests in both C++ and Python.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/rd_tests/test_rd_sum.py | Adds Hypothesis + unit tests for ResdataSMSPECNode hashing/comparison semantics and Summary.writer().add_variable() behavior. |
| python/resdata/summary/rd_sum.py | Switches add_variable()/smspec_node() to return the pybind11 ResdataSMSPECNode directly (no createCReference). |
| python/resdata/summary/rd_smspec_node.py | Removes the legacy cwrap-based ResdataSMSPECNode implementation. |
| lib/tests/test_rd_sum.cpp | Updates tests to use rd::smspec_node member accessors instead of removed free functions. |
| lib/resdata/tests/test_smspec_node.cpp | Adds C++ tests for smspec_node ordering, totals/rates identification, and default NUMS behavior. |
| lib/resdata/smspec_node.cpp | Fixes valid_type() ordering for safe dummy-well and nullptr handling; removes legacy free-function wrappers. |
| lib/resdata/smspec_node_pybind.cpp | Adds the new pybind11 module exporting ResdataSMSPECNode into Python. |
| lib/resdata/rd_sum.cpp | Updates internal callers to use rd::smspec_node methods (unit/key/params_index). |
| lib/resdata/rd_sum_vector.cpp | Updates vector building logic to use rd::smspec_node methods. |
| lib/resdata/rd_sum_tstep.cpp | Updates timestep node indexing to use rd::smspec_node::get_params_index(). |
| lib/resdata/rd_sum_pybind.cpp | Changes _get_var_node / _add_variable / _add_local_variable to return rd::smspec_node* directly with keep_alive. |
| lib/resdata/rd_sum_data.cpp | Updates interpolation/indexing logic to use rd::smspec_node methods (is_rate, get_params_index). |
| lib/resdata/rd_smspec.cpp | Updates SMSPEC IO/metadata code to use rd::smspec_node accessors. |
| lib/include/resdata/smspec_node.hpp | Removes the legacy free-function API declarations (partially) and adds C++ comparison operators. |
| lib/CMakeLists.txt | Builds the new rd_smspec_node pybind module and renames/adds the C++ smspec node test executable. |
| applications/resdata/sum_write.cpp | Updates documentation comments to reference rd::smspec_node methods instead of removed free functions. |
Comments suppressed due to low confidence (1)
lib/resdata/smspec_node.cpp:1353
smspec_node_cmp()is still declared in the public header (lib/include/resdata/smspec_node.hpp), but its implementation was removed from this translation unit. That will cause unresolved-symbol link failures for any downstream code still using this API. Either reintroduce the wrapper definition (preferred for compatibility) or remove the declaration from the header if the C-style API is being retired.
} // end namespace rd
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "\n" | ||
| " sum.smspec_node(\"FOPT\").num => None\n" | ||
| " sum.smspec_node(\"BPR:1000\").num => 1000\n" |
There was a problem hiding this comment.
This is not the case, but there is this weird SMSPECS_NUMS_INVALID check. We should not change this behavior, but it could return e.g. 0 if the internal field is not SMSPECS_NUMS_INVALID which the user could create through add_variable
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
lib/resdata/smspec_node_pybind.cpp:111
- The docstring examples for
numclaimsum.smspec_node("FOPT").num => None, but the current binding returns an integer wheneverneed_nums()is true (and the new tests expect0for field variables). Please update the example to match the actual behavior to avoid confusing users.
"Many of the summary keywords have an integer stored in the\n"
"vector NUMS as an attribute, i.e. the block properties have\n"
"the global index of the cell in the nums vector. If the\n"
"variable in question makes use of the NUMS value this "
"property\n"
"will return the value, otherwise it will return None:\n"
"\n"
" sum.smspec_node(\"FOPT\").num => None\n"
" sum.smspec_node(\"BPR:1000\").num => 1000\n"
"\n")
lib/resdata/smspec_node_pybind.cpp:116
- Typos in the
is_ratedocstring: "conecpt" → "concept" and "variabel" → "variable".
.def("is_rate", &rd::smspec_node::is_rate,
"Will check if the variable in question is a rate variable.\n"
"\n"
"The conecpt of rate variabel is important (internally) when\n"
"interpolation values to arbitrary times.\n")
943e29b to
345e19a
Compare
345e19a to
e998840
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 17 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
lib/resdata/smspec_node_pybind.cpp:104
- The
get_numdocstring examples implyFOPT.numis alwaysNone, but nodes created viaSummary.writer().add_variable()can exposenum == 0(andneed_nums()becomes true whennum != SMSPEC_NUMS_INVALID). This makes the example misleading and also leaves a couple of typos in theis_ratedocstring.
"Returns the NUMS value for this keyword; or None.\n"
"\n"
"Many of the summary keywords have an integer stored in the\n"
"vector NUMS as an attribute, i.e. the block properties have\n"
"the global index of the cell in the nums vector. If the\n"
c360269 to
5bbc240
Compare
0c87b6e to
fee2a36
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 17 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
lib/resdata/smspec_node_pybind.cpp:110
- The
get_num()docstring claimsFOPTreturnsNone, but nodes created programmatically (e.g. viaSummary.writer().add_variable("FOPT", ...)) can haveneed_nums()==trueand return0(see new tests assertingnode.num == 0). Please clarify the docstring to avoid giving users a false invariant.
"Returns the NUMS value for this keyword; or None.\n"
"\n"
"Many of the summary keywords have an integer stored in the\n"
"vector NUMS as an attribute, i.e. the block properties have\n"
"the global index of the cell in the nums vector. If the\n"
"variable in question makes use of the NUMS value this "
"property\n"
"will return the value, otherwise it will return None:\n"
"\n"
" sum.smspec_node(\"FOPT\").num => None\n"
" sum.smspec_node(\"BPR:1000\").num => 1000\n"
bb44701 to
c0828ce
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 17 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
lib/resdata/smspec_node_pybind.cpp:107
- The get_num()/num docstring currently implies the "FOPT" example always returns None, but nodes created via Summary.writer().add_variable("FOPT", ...) can have NUMS explicitly set (tests in this PR assert node.num == 0). Please clarify the sentence so it doesn’t overstate the guarantee.
"will return the value, otherwise it will return None:\n"
lib/resdata/smspec_node_pybind.cpp:116
- Docstring has spelling/grammar issues ("conecpt", "variabels", and the sentence fragment on the next line). This is user-facing help text, so it should be corrected.
"The conecpt of rate variabels is important (internally) when\n"
"interpolation values to arbitrary times.\n")
c0828ce to
3af14d7
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 17 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
lib/resdata/smspec_node_pybind.cpp:116
- Docstring has spelling/grammar issues: "conecpt" and "variabels" should be "concept" and "variables", and the sentence should read naturally (e.g. "interpolating values").
"The conecpt of rate variabels is important (internally) when\n"
"interpolation values to arbitrary times.\n")
3af14d7 to
02f1973
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 19 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
lib/resdata/smspec_node_pybind.cpp:98
- The
get_num()docstring example sayssum.smspec_node("FOPT").num => None, but this PR’s tests demonstrate valid nodes whereFOPThas NUMS (e.g. writer-created variables) and.numreturns0. Update the wording/example to reflect that the property can return an integer (including 0) whenneed_nums()is true.
"will return the value, otherwise it will return None:\n"
"\n"
" sum.smspec_node(\"FOPT\").num => None\n"
" sum.smspec_node(\"BPR:1000\").num => 1000\n"
MagnusSletten
left a comment
There was a problem hiding this comment.
Nice work! A couple of mostly minor comments. The hashing functionality is the most important to double check.
The operators would throw a TypeError before this fix, but now they follow the usual conventions of returning NotImplemented.
Also removes the ones that were unused and moves the ones only used in smspec_node.cpp there.
1420dbd to
9ab3684
Compare
Several paths in smspec_noe.cmp would assume that values were not nullptr. This fixes this issue by instead comparing the private std::strings directly.
9ab3684 to
88f7f4c
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 19 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
lib/resdata/smspec_node_pybind.cpp:111
- Spelling/grammar in the
is_ratedocstring: "conecpt" / "variabels" / "interpolation values".
"The conecpt of rate variabels is important (internally) when\n"
"interpolation values to arbitrary times.\n")
This fixes a bug with
smspec_node::valid_typewhere anullptrcheck was done too late. It also makes the operators ofResdataSMSPECNodefollow normal conventions for unimplemented types.