Source code for optiland.nonsequential.results.spectral_result

"""Spectral irradiance result for Non-Sequential Raytracing.

Kramer Harrison, 2026
"""

from __future__ import annotations

from typing import TYPE_CHECKING

import numpy as np

if TYPE_CHECKING:
    from pathlib import Path


[docs] class SpectralResult: """Per-wavelength irradiance on a planar detector. Attributes: irradiance: Irradiance per wavelength bin [W/mm^2], shape (ny, nx, n_lambda). Flux is binned, not divided by bin width, so summing over the last axis gives the broadband irradiance. x_coords: Bin centre x-coordinates [mm]. y_coords: Bin centre y-coordinates [mm]. wavelengths: Wavelength bin centres [µm]. total_flux: Total flux recorded [W]. num_rays_hit: Number of rays recorded. """ def __init__( self, irradiance: np.ndarray, x_coords: np.ndarray, y_coords: np.ndarray, wavelengths: np.ndarray, total_flux: float, num_rays_hit: int, ) -> None: """Initialize SpectralResult. Args: irradiance: 3D irradiance array [W/mm^2], shape (ny, nx, n_lambda). x_coords: Bin centre x-coordinates [mm]. y_coords: Bin centre y-coordinates [mm]. wavelengths: Wavelength bin centres [µm]. total_flux: Total detected flux [W]. num_rays_hit: Number of rays that contributed. """ self.irradiance = irradiance self.x_coords = x_coords self.y_coords = y_coords self.wavelengths = wavelengths self.total_flux = float(total_flux) self.num_rays_hit = int(num_rays_hit)
[docs] def plot_at_wavelength(self, wl: float, ax=None, **kwargs): """Plot the irradiance map at the wavelength closest to wl. Args: wl: Target wavelength [µm]. ax: Optional Matplotlib Axes. **kwargs: Additional arguments passed to imshow. Returns: The Matplotlib Figure object. """ import matplotlib.pyplot as plt # noqa: PLC0415 idx = int(np.argmin(np.abs(self.wavelengths - wl))) actual_wl = float(self.wavelengths[idx]) if ax is None: fig, ax = plt.subplots() else: fig = ax.get_figure() extent = [ self.x_coords[0], self.x_coords[-1], self.y_coords[0], self.y_coords[-1], ] im = ax.imshow( self.irradiance[:, :, idx], origin="lower", extent=extent, aspect="equal", **kwargs, ) plt.colorbar(im, ax=ax, label="Irradiance [W/mm^2]") ax.set_title(f"Irradiance at wl={actual_wl:.3f} µm") return fig
[docs] def save(self, path: str | Path) -> None: """Save spectral result to a .npz file. Args: path: Output file path. """ np.savez( path, irradiance=self.irradiance, x_coords=self.x_coords, y_coords=self.y_coords, wavelengths=self.wavelengths, total_flux=self.total_flux, num_rays_hit=self.num_rays_hit, )