epyr.lineshapes module

EPyR Tools - Lineshape Functions Module

Comprehensive collection of EPR lineshape functions for spectroscopy analysis. Includes Gaussian, Lorentzian, Voigt, and pseudo-Voigt profiles with:

  • Derivatives (1st and 2nd order)

  • Phase rotation (absorption/dispersion modes)

  • Spectrum convolution capabilities

  • Modern, optimized implementations

Classes and Functions:

Lineshape: Main lineshape class with all profiles gaussian: Pure Gaussian profiles lorentzian: Pure Lorentzian profiles voigtian: True Voigt profiles (convolution) pseudo_voigt: Pseudo-Voigt (linear combination) convspec: Spectrum convolution

Author: EPyR Tools Development Team License: MIT

class epyr.lineshapes.Lineshape(shape_type='gaussian', width=1.0, alpha=1.0, derivative=0, phase=0.0, normalize=True)[source]

Bases: object

Unified lineshape class for EPR spectroscopy.

This class provides a consistent interface for generating all types of EPR lineshapes including Gaussian, Lorentzian, Voigt, and pseudo-Voigt profiles with support for derivatives, phase rotation, and convolution.

Parameters:

shape_typestr, default=’gaussian’

Type of lineshape (‘gaussian’, ‘lorentzian’, ‘voigt’, ‘pseudo_voigt’)

widthfloat or tuple

Full width at half maximum - For single shapes: float - For Voigt: (gaussian_width, lorentzian_width) - For pseudo-Voigt: float (both components use same width)

alphafloat, default=1.0

Shape parameter for pseudo-Voigt (1=Gaussian, 0=Lorentzian)

derivativeint, default=0

Derivative order (0, 1, 2, or -1 for integral)

phasefloat, default=0.0

Phase rotation in radians (0=absorption, π/2=dispersion)

normalizebool, default=True

Whether to maintain area normalization

Examples:

>>> # Create Gaussian lineshape
>>> gauss = Lineshape('gaussian', width=5.0)
>>> x = np.linspace(-10, 10, 100)
>>> y = gauss(x, center=0)
>>>
>>> # Lorentzian with first derivative
>>> lorentz_deriv = Lineshape('lorentzian', width=4.0, derivative=1)
>>> y_deriv = lorentz_deriv(x, center=2)
>>>
>>> # Voigt profile with different widths
>>> voigt = Lineshape('voigt', width=(3.0, 2.0))
>>> y_voigt = voigt(x, center=0)
>>>
>>> # Pseudo-Voigt 50/50 mix
>>> pv = Lineshape('pseudo_voigt', width=5.0, alpha=0.5)
>>> y_pv = pv(x, center=0)
SUPPORTED_SHAPES = {'gaussian': <function gaussian>, 'general': <function lshape>, 'lorentzian': <function lorentzian>, 'pseudo_voigt': <function pseudo_voigt>, 'voigt': <function voigtian>}
__init__(shape_type='gaussian', width=1.0, alpha=1.0, derivative=0, phase=0.0, normalize=True)[source]
Parameters:
__call__(x, center, **override_params)[source]

Generate lineshape at specified points.

Parameters:

xarray

Abscissa points

centerfloat

Peak center position

**override_paramsdict

Parameters to override for this call only

Returns:

array

Lineshape values

Parameters:
Return type:

ndarray

absorption(x, center)[source]

Generate pure absorption lineshape

Parameters:
Return type:

ndarray

dispersion(x, center)[source]

Generate pure dispersion lineshape

Parameters:
Return type:

ndarray

derivative(x, center, order=1)[source]

Generate derivative lineshape

Parameters:
Return type:

ndarray

both_components(x, center)[source]

Generate both absorption and dispersion components.

Returns:

tuple

(absorption, dispersion) arrays

Parameters:
Return type:

Tuple[ndarray, ndarray]

set_width(width)[source]

Create new Lineshape with different width

