PyRXMesh 0.2.1rc0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. pyrxmesh-0.2.1rc0/.clang-format +42 -0
  2. pyrxmesh-0.2.1rc0/.gitignore +11 -0
  3. pyrxmesh-0.2.1rc0/CMakeLists.txt +186 -0
  4. pyrxmesh-0.2.1rc0/CUSTOM_CUDA_PLUGINS.md +107 -0
  5. pyrxmesh-0.2.1rc0/DEVELOPING.md +110 -0
  6. pyrxmesh-0.2.1rc0/LICENSE +25 -0
  7. pyrxmesh-0.2.1rc0/PKG-INFO +161 -0
  8. pyrxmesh-0.2.1rc0/README.md +145 -0
  9. pyrxmesh-0.2.1rc0/cmake/build_config.json.in +13 -0
  10. pyrxmesh-0.2.1rc0/cmake/pyrxmeshConfig.cmake.in +89 -0
  11. pyrxmesh-0.2.1rc0/conftest.py +24 -0
  12. pyrxmesh-0.2.1rc0/environment.yml +18 -0
  13. pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/CMakeLists.txt +31 -0
  14. pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/README.md +50 -0
  15. pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/pyproject.toml +24 -0
  16. pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/run_edge_lengths.py +39 -0
  17. pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/src/rxmesh_edge_lengths/__init__.py +5 -0
  18. pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/src/rxmesh_edge_lengths.cu +41 -0
  19. pyrxmesh-0.2.1rc0/examples/load_and_show.py +31 -0
  20. pyrxmesh-0.2.1rc0/include/pyrxmesh/plugin_api.h +292 -0
  21. pyrxmesh-0.2.1rc0/meshes/bumpy.obj +3762 -0
  22. pyrxmesh-0.2.1rc0/meshes/sphere3.obj +1156 -0
  23. pyrxmesh-0.2.1rc0/pyproject.toml +77 -0
  24. pyrxmesh-0.2.1rc0/pyrxmesh/__init__.py +382 -0
  25. pyrxmesh-0.2.1rc0/pyrxmesh/cmake_dir.py +17 -0
  26. pyrxmesh-0.2.1rc0/pyrxmesh/diff.py +8 -0
  27. pyrxmesh-0.2.1rc0/pyrxmesh/geometry.py +5 -0
  28. pyrxmesh-0.2.1rc0/pyrxmesh/plugin.py +229 -0
  29. pyrxmesh-0.2.1rc0/src/bindings/common.h +462 -0
  30. pyrxmesh-0.2.1rc0/src/bindings/core.cu +85 -0
  31. pyrxmesh-0.2.1rc0/src/bindings/dense_matrix_dlpack.h +369 -0
  32. pyrxmesh-0.2.1rc0/src/bindings/dlpack_minimal.h +44 -0
  33. pyrxmesh-0.2.1rc0/src/bindings/geometry.cu +105 -0
  34. pyrxmesh-0.2.1rc0/src/bindings/handles.cu +96 -0
  35. pyrxmesh-0.2.1rc0/src/bindings/mesh.cu +380 -0
  36. pyrxmesh-0.2.1rc0/src/bindings/py_attribute.h +616 -0
  37. pyrxmesh-0.2.1rc0/src/bindings/py_attributes.cu +584 -0
  38. pyrxmesh-0.2.1rc0/src/bindings/py_dense_matrix.cu +231 -0
  39. pyrxmesh-0.2.1rc0/src/bindings/py_dense_matrix.h +627 -0
  40. pyrxmesh-0.2.1rc0/src/bindings/py_hessian_sparse_matrix.h +65 -0
  41. pyrxmesh-0.2.1rc0/src/bindings/py_jacobian_sparse_matrix.h +92 -0
  42. pyrxmesh-0.2.1rc0/src/bindings/py_solvers.cu +173 -0
  43. pyrxmesh-0.2.1rc0/src/bindings/py_solvers.h +607 -0
  44. pyrxmesh-0.2.1rc0/src/bindings/py_sparse_matrix.cu +383 -0
  45. pyrxmesh-0.2.1rc0/src/bindings/py_sparse_matrix.h +579 -0
  46. pyrxmesh-0.2.1rc0/src/bindings/sparse_matrix_csr.h +150 -0
  47. pyrxmesh-0.2.1rc0/src/bindings/sparse_matrix_dlpack.h +624 -0
  48. pyrxmesh-0.2.1rc0/src/bindings.cu +19 -0
  49. pyrxmesh-0.2.1rc0/tests/test_attributes.py +261 -0
  50. pyrxmesh-0.2.1rc0/tests/test_core_mesh.py +127 -0
  51. pyrxmesh-0.2.1rc0/tests/test_dense_matrix.py +288 -0
  52. pyrxmesh-0.2.1rc0/tests/test_geometry_io.py +64 -0
  53. pyrxmesh-0.2.1rc0/tests/test_sparse_matrix.py +337 -0
