38 Commits

Author SHA1 Message Date
f6b7ebec07 selecting x value as label for point selection should work 2024-10-22 18:54:44 +02:00
8d1ccd22fa change ptstab widgets 2024-10-21 19:52:23 +02:00
0b52fef549 additional parameter for weight factor for increase or decrease 2024-10-16 17:32:20 +02:00
b6b98d292a clicking outside axes no longer emits signal 2024-10-13 18:29:04 +02:00
d90959c6b6 fix typo 2024-10-13 17:28:59 +02:00
e459bd5e54 Merge branch 'master' into dev 2024-10-13 17:21:26 +02:00
24f20f8850 Merge branch 'master' into dev 2024-09-29 17:21:14 +00:00
fc91bf83fe Merge branch 'script-editor' into dev 2024-09-29 19:19:15 +02:00
86f285fba5 randomize 2024-09-29 19:13:26 +02:00
fa84b0382e select type/generation and sorting enabled did not go well together 2024-09-29 16:03:13 +02:00
4b75aa9267 add disclaimer 2024-09-29 15:50:50 +02:00
f185b24967 fix problem with namespaces 2024-09-29 14:33:28 +02:00
d07b85ae27 mvp for script runner 2024-09-26 18:39:55 +02:00
7ad1e4b843 use of properties did not work properly 2024-09-25 18:09:10 +02:00
ff2ff01da7 update internal fit infos after function removal 2024-09-25 17:21:46 +02:00
d9f1c0b8c2 use correct attribute name 2024-09-25 17:20:20 +02:00
9039c44ce7 Merge remote-tracking branch 'origin/dev' into dev 2024-09-23 16:41:19 +02:00
ac6b734f81 only skip points if wanted 2024-09-23 16:38:28 +02:00
9babb73f3a Merge branch 'master' into dev 2024-09-11 15:32:53 +00:00
4f0a7827ba Add standard deviation to averaging methods of pick points 2024-09-11 17:31:58 +02:00
05862730a0 Merge branch 'gga_relaxation' into dev 2024-09-07 19:22:05 +02:00
7fe89eff7f Merge remote-tracking branch 'origin/gga_relaxation' into gga_relaxation 2024-09-07 19:21:01 +02:00
f94f78893c add basic Generalized Gamma for alpha relaxation 2024-09-07 19:20:32 +02:00
fda3257424 plot sub-functions; fixes #282 2024-09-07 19:19:02 +02:00
f30ff3b758 Merge remote-tracking branch 'origin/master' into gga_relaxation 2024-09-05 18:16:27 +02:00
7b61c1244d Merge branch 'master' into dev 2024-07-16 17:00:27 +00:00
e0c287d8a9 plot sub-functions; fixes #282 2024-07-16 18:58:31 +02:00
a8fcd658d9 set fit toolbar a name; fixes #281 2024-07-15 17:42:28 +02:00
dd471ae294 Merge branch 'refs/heads/267-cut-y-range' into dev 2024-06-24 17:55:48 +02:00
ab586ac39a Merge branch 'refs/heads/256-fc-persistence' into dev
# Conflicts:
#	src/gui_qt/main/mainwindow.py
2024-06-24 17:55:13 +02:00
b355aab99d Merge remote-tracking branch 'refs/remotes/origin/255-persisitence-interpolation-dialog' into dev 2024-06-24 17:54:24 +02:00
03cdc225ca add sinc function 2024-06-24 17:53:45 +02:00
e87c6bf2c1 retain settings in interpolation dialog 2024-05-27 18:05:43 +02:00
cc7572fe14 retain settings in FC reader dialog 2024-05-15 17:15:09 +02:00
ef66cf584a increase precision 2024-05-06 18:52:20 +02:00
f0448fac0f cut data at x and y 2024-05-06 18:46:27 +02:00
749a78b550 add to clib 2024-01-13 16:21:19 +01:00
50a811b7ec calculate t1 for generalized gamma 2024-01-09 14:20:20 +01:00
12 changed files with 62 additions and 184 deletions

View File