Parameters:

width (float | Tuple[float, float])

Return type:

Lineshape

set_alpha(alpha)[source]

Create new Lineshape with different alpha (for pseudo-Voigt)

Parameters:

alpha (float)

Return type:

Lineshape

set_derivative(derivative)[source]

Create new Lineshape with different derivative order

Parameters:

derivative (int)

Return type:

Lineshape

set_phase(phase)[source]

Create new Lineshape with different phase

Parameters:

phase (float)

Return type:

Lineshape

info()[source]

Get lineshape information

Return type:

Dict[str, Any]

__repr__()[source]

String representation

Return type:

str

__str__()[source]

Human-readable string

Return type:

str

Parameters:
epyr.lineshapes.gaussian(x, center, width, derivative=0, phase=0.0, return_both=False)[source]

Area-normalized Gaussian lineshape with derivatives and phase rotation.

The Gaussian profile represents inhomogeneous broadening from statistical distributions of local fields or magnetic environments.

Parameters:

xarray

Abscissa points

centerfloat

Peak center position

widthfloat

Full width at half maximum (FWHM)

derivativeint, default=0

Derivative order: - 0: Standard lineshape - 1: First derivative - 2: Second derivative - -1: Integral from -∞

phasefloat, default=0.0

Phase rotation in radians - 0: Pure absorption - π/2: Pure dispersion

return_bothbool, default=False

If True, return (absorption, dispersion) tuple

Returns:

array or tuple

Gaussian values, optionally with dispersion component

Examples:

>>> x = np.linspace(-10, 10, 1000)
>>> # Standard absorption Gaussian
>>> y = gaussian(x, 0, 4)
>>> # First derivative
>>> dy = gaussian(x, 0, 4, derivative=1)
>>> # Dispersion mode
>>> disp = gaussian(x, 0, 4, phase=np.pi/2)
>>> # Both absorption and dispersion
>>> abs_part, disp_part = gaussian(x, 0, 4, return_both=True)
epyr.lineshapes.lorentzian(x, center, width, derivative=0, phase=0.0, return_both=False)[source]

Area-normalized Lorentzian lineshape with derivatives and phase rotation.

The Lorentzian profile is fundamental in magnetic resonance, representing homogeneous broadening from finite lifetimes and collision processes.

Parameters:

xarray

Abscissa points

centerfloat

Peak center position

widthfloat

Full width at half maximum (FWHM)

derivativeint, default=0

Derivative order: - 0: Standard lineshape - 1: First derivative - 2: Second derivative - -1: Integral from -∞

phasefloat, default=0.0

Phase rotation in radians - 0: Pure absorption - π/2: Pure dispersion

return_bothbool, default=False

If True, return (absorption, dispersion) tuple

Returns:

array or tuple

Lorentzian values, optionally with dispersion component

Examples:

>>> x = np.linspace(-10, 10, 1000)
>>> # Standard absorption Lorentzian
>>> y = lorentzian(x, 0, 4)
>>> # First derivative
>>> dy = lorentzian(x, 0, 4, derivative=1)
>>> # Dispersion mode
>>> disp = lorentzian(x, 0, 4, phase=np.pi/2)
>>> # Both absorption and dispersion
>>> abs_part, disp_part = lorentzian(x, 0, 4, return_both=True)
epyr.lineshapes.voigtian(x, center, widths, derivative=0, phase=0.0, return_both=False)[source]

Area-normalized Voigt profile - convolution of Gaussian and Lorentzian.

The Voigt profile models combined inhomogeneous (Gaussian) and homogeneous (Lorentzian) broadening mechanisms commonly found in magnetic resonance and optical spectroscopy.

Parameters:

xarray

Abscissa points

centerfloat

Peak center position

widthstuple of two floats

(gaussian_fwhm, lorentzian_fwhm) - Full widths at half maximum

derivativeint, default=0

Derivative order: - 0: Standard lineshape - 1: First derivative - 2: Second derivative - -1: Integral from -∞

