Source code for glotaran.builtin.megacomplexes.decay.irf

"""This package contains irf items."""


import numpy as np

from glotaran.model import ModelError
from glotaran.model import ModelItemTyped
from glotaran.model import ParameterType
from glotaran.model import attribute
from glotaran.model import item


[docs] @item class Irf(ModelItemTyped): """Represents an IRF."""
[docs] @item class IrfMultiGaussian(Irf): """ Represents a gaussian IRF. One width and one center is a single gauss. One center and multiple widths is a multiple gaussian. Multiple center and multiple widths is Double-, Triple- , etc. Gaussian. Parameters ---------- label: label of the irf center: one or more center of the irf as parameter indices width: one or more widths of the gaussian as parameter index center_dispersion_coefficients: polynomial coefficients for the dispersion of the center as list of parameter indices. None for no dispersion. width_dispersion_coefficients: polynomial coefficients for the dispersion of the width as parameter indices. None for no dispersion. """ type: str = "multi-gaussian" center: list[ParameterType] width: list[ParameterType] scale: list[ParameterType] | None = None shift: list[ParameterType] | None = None normalize: bool = True backsweep: bool = False backsweep_period: ParameterType | None = None
[docs] def parameter( self, global_index: int, global_axis: np.ndarray ) -> tuple[np.ndarray, np.ndarray, np.ndarray, float, bool, float]: """Returns the properties of the irf with shift applied.""" centers = self.center if isinstance(self.center, list) else [self.center] centers = np.asarray([c.value for c in centers]) widths = self.width if isinstance(self.width, list) else [self.width] widths = np.asarray([w.value for w in widths]) len_centers = len(centers) len_widths = len(widths) if len_centers != len_widths: if min(len_centers, len_widths) != 1: raise ModelError( f"len(centers) ({len_centers}) not equal " f"len(widths) ({len_widths}) none of is 1." ) if len_centers == 1: centers = np.asarray([centers[0] for _ in range(len_widths)]) else: widths = np.asarray([widths[0] for _ in range(len_centers)]) scales = self.scale if self.scale is not None else [1.0 for _ in centers] scales = scales if isinstance(scales, list) else [scales] scales = np.asarray(scales) shift = 0 if self.shift is not None: if global_index >= len(self.shift): raise ModelError( f"No shift parameter for index {global_index} " f"({global_axis[global_index]}) in irf {self.label}" ) shift = self.shift[global_index] backsweep = self.backsweep backsweep_period = self.backsweep_period.value if self.backsweep else 0 return centers, widths, scales, shift, backsweep, backsweep_period
[docs] def calculate(self, index: int, global_axis: np.ndarray, model_axis: np.ndarray) -> np.ndarray: centers, widths, scales, _, _, _ = self.parameter(index, global_axis) return sum( scale * np.exp(-1 * (model_axis - center) ** 2 / (2 * width**2)) for center, width, scale in zip(centers, widths, scales) )
[docs] def is_index_dependent(self): return self.shift is not None
[docs] @item class IrfGaussian(IrfMultiGaussian): type: str = "gaussian" center: ParameterType width: ParameterType
[docs] @item class IrfSpectralMultiGaussian(IrfMultiGaussian): """ Represents a gaussian IRF. One width and one center is a single gauss. One center and multiple widths is a multiple gaussian. Multiple center and multiple widths is Double-, Triple- , etc. Gaussian. Parameters ---------- label: label of the irf center: one or more center of the irf as parameter indices width: one or more widths of the gaussian as parameter index center_dispersion_coefficients: list of parameters with polynomial coefficients describing the dispersion of the irf center location. None for no dispersion. width_dispersion_coefficients: list of parameters with polynomial coefficients describing the dispersion of the width of the irf. None for no dispersion. """ type: str = "spectral-multi-gaussian" dispersion_center: ParameterType center_dispersion_coefficients: list[ParameterType] width_dispersion_coefficients: list[ParameterType] = attribute(factory=list) model_dispersion_with_wavenumber: bool = False
[docs] def parameter(self, global_index: int, global_axis: np.ndarray): """Returns the properties of the irf with shift and dispersion applied.""" centers, widths, scale, shift, backsweep, backsweep_period = super().parameter( global_index, global_axis ) index = global_axis[global_index] if global_index is not None else None if self.dispersion_center is not None: dist = ( (1e3 / index - 1e3 / self.dispersion_center) if self.model_dispersion_with_wavenumber else (index - self.dispersion_center) / 100 ) if len(self.center_dispersion_coefficients) != 0: if self.dispersion_center is None: raise ModelError(f"No dispersion center defined for irf '{self.label}'") for i, disp in enumerate(self.center_dispersion_coefficients): centers += disp * np.power(dist, i + 1) if len(self.width_dispersion_coefficients) != 0: if self.dispersion_center is None: raise ModelError(f"No dispersion center defined for irf '{self.label}'") for i, disp in enumerate(self.width_dispersion_coefficients): widths = widths + disp * np.power(dist, i + 1) return centers, widths, scale, shift, backsweep, backsweep_period
[docs] def calculate_dispersion(self, axis): dispersion = [] for index, _ in enumerate(axis): center, _, _, _, _, _ = self.parameter(index, axis) dispersion.append(center) return np.asarray(dispersion).T
[docs] def is_index_dependent(self): return super().is_index_dependent() or self.dispersion_center is not None
[docs] @item class IrfSpectralGaussian(IrfSpectralMultiGaussian): type: str = "spectral-gaussian" center: ParameterType width: ParameterType