GPU-accelerated SPH neighbor search and operators built with NVIDIA Warp and PyTorch
Project description
sphWarpCore
sphWarpCore is a Warp- and PyTorch-based backend for core Smoothed Particle Hydrodynamics (SPH) operations. The package focuses on GPU-accelerated neighborhood construction and particle operators such as density estimation, interpolation, gradients, divergence, curl, Laplacians, and CRK-corrected variants.
The repository also includes notebooks that compare the Warp implementation against diffSPH reference workflows and demonstrate common operator setups.
Highlights
- Compact-hash radius search for particle neighborhoods
- Unified SPH operator entry point via
sphOperation_warp - Multiple support and gradient schemes
- CRK correction utilities for corrected interpolation and gradients
- PyTorch tensor inputs and outputs, with Warp kernels under the hood
Installation
Install the package in editable mode while developing:
pip install -e .
If you want to run the example notebooks in this repository, install the notebook extras as well:
pip install -e ".[notebooks]"
For packaging and publishing, install the development extras or at least build and twine:
pip install -e ".[dev]"
Requirements
Core package requirements:
- Python 3.10+
- PyTorch
- warp-lang
- NumPy
Notebook and plotting extras used in this repository:
- matplotlib
- ipywidgets
- ipympl
GPU notes:
- For GPU execution, use a CUDA-capable PyTorch build and a compatible NVIDIA driver.
- A separate CUDA toolkit installation is not required anymore for this package setup.
- Warp still needs to be initialized once per process with
wp.init().
Package Overview
Common entry points:
sphWarpCore.radiusSearchCompactHashMap: builds adjacency lists with compact hashingsphWarpCore.sphOperation_warp: dispatches SPH operators from one high-level functionsphWarpCore.crk.computeCRKFactors: computes CRK apparent area and correction tensorssphWarpCore.util.generateNeighborTestData: helper for generating regular particle test setssphWarpCore.util.getNextPrime: helper for choosing compact-hash table sizes
Important enums:
WarpOperation: selects the SPH operatorKernelFunctions: selects the smoothing kernelSupportScheme: selects gather/scatter/symmetric support handlingGradientScheme: selects the gradient formulationOperationDirection: selects all-to-all or filtered interaction directionality
Example: Radius Search with Compact Hashing
This follows the same setup pattern used by prepData in the demo utilities.
import torch
import warp as wp
from sphWarpCore import radiusSearchCompactHashMap
from sphWarpCore.util import generateNeighborTestData, getNextPrime
wp.init()
device = torch.device("cuda")
nx = 128
dim = 2
target_num_neighbors = 50
periodic = True
positions, supports, num_particles, domain, dx = generateNeighborTestData(
nx, target_num_neighbors, dim, periodic, device
)
query_positions = positions.contiguous()
reference_positions = positions.contiguous()
query_supports = supports
reference_supports = supports
hash_map_length = getNextPrime(num_particles)
adjacency = radiusSearchCompactHashMap(
query_positions,
reference_positions,
query_supports,
reference_supports,
domain.periodic,
domain,
"gather",
hash_map_length,
)
print(adjacency.numNeighbors.shape)
print(adjacency.edgeOffsets[:5])
print(adjacency.j[:10])
The returned adjacency list stores edge-level connectivity in COO/CSR-like form:
adjacency.i: query particle index per edgeadjacency.j: neighbor particle index per edgeadjacency.numNeighbors: neighbor count per query particleadjacency.edgeOffsets: CSR-style start offset per query particle
Example: SPH Interpolation
This mirrors the interpolation workflow used in warp_interpolate.ipynb.
import torch
import warp as wp
from sphWarpCore import radiusSearchCompactHashMap, sphOperation_warp
from sphWarpCore.enumTypes import KernelFunctions, OperationDirection, SupportScheme, WarpOperation
from sphWarpCore.util import generateNeighborTestData, getNextPrime
wp.init()
device = torch.device("cuda")
nx = 128
dim = 2
target_num_neighbors = 50
periodic = True
positions, supports, num_particles, domain, dx = generateNeighborTestData(
nx, target_num_neighbors, dim, periodic, device
)
query_positions = positions.contiguous()
reference_positions = positions.contiguous()
query_supports = supports
reference_supports = supports
particle_mass = dx ** dim
query_masses = torch.full((num_particles,), particle_mass, device=device)
reference_masses = torch.full((num_particles,), particle_mass, device=device)
adjacency = radiusSearchCompactHashMap(
query_positions,
reference_positions,
query_supports,
reference_supports,
domain.periodic,
domain,
"gather",
getNextPrime(num_particles),
)
densities = sphOperation_warp(
query_positions,
reference_positions,
query_supports,
reference_supports,
query_masses,
reference_masses,
None,
None,
None,
None,
domain,
adjacency,
operation=WarpOperation.Density,
kernel=KernelFunctions.Wendland2,
supportMode=SupportScheme.Gather,
)
field = torch.sin(query_positions[:, 0])
interpolated = sphOperation_warp(
query_positions,
reference_positions,
query_supports,
reference_supports,
query_masses,
reference_masses,
densities,
densities,
field,
field,
domain=domain,
adjacency=adjacency,
operation=WarpOperation.Interpolate,
operationMode=OperationDirection.AllToAll,
kernel=KernelFunctions.Wendland2,
supportMode=SupportScheme.Gather,
)
print(interpolated.shape)
Example: CRK-Corrected Gradient
This matches the corrected linear-field gradient workflow in warp_gradient.ipynb.
import torch
import warp as wp
from sphWarpCore import radiusSearchCompactHashMap, sphOperation_warp
from sphWarpCore.crk import computeCRKFactors
from sphWarpCore.enumTypes import (
GradientScheme,
KernelFunctions,
OperationDirection,
SupportScheme,
WarpOperation,
)
from sphWarpCore.util import generateNeighborTestData, getNextPrime
wp.init()
device = torch.device("cuda")
nx = 128
dim = 2
target_num_neighbors = 50
periodic = True
positions, supports, num_particles, domain, dx = generateNeighborTestData(
nx, target_num_neighbors, dim, periodic, device
)
query_positions = positions.contiguous()
reference_positions = positions.contiguous()
query_supports = supports
reference_supports = supports
particle_mass = dx ** dim
query_masses = torch.full((num_particles,), particle_mass, device=device)
reference_masses = torch.full((num_particles,), particle_mass, device=device)
adjacency = radiusSearchCompactHashMap(
query_positions,
reference_positions,
query_supports,
reference_supports,
domain.periodic,
domain,
"gather",
getNextPrime(num_particles),
)
densities = sphOperation_warp(
query_positions,
reference_positions,
query_supports,
reference_supports,
query_masses,
reference_masses,
None,
None,
None,
None,
domain,
adjacency,
operation=WarpOperation.Density,
kernel=KernelFunctions.Wendland2,
supportMode=SupportScheme.Gather,
)
apparent_area, crk_density, A, B, gradA, gradB = computeCRKFactors(
query_positions,
reference_positions,
query_supports,
reference_supports,
query_masses,
reference_masses,
domain=domain,
adjacency=adjacency,
operationMode=OperationDirection.AllToAll,
kernel=KernelFunctions.Wendland2,
supportMode=SupportScheme.Gather,
)
field = query_positions[:, 0] * 5.0 + 10.0
gradient = sphOperation_warp(
query_positions,
reference_positions,
query_supports,
reference_supports,
query_masses,
reference_masses,
densities,
densities,
field,
field,
domain=domain,
adjacency=adjacency,
operation=WarpOperation.Gradient,
operationMode=OperationDirection.AllToAll,
kernel=KernelFunctions.Wendland2,
supportMode=SupportScheme.SuperSymmetric,
gradientMode=GradientScheme.Naive,
useCRK=True,
crk_A=A,
crk_B=B,
crk_gradA=gradA,
crk_gradB=gradB,
useVolume=True,
queryVolumes=apparent_area,
referenceVolumes=apparent_area,
)
print(gradient[:5])
computeCRKFactors also returns crk_density, which can be useful in other corrected workflows, but the gradient notebook example uses the standard density estimate together with CRK volume and correction tensors.
Repository Notes
demo_util.pycontains helper setup code used across the notebooks.warp_interpolate.ipynbdemonstrates interpolation calls and visualization.warp_gradient.ipynbdemonstrates both standard and CRK-corrected gradients.packages.mdis no longer authoritative for CUDA toolkit setup; the separate CUDA install noted there is not required anymore.
Publishing To PyPI
This repository now includes two helper scripts:
scripts/setup_pypi_token.sh: stores a PyPI API token in~/.pypircscripts/publish_pypi.sh: builds, validates, and uploads the package
Typical release flow:
bash scripts/setup_pypi_token.sh pypi
bash scripts/publish_pypi.sh
For a TestPyPI dry run:
bash scripts/setup_pypi_token.sh testpypi
bash scripts/publish_pypi.sh --testpypi
Before publishing, bump the package version in both pyproject.toml and src/sphWarpCore/__init__.py. The publish script checks that these two versions match and stops if they do not.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sphwarpcore-0.2.1.tar.gz.
File metadata
- Download URL: sphwarpcore-0.2.1.tar.gz
- Upload date:
- Size: 82.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d136d0a207dee17cfbab62a032f7d42fdc272025d992563aa53289ddfa260bd9
|
|
| MD5 |
342259a670501bcb147feb4643756e54
|
|
| BLAKE2b-256 |
338b36f3fcef9714049478af7c68b98cdfdcb7393d3be570e395ff3bc4a93a1c
|
File details
Details for the file sphwarpcore-0.2.1-py3-none-any.whl.
File metadata
- Download URL: sphwarpcore-0.2.1-py3-none-any.whl
- Upload date:
- Size: 141.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6b6fcc7a8c3fe3c5f6d43c9d93cc4d368bd8695aeceaa9a7d9f3fd01e5973aa3
|
|
| MD5 |
972fd6df0e638be5a48e91507fdd1fe1
|
|
| BLAKE2b-256 |
b80bd9c565009ccf4edbdc0134cc2e34b0a1e53a70e604e9382bef75fa7b6132
|