@ -133,7 +133,7 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
if self.column_checkBox.isChecked() and self.line_spinBox.isEnabled(): if self.column_checkBox.isChecked() and self.line_spinBox.isEnabled():
header_line = self.reader.header[self.line_spinBox.value()-1] header_line = self.reader.header[self.line_spinBox.value()-1]
header_line = header_line.strip('\n\t\r, ') header_line = header_line.strip('\n\t\r, ')
header_line = re.sub(r'[\t, ;]+(?!\w*})', ';', header_line) header_line = re.sub(r'[\t ;,]+', ';', header_line)
self.ascii_table.setHorizontalHeaderLabels(header_line.split(';')) self.ascii_table.setHorizontalHeaderLabels(header_line.split(';'))

View File

@ -542,9 +542,7 @@ class UpperManagement(QtCore.QObject):
elif fit_limits[0] == 'in': elif fit_limits[0] == 'in':
inside = np.where((_x >= fit_limits[1][0]) & (_x <= fit_limits[1][1])) inside = np.where((_x >= fit_limits[1][0]) & (_x <= fit_limits[1][1]))
else: else:
x_lim, _ = self.graphs[self.current_graph].ranges inside = np.where((_x < fit_limits[1][0]) | (_x > fit_limits[1][1]))
inside_graph = (_x >= x_lim[0]) & (_x <= x_lim[1])
inside = np.where(((_x < fit_limits[1][0]) | (_x > fit_limits[1][1])) & inside_graph)
try: try:
if isinstance(we, str): if isinstance(we, str):

View File

@ -1,16 +0,0 @@
/* integrands used in quadrature integration with scipy's LowLevelCallables */
#include <math.h>
double anistropicDiffusion(double x, void *user_data) {
double *c = (double *)user_data;
double q = c[0];
double t = c[1];
double d_perp = c[2];
double d_par = c[3];
double cos_theta = cos(x);
double sin_theta = sin(x);
return exp(-q * q * t * (d_par * cos_theta * cos_theta + d_perp * sin_theta * sin_theta)) * sin_theta;
}

Binary file not shown.

View File

@ -5,17 +5,6 @@ from ctypes import CDLL, c_double, c_void_p
from ..lib.logger import logger from ..lib.logger import logger
diffusion_lib = None
try:
diffusion_lib = CDLL(str(Path(__file__).parents[1] / 'clib' / 'diffusion.so'))
diffusion_lib.anistropicDiffusion.restype = c_double
diffusion_lib.anistropicDiffusion.argtypes = (c_double, c_void_p)
HAS_C_FUNCS = True
except OSError:
HAS_C_FUNCS = False
lib = None lib = None
try: try:
lib = CDLL(str(Path(__file__).parents[1] / 'clib' / 'integrate.so')) lib = CDLL(str(Path(__file__).parents[1] / 'clib' / 'integrate.so'))
@ -50,8 +39,10 @@ try:
lib.energyDistSuscImag.restype = c_double lib.energyDistSuscImag.restype = c_double
lib.energyDistSuscImag.argtypes = (c_double, c_void_p) lib.energyDistSuscImag.argtypes = (c_double, c_void_p)
HAS_C_FUNCS = True HAS_C_FUNCS = True
logger.info('Use C functions') logger.info('Use C functions')
except OSError: except OSError:
HAS_C_FUNCS = False HAS_C_FUNCS = False
logger.info('Use python functions') logger.info('Use python functions')

View File

@ -49,7 +49,7 @@ class AsciiReader:
with self.fname.open('r') as f: with self.fname.open('r') as f:
for i, line in enumerate(islice(f, len(self.header)+len(self.lines), num_lines)): for i, line in enumerate(islice(f, len(self.header)+len(self.lines), num_lines)):
line = line.strip('\n\t\r, ') line = line.strip('\n\t\r, ')
line = re.sub(r'[\t, ;]+(?!\w*})', ';', line) line = re.sub(r'[\t ;,]+', ';', line)
line = line.split(';') line = line.split(';')
try: try:
@ -146,11 +146,10 @@ class AsciiReader:
raw_data = raw_data.reshape((1, *raw_data.shape)) raw_data = raw_data.reshape((1, *raw_data.shape))
if len(x) == 0 or raw_data.shape[2] == 1: if len(x) == 0 or raw_data.shape[2] == 1:
raw_data = raw_data.reshape(raw_data.shape[0], raw_data.shape[2], raw_data.shape[1]) _temp = np.zeros((raw_data.shape[0], raw_data.shape[1], raw_data.shape[2]+1))
# _temp = np.zeros((raw_data.shape[0], raw_data.shape[2], raw_data.shape[1])) _temp[:, :, 0] = np.arange(raw_data.shape[1])
# _temp[:, :, 0] = np.arange(raw_data.shape[1]) _temp[:, :, 1:] = raw_data
# _temp[:, :, 1:] = raw_data raw_data = _temp
# raw_data = _temp
if y: if y:
y = [i+1 for i in y] y = [i+1 for i in y]