phasefloat, default=0.0

Phase rotation in radians - 0: Pure absorption - π/2: Pure dispersion

return_bothbool, default=False

If True, return (absorption, dispersion) tuple

Returns:

array or tuple

Voigt profile values, optionally with dispersion component

Examples:

>>> x = np.linspace(-10, 10, 1000)
>>> # Equal Gaussian and Lorentzian widths
>>> y = voigtian(x, 0, (4, 4))
>>> # Gaussian-dominated profile
>>> y_gauss = voigtian(x, 0, (6, 2))
>>> # Lorentzian-dominated profile
>>> y_lorentz = voigtian(x, 0, (2, 6))
epyr.lineshapes.lshape(x, center, width, derivative=0, alpha=1.0, phase=0.0)[source]

General normalized lineshape function.

Computes a linear combination of Gaussian and Lorentzian lineshapes: alpha * Gaussian + (1-alpha) * Lorentzian

This creates pseudo-Voigt profiles commonly used in spectroscopy.

Parameters:

xarray

Abscissa points

centerfloat

Peak center position

widthfloat or (float, float)

Full width at half maximum If single value: same width for both components If tuple: (gaussian_width, lorentzian_width)

derivativeint, default=0

Derivative order (0=function, 1=first derivative, 2=second, -1=integral)

alphafloat, default=1.0

Mixing parameter (0=pure Lorentzian, 1=pure Gaussian)

phasefloat, default=0.0

Phase rotation (0=absorption, π/2=dispersion)

Returns:

array

Lineshape values

Examples:

>>> x = np.linspace(-10, 10, 1000)
>>> # Pure Gaussian
>>> gauss = lshape(x, 0, 5, alpha=1.0)
>>> # Pure Lorentzian
>>> lorentz = lshape(x, 0, 5, alpha=0.0)
>>> # 50/50 mix (pseudo-Voigt)
>>> mixed = lshape(x, 0, 5, alpha=0.5)
>>> # Different widths for each component
>>> mixed_widths = lshape(x, 0, (3, 7), alpha=0.3)
Parameters:
Return type:

ndarray

epyr.lineshapes.pseudo_voigt(x, center, width, eta=0.5, derivative=0, phase=0.0)[source]

Pseudo-Voigt profile: η*Lorentzian + (1-η)*Gaussian

Parameters:

xarray

Abscissa points

centerfloat

Peak center position

widthfloat

Full width at half maximum

etafloat, default=0.5

Mixing parameter (0=Gaussian, 1=Lorentzian)

derivativeint, default=0

Derivative order (0=function, 1=first derivative, 2=second)

phasefloat, default=0.0

Phase rotation (0=absorption, π/2=dispersion)

Returns:

array

Pseudo-Voigt profile values

Examples:

>>> x = np.linspace(-10, 10, 1000)
>>> # Standard pseudo-Voigt
>>> y = pseudo_voigt(x, 0, 5, eta=0.5)
>>> # First derivative
>>> dy = pseudo_voigt(x, 0, 5, eta=0.5, derivative=1)
epyr.lineshapes.convspec(spectrum, step_size, width, derivative=0, alpha=1.0, phase=0.0)[source]

Convolve spectrum with lineshape functions.

Applies broadening to stick spectra or other discrete data by convolution with Gaussian, Lorentzian, or pseudo-Voigt profiles.

Parameters:

spectrumarray

Input spectrum to convolve

step_sizefloat or array

Abscissa step size for each dimension

widthfloat or array

Full width at half maximum for lineshape

derivativeint or array, default=0

Derivative order (0=function, 1=first deriv, 2=second deriv)

alphafloat or array, default=1.0

Shape parameter (1=Gaussian, 0=Lorentzian, 0-1=pseudo-Voigt)

phasefloat or array, default=0.0

Phase (0=absorption, π/2=dispersion)

Returns:

array

