3D polarization vector (electric field direction), shape (N, 3)
Unit vector perpendicular to ray direction representing E-field orientation.
Used for tracking polarization state through reflections/refractions.
>>> # Air to glass at 45 degrees>>> cos_theta_i=np.cos(np.radians(45))>>> R,T=fresnel_coefficients(1.0,1.5,cos_theta_i)>>> print(f"Reflection: {R:.3f}, Transmission: {T:.3f}")
Compute reflected ray direction using law of reflection.
Parameters:
incident (ndarray, shape (N, 3)) – Incident ray directions (should be normalized)
normal (ndarray, shape (N, 3)) – Surface normals at intersection points (should be normalized)
Returns:
reflected – Reflected ray directions (normalized)
Return type:
ndarray, shape (N, 3)
Notes
Reflection formula: r = d - 2(d·n)n
where d is incident direction and n is surface normal.
The normal should point toward the incident side.
Examples
>>> # Reflect ray at 45° off horizontal surface>>> incident=np.array([[1/np.sqrt(2),0,-1/np.sqrt(2)]])>>> normal=np.array([[0,0,1]])>>> reflected=compute_reflection_direction(incident,normal)>>> print(reflected)# Should be [1/√2, 0, 1/√2]
Vector form of Snell’s law:
t = (n1/n2)[d - (d·n)n] - n*sqrt(1 - (n1/n2)²*[1-(d·n)²])
Total internal reflection occurs when (n1/n2)²*[1-(d·n)²] > 1
Examples
>>> # Air to glass at normal incidence>>> incident=np.array([[0,0,-1]])>>> normal=np.array([[0,0,1]])>>> refracted,tir=compute_refraction_direction(incident,normal,1.0,1.5)>>> print(refracted)# Should be [0, 0, -1] (straight through)>>> print(tir)# Should be False
Propagator for inhomogeneous media using ray equation integration.
This propagator handles materials with spatially-varying refractive
indices by numerically integrating the ray equation (eikonal equation).
Supports both Euler and RK4 integration methods.
This is the unified interface method compatible with GPU propagators.
Delegates to propagate_step_cpu internally.
Parameters:
rays (RayBatch) – Ray batch containing positions, directions, and other ray properties.
Modified in-place.
step_size (float) – Integration step size in meters.
wavelength (float, optional) – Wavelength in meters, default 532 nm.
material (MaterialFieldProtocol, optional) – Material to propagate through. If not provided, must be set via
a separate mechanism (e.g., stored during initialization).
compute_travel_time (bool) – If True, add travel time to intersection to ray’s accumulated time
speed_of_light (float) – Speed of light for time computation
max_propagation_distance (float, optional) – Maximum distance rays can propagate before detection (meters).
If None, no limit is applied. Use this to prevent detecting rays
that would hit the sphere from the opposite hemisphere.
Dictionary with:
- ‘elevation’: Latitude angle above equator (radians, -π/2 to π/2)
- ‘azimuth’: Longitude angle (radians, -π to π)
- ‘zenith’: Zenith angle from north pole (radians, 0 to π)
- ‘incidence’: Angle between ray direction and outward radial (radians)
Compute elevation and azimuth angles of ray directions.
Calculates the angles of the ray direction vectors themselves,
not the position coordinates. Useful for understanding the
angular distribution of ray propagation.
Returns:
Dictionary with:
- ‘elevation’: Angle above horizontal plane in radians (-π/2 to π/2)
Estimate time spread for a diverging beam reflecting to a detector.
Computes geometric path lengths from source through surface edge points
to detector, giving an upper bound estimate on arrival time spread.
Parameters:
source_position (tuple) – (x, y, z) source position in meters
beam_direction (tuple) – Beam center direction (will be normalized)
divergence_angle (float) – Beam half-angle divergence in radians
detector_position (tuple) – (x, y, z) detector position in meters
surface (Surface, optional) – Surface object to intersect with (e.g., GerstnerWaveSurface,
CurvedWaveSurface, PlanarSurface). If None, uses flat surface at z=0.
n_edge_points (int) – Number of points around beam edge for sampling
divergence_angle (float) – Beam half-angle divergence in radians
detector_positions (ndarray, shape (N, 3)) – Array of detector positions to evaluate
surface (Surface, optional) – Surface object to intersect with. If None, uses flat surface at z=0.
n_edge_points (int) – Number of edge points for beam footprint
Returns:
Dictionary containing:
- time_spread_ns : ndarray, shape (N,) - Time spread at each position
- path_spread : ndarray, shape (N,) - Path spread at each position
- min_path : ndarray, shape (N,) - Minimum path at each position
- max_path : ndarray, shape (N,) - Maximum path at each position
Compute where the edges of a diverging beam hit a surface.
Parameters:
source_position (tuple) – (x, y, z) position of the source in meters
beam_direction (tuple) – Unit vector of beam center direction
divergence_angle (float) – Half-angle divergence of the beam in radians
n_edge_points (int) – Number of points around the beam edge cone
surface (Surface, optional) – Surface object to intersect with (e.g., GerstnerWaveSurface,
CurvedWaveSurface, PlanarSurface). If None, uses flat surface at z=0.
Returns:
Dictionary containing:
- edge_points : ndarray, shape (N, 3) - Surface intersection points
- center_point : ndarray, shape (3,) - Center ray intersection
- edge_distances : ndarray - Distances from source to each edge point
- center_distance : float - Distance from source to center point
This function uses lat/lon binning which has anisotropic resolution
(bins are smaller near poles). For more uniform resolution, use
find_peak_irradiance_local() which uses local tangent plane coordinates.
Find peak irradiance using local tangent plane coordinates.
Uses a local East-North coordinate system centered on the peak region,
providing constant resolution in physical units (meters). This avoids
the polar singularities and anisotropic bin sizes of lat/lon binning.
Parameters:
recorded_rays (RecordedRays) – Recorded rays on detection sphere
detector_radius (float) – Radius of the detector sphere (m)
detector_center (array-like, optional) – Center of the detector sphere (default origin)
n_bins (int) – Number of bins in each dimension (default 50)
bin_size_meters (float, optional) – Physical size of each bin in meters. If None, auto-computed
to cover the data extent with n_bins.
Returns:
Dictionary containing:
- peak_east, peak_north: Peak location in local coordinates (m)
- peak_lon, peak_lat: Peak location in radians
- peak_lon_deg, peak_lat_deg: Peak location in degrees
- peak_position: Peak location in Cartesian (x, y, z)
- peak_irradiance: Irradiance at peak (W/m²)
- total_power: Total detected power (W)
- histogram: 2D irradiance histogram
- east_edges, north_edges: Bin edges in local coords (m)
- bin_size: Physical bin size (m)
Compute Pareto front for irradiance vs time spread trade-off.
Parameters:
recorded_rays (RecordedRays) – Recorded rays on detection sphere
detector_radius (float) – Radius of the detector sphere (m)
detector_center (array-like, optional) – Center of the detector sphere (default origin)
n_bins (int) – Number of bins in each angular dimension
min_rays_per_bin (int) – Minimum rays required per bin for reliable statistics
Returns:
Dictionary containing:
- bin_data: List of dicts with (lon, lat, irradiance, time_spread, n_rays)
- pareto_indices: Indices of Pareto-optimal bins
- pareto_front: List of Pareto-optimal bin data
- all_irradiances: Array of all bin irradiances (W/m²)
- all_time_spreads: Array of all bin time spreads
min_rays_per_pixel (int) – Minimum rays required per pixel for valid statistics
Returns:
Dictionary containing:
- peak_pixel_id: HEALPix pixel with highest irradiance
- peak_lon_deg, peak_lat_deg: Peak location in degrees
- peak_irradiance: Irradiance at peak (W/m²)
- total_power: Total detected power (W)
- pixel_area: Area of each HEALPix pixel (m²)
- pixel_data: List of dicts with per-pixel data:
min_rays_per_pixel (int) – Minimum rays required per pixel for valid statistics
Returns:
Dictionary containing:
- pixel_data: List of all valid pixel dicts
- pareto_indices: Indices of Pareto-optimal pixels
- pareto_front: List of Pareto-optimal pixel data
- all_irradiances: Array of all pixel irradiances
- all_time_spreads: Array of all pixel time spreads
wavelength (float or ndarray, optional) – Wavelength for computing refractive indices (default: 500 nm)
If rays have multiple wavelengths, use rays.wavelengths
polarization (str, optional) – Polarization state: ‘s’, ‘p’, or ‘unpolarized’ (default)
Used for Fresnel coefficient calculation.
track_polarization_vector (bool, optional) – Whether to track 3D polarization vectors through the interaction.
If True, polarization vectors are initialized (if not present) and
transformed through reflection/refraction. (default: False)
Returns:
reflected_rays (RayBatch or None) – Reflected rays (None if generate_reflected=False or no hits)
refracted_rays (RayBatch or None) – Refracted rays (None if generate_refracted=False or no hits)
Only active rays are tested for intersection.
Input rays are not modified.
When track_polarization_vector=True, the function:
1. Initializes polarization vectors if rays.polarization_vector is None
2. Transforms polarization vectors through reflection/refraction
3. Stores the transformed vectors in the output ray batches
Examples
>>> # Create surface and rays>>> surface=PlanarSurface(... point=(0,0,1),... normal=(0,0,-1),... material_front=BK7_GLASS,... material_back=AIR_STP... )>>> rays=...# Create rays>>>>>> # Process interaction with polarization tracking>>> reflected,refracted=process_surface_interaction(... rays,surface,generate_reflected=True,generate_refracted=True,... track_polarization_vector=True... )
final_reflected (RayBatch) – Final state of all reflected rays that exited bounding sphere
final_refracted (RayBatch) – Final state of all refracted rays (combined from all bounces)
ray_paths (dict) – Dictionary containing:
- ‘reflected_paths’: list of paths, each path is Nx3 array of positions
- ‘refracted_paths’: list of paths for refracted rays (start from refraction point)
- ‘reflected_final_dirs’: list of final direction vectors for each reflected path
- ‘refracted_final_dirs’: list of final direction vectors for each refracted path
The function tracks reflected rays through multiple bounces on the
wavy surface. Each ray’s complete path (all positions) is stored for
visualization. Refracted rays are collected but not further traced
(they go into the water and don’t re-interact with the air-water
interface from below in typical scenarios).
Examples
>>> # Trace rays with up to 5 bounces>>> final_refl,final_refr,paths=trace_rays_multi_bounce(... rays,surface,max_bounces=5,bounding_radius=5000.0... )>>> # Plot a ray's path>>> path=paths['reflected_paths'][0]# First ray's path>>> plt.plot(path[:,0],path[:,2])# x-z projection
Trace rays through multiple surfaces with proper Fresnel ray splitting.
At each surface interaction, every ray is split into two child rays:
- A reflected ray with intensity scaled by the Fresnel reflection coefficient R
- A refracted ray with intensity scaled by the Fresnel transmission coefficient T
This creates a ray tree where both reflected and refracted paths are traced
until termination conditions are met.
surfaces (list of Surface) – List of surfaces to interact with (tested in order for closest hit)
max_bounces (int, optional) – Maximum number of surface interactions per ray tree branch (default: 10)
bounding_radius (float, optional) – Radius of bounding sphere in meters (default: 10000)
bounding_center (tuple of float, optional) – Center of bounding sphere (x, y, z) in meters. Default is (0, 0, 0).
For curved Earth simulations, use (0, 0, -EARTH_RADIUS).
wavelength (float, optional) – Wavelength for Fresnel calculations (default: 532nm)
min_intensity (float, optional) – Minimum intensity threshold for ray termination (default: 1e-10)
final_rays (RayBatch) – All terminal rays (rays that exited the scene or hit max bounces)
Each ray has its intensity weighted by the product of all Fresnel
coefficients along its path.
trace_info (dict) – Dictionary containing tracing statistics:
- ‘total_rays_created’: Total number of rays created during tracing
- ‘max_depth_reached’: Maximum tree depth reached
- ‘terminated_by_intensity’: Number of rays terminated due to low intensity
- ‘terminated_by_bounds’: Number of rays that exited bounding sphere
- ‘terminated_by_max_bounces’: Number of rays that hit max bounce limit