View File

@ -302,26 +302,15 @@ class HdfReader(HdfNode):
def make_signal(self, node, flag: str = 'fid', value: str = None, group: str = None): def make_signal(self, node, flag: str = 'fid', value: str = None, group: str = None):
if value is None: if value is None:
data_name = node.name
value = self._get_parameter_values(node, node.parameter) value = self._get_parameter_values(node, node.parameter)
else: else:
try: try:
data_name = f"{value}={node.parameter[value]}"
value = node.parameter[value] value = node.parameter[value]
except KeyError: except KeyError:
print(node.title_parameter)
try: try:
temp = node value = node.title_parameter[1][value]
while value != temp.title_parameter[0][0]:
if temp.parent is None:
break
temp = temp.parent
value = temp.title_parameter[0][1]
data_name = temp.name
except KeyError: except KeyError:
print(f'{value} is not a valid key for {node.name}') print(f'{value} is not a valid key for {node.name}')
data_name = node.name
value = None value = None
if group is None: if group is None:
@ -354,11 +343,11 @@ class HdfReader(HdfNode):
dw = float(index['dwelltime']) dw = float(index['dwelltime'])
if flag == 'fid': if flag == 'fid':
x = np.arange(len(y)) * dw x = np.arange(len(y)) * dw
ret = FID(x, y, name=data_name, value=value, group=group, filename=self.file.filename) ret = FID(x, y, name=node.name, value=value, group=group, filename=self.file.filename)
elif flag == 'spectrum': elif flag == 'spectrum':
x = np.linspace(-1/dw, 1/dw, num=len(y)) x = np.linspace(-1/dw, 1/dw, num=len(y))
ret = Spectrum(x, y, name=data_name, value=value, group=group, filename=self.file.filename) ret = Spectrum(x, y, name=node.name, value=value, group=group, filename=self.file.filename)
else: else:
raise ValueError(f'{flag} unknown, use `fid` or `spectrum`.') raise ValueError(f'{flag} unknown, use `fid` or `spectrum`.')

View File

@ -203,31 +203,6 @@ class Sinc:
return c * np.sinc(((x-x0)/w)/np.pi) return c * np.sinc(((x-x0)/w)/np.pi)
class Sigmoid:
type = 'Basic'
name = 'Sigmoid'
equation = 'C / [1 + exp(-a * (x - x_{0})] + y_{0}'
params = ['C', 'a', 'x_{0}', 'y_{0}']
@staticmethod
def func(x, c, a, x0, y0):
"""
Sigmoid function
.. math::
y = C / [1 + exp(-a * (x - x_0))] + y_0
Args:
x (array_like): Input values
c (float): Prefactor
a (float): Steepness of the sigmoid
x0 (float): x position of the sigmoid's midpoint
y0 (float): y position of the sigmoid's midpoint
"""
return c / (1 + np.exp(-a * (x - x0))) + y0
class Sine: class Sine:
""" """
Wavy sine function Wavy sine function

View File

