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.
- pyrxmesh-0.2.1rc0/.clang-format +42 -0
- pyrxmesh-0.2.1rc0/.gitignore +11 -0
- pyrxmesh-0.2.1rc0/CMakeLists.txt +186 -0
- pyrxmesh-0.2.1rc0/CUSTOM_CUDA_PLUGINS.md +107 -0
- pyrxmesh-0.2.1rc0/DEVELOPING.md +110 -0
- pyrxmesh-0.2.1rc0/LICENSE +25 -0
- pyrxmesh-0.2.1rc0/PKG-INFO +161 -0
- pyrxmesh-0.2.1rc0/README.md +145 -0
- pyrxmesh-0.2.1rc0/cmake/build_config.json.in +13 -0
- pyrxmesh-0.2.1rc0/cmake/pyrxmeshConfig.cmake.in +89 -0
- pyrxmesh-0.2.1rc0/conftest.py +24 -0
- pyrxmesh-0.2.1rc0/environment.yml +18 -0
- pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/CMakeLists.txt +31 -0
- pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/README.md +50 -0
- pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/pyproject.toml +24 -0
- pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/run_edge_lengths.py +39 -0
- pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/src/rxmesh_edge_lengths/__init__.py +5 -0
- pyrxmesh-0.2.1rc0/examples/custom_kernel_plugin/src/rxmesh_edge_lengths.cu +41 -0
- pyrxmesh-0.2.1rc0/examples/load_and_show.py +31 -0
- pyrxmesh-0.2.1rc0/include/pyrxmesh/plugin_api.h +292 -0
- pyrxmesh-0.2.1rc0/meshes/bumpy.obj +3762 -0
- pyrxmesh-0.2.1rc0/meshes/sphere3.obj +1156 -0
- pyrxmesh-0.2.1rc0/pyproject.toml +77 -0
- pyrxmesh-0.2.1rc0/pyrxmesh/__init__.py +382 -0
- pyrxmesh-0.2.1rc0/pyrxmesh/cmake_dir.py +17 -0
- pyrxmesh-0.2.1rc0/pyrxmesh/diff.py +8 -0
- pyrxmesh-0.2.1rc0/pyrxmesh/geometry.py +5 -0
- pyrxmesh-0.2.1rc0/pyrxmesh/plugin.py +229 -0
- pyrxmesh-0.2.1rc0/src/bindings/common.h +462 -0
- pyrxmesh-0.2.1rc0/src/bindings/core.cu +85 -0
- pyrxmesh-0.2.1rc0/src/bindings/dense_matrix_dlpack.h +369 -0
- pyrxmesh-0.2.1rc0/src/bindings/dlpack_minimal.h +44 -0
- pyrxmesh-0.2.1rc0/src/bindings/geometry.cu +105 -0
- pyrxmesh-0.2.1rc0/src/bindings/handles.cu +96 -0
- pyrxmesh-0.2.1rc0/src/bindings/mesh.cu +380 -0
- pyrxmesh-0.2.1rc0/src/bindings/py_attribute.h +616 -0
- pyrxmesh-0.2.1rc0/src/bindings/py_attributes.cu +584 -0
- pyrxmesh-0.2.1rc0/src/bindings/py_dense_matrix.cu +231 -0
- pyrxmesh-0.2.1rc0/src/bindings/py_dense_matrix.h +627 -0
- pyrxmesh-0.2.1rc0/src/bindings/py_hessian_sparse_matrix.h +65 -0
- pyrxmesh-0.2.1rc0/src/bindings/py_jacobian_sparse_matrix.h +92 -0
- pyrxmesh-0.2.1rc0/src/bindings/py_solvers.cu +173 -0
- pyrxmesh-0.2.1rc0/src/bindings/py_solvers.h +607 -0
- pyrxmesh-0.2.1rc0/src/bindings/py_sparse_matrix.cu +383 -0
- pyrxmesh-0.2.1rc0/src/bindings/py_sparse_matrix.h +579 -0
- pyrxmesh-0.2.1rc0/src/bindings/sparse_matrix_csr.h +150 -0
- pyrxmesh-0.2.1rc0/src/bindings/sparse_matrix_dlpack.h +624 -0
- pyrxmesh-0.2.1rc0/src/bindings.cu +19 -0
- pyrxmesh-0.2.1rc0/tests/test_attributes.py +261 -0
- pyrxmesh-0.2.1rc0/tests/test_core_mesh.py +127 -0
- pyrxmesh-0.2.1rc0/tests/test_dense_matrix.py +288 -0
- pyrxmesh-0.2.1rc0/tests/test_geometry_io.py +64 -0
- 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,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.
|