A 3D optical ray tracer written in Python and NumPy, built as part of Imperial College London's second-year physics computing project. It propagates bundles of rays through sequences of refracting surfaces using a vector form of Snell's law, locates focal points, and quantifies imaging performance through spot diagrams and RMS spot-size analysis against the diffraction limit.
- Vector refraction.
physics.refractimplements Snell's law in full vector form on arbitrary surface normals, returning the refracted direction and handling total internal reflection. - Optical elements. A small class hierarchy (
OpticalElement→Sphere→SphericalRefraction, plusPlane/OutputPlane) where each element knows how to intercept and propagate a ray. Spherical surfaces compute their own paraxial focal point. - Compound lenses.
PlanoConvexandConvexPlanolenses are composed of two refracting surfaces, allowing direct comparison of the two orientations of the same singlet. - Ray bundles.
RayBundlegenerates concentric rings of parallel rays, propagates them through any element sequence, and produces 3D track plots, focal-plane spot diagrams, and the RMS spot size of the bundle. - Aberration analysis. The analysis tasks sweep input beam radius and compare the geometric RMS spot size against the diffraction scale λf/2r, locating the beam radius at which spherical aberration overtakes diffraction as the dominant blur. The plano-convex vs convex-plano comparison shows the classic result that orientation alone changes the aberration of an identical lens.
raytracer/
├── rays.py # Ray and RayBundle
├── physics.py # vector Snell's law refraction
├── elements.py # OpticalElement, Sphere, SphericalRefraction, Plane, OutputPlane
├── lenses.py # PlanoConvex and ConvexPlano singlet lenses
└── analysis.py # analysis tasks: focal points, spot diagrams, aberration sweeps
tests/ # pytest suite, including code-quality checks (pylint, pydocstyle, darglint)
Trace a bundle through a single refracting surface and measure the spot at its focal plane:
from raytracer.rays import RayBundle
from raytracer.elements import SphericalRefraction, OutputPlane
surface = SphericalRefraction(z_0=100, aperture=10, curvature=0.03, n_1=1.0, n_2=1.5)
screen = OutputPlane(surface.focal_point())
bundle = RayBundle(rmax=5.0, nrings=5, multi=6)
bundle.propagate_bundle([surface, screen])
bundle.track_plot() # 3D ray paths
bundle.spot_plot() # spot diagram at the focal plane
print(f"RMS spot size: {bundle.rms():.4f} mm")pip install -e .
pytestThe test suite checks both physical correctness of the tasks and code quality via pylint, pydocstyle and darglint.
Written for Imperial's Year 2 Physics Computing Lab (Project A). The project brief and test scaffolding were provided by the course; all ray-tracing physics, element classes, lens models and analysis are my own implementation.