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.
Metadata
Release files for lsurf 1.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| lsurf-1.0.0.tar.gz | 555.4 kB | Without provenance | Details for lsurf-1.0.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| lsurf-1.0.0-py3-none-any.whl | Python 3 | none | any | Details for lsurf-1.0.0-py3-none-any.whl |
Total release size: 1.2 MB
Release files / lsurf-1.0.0.tar.gz
| Download URL | lsurf-1.0.0.tar.gz |
|---|---|
| Size | 555.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9384e8a40ce5bca77369fb29fe6282754bb31f559965575204c2f9cc93d00862
|
|
BLAKE2b-256 checksum How to use checksums |
93897f303b5dbbc87cf468d319163aa3065d2e48f2c37785b3dbee7f4ee785b5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Release files / lsurf-1.0.0-py3-none-any.whl
| Download URL | lsurf-1.0.0-py3-none-any.whl |
|---|---|
| Size | 648.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
47e5e384cf04b93b18dcb4e8dda60d0556657e59b3310874cf919c9829cb3b75
|
|
BLAKE2b-256 checksum How to use checksums |
be31526675f6f8573526c163c3364b8edfeb4f193ec791622df2fb232e96dd8a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.2
|
Security for lsurf 1.0.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.