Source code for qens.models.lineshapes

"""
Normalised lineshape primitives.

"""
from __future__ import annotations

import numpy as np

__all__ = ["lorentz", "gnorm", "lorentz_sum"]

#: smallest Γ allowed before clipping — below this Lorentzian becomes a δ-fn
GAMMA_FLOOR = 1e-5


[docs] def lorentz(omega: np.ndarray, gamma: float) -> np.ndarray: """Area normalised Lorentzian, half-width-at-half-maximum ``gamma``. .. math:: L(\\omega; \\Gamma) = \\frac{1}{\\pi} \\frac{\\Gamma}{\\omega^2 + \\Gamma^2} Parameters ---------- omega : array Energy-transfer grid (any unit; HWHM ``gamma`` must match). gamma : float HWHM. Will be clipped to ``GAMMA_FLOOR`` if smaller, to avoid producing a δ-function and breaking later FFT-convolutions. """ g = max(float(gamma), GAMMA_FLOOR) w = np.asarray(omega, dtype=float) return (1.0 / np.pi) * g / (w * w + g * g)
[docs] def gnorm(omega: np.ndarray, sigma: float) -> np.ndarray: """Area-normalised Gaussian with standard deviation ``sigma``. .. math:: G(\\omega; \\sigma) = \\frac{1}{\\sigma\\sqrt{2\\pi}} \\exp\\!\\left( -\\frac{\\omega^2}{2\\sigma^2} \\right) For FWHM use ``sigma = FWHM / 2.355``. """ if sigma <= 0: raise ValueError(f"sigma must be > 0, got {sigma}") w = np.asarray(omega, dtype=float) return np.exp(-0.5 * (w / sigma) ** 2) / (sigma * np.sqrt(2 * np.pi))
[docs] def lorentz_sum(omega: np.ndarray, weights: np.ndarray, gammas: np.ndarray, ) -> np.ndarray: """Weighted sum of Lorentzians: ``Σ w_i L(ω; Γ_i)``. Vectorised — useful for evaluating multi-channel rotational models on a Q-grid efficiently. Parameters ---------- omega : array, shape (N,) weights : array, shape (M,) gammas : array, shape (M,) Returns ------- array, shape (N,) """ weights = np.asarray(weights, dtype=float) gammas = np.maximum(np.asarray(gammas, dtype=float), GAMMA_FLOOR) w = np.asarray(omega, dtype=float)[:, None] L = (1.0 / np.pi) * gammas / (w * w + gammas * gammas) return L @ weights