diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index bb787fb..7c5d998 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -23,6 +23,13 @@ releases. + +============ +TODO +============ +This is a general guide to contribute to python based projects and does not yet contain any ``cristallina`` specific information. + + ============ Contributing ============ diff --git a/LICENSE.txt b/LICENSE.txt index 7cb4559..2f40fc1 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,21 +1 @@ -The MIT License (MIT) - -Copyright (c) 2022 Alexander Steppke - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +No explicit LICENSE given, all code belongs to the respective authors. diff --git a/README.rst b/README.rst index 8d43a37..84b104f 100644 --- a/README.rst +++ b/README.rst @@ -37,13 +37,12 @@ cristallina Cristallina data analysis modules and plotting utilities. -A longer description of your project goes here... +Here we collect modules for data analysis, plotting and utility functions for the Cristallina endstation. + +The data analysis is based on the common SwissFEL data architecture, with convienent access provided by [sf_datafiles](https://github.com/paulscherrerinstitute/sf_datafiles). + +The test suite (based on pytest) requires access to some data only available on either the cristallina consoles or the RA cluster. -.. _pyscaffold-notes: -Note -==== -This project has been set up using PyScaffold 4.2.3. For details and usage -information on PyScaffold see https://pyscaffold.org/. diff --git a/src/cristallina/utils.py b/src/cristallina/utils.py index 4d7b098..9205cf7 100644 --- a/src/cristallina/utils.py +++ b/src/cristallina/utils.py @@ -134,7 +134,91 @@ def heuristic_extract_smalldata_path(): small_data_path = f"/das/work/units/cristallina/p{p_number}/smalldata/" return small_data_path +######################## Little useful functions ######################## + + def find_nearest(array, value): + '''Finds an index in an array with a value that is nearest to given number''' + array = np.asarray(array) + idx = (np.abs(array - value)).argmin() + return idx + +def find_two_nearest(time_array,percentage): + '''Finds indeces of the two values that are the nearest to the given value in an array''' + array = np.asarray(time_array) + value = (np.max(array)-np.min(array))*percentage+np.min(array) + idx = (np.abs(array - value)).argmin() + indices = np.sort([np.argsort(np.abs(array-value))[0], np.argsort(np.abs(array-value))[1]]) + return indices + +def gauss(x, H, A, x0, sigma): + """Returns gauss function value""" + return H + A * np.exp(-(x - x0) ** 2 / (2 * sigma ** 2)) + +def gauss_fit(x, y, fit_details=None, plot=None: + '''Returns [baseline_offset, Amplitude, center, sigma, FWHM]''' + + # Initial guesses + mean = sum(x * y) / sum(y) + sigma = np.sqrt(sum(y * (x - mean) ** 2) / sum(y)) + FWHM = 2.35482 * sigma + + # Fit + popt, pcov = curve_fit(gauss, x, y, p0=[min(y), max(y), mean, sigma]) + + # Add FWHM to the ouptuts + popt = np.append(popt,2.35482 * popt[3]) + + # Print results + if fit_details : + print('The baseline offset is', popt[0]) + print('The center is', popt[2]) + print('The sigma of the fit is', popt[3]) + print('The maximum intensity is', popt[0] + popt[1]) + print('The Amplitude is', popt[1]) + print('The FWHM is', 2.35482 * popt[3]) + + # Show plot + if plot: + plt.figure() + plt.plot(x, y, '.k', label='data') + plt.plot(x, gauss(x, *gauss_fit(x, y)[0:4]), '--r', label='fit') + + plt.legend() + plt.title('Gaussian fit') + plt.xlabel('X') + plt.ylabel('Y') + plt.show() + + return popt + +######################## Unit conversions ######################## + +def joules_to_eV(joules): + """Just a unit conversion""" + eV = joules * 6.241509e18 + return eV + +def eV_to_joules(eV): + """Just a unit conversion""" + joules = eV * 1.602176565e-19 + return joules - - - +def photon_energy_from_wavelength(wavelength): + '''Returns photon energy in eV from wavelength in meters. Source https://www.kmlabs.com/en/wavelength-to-photon-energy-calculator''' + Eph = 1239.8 / (wavelength*1e9) + return Eph + +def wavelength_from_photon_energy(Eph): + '''Returns wavelength in meters from photon energy in eV. Source https://www.kmlabs.com/en/wavelength-to-photon-energy-calculator''' + wavelength = 1239.8 / (Eph*1e9) + return wavelength + +def sigma_to_FWHM(sigma): + """Gaussian sigma to FWHM""" + FWHM = sigma * 2.355 + return FWHM + +def FWHM_to_sigma(FWHM): + """FWHM to gaussian sigma""" + sigma = FWHM / 2.355 + return sigma \ No newline at end of file diff --git a/tests/test_utils.py b/tests/test_utils.py index af6d24b..48386f9 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,7 +1,7 @@ import pytest import os -from cristallina.utils import ROI, print_run_info, heuristic_extract_pgroup +from cristallina.utils import ROI, print_run_info, heuristic_extract_pgroup, gauss __author__ = "Alexander Steppke" @@ -25,3 +25,12 @@ def test_ROI(): def test_extract_pgroup(): os.chdir("/sf/cristallina/data/p19739") assert heuristic_extract_pgroup() == '19739' + +def test_gauss(): + # Test a random Gauss value and check whether the value didn't change in time + assert gauss(1.5,2.7,7,4.33,3) == 7.186044070987355 + +def test_find_nearest(): + # Make an array of 1 to 100 and check that the nearest index is the value + a = np.linspace(0,99,100) + assert find_nearest(a,10.1) == 10 \ No newline at end of file