@@ -0,0 +1,42 @@
1
+ ---
2
+ Language: Cpp
3
+ BasedOnStyle: Chromium
4
+ TabWidth: 4
5
+ UseTab: Never
6
+
7
+ AlignConsecutiveAssignments: true
8
+ AllowShortFunctionsOnASingleLine: false
9
+ AllowShortIfStatementsOnASingleLine: false
10
+ AllowShortLoopsOnASingleLine: false
11
+ AlwaysBreakTemplateDeclarations: true
12
+ AlignTrailingComments: true
13
+ BinPackArguments: false
14
+ BinPackParameters: false
15
+ BreakBeforeTernaryOperators: false
16
+ ConstructorInitializerAllOnOneLineOrOnePerLine: true
17
+ Cpp11BracedListStyle: true
18
+ IndentCaseLabels: true
19
+ IndentWidth: 4
20
+ IndentWrappedFunctionNames: false
21
+ KeepEmptyLinesAtTheStartOfBlocks: true
22
+ MacroBlockBegin: ''
23
+ MacroBlockEnd: ''
24
+ MaxEmptyLinesToKeep: 2
25
+ NamespaceIndentation: None
26
+ ObjCBlockIndentWidth: 2
27
+ ColumnLimit: 80
28
+ AlignConsecutiveDeclarations: true
29
+
30
+ BreakBeforeBraces: Custom
31
+ BraceWrapping:
32
+ AfterClass: true
33
+ AfterControlStatement: false
34
+ AfterEnum: true
35
+ AfterFunction: true
36
+ AfterNamespace: false
37
+ AfterStruct: true
38
+ AfterUnion: true
39
+ AfterExternBlock: true
40
+ BeforeCatch: false
41
+ BeforeElse: false
42
+ ...
@@ -0,0 +1,11 @@
1
+ build/
2
+ /dist/
3
+ *.egg-info/
4
+ __pycache__/
5
+ *.py[cod]
6
+ *.pyd
7
+ *.so
8
+ *.dylib
9
+ RXMesh.log
10
+ .polyscope.ini
11
+ imgui.ini
@@ -0,0 +1,186 @@
1
+ cmake_minimum_required(VERSION 3.24 FATAL_ERROR)
2
+
3
+ if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
4
+ set(CMAKE_CUDA_ARCHITECTURES native)
5
+ endif()
6
+
7
+ file(READ "${CMAKE_CURRENT_SOURCE_DIR}/pyproject.toml" PYRXMESH_PYPROJECT_TOML)
8
+ string(REGEX MATCH
9
+ "\\[project\\][^[]*version[ \t]*=[ \t]*\"([^\"]+)\""
10
+ PYRXMESH_VERSION_MATCH
11
+ "${PYRXMESH_PYPROJECT_TOML}"
12
+ )
13
+ set(PYRXMESH_VERSION "${CMAKE_MATCH_1}")
14
+
15
+ project(PyRXMesh LANGUAGES C CXX CUDA)
16
+ # Increment when the compiled custom-plugin capsule/API contract changes incompatibly and old plugins will no longer work with the new PyRXMesh version. This is separate from the overall project version, which can be incremented for any change including compatible ones.
17
+ set(PYRXMESH_PLUGIN_ABI_VERSION 2)
18
+
19
+ set(CMAKE_CXX_STANDARD 17)
20
+ set(CMAKE_CUDA_STANDARD 17)
21
+ set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
22
+ set(CMAKE_CUDA_STANDARD_REQUIRED TRUE)
23
+ set(CMAKE_CXX_EXTENSIONS OFF)
24
+
25
+ include(FetchContent)
26
+
27
+ find_package(Python3 REQUIRED COMPONENTS Interpreter Development.Module)
28
+ find_package(pybind11 CONFIG QUIET)
29
+ if(NOT pybind11_FOUND)
30
+ FetchContent_Declare(pybind11
31
+ GIT_REPOSITORY https://github.com/pybind/pybind11.git
32
+ GIT_TAG v2.13.6
33
+ GIT_SHALLOW TRUE
34
+ )
35
+ FetchContent_MakeAvailable(pybind11)
36
+ endif()
37
+
38
+ set(PYRXMESH_RXMESH_GIT_REPO "https://github.com/owensgroup/RXMesh.git" CACHE STRING "RXMesh Git repository URL")
39
+ set(PYRXMESH_RXMESH_GIT_TAG "main" CACHE STRING "RXMesh Git tag, branch, or commit to build against")
40
+ set(PYRXMESH_RXMESH_SOURCE_DIR "" CACHE PATH "Optional local RXMesh source checkout. If set, Git fetch is skipped.")
41
+ set(PYRXMESH_USE_POLYSCOPE "ON" CACHE BOOL "Build RXMesh with Polyscope visualization support")
42
+ set(PYRXMESH_BUILD_RXMESH_TESTS "OFF" CACHE BOOL "Build RXMesh tests when building PyRXMesh")
43
+ set(PYRXMESH_BUILD_RXMESH_APPS "OFF" CACHE BOOL "Build RXMesh apps when building PyRXMesh")
44
+ set(PYRXMESH_USE_DOUBLE "OFF" CACHE BOOL "Build RXMesh with double precision coordinate input")
45
+ set(PYRXMESH_USE_CUDSS "OFF" CACHE BOOL "Build RXMesh with cuDSS support")
46
+ set(PYRXMESH_USE_SUITESPARSE "OFF" CACHE BOOL "Build RXMesh with SuiteSparse support")
47
+ set(PYRXMESH_INSTALL_PLUGIN_SDK "ON" CACHE BOOL "Install headers, libraries, and CMake files needed to build PyRXMesh plugins")
48
+
49
+
50
+ string(REPLACE "\\" "/" PYRXMESH_RXMESH_SOURCE_DIR_TAG "${PYRXMESH_RXMESH_SOURCE_DIR}")
51
+ set(PYRXMESH_CUDA_ARCHITECTURES_TAG "${CMAKE_CUDA_ARCHITECTURES}")
52
+ string(REPLACE ";" "," PYRXMESH_CUDA_ARCHITECTURES_TAG "${PYRXMESH_CUDA_ARCHITECTURES_TAG}")
53
+
54
+ # Captures build options that plugins must match to safely link against this PyRXMesh/RXMesh install. Used by plugins to check compatibility at runtime and refuse to load if incompatible, preventing hard-to-debug crashes due to ABI incompatibility.
55
+ set(PYRXMESH_BUILD_CONFIG_TAG
56
+ "abi=${PYRXMESH_PLUGIN_ABI_VERSION},pyrxmesh=${PYRXMESH_VERSION},rxmesh_repo=${PYRXMESH_RXMESH_GIT_REPO},rxmesh_tag=${PYRXMESH_RXMESH_GIT_TAG},rxmesh_source=${PYRXMESH_RXMESH_SOURCE_DIR_TAG},polyscope=${PYRXMESH_USE_POLYSCOPE},double=${PYRXMESH_USE_DOUBLE},cudss=${PYRXMESH_USE_CUDSS},suitesparse=${PYRXMESH_USE_SUITESPARSE},cuda_arch=${PYRXMESH_CUDA_ARCHITECTURES_TAG}"
57
+ )
58
+
59
+ # RXMesh uses these option names internally. Force them before adding RXMesh so PyRXMesh controls the dependency build in both Git and local-source modes.
60
+ set(RX_BUILD_TESTS ${PYRXMESH_BUILD_RXMESH_TESTS} CACHE BOOL "" FORCE)
61
+ set(RX_BUILD_APPS ${PYRXMESH_BUILD_RXMESH_APPS} CACHE BOOL "" FORCE)
62
+ set(RX_USE_POLYSCOPE ${PYRXMESH_USE_POLYSCOPE} CACHE BOOL "" FORCE)
63
+ set(RX_USE_DOUBLE ${PYRXMESH_USE_DOUBLE} CACHE BOOL "" FORCE)
64
+ set(RX_USE_CUDSS ${PYRXMESH_USE_CUDSS} CACHE BOOL "" FORCE)
65
+ set(RX_USE_SUITESPARSE ${PYRXMESH_USE_SUITESPARSE} CACHE BOOL "" FORCE)
66
+ set(RXMESH_INSTALL_INCLUDEDIR "pyrxmesh/include" CACHE STRING "" FORCE)
67
+ set(RXMESH_INSTALL_THIRD_PARTY_INCLUDEDIR "pyrxmesh/third_party/include" CACHE STRING "" FORCE)
68
+ set(RXMESH_INSTALL_LIBDIR "pyrxmesh/lib" CACHE STRING "" FORCE)
69
+ set(RXMESH_INSTALL_BINDIR "pyrxmesh/bin" CACHE STRING "" FORCE)
70
+ set(RXMESH_INSTALL_CMAKEDIR "pyrxmesh/cmake/RXMesh" CACHE STRING "" FORCE)
71
+ if(PYRXMESH_INSTALL_PLUGIN_SDK)
72
+ set(RXMESH_INSTALL_COMPONENT "python" CACHE STRING "" FORCE)
73
+ else()
74
+ set(RXMESH_INSTALL_COMPONENT "plugin_sdk" CACHE STRING "" FORCE)
75
+ endif()
76
+
77
+ if(PYRXMESH_RXMESH_SOURCE_DIR)
78
+ get_filename_component(PYRXMESH_RXMESH_SOURCE_DIR_ABS "${PYRXMESH_RXMESH_SOURCE_DIR}" ABSOLUTE)
79
+ if(NOT EXISTS "${PYRXMESH_RXMESH_SOURCE_DIR_ABS}/CMakeLists.txt")
80
+ message(FATAL_ERROR "PYRXMESH_RXMESH_SOURCE_DIR does not point to an RXMesh source tree: ${PYRXMESH_RXMESH_SOURCE_DIR_ABS}")
81
+ endif()
82
+ add_subdirectory("${PYRXMESH_RXMESH_SOURCE_DIR_ABS}" "${CMAKE_BINARY_DIR}/_deps/rxmesh-build")
83
+ else()
84
+ FetchContent_Declare(rxmesh
85
+ GIT_REPOSITORY "${PYRXMESH_RXMESH_GIT_REPO}"
86
+ GIT_TAG "${PYRXMESH_RXMESH_GIT_TAG}"
87
+ GIT_SHALLOW TRUE
88
+ )
89
+ FetchContent_MakeAvailable(rxmesh)
90
+ endif()
91
+
92
+ set_target_properties(RXMesh PROPERTIES POSITION_INDEPENDENT_CODE ON)
93
+
94
+ pybind11_add_module(_rxmesh MODULE
95
+ src/bindings.cu
96
+ src/bindings/core.cu
97
+ src/bindings/geometry.cu
98
+ src/bindings/handles.cu
99
+ src/bindings/mesh.cu
100
+ src/bindings/common.h
101
+ src/bindings/dlpack_minimal.h
102
+
103
+ src/bindings/py_attributes.cu
104
+ src/bindings/py_attribute.h
105
+
106
+ src/bindings/py_dense_matrix.cu
107
+ src/bindings/py_dense_matrix.h
108
+ src/bindings/dense_matrix_dlpack.h
109
+
110
+ src/bindings/py_sparse_matrix.cu
111
+ src/bindings/py_sparse_matrix.h
112
+ src/bindings/py_solvers.cu
113
+ src/bindings/py_solvers.h
114
+ src/bindings/py_hessian_sparse_matrix.h
115
+ src/bindings/py_jacobian_sparse_matrix.h
116
+ src/bindings/sparse_matrix_csr.h
117
+ src/bindings/sparse_matrix_dlpack.h
118
+ )
119
+
120
+ target_link_libraries(_rxmesh PRIVATE RXMesh)
121
+ target_include_directories(_rxmesh
122
+ PRIVATE
123
+ "${CMAKE_CURRENT_SOURCE_DIR}/include"
124
+ "${CMAKE_CURRENT_SOURCE_DIR}/src"
125
+ )
126
+ target_compile_features(_rxmesh PRIVATE cxx_std_17)
127
+ target_compile_definitions(_rxmesh
128
+ PRIVATE PYRXMESH_PLUGIN_ABI_VERSION=${PYRXMESH_PLUGIN_ABI_VERSION}
129
+ PRIVATE PYRXMESH_BUILD_CONFIG="${PYRXMESH_BUILD_CONFIG_TAG}"
130
+ )
131
+ set_target_properties(_rxmesh PROPERTIES
132
+ CUDA_SEPARABLE_COMPILATION ON
133
+ CUDA_RESOLVE_DEVICE_SYMBOLS ON
134
+ )
135
+
136
+ if(UNIX AND NOT APPLE)
137
+ set_target_properties(_rxmesh PROPERTIES
138
+ INSTALL_RPATH "$ORIGIN;$ORIGIN/lib;$ORIGIN/bin"
139
+ )
140
+ endif()
141
+
142
+ if(WIN32)
143
+ target_compile_definitions(_rxmesh
144
+ PRIVATE _USE_MATH_DEFINES
145
+ PRIVATE NOMINMAX
146
+ PRIVATE _CRT_SECURE_NO_WARNINGS
147
+ )
148
+ endif()
149
+
150
+ if(PYRXMESH_USE_CUDSS)
151
+ target_compile_definitions(_rxmesh PRIVATE USE_CUDSS)
152
+ endif()
153
+
154
+ install(TARGETS _rxmesh
155
+ LIBRARY DESTINATION pyrxmesh COMPONENT python
156
+ RUNTIME DESTINATION pyrxmesh COMPONENT python
157
+ )
158
+
159
+ configure_file(
160
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/pyrxmeshConfig.cmake.in"
161
+ "${CMAKE_CURRENT_BINARY_DIR}/pyrxmeshConfig.cmake"
162
+ @ONLY
163
+ )
164
+ configure_file(
165
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_config.json.in"
166
+ "${CMAKE_CURRENT_BINARY_DIR}/build_config.json"
167
+ @ONLY
168
+ )
169
+
170
+ if(PYRXMESH_INSTALL_PLUGIN_SDK)
171
+ install(FILES
172
+ "${CMAKE_CURRENT_SOURCE_DIR}/include/pyrxmesh/plugin_api.h"
173
+ DESTINATION pyrxmesh/include/pyrxmesh
174
+ COMPONENT python
175
+ )
176
+ install(FILES
177
+ "${CMAKE_CURRENT_BINARY_DIR}/pyrxmeshConfig.cmake"
178
+ DESTINATION pyrxmesh/cmake
179
+ COMPONENT python
180
+ )
181
+ endif()
182
+ install(FILES
183
+ "${CMAKE_CURRENT_BINARY_DIR}/build_config.json"
184
+ DESTINATION pyrxmesh
185
+ COMPONENT python
186
+ )
@@ -0,0 +1,107 @@
1
+ # Custom CUDA Plugins
2
+
3
+ Most PyRXMesh workflows should stay in Python. Custom CUDA plugins are for the parts of RXMesh that require C++/CUDA device lambdas.
4
+
5
+ The intended workflow is to keep orchestration and data management in Python, and put only the hot RXMesh lambda code in a small compiled plugin package.
6
+
7
+ ## Creating a Plugin Package
8
+
9
+ ```bash
10
+ python -m pyrxmesh.plugin init my_kernels
11
+ cd my_kernels
12
+ python -m pip install -v --no-build-isolation .
13
+ ```
14
+
15
+ The scaffolder generates a Python "src-layout" tree:
16
+
17
+ ```text
18
+ my_kernels/
19
+ pyproject.toml
20
+ CMakeLists.txt
21
+ README.md
22
+ src/
23
+ my_kernels.cu # CUDA source for the plugin
24
+ my_kernels/__init__.py # Python package source
25
+ my_script.py # your own scripts can live here
26
+ ```
27
+
28
+ The generated plugin builds against the `pyrxmesh` package installed in the active Python environment. It reuses the RXMesh headers and library installed with PyRXMesh, so plugin builds should compile only the plugin code instead of rebuilding RXMesh. The plugin also checks the PyRXMesh/RXMesh build configuration at runtime.
29
+
30
+ After `pip install`, `my_kernels` is in your environment's site-packages and importable from any directory, exactly like `pyrxmesh` itself.
31
+
32
+ ### Why src-layout?
33
+
34
+ Python's `sys.path[0]` is always the directory containing the script you ran. If a plugin's Python source package sits next to that script (the natural place to put it), `import my_kernels` resolves to the **source** directory rather than the installed wheel. Because the compiled CUDA extension (`_my_kernels.<ext>`) lives only in the installed wheel, the import then fails.
35
+
36
+ The src-layout sidesteps this by tucking Python sources under `src/my_kernels/`. The plugin root contains no importable `my_kernels/` directory, so `import my_kernels` always resolves to site-packages with the compiled extension alongside it. No `sys.path` munging or `cd` discipline is required.
37
+
38
+
39
+ ## Use a Plugin From Python
40
+
41
+ Generated Python usage:
42
+
43
+ ```python
44
+ import pyrxmesh as rx
45
+ import my_kernels
46
+
47
+ mesh = rx.RXMeshStatic("mesh.obj")
48
+ coords = mesh.input_vertex_coordinates()
49
+ edge_lengths = mesh.add_edge_attribute("edge_lengths", dtype="float32", dim=1)
50
+
51
+ my_kernels.compute_edge_lengths(mesh, coords, edge_lengths)
52
+ ```
53
+
54
+ The CUDA code receives PyRXMesh objects and unwraps them through
55
+ `pyrxmesh/plugin_api.h`:
56
+
57
+ ```cpp
58
+ auto coords = pyrxmesh::vertex_attribute<float>(coords_obj);
59
+ auto out = pyrxmesh::edge_attribute<float>(out_obj);
60
+
61
+ pyrxmesh::for_each<Op::EV, 256>(
62
+ mesh_obj,
63
+ [coords, out] __device__(const EdgeHandle& eh,
64
+ const VertexIterator& iter) mutable {
65
+ const Eigen::Vector3f a = coords.to_eigen<3>(iter[0]);
66
+ const Eigen::Vector3f b = coords.to_eigen<3>(iter[1]);
67
+ out(eh) = (a - b).norm();
68
+ });
69
+ ```
70
+
71
+ Use `pyrxmesh::for_each` for RXMesh query operations from plugin modules. It delegates launch-box preparation to the installed PyRXMesh runtime and then launches the plugin's CUDA lambda without an extra Python data copy.
72
+
73
+ ## Examples
74
+
75
+ The repository includes a complete custom-kernel plugin example in [`examples/custom_kernel_plugin`](examples/custom_kernel_plugin) using the same src-layout the scaffolder emits:
76
+
77
+ ```text
78
+ examples/custom_kernel_plugin/
79
+ pyproject.toml
80
+ CMakeLists.txt
81
+ run_edge_lengths.py
82
+ src/
83
+ rxmesh_edge_lengths.cu
84
+ rxmesh_edge_lengths/__init__.py
85
+ ```
86
+
87
+ It computes one scalar edge-length attribute on the GPU using an RXMesh `Op::EV` device lambda, then reads the result back from Python.
88
+
89
+ Build the example plugin from the PyRXMesh repository root:
90
+
91
+ ```bash
92
+ python -m pip install -v --no-build-isolation examples/custom_kernel_plugin
93
+ ```
94
+
95
+ After PyRXMesh is installed, this build links against the installed PyRXMesh package and should not fetch or compile RXMesh again.
96
+
97
+ Run it as:
98
+
99
+ ```bash
100
+ python examples/custom_kernel_plugin/run_edge_lengths.py --input mesh.obj
101
+ ```
102
+
103
+ The example package shows the intended split where Python loads the mesh and owns the workflow while `src/rxmesh_edge_lengths.cu` contains only the performance critical RXMesh lambda.
104
+
105
+
106
+ For PyRXMesh source-build and incremental-build notes, see
107
+ [DEVELOPING.md](DEVELOPING.md).
@@ -0,0 +1,110 @@
1
+ # Developing PyRXMesh
2
+
3
+ This guide is for building PyRXMesh from source, testing changes, and working against RXMesh branches, forks, or local checkouts. If you only want to use PyRXMesh from Python, start with [README.md](README.md).
4
+
5
+ ## Prerequisites
6
+
7
+ You need the platform CUDA/C++ toolchain:
8
+
9
+ - Windows: Visual Studio C++ tools plus NVIDIA CUDA Toolkit with `nvcc`.
10
+ - Linux: GCC/Clang compatible with your CUDA Toolkit, NVIDIA CUDA Toolkit with
11
+ `nvcc`, and the OpenGL/X11 development packages required by Polyscope.
12
+
13
+ ## Conda Environment
14
+
15
+ ```bash
16
+ conda env create -f environment.yml
17
+ conda activate PyRXMesh
18
+ ```
19
+
20
+ Install build requirements into the active environment when you want faster developer rebuilds without build isolation:
21
+
22
+ ```bash
23
+ python -m pip install scikit-build-core pybind11 numpy
24
+ ```
25
+
26
+ ## Build From Source
27
+
28
+ The normal developer build uses the local default CUDA architecture behavior and the RXMesh ref configured in `pyproject.toml`:
29
+
30
+ ```bash
31
+ python -m pip install -v .
32
+ ```
33
+
34
+ For a faster inner loop after installing build requirements:
35
+
36
+ ```bash
37
+ python -m pip install -v --no-build-isolation .
38
+ ```
39
+
40
+ ## Select An RXMesh Source
41
+
42
+ For release packages, the RXMesh ref should be source-controlled in `pyproject.toml`:
43
+
44
+ ```toml
45
+ [tool.scikit-build.cmake.define]
46
+ PYRXMESH_RXMESH_GIT_TAG = "main"
47
+ ```
48
+
49
+ For local experiments, override the RXMesh tag or commit from the command line:
50
+
51
+ ```bash
52
+ python -m pip install -v . -Ccmake.define.PYRXMESH_RXMESH_GIT_TAG=<tag-or-commit>
53
+ ```
54
+
55
+ Examples:
56
+
57
+ ```bash
58
+ python -m pip install -v . -Ccmake.define.PYRXMESH_RXMESH_GIT_TAG=main
59
+ python -m pip install -v . -Ccmake.define.PYRXMESH_RXMESH_GIT_TAG=v0.2.1
60
+ ```
61
+
62
+ To build against an RXMesh fork:
63
+
64
+ ```bash
65
+ python -m pip install -v . \
66
+ -Ccmake.define.PYRXMESH_RXMESH_GIT_REPO=https://github.com/<user>/RXMesh.git \
67
+ -Ccmake.define.PYRXMESH_RXMESH_GIT_TAG=<tag-or-commit>
68
+ ```
69
+
70
+ For local RXMesh development without fetching from Git:
71
+
72
+ ```bash
73
+ python -m pip install -v . -Ccmake.define.PYRXMESH_RXMESH_SOURCE_DIR=C:/path/to/RXMesh
74
+ ```
75
+
76
+ ## Release-Like Local Build
77
+
78
+ Release wheels build with Polyscope enabled and a broad CUDA architecture set:
79
+
80
+ ```bash
81
+ python -m pip install -v . \
82
+ -Ccmake.define.CMAKE_CUDA_ARCHITECTURES="75;80;86;89;90" \
83
+ -Ccmake.define.PYRXMESH_USE_POLYSCOPE=ON
84
+ ```
85
+
86
+ ## Incremental Builds
87
+
88
+ Builds reuse a persistent scikit-build-core build directory:
89
+
90
+ ```text
91
+ build/{wheel_tag}
92
+ ```
93
+
94
+ The first install for a Python/platform/RXMesh configuration is a full build. Subsequent installs with the same settings should be incremental.
95
+
96
+ To force a clean rebuild, delete the matching `build/<wheel_tag>` directory.
97
+
98
+ ## Run Examples
99
+
100
+ Examples are not part of the installed package, so editing them does not require reinstalling/recompiling PyRXMesh:
101
+
102
+ ```bash
103
+ python examples/load_and_show.py --input mesh.obj
104
+ ```
105
+
106
+ ## Custom CUDA Plugins
107
+
108
+ Most PyRXMesh workflows should stay in Python. For RXMesh operations that require CUDA device lambdas, PyRXMesh supports small compiled plugin packages that operate on PyRXMesh meshes and attributes without extra Python-side copies.
109
+
110
+ See [CUSTOM_CUDA_PLUGINS.md](CUSTOM_CUDA_PLUGINS.md) for the plugin workflow.
@@ -0,0 +1,25 @@
1
+ BSD 2-Clause License
2
+
3
+ Copyright (c) 2026, Ahmed Mahmoud and PyRXMesh contributors
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
20
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,161 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyRXMesh
3
+ Version: 0.2.1rc0
4
+ Summary: Python bindings for RXMesh, a CUDA/C++ library for mesh processing on the GPU.
5
+ Author: Ahmed Mahmoud
6
+ License-Expression: BSD-2-Clause
7
+ License-File: LICENSE
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Programming Language :: C++
10
+ Classifier: Programming Language :: Python :: 3
11
+ Project-URL: RXMesh, https://github.com/owensgroup/RXMesh
12
+ Project-URL: Documentation, https://ahdhn.github.io/RXMeshDocs/
13
+ Requires-Python: >=3.10
14
+ Requires-Dist: numpy>=1.26
15
+ Description-Content-Type: text/markdown
16
+
17
+ # PyRXMesh
18
+
19
+ Python bindings for [RXMesh](https://github.com/owensgroup/RXMesh), a CUDA/C++ library for GPU mesh processing.
20
+
21
+ PyRXMesh allows you to keep mesh workflows in Python while using RXMesh data structures and GPU kernels underneath. It supports exchanging arrays and attributes with NumPy and PyTorch, building sparse matrices, and solving linear systems. We use a Python plugin to allow CUDA kernels to be written, compiled, and used directly in Python. Check out [CUSTOM_CUDA_PLUGINS.md](CUSTOM_CUDA_PLUGINS.md) for more details.
22
+
23
+
24
+ ## Installation
25
+
26
+ Install PyRXMesh with:
27
+
28
+ ```bash
29
+ python -m pip install PyRXMesh
30
+ ```
31
+
32
+ PyRXMesh is a CUDA package. You need an NVIDIA driver compatible with the CUDA version used by the wheel. For source builds and development setup, see [DEVELOPING.md](DEVELOPING.md).
33
+
34
+ ## Simple Example
35
+
36
+ ```python
37
+ import pyrxmesh as rx
38
+
39
+ #Use GPU 0
40
+ rx.init(0)
41
+
42
+ mesh = rx.RXMeshStatic("mesh.obj")
43
+ print(mesh.num_vertices, mesh.num_edges, mesh.num_faces)
44
+
45
+ rx.show()
46
+ ```
47
+
48
+ The repository includes a small viewer example:
49
+
50
+ ```bash
51
+ python examples/load_and_show.py --input mesh.obj
52
+ ```
53
+
54
+ ## Mesh Attributes
55
+
56
+ Attributes are data attached to vertices, edges, or faces
57
+
58
+ ```python
59
+ import pyrxmesh as rx
60
+
61
+ mesh = rx.RXMeshStatic("mesh.obj")
62
+
63
+ coords = mesh.input_vertex_coordinates()
64
+ velocity = mesh.add_vertex_attribute("velocity", dtype="float32",
65
+ dim=3, location=rx.Location.ALL)
66
+
67
+ velocity.reset(0.0, rx.Location.DEVICE)
68
+
69
+ host_coords = coords.to_numpy_copy(source=rx.Location.HOST)
70
+ print(host_coords.shape)
71
+ ```
72
+
73
+ ## NumPy And Torch Interop
74
+
75
+ Unsuffixed `to_*` methods return zero-copy views when possible. Methods ending
76
+ in `_copy` make an explicit copy.
77
+
78
+ ```python
79
+ import pyrxmesh as rx
80
+
81
+ mesh = rx.RXMeshStatic("mesh.obj")
82
+ attr = mesh.add_vertex_attribute("temperature", dtype="float32",
83
+ dim=1, location=rx.Location.ALL)
84
+
85
+ attr.reset(1.0, rx.Location.ALL)
86
+
87
+ view = attr.to_numpy(rx.Location.HOST)
88
+ view[0, 0] = 42.0
89
+
90
+ owned = attr.to_numpy_copy(source=rx.Location.HOST)
91
+ print(owned[0, 0])
92
+ ```
93
+
94
+ Torch views use DLPack:
95
+
96
+ ```python
97
+ tensor = attr.to_torch(rx.Location.DEVICE)
98
+ tensor += 2.0
99
+ ```
100
+
101
+ ## Dense And Sparse Matrices
102
+
103
+ PyRXMesh exposes RXMesh dense matrices and CSR sparse matrices.
104
+
105
+ ```python
106
+ import numpy as np
107
+ import pyrxmesh as rx
108
+
109
+ matrix = rx.DenseMatrix(4, 3, dtype="float32", location=rx.Location.ALL)
110
+ values = np.arange(12, dtype=np.float32).reshape(4, 3)
111
+
112
+ matrix.from_numpy_copy(values, target=rx.Location.ALL)
113
+ print(matrix.norm2())
114
+ ```
115
+
116
+ Sparse matrices are CSR-only:
117
+
118
+ ```python
119
+ mesh = rx.RXMeshStatic("mesh.obj")
120
+ laplace_like = mesh.sparse_matrix(rx.Op.VV, dtype="float32")
121
+
122
+ row_ptr, col_idx, values = laplace_like.to_numpy_copy()
123
+ print(laplace_like.shape, laplace_like.nnz)
124
+ ```
125
+
126
+ You can multiply sparse matrices by dense vectors:
127
+
128
+ ```python
129
+ x = np.ones((laplace_like.cols, 1), dtype=np.float32)
130
+ y = laplace_like.multiply_vector(x)
131
+ print(y.to_numpy_copy(source=rx.Location.HOST))
132
+ ```
133
+
134
+ ## Solvers
135
+
136
+ RXMesh solver bindings work with `SparseMatrix` and `DenseMatrix` objects:
137
+
138
+ ```python
139
+ import numpy as np
140
+ import pyrxmesh as rx
141
+
142
+ row_ptr = np.array([0, 2, 5, 7], dtype=np.int32)
143
+ col_idx = np.array([0, 1, 0, 1, 2, 1, 2], dtype=np.int32)
144
+ values = np.array([4, 1, 1, 3, 1, 1, 2], dtype=np.float32)
145
+
146
+ A = rx.SparseMatrix.from_numpy_copy(row_ptr, col_idx, values,
147
+ shape=(3, 3), dtype="float32")
148
+
149
+ b = rx.DenseMatrix(3, 1, dtype="float32", location=rx.Location.ALL)
150
+ b.from_numpy_copy(np.array([[1], [2], [3]], dtype=np.float32))
151
+
152
+ solver = rx.CGSolver(A, unknown_dim=1)
153
+ x = solver.solve(b)
154
+
155
+ print(x.to_numpy_copy(source=rx.Location.HOST))
156
+ ```
157
+
158
+ ## Documentation
159
+ - [RXMeshDocs](https://ahdhn.github.io/RXMeshDocs/): RXMesh CUDA/C++ documentation website
160
+ - [DEVELOPING.md](DEVELOPING.md): build PyRXMesh from source and work against RXMesh forks, tags, or local checkouts.
161
+ - [CUSTOM_CUDA_PLUGINS.md](CUSTOM_CUDA_PLUGINS.md): write small compiled CUDA plugins that operate on PyRXMesh meshes and attributes.