Convolved spectrum with same shape as input

Examples:

>>> # Simple 1D convolution
>>> x = np.linspace(0, 100, 1000)
>>> stick_spec = np.zeros_like(x)
>>> stick_spec[500] = 1.0  # Delta peak at center
>>> broadened = convspec(stick_spec, 0.1, 2.0)  # Gaussian, FWHM=2
>>>
>>> # Lorentzian broadening
>>> lorentz = convspec(stick_spec, 0.1, 2.0, alpha=0.0)
>>>
>>> # First derivative
>>> deriv = convspec(stick_spec, 0.1, 2.0, derivative=1)
epyr.lineshapes.create_gaussian(width=1.0, **kwargs)[source]

Create Gaussian lineshape

Parameters:

width (float)

Return type:

Lineshape

epyr.lineshapes.create_lorentzian(width=1.0, **kwargs)[source]

Create Lorentzian lineshape

Parameters:

width (float)

Return type:

Lineshape

epyr.lineshapes.create_voigt(gaussian_width, lorentzian_width, **kwargs)[source]

Create Voigt lineshape

Parameters:
Return type:

Lineshape

epyr.lineshapes.create_pseudo_voigt(width=1.0, alpha=0.5, **kwargs)[source]

Create pseudo-Voigt lineshape

Parameters:
Return type:

Lineshape

epyr.lineshapes.gaussian_absorption(x, center, width)[source]

Pure absorption Gaussian

epyr.lineshapes.gaussian_dispersion(x, center, width)[source]

Pure dispersion Gaussian

epyr.lineshapes.gaussian_derivative(x, center, width, order=1)[source]

Gaussian derivatives

epyr.lineshapes.lorentzian_absorption(x, center, width)[source]

Pure absorption Lorentzian

epyr.lineshapes.lorentzian_dispersion(x, center, width)[source]

Pure dispersion Lorentzian

epyr.lineshapes.lorentzian_derivative(x, center, width, order=1)[source]

Lorentzian derivatives

epyr.lineshapes.fit_epr_signal(x_data, y_data, shape_type='gaussian', initial_params=None, bounds=None, derivative=0, fit_phase=False, fit_baseline=False, mask=None, plot=True, **fit_kwargs)[source]

Fit EPR signal with specified lineshape function.

Parameters:
  • x_data (np.ndarray) – Magnetic field axis, in Gauss.

  • y_data (np.ndarray) – EPR signal intensity (arbitrary units).

  • shape_type (str, optional) – Lineshape model: ‘gaussian’, ‘lorentzian’, ‘voigt’, or ‘pseudo_voigt’ (default: ‘gaussian’).

  • initial_params (dict, optional) – Initial parameter guesses. Auto-estimated from data if None. Keys depend on shape_type: basic models use {‘center’, ‘width’, ‘amplitude’}; voigt uses {‘center’, ‘gaussian_width’, ‘lorentzian_width’, ‘amplitude’}; pseudo_voigt adds ‘alpha’; phase fitting adds ‘phase’; baseline fitting adds ‘baseline_slope’ and ‘baseline_offset’.

  • bounds (dict, optional) – Parameter bounds as {name: (lower, upper)}, overriding data-derived defaults.

  • derivative (int, optional) – Derivative order: 0 (absorption), 1, or 2. Fixed, not fitted (default: 0).

  • fit_phase (bool, optional) – Fit the phase angle controlling absorption/dispersion mixing (default: False).

  • fit_baseline (bool, optional) – Include an affine baseline a*x + b in the model. Adds ‘baseline_slope’ and ‘baseline_offset’ as fitted parameters (default: False).

  • mask (np.ndarray of bool, optional) – Boolean array of the same length as x_data. True selects a point for fitting; False excludes it. Useful to reject artefacts or solvent peaks. If None, all non-NaN points are used.

  • plot (bool, optional) – Display a fit plot with residuals panel (default: True).

  • **fit_kwargs – Additional keyword arguments passed to scipy.optimize.curve_fit.

