import numpy as np
from typing import Union
try:
import QENSmodels
except ImportError:
print('Module QENSmodels not found')
[docs]def sqwDeltaLorentz(
w: Union[float, list, np.ndarray],
q: Union[float, list, np.ndarray],
scale: float = 1.0,
center: float = 0.0,
A0: Union[float, list, np.ndarray] = 0.0,
hwhm: Union[float, list, np.ndarray] = 1.0
) -> Union[float, list, np.ndarray]:
r"""
Model corresponding to a delta representing a fraction p of
fixed atoms and a Lorentzian corresponding to a Brownian
Translational diffusion model for the remaining (1 - p) atoms.
Model = A0*delta + (1-A0)*Lorentz(Gamma)
Parameters
----------
w: float, list or :class:`~numpy:numpy.ndarray`
energy transfer (in 1/ps)
q: float, list or :class:`~numpy:numpy.ndarray`
momentum transfer (non-fitting, in 1/Angstrom)
scale: float
scale factor. Default to 1.
center: float
peak center. Default to 0.
A0: float, list or :class:`~numpy:numpy.ndarray` of the same size as q
proportion of immobile atoms, must be between 0 and 1. Default to 0.
hwhm: float, list or :class:`~numpy:numpy.ndarray` of the same size as q
half width half maximum. Default to 1.
Return
------
:class:`~numpy:numpy.ndarray`
output array
Examples
--------
>>> sqw = sqwDeltaLorentz([1, 2, 3], 0.1)
>>> round(sqw[0], 1)
0.2
>>> round(sqw[1], 3)
0.064
>>> round(sqw[2], 3)
0.032
Notes
-----
The `sqwDeltaLorentz` is expressed as
.. math::
S(q, \omega) &= A_0 \delta(\omega, \text{scale}, \text{center}) \\
&+ (1 - A_0) \text{Lorentzian}(\omega, \text{scale}, \text{center},
\text{hwhm})
"""
w = np.asarray(w)
# Input validation
q = np.asarray(q, dtype=np.float32)
A0 = np.asarray(A0)
hwhm = np.asarray(hwhm)
# Create output array
sqw = np.zeros((q.size, w.size))
# Model
if q.size > 1:
# if only a single float is given for A0, adapt to size of q
if A0.size == 1:
A0 = A0 * np.ones(q.size)
# else
# check that enough values of A0 are given to match the size of q
else:
assert A0.shape == q.shape, \
"If A0.size>1, it should match the size of q"
# same procedure for hwhm
if hwhm.size == 1:
hwhm = hwhm * np.ones(q.size)
else:
assert hwhm.shape == q.shape, \
"If hwhm.size>1, it should match the size of q"
# Validator for A0. We must have 0<= A0 <= 1
if any(item > 1 or item < 0 for item in A0):
raise ValueError('The proportion of immobile atoms, A0, '
'should be comprised between 0 and 1, included.')
try:
for i in range(q.size):
sqw[i, :] = A0[i] * QENSmodels.delta(w, scale, center)
sqw[i, :] += (1 - A0[i]) * QENSmodels.lorentzian(
w,
scale,
center,
hwhm[i])
except TypeError as detail:
msg = "At least one parameter has an incorrect type"
raise TypeError(detail.__str__() + "\n" + msg)
except IndexError as detail:
msg = "At least one array has an incorrect size"
raise IndexError(detail.__str__() + "\n" + msg)
else:
if A0 > 1 or A0 < 0:
raise ValueError('The proportion of immobile atoms, A0, '
'should be comprised between 0 and 1, included.')
sqw[0, :] = A0 * QENSmodels.delta(w, scale, center)
sqw[0, :] += (1 - A0) * QENSmodels.lorentzian(w, scale, center, hwhm)
# For Bumps use (needed for final plotting)
# Using a 'Curve' in bumps for each Q --> needs vector array
if q.size == 1:
sqw = np.reshape(sqw, w.size)
return sqw