L-SURF: GPU-accelerated physically-accurate raytracing framework for simulating light-surface interactions
Project description
L-SURF
Light SURFace Reflections - GPU-accelerated physically-accurate raytracing framework for simulating light-surface interactions.
Documentation: https://l-surf-b86f2d.gitlab.io
Features
- Fresnel reflection and refraction - Physically accurate polarization-dependent coefficients
- Multiple scattering - Multi-bounce ray tracing with intensity splitting
- Ocean wave surfaces - Gerstner wave modeling with curved Earth geometry
- GPU acceleration - CUDA-accelerated via Numba for high-performance simulations
- Wavelength-dependent materials - Sellmeier and Cauchy dispersion models
- Polarization tracking - s and p polarization component handling
Installation
Prerequisites
NVIDIA GPU Support (Recommended)
For GPU-accelerated ray tracing, you need:
- NVIDIA GPU with CUDA Compute Capability 3.5+ (most GPUs from 2012 onwards)
- NVIDIA Driver (version 450+ recommended)
- CUDA Toolkit (version 11.0+ recommended)
Check your system:
# Check NVIDIA driver
nvidia-smi
# Check CUDA version (if installed)
nvcc --version
Installing NVIDIA drivers (if needed):
# Ubuntu/Debian
sudo apt update
sudo apt install nvidia-driver-535 # or latest version
# Fedora
sudo dnf install akmod-nvidia
Installing CUDA Toolkit:
- Download from NVIDIA CUDA Downloads
- Or use your distribution's package manager
Note: The package works without a GPU (CPU fallback), but simulations will be significantly slower.
Python Environment
- Python >= 3.13
- pip, conda, or mamba
Install from PyPI
pip install lsurf
Development Installation
git clone https://github.com/tobi-h/lsurf.git
cd lsurf
pip install -e .
Verifying GPU Setup
After installation, verify everything works:
from numba import cuda
# Check CUDA availability
print(f"CUDA available: {cuda.is_available()}")
if cuda.is_available():
gpu = cuda.get_current_device()
print(f"GPU: {gpu.name}")
print(f"Compute Capability: {gpu.compute_capability}")
print(f"Memory: {gpu.total_memory / 1e9:.1f} GB")
Troubleshooting
| Issue | Solution |
|---|---|
CUDA not available |
Install NVIDIA drivers and CUDA toolkit |
conda: PackagesNotFoundError |
Update conda: conda update -n base conda |
numba.cuda import error |
Ensure CUDA_HOME is set and nvcc is in PATH |
Out of memory |
Reduce num_rays or use batched processing |
Quick Start
Using the CLI (Recommended)
The command-line interface is the recommended way to run simulations:
# Build a configuration interactively
lsurf build -o my_simulation.yaml
# Or use a built-in template
lsurf build --template ocean -o ocean_sim.yaml
# Validate the configuration
lsurf run my_simulation.yaml --dry-run
# Run the simulation
lsurf run my_simulation.yaml --progress
# Run with custom parameters
lsurf run my_simulation.yaml --num-rays 100000 --output-dir ./results
Using the GUI
For interactive exploration and visualization, use the graphical interface:
# Launch the GUI
lsurf gui
# Or load an existing configuration
lsurf gui my_simulation.yaml
The GUI provides:
- Interactive 3D visualization of geometry
- Configuration editor with live preview
- One-click simulation execution
- Built-in result visualization and analysis
Python API
For custom workflows and advanced use cases, use the Python API with GeometryBuilder:
import lsurf as sr
from lsurf.geometry import GeometryBuilder
from lsurf.simulation import Simulation, SimulationConfig
from lsurf.surfaces import SphereSurface, PlaneSurface, SurfaceRole
# Define constants
EARTH_RADIUS = 6.371e6 # meters
# Create materials
atmosphere = sr.ExponentialAtmosphere(n_sea_level=1.000293)
# Create surfaces
ocean = SphereSurface(
center=(0, 0, -EARTH_RADIUS),
radius=EARTH_RADIUS,
role=SurfaceRole.OPTICAL,
name="ocean",
)
detector = PlaneSurface(
point=(0, 0, 35000),
normal=(0, 0, 1),
role=SurfaceRole.DETECTOR,
name="detector_35km",
)
# Build geometry with named media
geometry = (
GeometryBuilder()
.register_medium("atmosphere", atmosphere)
.register_medium("ocean", sr.WATER)
.set_background("atmosphere") # Ray propagation medium
.add_surface(ocean, front="atmosphere", back="ocean")
.add_detector(detector)
.build()
)
# Configure simulation
config = SimulationConfig(
step_size=100.0, # Max step size in meters
max_bounces=5, # Maximum surface interactions
adaptive_stepping=True, # Use smaller steps near surfaces
min_step_size=3e-4, # 0.3mm for ~1ps time resolution
)
# Create simulation and run
sim = Simulation(geometry, config)
# Generate rays from a source
source = sr.CollimatedBeam(
center=(0, 0, 1000),
direction=(0.17, 0, -0.98), # ~10° grazing angle
radius=10.0,
num_rays=10000,
wavelength=532e-9,
)
rays = source.generate()
# Run simulation
result = sim.run(rays)
print(f"Detected: {result.statistics.rays_detected}")
print(f"Absorbed: {result.statistics.rays_absorbed}")
Simple Surface Interaction
For quick tests without the full simulation framework:
import lsurf as sr
# Create a water surface
surface = sr.PlaneSurface(
point=(0, 0, 0),
normal=(0, 0, 1),
material_front=sr.AIR_STP,
material_back=sr.WATER,
role=sr.SurfaceRole.OPTICAL,
name="water_surface",
)
# Create a collimated beam
source = sr.CollimatedBeam(
center=(0, 0, 0.1),
direction=(0.707, 0, -0.707), # 45° incidence
radius=0.01,
num_rays=1000,
wavelength=532e-9,
)
rays = source.generate()
# Process reflection/refraction
reflected, refracted = sr.process_surface_interaction(
rays, surface,
wavelength=532e-9,
generate_reflected=True,
generate_refracted=True,
)
print(f"Reflected rays: {reflected.num_rays}")
print(f"Refracted rays: {refracted.num_rays}")
Example Scripts
The scripts/ directory contains educational example scripts that demonstrate specific features and techniques. These are provided as learning resources and references for custom workflows.
Note: For standard simulations, use the CLI (
lsurf run) or GUI (lsurf gui) instead of writing custom scripts. The CLI/GUI handle configuration management, validation, and output automatically.
| Script | Description |
|---|---|
01_basic.py |
Basic raytracing setup |
02_sources.py |
Different ray source types |
03_visualization.py |
Visualization capabilities |
04_glass_reflection.py |
Fresnel reflection at glass interface |
05_water_brewster.py |
Brewster angle validation |
06_detector_scan.py |
Detector position scanning (planar) |
07_detector_scan_waves.py |
Detector scanning with wave surface |
08_detector_scan_waves_largescale.py |
Large-scale ocean simulation |
09_full_3d_curved_ocean.py |
Full 3D ray tracing with curved ocean surface |
10_time_spread_estimate.py |
Geometric time spread estimation |
Run an example:
cd scripts
python 01_basic.py
Dependencies
| Category | Packages |
|---|---|
| Core | numpy >= 1.24, matplotlib >= 3.7, pydantic >= 2.0 |
| GPU | numba >= 0.58, CUDA toolkit >= 11.0 |
| Optional | h5py >= 3.8 (HDF5 support), astropy-healpix (spherical analysis) |
| Dev | pytest, black, ruff, mypy, pre-commit |
All dependencies are automatically installed via environment.yml or pip install -e ".[dev]".
Project Structure
lsurf/
├── src/
│ └── lsurf/ # Main package
│ ├── geometry/ # GeometryBuilder and Geometry
│ ├── simulation/ # Simulation, SimulationConfig, results
│ ├── propagation/ # Ray propagation engines and GPU kernels
│ ├── materials/ # Material definitions (homogeneous, atmosphere)
│ ├── sources/ # Ray source generators
│ ├── surfaces/ # Surface geometries (cpu/ and gpu/)
│ ├── detectors/ # Detection and analysis
│ ├── utilities/ # Ray data, fresnel, recording
│ ├── visualization/ # Plotting functions
│ └── interactions.py # Surface interaction processing
├── scripts/ # Example scripts
├── tests/ # Test suite
├── docs/ # Sphinx documentation
├── pyproject.toml # Python packaging config
└── environment.yml # Development environment
Testing
pytest tests/ -v
License
Clear BSD License - see LICENSE for details.
Copyright (c) 2026 Tobias Heibges. All rights reserved.
Project details
Release history Release notifications | RSS feed
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 lsurf-1.0.0.tar.gz.
File metadata
- Download URL: lsurf-1.0.0.tar.gz
- Upload date:
- Size: 555.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9384e8a40ce5bca77369fb29fe6282754bb31f559965575204c2f9cc93d00862
|
|
| MD5 |
792a633ffd0c90a711fbfb97c1e867c1
|
|
| BLAKE2b-256 |
93897f303b5dbbc87cf468d319163aa3065d2e48f2c37785b3dbee7f4ee785b5
|
File details
Details for the file lsurf-1.0.0-py3-none-any.whl.
File metadata
- Download URL: lsurf-1.0.0-py3-none-any.whl
- Upload date:
- Size: 648.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47e5e384cf04b93b18dcb4e8dda60d0556657e59b3310874cf919c9829cb3b75
|
|
| MD5 |
1d27d797078ebac99e096c590d784c2d
|
|
| BLAKE2b-256 |
be31526675f6f8573526c163c3364b8edfeb4f193ec791622df2fb232e96dd8a
|