From cec2b7baabd1055ddd299b4a3c2f930344512604 Mon Sep 17 00:00:00 2001 From: Danilo Ferreira de Lima <danilo.enoque.ferreira.de.lima@xfel.de> Date: Mon, 2 Oct 2023 18:58:29 +0200 Subject: [PATCH] Added resolution estimate. --- pes_to_spec/model.py | 45 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/pes_to_spec/model.py b/pes_to_spec/model.py index dcd5265..3e88209 100644 --- a/pes_to_spec/model.py +++ b/pes_to_spec/model.py @@ -3,6 +3,7 @@ from __future__ import annotations import joblib import numpy as np +import lmfit from scipy.signal import fftconvolve from sklearn.decomposition import IncrementalPCA, PCA from sklearn.base import TransformerMixin, BaseEstimator @@ -32,6 +33,36 @@ def matching_two_ids(a: np.ndarray, b: np.ndarray) -> np.ndarray: unique_ids = list(set(a).intersection(b)) return np.array(unique_ids) +def fwhm(x: np.ndarray, y: np.ndarray) -> float: + """Return the full width at half maximum of x.""" + # half maximum + half_max = np.amax(y)*0.5 + # signum(y - half_max) is zero before and after the half maximum, + # and it is 1 in the range above the half maximum + # The difference will be +/- 1 only at the transitions + d = np.diff(np.sign(y - half_max)) + left_idx = np.where(d > 0)[0] + right_idx = np.where(d < 0)[-1] + return x[right_idx] - x[left_idx] + +def get_resolution(x: np.ndarray, y: np.ndarray) -> float: + """ + Get resolution from an auto-correlation function y. + + Args: + x: Energy axis, assumed centred at 0, symmetric and equally spaced. + y: Auto-correlation function. + """ + def gaussian_model(x, amp, cen, wid): + """Gaussian.""" + return amp * np.exp(-0.5 * (x-cen)**2 / (wid**2)) + gmodel = lmfit.Model(gaussian_model) + first = np.where(x > -0.5)[0][0] + last = np.where(x > 0.5)[0][0] + initial_guess = 0.1 # eV + result = gmodel.fit(y[first:last], x=x[first:last], amp=1.0, cen=0.0, wid=initial_guess) + return 2.355*result.best_values["wid"] + class PromptNotFoundError(Exception): """ Exception representing the error condition generated by not finding the prompt peak. @@ -91,7 +122,8 @@ class HighResolutionSmoother(TransformerMixin, BaseEstimator): # get the centre value of the energy axis mu = energy[:, n_features//2, np.newaxis] # generate a gaussian - gaussian = np.exp(-0.5*(energy - mu)**2/self.high_res_sigma**2) + std = self.high_res_sigma*2.355 + gaussian = np.exp(-0.5*(energy - mu)**2/std**2) gaussian /= np.sum(gaussian, axis=1, keepdims=True) # apply it to the data high_res_gc = fftconvolve(X, gaussian, mode="same", axes=1) @@ -873,11 +905,14 @@ class Model(TransformerMixin, BaseEstimator): self.wiener_energy_ft = E self.transfer_function = H h = np.fft.fftshift(np.fft.ifft(H)) - hmod = np.real(np.absolute(h)) self.impulse_response = h - energy_mu = np.sum(e_axis*hmod)/np.sum(hmod) - energy_var = np.sum(((e_axis - energy_mu)**2)*hmod)/np.sum(hmod) - self.resolution = np.sqrt(energy_var) + self.auto_corr = np.mean(np.fft.fftshift(np.fft.ifft(np.absolute(np.fft.fft(z))**2), axes=(-1,)), axis=0) + self.auto_corr = np.real(self.auto_corr) + self.auto_corr /= np.amax(self.auto_corr) + try: + self.resulution = get_resolution(e_axis, self.auto_corr) + finally: + self.resolution = -1.0 #print("Resolution:", self.resolution) # for consistency check per channel -- GitLab