Source code for eradiate.scenes.spectra._multi_delta
from __future__ import annotations
import attrs
import numpy as np
import pint
import pinttr
from ._core import Spectrum
from ...attrs import documented, parse_docs
from ...spectral.ckd import BinSet
from ...spectral.mono import WavelengthSet
from ...units import unit_context_kernel as uck
from ...units import unit_registry as ureg
def wavelengths_converter(value):
return np.sort(np.atleast_1d(value))
[docs]@parse_docs
@attrs.define(eq=False, slots=False)
class MultiDeltaSpectrum(Spectrum):
"""
A spectrum made of multiple translated Dirac delta [``multi_delta``].
Notes
-----
This spectrum is for special use.
It does not have a kernel representation.
The spectrum cannot be evaluated.
As a result, neither can it be plotted.
"""
wavelengths: pint.Quantity = documented(
pinttr.field(
default=550.0 * ureg.nm,
units=uck.deferred("wavelength"),
converter=[
wavelengths_converter,
pinttr.converters.to_units(uck.deferred("wavelength")),
],
),
doc="An array of wavelengths specifying the translation wavelength of each "
"Dirac delta. Wavelength values are positive and unique."
"When a single value is provided, it is converted to a 1-element array."
"Wavelength values are sorted by increasing magnitude.",
type="quantity",
init_type="array-like or quantity",
)
@wavelengths.validator
def _w_validator(self, attribute, value):
if not np.all(value > 0):
raise ValueError(f"w values must be all positive (got {value})")
if np.unique(value.m).size != value.m.size:
raise ValueError(f"w values must be unique (got {value})")
[docs] def eval_mono(self, w: pint.Quantity) -> pint.Quantity:
raise NotImplementedError
[docs] def eval_ckd(self, w: pint.Quantity, g: float) -> pint.Quantity:
raise NotImplementedError
[docs] def integral(self, wmin: pint.Quantity, wmax: pint.Quantity) -> pint.Quantity:
raise NotImplementedError
@property
def template(self) -> dict:
raise NotImplementedError
@property
def params(self) -> dict:
raise NotImplementedError
def select_in_wavelength_set(self, wset: WavelengthSet) -> WavelengthSet:
# the input wavelength set is completely ignored
# only the attribute wavelengths are included in the returned
# wavelength set
return WavelengthSet(self.wavelengths)
def select_in_bin_set(self, binset: BinSet) -> BinSet:
bins = binset.bins
wunits = "nm"
xmin = np.array([bin.wmin.m_as(wunits) for bin in bins])
xmax = np.array([bin.wmax.m_as(wunits) for bin in bins])
x = self.wavelengths.m_as(wunits)
selected = _select(xmin, xmax, x)
return BinSet(bins=list(np.array(bins)[selected]))
def _select(xmin, xmax, x):
selmin = np.searchsorted(xmin, x)
selmax = np.searchsorted(xmax, x) + 1
hit = selmin == selmax # Mask where x values which triggered a bin hit
# Map x values to selected bin (index -999 means not selected)
bin_index = np.where(hit, selmin - 1, np.full_like(x, -999)).astype("int")
# Get selected bins only
selected = np.unique(bin_index)[bin_index >= 0] # mask removes -999 value
return selected