Returns:

Fit parameters, errors, statistics, fitted curve, and residuals. fitted_curve and residuals are defined on x_fit (masked points only).

Return type:

FitResult

Examples

>>> from epyr import eprload
>>> x, y, params, filepath = eprload('data.DTA')
>>> result = fit_epr_signal(x, y, 'gaussian')
>>> print(result.summary())
>>>
>>> # 1st derivative with phase
>>> result = fit_epr_signal(x, y, 'gaussian', derivative=1, fit_phase=True)
>>>
>>> # Exclude a spectral artefact between 3480-3510 G
>>> mask = ~((x >= 3480) & (x <= 3510))
>>> result = fit_epr_signal(x, y, 'gaussian', mask=mask)
>>>
>>> # 2nd derivative with explicit bounds
>>> bounds = {'center': (3400, 3600), 'width': (5, 50), 'phase': (0, 3.14)}
>>> result = fit_epr_signal(x, y, 'gaussian', derivative=2,
...                         fit_phase=True, bounds=bounds)
epyr.lineshapes.fit_multiple_shapes(x_data, y_data, shapes=None, derivative=0, fit_phase=False, fit_baseline=False, mask=None, plot=True)[source]

Fit EPR signal with multiple lineshape types and compare results.

Parameters:
  • x_data (np.ndarray) – Magnetic field axis, in Gauss.

  • y_data (np.ndarray) – EPR signal intensity.

  • shapes (list of str, optional) – Lineshape models to fit. Default: [‘gaussian’, ‘lorentzian’, ‘pseudo_voigt’].

  • derivative (int, optional) – Derivative order (0, 1, or 2). Fixed, not fitted (default: 0).

  • fit_phase (bool, optional) – Fit the phase parameter in each model (default: False).

  • fit_baseline (bool, optional) – Include an affine baseline in each model (default: False).

  • mask (np.ndarray of bool, optional) – Boolean array selecting points to include (True = include). Passed unchanged to each fit_epr_signal call.

  • plot (bool, optional) – Display a side-by-side comparison plot (default: True).

Returns:

Mapping of shape name to FitResult for all attempted fits.

Return type:

dict

class epyr.lineshapes.FitResult(shape_type, parameters, parameter_errors, fitted_curve, residuals, r_squared, chi_squared, success, message, covariance_matrix=None, x_fit=None)[source]

Bases: object

Container for lineshape fit results.

Parameters:
shape_type

Name of the fitted lineshape model.

Type:

str

parameters

Fitted parameter values keyed by parameter name.

Type:

dict

parameter_errors

Standard errors of fitted parameters (square root of covariance diagonal).

Type:

dict

fitted_curve

Model evaluated at the fitted points (x_fit).

Type:

np.ndarray

residuals

Data minus model at the fitted points.

Type:

np.ndarray

r_squared

Coefficient of determination R².

Type:

float

chi_squared

Reduced chi-squared: sum of squared residuals divided by degrees of freedom.

Type:

float

success

True if curve_fit converged.

Type:

bool

message

Convergence message or error description.

Type:

str

covariance_matrix

Full parameter covariance matrix returned by curve_fit.

Type:

np.ndarray or None

x_fit

X values used for fitting, after NaN removal and masking.

Type:

np.ndarray or None

shape_type: str
parameters: Dict[str, float]
parameter_errors: Dict[str, float]
fitted_curve: ndarray
residuals: ndarray
r_squared: float
chi_squared: float
success: bool
message: str
covariance_matrix: ndarray | None = None
x_fit: ndarray | None = None
summary()[source]

Return a formatted string summarizing fit quality and parameters.

Return type:

str

__init__(shape_type, parameters, parameter_errors, fitted_curve, residuals, r_squared, chi_squared, success, message, covariance_matrix=None, x_fit=None)
Parameters:
Return type:

None

Submodules