Enhancement of Pybind11 interface: Trampolines, more default arguments, and more#880
Open
hverhelst wants to merge 3 commits into
Open
Enhancement of Pybind11 interface: Trampolines, more default arguments, and more#880hverhelst wants to merge 3 commits into
hverhelst wants to merge 3 commits into
Conversation
- gsBasis::uniformRefine/Coarsen_withTransfer - gsConstantFunction - gsField - gsFunctionExpr::set_u - trampoline for gsFunctionSet and gsFunction - Extra functions (refinement, degree elevation etc) for gsMultiBasis - Improvements of templated basis bindings (gsHTensorBasis, gsTHBSpline) - gsOptionList: add function that writes to python dict - Improve argument names and default args of gsWriteParaview bindings - SparseMatrix Major template exposure to Pybind (for transfer matrix) - SparseMatrix cast to CSC Python structure - System, matrix and rhs independent assembly code for gsL2Projection - Exposure of quasi interpolation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR significantly expands the G+Smo Python (pybind11) surface area, primarily by adding trampoline support for overriding core function interfaces in Python, exposing additional core/util classes (e.g., gsField, gsConstantFunction, gsL2Projection, gsQuasiInterpolate), and improving/templating several dimension-dependent bindings.
Changes:
- Add pybind11 trampolines for
gsFunction/gsFunctionSetto enable Python-side subclassing and overrides. - Add new Python bindings for utilities and core objects (e.g.,
gsL2Projectionsystem/matrix/rhs assembly,gsQuasiInterpolate,gsField,gsConstantFunction) and improve argument defaults/names across multiple bindings. - Extend sparse matrix + IO interoperability (SciPy sparse integration helpers, XML template updates, labeled
gsFileDataaccess).
Reviewed changes
Copilot reviewed 42 out of 42 changed files in this pull request and generated 15 comments.
Show a summary per file
| File | Description |
|---|---|
| src/misc/gsPyBind11.cpp | Registers new submodules/bindings; templates dimension bindings |
| src/gsUtils/gsQuasiInterpolate.h | Declares pybind init hook |
| src/gsUtils/gsQuasiInterpolate_.cpp | Implements gsQuasiInterpolate Python bindings |
| src/gsUtils/gsL2Projection.hpp | Adds _system/_matrix/_rhs assembly helpers |
| src/gsUtils/gsL2Projection.h | Adds public system/matrix/rhs overload set + pybind hook |
| src/gsUtils/gsL2Projection_.cpp | Exposes gsL2Projection API to Python (project/system/matrix/rhs) |
| src/gsPde/gsBoundaryConditions_.cpp | Adds __str__ binding |
| src/gsNurbs/gsNurbsCreator_.cpp | Fixes docstring + adds default args |
| src/gsNurbs/gsKnotVector_.cpp | Adds default arg + set_degree binding |
| src/gsMSplines/gsMappedSingleBasis.h | Switches to templated pybind init decl |
| src/gsMSplines/gsMappedBasis.h | Switches to templated pybind init decl |
| src/gsMSplines/gsMappedBasis_.cpp | Refactors bindings into templates |
| src/gsModeling/gsBarrierPatch.h | Switches to templated pybind init decl |
| src/gsModeling/gsBarrierPatch_.cpp | Refactors bindings into templates |
| src/gsMatrix/gsSparseMatrix.h | Adds SciPy accessors + pybind type_caster override |
| src/gsMatrix/gsMatrix.h | Minor binding cleanup (comment removal) |
| src/gsIO/gsXmlUtils.hpp | Generalizes XML support for sparse matrix template params |
| src/gsIO/gsXmlInstance_.cpp | Instantiates XML for Row/Col major sparse matrices |
| src/gsIO/gsXml.hpp | Generalizes sparse XML helpers for template params |
| src/gsIO/gsXml.h | Generalizes sparse XML helper declaration |
| src/gsIO/gsXml_.cpp | Instantiates sparse XML helper for Row/Col major |
| src/gsIO/gsWriteParaview_.cpp | Improves arg names/defaults + adds multipatch/field bindings |
| src/gsIO/gsOptionList.cpp | Adds Python-dict constructor |
| src/gsIO/gsFileData.h | Adds getLabelTag helper |
| src/gsIO/gsFileData_.cpp | Adds label-based read/write helpers in Python binding |
| src/gsHSplines/gsTHBSplineBasis.h | Switches to templated pybind init decl |
| src/gsHSplines/gsTHBSpline.h | Switches to templated pybind init decl |
| src/gsHSplines/gsTHBSpline_.cpp | Refactors hspline bindings into templates |
| src/gsHSplines/gsHTensorBasis.h | Switches to templated pybind init decl |
| src/gsCore/gsMultiBasis_.cpp | Adds more mutators + reference return policies |
| src/gsCore/gsFunctionSet_.cpp | Adds gsFunctionSet trampoline + updates bindings |
| src/gsCore/gsFunctionExpr_.cpp | Adds set_u binding |
| src/gsCore/gsFunction_.cpp | Adds gsFunction trampoline + updates bindings |
| src/gsCore/gsField.hpp | Removes unused numEvals params in distance methods |
| src/gsCore/gsField.h | Updates distance method signatures + adds pybind init hook |
| src/gsCore/gsField_.cpp | Adds gsField Python bindings |
| src/gsCore/gsConstantFunction.h | Adds pybind init hook |
| src/gsCore/gsConstantFunction_.cpp | Adds gsConstantFunction Python bindings |
| src/gsCore/gsBasis_.cpp | Adds refine/coarsen transfer-matrix bindings + makeGeometry |
| setup.py | Enables OpenMP; modifies install requirements (needs correction) |
| python_examples/function_trampoline.py | Adds example for Python-side function override |
| pyproject.toml | Pins pybind11 build requirement (>= 2.12) |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
240
to
242
| install_requires=[ | ||
| "numpy<2", | ||
| "", | ||
| ], |
| py::gil_scoped_acquire acquire; | ||
| py::function overload = py::get_override(static_cast<const Base*>(this), "deriv2_into"); | ||
| if (overload) { | ||
| result.resize(this->targetDim() * this->domainDim() * 2, u.cols()); |
| } | ||
|
|
||
| // Fallback: If no Python clone exists, this is an error for a trampoline | ||
| GISMO_ERROR("A Python-derived gsBasis must implement a clone() method " |
| } | ||
|
|
||
| // Fallback: If no Python clone exists, this is an error for a trampoline | ||
| GISMO_ERROR("A Python-derived gsBasis must implement a clone() method " |
Comment on lines
+35
to
+38
| .def("distanceH2", &Class::distanceH2, "Computes the H2-seminorm of the difference between a field and a function", py::arg("func"), py::arg("isFunc_param")=false) | ||
| .def("distanceDG", &Class::distanceDG, "Computes the DG-distance between a field and a function", py::arg("func"), py::arg("isFunc_param")=false) | ||
| .def("__str__", &Class::print, "Returns the string representation of the field") | ||
| .def("parDim", &Class::parDim, "Returns the parametric dimension of the field") |
Comment on lines
+258
to
+261
| * @param options The options that control the projection process | ||
| * | ||
| * @return The L2 error of the projection | ||
| */ |
Comment on lines
+571
to
+591
| // Iterate over dict items and try to set them as int, real, or switch | ||
| for (auto& item : dict_opts) | ||
| { | ||
| std::string key = pybind11::cast<std::string>(item.first); | ||
| py::handle val_handle = item.second; | ||
|
|
||
| // Try to interpret value as int, real, or bool, in that order | ||
| try { | ||
| opt->addInt(key, "", pybind11::cast<int>(val_handle)); | ||
| } | ||
| catch (...) { | ||
| try { | ||
| opt->addReal(key, "", pybind11::cast<real_t>(val_handle)); | ||
| } | ||
| catch (...) { | ||
| try { | ||
| opt->addSwitch(key, "", pybind11::cast<bool>(val_handle)); | ||
| } | ||
| catch (...) { | ||
| // Skip entries that can't be converted | ||
| } |
Comment on lines
+675
to
+679
| return pybind11::array_t<Index>( | ||
| {static_cast<pybind11::ssize_t>(s.nonZeros())}, | ||
| {sizeof(Index)}, | ||
| const_cast<Index*>(s.innerIndexPtr()), | ||
| pybind11::cast(s)); |
Comment on lines
+54
to
+58
| .def("uniformRefine_withTransfer", | ||
| [](Class& self, int numKnots, int mul) { | ||
| gsSparseMatrix<real_t, RowMajor> transfer; | ||
| self.uniformRefine_withTransfer(transfer, numKnots, mul); | ||
| return transfer; |
Comment on lines
+262
to
+266
| static void system( const gsMultiBasis<T> & projectionBasis, | ||
| const gsMultiPatch<T> & geometryMap, | ||
| gsSparseMatrix<T> & systemMatrix, | ||
| gsMatrix<T> & rhs, | ||
| const gsOptionList & options = gsOptionList()) |
* add factories like `gsTensorBSplineBasis` which do not need a number for dim * add vararg constructors for `gsTensorBSplineBasis`instead of hardcoded constructors
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Among many other improvement of the Python interface (see list below), this PR introduces Trampolines to Python.
An example (see
python_examples/function_trampoline.py):One can overload
gs.core.gsFunctioninside Python. This creates a Python class inheriting from the (trampoline of the) C++ classgsFunction, which can therefore directly be used in assemblers, projections etc defined inside Python.NEW:
Add pybind11 interface for
gsBasis::uniformRefine/Coarsen_withTransferAdd pybind11 interface for
gsConstantFunctionAdd pybind11 interface for
gsFieldAdd pybind11 interface for
gsFunctionExpr::set_uAdd pybind11 trampolines for
gsFunctionSetandgsFunctionAdd pybind11 interface for refinement, degree elevation etc in
gsMultiBasisAdd pybind11 interface for writing Python dictionary from
gsOptionListAdd pybind11 interface for SciPy sparse matrices from
gsSparseMatrixAdd assembly of full system, only matrix or only rhs in
gsL2Projection+ bindingsAdd pybind11 interface for
gsQuasiInterpolateIMPROVED:
More concise bindings for dimension-based template classes (e.g., gsHTensorBasis, gsTHBSpline)
Improve argument names and default args of gsWriteParaview bindings
SparseMatrix Row/Col Major template exposure to Pybind (for transfer matrix)
Please consider the following checklist before issuing a pull
request:
you'd like us to include them?