Quick Start =========== This guide will get you started with L-SURF in minutes. Full Simulation Pipeline ------------------------ The recommended approach uses ``GeometryBuilder`` to define your simulation geometry and ``Simulation`` to run the ray tracing: .. code-block:: python import lsurf as sr from lsurf.geometry import GeometryBuilder from lsurf.simulation import Simulation, SimulationConfig from lsurf.surfaces import SphereSurface, PlaneSurface, SurfaceRole # Constants EARTH_RADIUS = 6.371e6 # meters # Create materials atmosphere = sr.ExponentialAtmosphere(n_sea_level=1.000293) # Create surfaces with roles ocean = SphereSurface( center=(0, 0, -EARTH_RADIUS), radius=EARTH_RADIUS, role=SurfaceRole.OPTICAL, # Reflects/refracts rays name="ocean", ) detector = PlaneSurface( point=(0, 0, 35000), normal=(0, 0, 1), role=SurfaceRole.DETECTOR, # Records rays name="detector_35km", ) # Build geometry with named media geometry = ( GeometryBuilder() .register_medium("atmosphere", atmosphere) .register_medium("ocean", sr.WATER) .set_background("atmosphere") .add_surface(ocean, front="atmosphere", back="ocean") .add_detector(detector) .build() ) # Configure simulation config = SimulationConfig( step_size=100.0, # Maximum step size (meters) max_bounces=5, # Maximum surface interactions min_intensity=1e-10, # Terminate weak rays ) # Create and run simulation sim = Simulation(geometry, config) source = sr.CollimatedBeam( center=(0, 0, 1000), direction=(0.17, 0, -0.98), radius=10.0, num_rays=10000, wavelength=532e-9, ) result = sim.run(source.generate()) 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: .. code-block:: python import lsurf as sr # Create a flat water surface at z=0 surface = sr.PlanarSurface( point=(0, 0, 0), normal=(0, 0, 1), material_front=sr.AIR_STP, material_back=sr.WATER, role=sr.SurfaceRole.OPTICAL, name="water", ) # Create a collimated beam at 45° incidence source = sr.CollimatedBeam( center=(0, 0, 0.1), direction=(0.707, 0, -0.707), radius=0.01, num_rays=1000, wavelength=532e-9, ) rays = source.generate() # Process surface interaction 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}") Key Concepts ------------ GeometryBuilder ~~~~~~~~~~~~~~~ The ``GeometryBuilder`` provides a fluent interface for constructing simulations: 1. **Register media** - Name your materials for consistency across surfaces 2. **Set background** - Define the ambient propagation medium 3. **Add surfaces** - Add optical surfaces with front/back media 4. **Add detectors** - Add detection surfaces 5. **Build** - Create the immutable ``Geometry`` object .. code-block:: python geometry = ( GeometryBuilder() .register_medium("air", sr.AIR_STP) .register_medium("glass", sr.BK7_GLASS) .set_background("air") .add_surface(lens, front="air", back="glass") .add_detector(screen) .build() ) SimulationConfig ~~~~~~~~~~~~~~~~ Configure simulation behavior with ``SimulationConfig``: .. code-block:: python config = SimulationConfig( step_size=100.0, # Max step size (meters) min_step_size=3e-4, # Min step (0.3mm → ~1ps resolution) adaptive_stepping=True, # Reduce step near surfaces max_bounces=10, # Max surface interactions min_intensity=1e-10, # Terminate weak rays bounding_radius=500_000.0, # Terminate rays outside this polarization="unpolarized", # 's', 'p', or 'unpolarized' use_gpu=True, # Use GPU if available ) Surface Roles ~~~~~~~~~~~~~ Surfaces have roles that determine their behavior: * **SurfaceRole.OPTICAL** - Reflects and/or refracts rays (Fresnel) * **SurfaceRole.DETECTOR** - Records rays that hit (terminates them) * **SurfaceRole.ABSORBER** - Terminates rays without recording Surfaces ~~~~~~~~ L-SURF supports several surface types: * **PlaneSurface** - Flat surfaces (mirrors, windows, detectors) * **SphereSurface** - Curved spherical surfaces (lenses, curved Earth) * **GerstnerWaveSurface** - Ocean wave surfaces (CPU) * **CurvedWaveSurface** - Large-scale curved ocean surfaces (CPU) * **GPUCurvedWaveSurface** - GPU-accelerated curved wave surfaces * **LocalRecordingSphereSurface** - Spherical detector at altitude Materials ~~~~~~~~~ Built-in materials: * ``AIR_STP`` - Standard temperature/pressure air (n ≈ 1.000293) * ``WATER`` - Pure water (n ≈ 1.33) * ``BK7_GLASS`` - Common optical glass (n ≈ 1.52) * ``VACUUM`` - Perfect vacuum (n = 1.0) * ``ExponentialAtmosphere`` - Height-dependent refractive index Ray Sources ~~~~~~~~~~~ Generate rays from various sources: * **PointSource** - Point source with spherical emission * **CollimatedBeam** - Parallel beam of rays * **DivergingBeam** - Diverging conical beam * **GaussianBeam** - Gaussian intensity profile Simulation Results ~~~~~~~~~~~~~~~~~~ The ``SimulationResult`` contains: .. code-block:: python result = sim.run(rays) # Access detected rays detected = result.detected # RecordedRays object print(f"Detected {detected.num_rays} rays") print(f"Positions: {detected.positions.shape}") print(f"Times: {detected.times}") # Statistics stats = result.statistics print(f"Total created: {stats.total_rays_created}") print(f"Detected: {stats.rays_detected}") print(f"Absorbed: {stats.rays_absorbed}") print(f"Bounces: {stats.bounces_completed}") # Per-detector counts for name, count in result.detections_per_surface.items(): print(f" {name}: {count} hits") Logging ~~~~~~~ Enable logging to see simulation progress: .. code-block:: python import lsurf as sr # INFO level shows simulation summaries sr.configure_logging("INFO") # DEBUG level shows per-bounce details sr.configure_logging("DEBUG") Next Steps ---------- * :doc:`examples/index` - Walk through example applications * :doc:`user_guide/index` - Detailed user guide * :doc:`api/index` - Complete API reference