Source code for glotaran.builtin.models.kinetic_spectrum.spectral_irf

import typing

import numba as nb
import numpy as np

from glotaran.builtin.models.kinetic_image.irf import Irf
from glotaran.builtin.models.kinetic_image.irf import IrfMultiGaussian
from glotaran.model import model_attribute
from glotaran.parameter import Parameter


[docs]@model_attribute( properties={ "dispersion_center": {"type": Parameter, "allow_none": True}, "center_dispersion": {"type": typing.List[Parameter], "default": []}, "width_dispersion": {"type": typing.List[Parameter], "default": []}, "model_dispersion_with_wavenumber": {"type": bool, "default": False}, }, has_type=True, ) 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: polynomial coefficients for the dispersion of the center as list of parameter indices. None for no dispersion. width_dispersion: polynomial coefficients for the dispersion of the width as parameter indices. None for no dispersion. """
[docs] def parameter(self, index): centers, widths, scale, backsweep, backsweep_period = super().parameter(index) 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) != 0: if self.dispersion_center is None: raise Exception(self, f'No dispersion center defined for irf "{self.label}"') for i, disp in enumerate(self.center_dispersion): centers += disp * np.power(dist, i + 1) if len(self.width_dispersion) != 0: if self.dispersion_center is None: raise Exception(self, f'No dispersion center defined for irf "{self.label}"') for i, disp in enumerate(self.width_dispersion): widths = widths + disp * np.power(dist, i + 1) return centers, widths, scale, backsweep, backsweep_period
[docs] def calculate_dispersion(self, axis): dispersion = [] for index in axis: center, _, _, _, _ = self.parameter(index) dispersion.append(center) return np.asarray(dispersion).T
[docs]@model_attribute( properties={ "center": Parameter, "width": Parameter, }, has_type=True, ) class IrfSpectralGaussian(IrfSpectralMultiGaussian): pass
[docs]@model_attribute( properties={ "coherent_artifact_order": {"type": int}, "coherent_artifact_width": {"type": Parameter, "allow_none": True}, }, has_type=True, ) class IrfGaussianCoherentArtifact(IrfSpectralGaussian):
[docs] def clp_labels(self): return [f"coherent_artifact_{i}" for i in range(1, self.coherent_artifact_order + 1)]
[docs] def calculate_coherent_artifact(self, axis): if not 1 <= self.coherent_artifact_order <= 3: raise Exception(self, "Coherent artifact order must be between in [1,3]") center, width, _, _, _ = self.parameter(None) center = center[0] width = ( self.coherent_artifact_width.value if self.coherent_artifact_width is not None else width[0] ) clp_label = self.clp_labels() matrix = self._calculate_coherent_artifact_matrix( center, width, axis, self.coherent_artifact_order ) return clp_label, matrix
@staticmethod @nb.jit(nopython=True, parallel=True) def _calculate_coherent_artifact_matrix(center, width, axis, order): matrix = np.zeros((axis.size, order), dtype=np.float64) matrix[:, 0] = np.exp(-1 * (axis - center) ** 2 / (2 * width ** 2)) if order > 1: matrix[:, 1] = matrix[:, 0] * (center - axis) / width ** 2 if order > 2: matrix[:, 2] = ( matrix[:, 0] * (center ** 2 - width ** 2 - 2 * center * axis + axis ** 2) / width ** 4 ) return matrix
Irf.add_type("spectral-multi-gaussian", IrfSpectralMultiGaussian) Irf.add_type("spectral-gaussian", IrfSpectralGaussian) Irf.add_type("gaussian-coherent-artifact", IrfGaussianCoherentArtifact)