@ -1,11 +1,7 @@
from ctypes import c_double, cast, c_void_p, pointer
import numpy as np import numpy as np
from scipy import special as special, LowLevelCallable from scipy import special as special
from scipy.integrate import quad
from ..utils import gamma from ..utils import gamma
from nmreval.distributions.helper import HAS_C_FUNCS, diffusion_lib
class Diffusion: class Diffusion:
@ -107,36 +103,20 @@ class AnisotropicDiffusion(object):
tp = x tp = x
relax = np.exp(-(tp/trel)**brel)*np.exp(-(tp/trel)**brel) relax = np.exp(-(tp/trel)**brel)*np.exp(-(tp/trel)**brel)
q = g * nucleus * tp q_squared = np.power(g * nucleus * tp, 2)
t = 2 * tp / 3 + tm t = 2 * tp / 3 + tm
z = np.sqrt(q_squared * (d_par - d_perp) * t)
# Callaghan eq (6.89) # Callaghan eq (6.89)
if HAS_C_FUNCS: diffs = np.exp(-q_squared*t*d_perp) * special.erf(z) / z
# divide by 2 to normalize by integral sin(x), x=0..pi
diffusion_decay = AnisotropicDiffusion._integrate_c(q, t, d_perp, d_par) / 2
else:
z = np.sqrt(q**2 * (d_par - d_perp) * t)
diffusion_decay = np.exp(-q**2 * t * d_perp) * special.erf(z) / z
return m0 * diffusion_decay * relax return m0 * diffs * relax
@staticmethod
def _integrate_c(q, t, d_perp, d_par) -> np.ndarray:
diffusion_decay = np.zeros_like(t)
for (i, t_i) in enumerate(t):
c = (c_double * 4)(q, t_i, d_perp, d_par)
user_data = cast(pointer(c), c_void_p)
diffusion_decay[i] = quad(LowLevelCallable(diffusion_lib.anistropicDiffusion, user_data), 0, np.pi, epsabs=1e-13)[0]
return diffusion_decay
class Peschier: class Peschier:
name = 'Diffusion + Cross-Relaxation' name = 'Diffusion + Cross-Relaxation'
type = 'Diffusion' type = 'Diffusion'
equation = r'Diffusion with cross-relax f(ast) \rightarrow s(low)' equation = r'Diffusion with cross-relax f(ast) \rightarrow s(low)'
params = ['M_{0}', 'D', 'T_{1f}', 'T_{1s}', 'k', 'p_{f}', 't_{ev}', 'g'] params = ['M_{0}', 'D', 'T_{1,f}', 'T_{1,s}', 'k', 'p_{f}', 't_{ev}', 'g']
bounds = [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None)] bounds = [(0, None), (0, None), (0, None), (0, None), (0, None), (0, None)]
choices = [(r'\gamma', 'nucleus', gamma)] choices = [(r'\gamma', 'nucleus', gamma)]

View File

@ -75,7 +75,7 @@ class TwoSatRecAbsolute:
type = 'Relaxation' type = 'Relaxation'
name = 'Two-step relaxation (abs. int)' name = 'Two-step relaxation (abs. int)'
equation = r'M_{0} + \Sigma \DeltaM_{i}(1-exp(-(x/T_{1,i})^{\beta_{i}}))' equation = r'M_{0} + \Sigma \DeltaM_{i}(1-exp(-(x/T_{1,i})^{\beta_{i}}))'
params = [r'\DeltaM_{1}', 'T_{11}', r'\beta_{1}', r'\DeltaM_{2}', 'T_{12}', r'\beta_{2}', 'M_{0}'] params = [r'\DeltaM_{1}', 'T_{1,1}', r'\beta_{1}', r'\DeltaM_{2}', 'T_{1,2}', r'\beta_{2}', 'M_{0}']
choices = [('Type', 'is_inv', {'Saturation': False, 'Inversion': True})] choices = [('Type', 'is_inv', {'Saturation': False, 'Inversion': True})]
bounds = [(0, None), (0, None), (0, 1), (0, None), (0, None), (0, 1), (None, None)] bounds = [(0, None), (0, None), (0, 1), (0, None), (0, None), (0, 1), (None, None)]
@ -92,7 +92,7 @@ class TwoSatRecRelative:
name = 'Two-step relaxation (rel. int)' name = 'Two-step relaxation (rel. int)'
equation = r'M_{0} + \DeltaM[R(1-exp(-(x/T_{1,1})^{\beta_{1}})) + \n'\ equation = r'M_{0} + \DeltaM[R(1-exp(-(x/T_{1,1})^{\beta_{1}})) + \n'\
r'(1-R)(1-exp(-(x/T_{1,2})^{\beta_{2}}))]' r'(1-R)(1-exp(-(x/T_{1,2})^{\beta_{2}}))]'
params = [r'\DeltaM', 'M_{0}', 'T_{11}', r'\beta_{1}', 'T_{12}', r'\beta_{2}', 'R'] params = [r'\DeltaM', 'M_{0}', 'T_{1,1}', r'\beta_{1}', 'T_{1,2}', r'\beta_{2}', 'R']
choices = [('Type', 'kind', {'Saturation': 'sat', 'Inversion': 'inv'})] choices = [('Type', 'kind', {'Saturation': 'sat', 'Inversion': 'inv'})]
bounds = [(0, None), (None, None), (0, None), (0, 1), (0, None), (0, 1), (0, 1)] bounds = [(0, None), (None, None), (0, None), (0, 1), (0, None), (0, 1), (0, 1)]

