Skip to main content

L-SURF: GPU-accelerated physically-accurate raytracing framework for simulating light-surface interactions

Project description

L-SURF

L-SURF Logo

PyPI version Python 3.13+ License Documentation

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:

  1. NVIDIA GPU with CUDA Compute Capability 3.5+ (most GPUs from 2012 onwards)
  2. NVIDIA Driver (version 450+ recommended)
  3. 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:

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lsurf-1.0.0.tar.gz (555.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lsurf-1.0.0-py3-none-any.whl (648.9 kB view details)

Uploaded Python 3

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

Hashes for lsurf-1.0.0.tar.gz
Algorithm Hash digest
SHA256 9384e8a40ce5bca77369fb29fe6282754bb31f559965575204c2f9cc93d00862
MD5 792a633ffd0c90a711fbfb97c1e867c1
BLAKE2b-256 93897f303b5dbbc87cf468d319163aa3065d2e48f2c37785b3dbee7f4ee785b5

See more details on using hashes here.

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

Hashes for lsurf-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 47e5e384cf04b93b18dcb4e8dda60d0556657e59b3310874cf919c9829cb3b75
MD5 1d27d797078ebac99e096c590d784c2d
BLAKE2b-256 be31526675f6f8573526c163c3364b8edfeb4f193ec791622df2fb232e96dd8a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page