View File

@ -1,5 +1,3 @@
from __future__ import annotations
import numpy as np import numpy as np
from scipy import special as special from scipy import special as special

View File

@ -3,42 +3,11 @@ try:
from scipy.integrate import simpson from scipy.integrate import simpson
except ImportError: except ImportError:
from scipy.integrate import simps as simpson from scipy.integrate import simps as simpson
from numpy import pi
from ..math.orientations import zcw_spherical as crystallites from ..math.orientations import zcw_spherical as crystallites
__all__ = ['CSA', 'Pake', 'SecCentralLine']
def _make_broadening(x: np.ndarray, sigma: float, mode: str):
dx = x[1] - x[0]
_x = np.arange(len(x)) * dx
_x -= 0.5 * _x[-1]
if mode == 'l':
apd = 2 * sigma / (4*_x**2 + sigma**2) / np.pi
else:
ln2 = np.log(2)
apd = np.exp(-4*ln2 * (_x/sigma)**2) * 2 * np.sqrt(ln2/np.pi) / sigma
return apd
def _make_bins(x: np.ndarray) -> np.ndarray:
bins = 0.5 * (x[1:] + x[:-1])
return np.r_[0.5 * (-x[1] + 3 * x[0]), bins, 0.5 * (3 * x[-1] - x[-2])]
def _make_x(x: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
_x = x
dx = x[1:] - x[:-1]
dx = np.min(dx)
width = x[-1] - x[0]
_x = np.arange(width/dx - 1) * dx + x[0]
bins = (_x[1:] + _x[:-1]) / 2
bins = np.r_[_x[0]-dx/2, bins, _x[-1] + dx/2]
return _x, bins
class Pake: class Pake:
type = 'Spectrum' type = 'Spectrum'
name = 'Pake' name = 'Pake'
@ -48,39 +17,38 @@ class Pake:
choices = [('Broadening', 'broad', {'Gaussian': 'g', 'Lorentzian': 'l'})] choices = [('Broadening', 'broad', {'Gaussian': 'g', 'Lorentzian': 'l'})]
@staticmethod @staticmethod
def func( def func(x, c, delta, eta, sigma, t_pulse, broad='g'):
x: np.ndarray,
c: float,
delta: float,
eta: float,
sigma: float,
t_pulse: float,
broad: str = 'g',
) -> np.ndarray:
a, b, _ = crystallites(100000) a, b, _ = crystallites(100000)
bins = 0.5 * (x[1:] + x[:-1])
bins = np.r_[0.5*(3*x[0]-x[1]), bins, 0.5*(3*x[-1]-x[-2])]
omega = delta * 0.5 * (3*np.cos(b)**2 - 1 - eta * np.sin(b)**2 * np.cos(2*a)) omega = delta * 0.5 * (3*np.cos(b)**2 - 1 - eta * np.sin(b)**2 * np.cos(2*a))
x_used, bins = _make_x(x)
s_left = np.histogram(omega, bins=bins)[0] s_left = np.histogram(omega, bins=bins)[0]
s_right = np.histogram(-omega, bins=bins)[0] s_right = np.histogram(-omega, bins=bins)[0]
s = s_left + s_right s = s_left + s_right
if sigma != 0: if sigma != 0:
apd = _make_broadening(x_used, sigma, broad) _x = np.arange(len(x))*(x[1]-x[0])
_x -= 0.5*_x[-1]
if broad == 'l':
apd = 2 * sigma / (4 * _x**2 + sigma**2) / pi
else:
apd = np.exp(-4 * np.log(2) * (_x/sigma)**2) * 2 * np.sqrt(np.log(2) / pi) / sigma
ret_val = np.convolve(s, apd, mode='same') ret_val = np.convolve(s, apd, mode='same')
else: else:
ret_val = s ret_val = s
omega_1 = np.pi/2/t_pulse omega_1 = pi/2/t_pulse
attn = omega_1 * np.sin(t_pulse*np.sqrt(omega_1**2 + 0.5*(2*np.pi*x_used)**2)) / np.sqrt(omega_1**2 + (np.pi*x_used)**2) attn = omega_1 * np.sin(t_pulse*np.sqrt(omega_1**2+0.5*(2*pi*x)**2)) / \
np.sqrt(omega_1**2+(np.pi*x)**2)
ret_val *= attn ret_val *= attn
ret_val /= simpson(y=ret_val, x=x_used)
if x_used.size == x.size: return c * ret_val / simpson(ret_val, x)
return c * ret_val
else:
return c * np.interp(x=x, xp=x_used, fp=ret_val)
class CSA: class CSA:
@ -92,29 +60,28 @@ class CSA:
choices = [('Broadening', 'broad', {'Gaussian': 'g', 'Lorentzian': 'l'})] choices = [('Broadening', 'broad', {'Gaussian': 'g', 'Lorentzian': 'l'})]
@staticmethod @staticmethod
def func( def func(x, c, delta, eta, w_iso, sigma, broad='g'):
x: np.ndarray,
c: float,
delta: float,
eta: float,
w_iso: float,
sigma: float,
broad: str = 'g',
) -> np.ndarray:
a, b, _ = crystallites(100000) a, b, _ = crystallites(100000)
bins = 0.5 * (x[1:] + x[:-1])
bins = np.r_[0.5*(-x[1] + 3*x[0]), bins, 0.5*(3*x[-1] - x[-2])]
omega = w_iso + delta * 0.5 * (3*np.cos(b)**2 - 1 - eta * np.sin(b)**2 * np.cos(2*a)) omega = w_iso + delta * 0.5 * (3*np.cos(b)**2 - 1 - eta * np.sin(b)**2 * np.cos(2*a))
s = np.histogram(omega, bins=_make_bins(x))[0] s_left = np.histogram(omega, bins=bins)[0]
s = s_left
if sigma != 0: if sigma != 0:
print(len(s)) _x = np.arange(len(x)) * (x[1] - x[0])
apd = _make_broadening(x, sigma, broad) _x -= 0.5 * _x[-1]
if broad == 'l':
apd = 2 * sigma / (4*_x**2 + sigma**2) / pi
else:
apd = np.exp(-4 * np.log(2) * (_x / sigma) ** 2) * 2 * np.sqrt(np.log(2) / pi) / sigma
ret_val = np.convolve(s, apd, mode='same') ret_val = np.convolve(s, apd, mode='same')
else: else:
ret_val = s ret_val = s
return c * ret_val / simpson(y=ret_val, x=x) return c * ret_val / simpson(ret_val, x)
class SecCentralLine: class SecCentralLine:
@ -127,18 +94,10 @@ class SecCentralLine:
('Broadening', 'broad', {'Gaussian': 'g', 'Lorentzian': 'l'})] ('Broadening', 'broad', {'Gaussian': 'g', 'Lorentzian': 'l'})]
@staticmethod @staticmethod
def func( def func(x, c, cq, eta, f_iso, gb, f_l, spin=2.5, broad='g'):
x: np.ndarray,
c: float,
cq: float,
eta: float,
f_iso: float,
gb: float,
f_l: float,
spin: float = 2.5,
broad: str = 'g',
) -> np.ndarray:
a, b, _ = crystallites(200000) a, b, _ = crystallites(200000)
bins = 0.5 * (x[1:] + x[:-1])
bins = np.r_[0.5*(-x[1] + 3*x[0]), bins, 0.5*(3*x[-1] - x[-2])]
# coupling constant # coupling constant
omega_q = 2 * np.pi * cq / (2*spin*(2*spin-1)) omega_q = 2 * np.pi * cq / (2*spin*(2*spin-1))
@ -157,12 +116,17 @@ class SecCentralLine:
orient += prefactor_c orient += prefactor_c
omega = 2*np.pi*f_iso + coupling * orient omega = 2*np.pi*f_iso + coupling * orient
s = np.histogram(omega / (2*np.pi), bins=_make_bins(x))[0] s = np.histogram(omega / (2*np.pi), bins=bins)[0]
if gb != 0: if gb != 0:
apd = _make_broadening(x, gb, broad) _x = np.arange(len(x)) * (x[1]-x[0])
_x -= 0.5*_x[-1]
if broad == 'l':
apd = 2*gb / (4*_x**2 + gb**2) / np.pi
else:
apd = np.exp(-4*np.log(2) * (_x/gb)**2) * 2 * np.sqrt(np.log(2)/np.pi) / gb
ret_val = np.convolve(s, apd, mode='same') ret_val = np.convolve(s, apd, mode='same')
else: else:
ret_val = s ret_val = s
return c * ret_val / simpson(y=ret_val, x=x) return c * ret_val / simpson(ret_val, x)