Created
March 21, 2021 19:23
-
-
Save mszegedy/7acbd6ff8e8cee1113d1aba6164f2175 to your computer and use it in GitHub Desktop.
Writing this gave me brain damage.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/opt/anaconda/bin/python | |
import os | |
import math | |
import re | |
import json | |
import csv | |
import copy | |
import itertools | |
import numpy as np | |
import scipy as sp | |
import scipy.signal | |
import matplotlib.pyplot as plt | |
import matplotlib.colors as clr | |
import seaborn as sns | |
sns.set() | |
import latex | |
SMOOTHING_WINDOW = 21 | |
FWHM = 0.014 | |
def smooth(x,window_len=11,window='hanning'): | |
"""smooth the data using a window with requested size. | |
This method is based on the convolution of a scaled window with the signal. | |
The signal is prepared by introducing reflected copies of the signal | |
(with the window size) in both ends so that transient parts are minimized | |
in the begining and end part of the output signal. | |
input: | |
x: the input signal | |
window_len: the dimension of the smoothing window; should be an odd integer | |
window: the type of window from 'flat', 'hanning', 'hamming', 'bartlett', 'blackman' | |
flat window will produce a moving average smoothing. | |
output: | |
the smoothed signal | |
example: | |
t=linspace(-2,2,0.1) | |
x=sin(t)+randn(len(t))*0.1 | |
y=smooth(x) | |
see also: | |
np.hanning, np.hamming, np.bartlett, np.blackman, np.convolve | |
scipy.signal.lfilter | |
TODO: the window parameter could be the window itself if an array instead of a string | |
NOTE: length(output) != length(input), to correct this: return y[(window_len/2-1):-(window_len/2)] instead of just y. | |
""" | |
if x.ndim != 1: | |
raise ValueError("smooth only accepts 1 dimension arrays.") | |
if x.size < window_len: | |
raise ValueError("Input vector needs to be bigger than window size.") | |
if window_len<3: | |
return x | |
if not window in ['flat', 'hanning', 'hamming', 'bartlett', 'blackman']: | |
raise ValueError("Window is on of 'flat', 'hanning', 'hamming', 'bartlett', 'blackman'") | |
s=np.r_[x[window_len-1:0:-1],x,x[-2:-window_len-1:-1]] | |
#print(len(s)) | |
if window == 'flat': #moving average | |
w=np.ones(window_len,'d') | |
else: | |
w=eval('np.'+window+'(window_len)') | |
y=np.convolve(w/w.sum(),s,mode='valid') | |
return y[window_len//2:-window_len//2+1] | |
with open('calibration-curve.csv') as c_curve_f: | |
global c_curve | |
reader = csv.reader(c_curve_f) | |
c_curve = np.array(list(reader), dtype=np.float64) | |
c_curve_smoothed = (c_curve[:11,1]+c_curve[10:,1])/2 | |
def b(i, direction='up'): | |
if direction=='up': | |
if abs(i-round(i)) < 0.05: | |
return c_curve[round(i),1] | |
raise NotImplementedError('too far from int') | |
elif direction=='down': | |
if abs(i-round(i)) < 0.05: | |
return c_curve[20-round(i),1] | |
raise NotImplementedError('too far from int') | |
def b_err(i, direction='up'): | |
if abs(i-round(i)) > 0.05: | |
raise NotImplementedError('too far from int') | |
return abs(b(i, direction)-c_curve_smoothed[round(i)])*0.5+0.1 | |
class MagnetSpectrum: | |
INTENDED_G_EFFS = {('hg', 404.7): (2,), | |
('hg', 435.8): (1.5, 2.), | |
('ne', 585.3): (1,)} | |
def __init__(self, path): | |
self.path = path | |
matcher = re.compile(r'([a-z]+)-([0-9.]+)-([0-9.]+)s-24deg-([0-9.]+)A.csv') | |
matches = matcher.match(path) | |
self.gas = matches.group(1) | |
self.intended_peak = float(matches.group(2)) | |
self.intended_g_effs = MagnetSpectrum.INTENDED_G_EFFS[(self.gas, self.intended_peak)] | |
self.int_time = float(matches.group(3)) | |
self.current = float(matches.group(4)) | |
self.b = b(self.current) | |
self.b_err = b_err(self.current) | |
self.factor = 1 / (4.668e-8 \ | |
* self.intended_peak**2 \ | |
* self.b) | |
with open(path) as f: | |
reader = csv.reader(f) | |
self.data = np.array(list(reader)[2:], dtype=np.float64) | |
self.xdata = self.data.T[0] | |
self.inc = self.xdata[1]-self.xdata[0] | |
self.ydata = self.data.T[1]-np.amin(self.data.T[1]) | |
self.ydata /= np.amax(self.ydata) | |
self.ydata_smoothed = smooth(self.ydata, window_len=SMOOTHING_WINDOW) | |
self.noise = np.linalg.norm(self.ydata-self.ydata_smoothed)/len(self.ydata_smoothed) | |
if self.intended_peak in (404.7, 585.3): | |
peak_is, _ = \ | |
sp.signal.find_peaks(self.ydata, prominence=0.06) | |
self.peak_is = list(peak_is) | |
self.peak_ws, _, _, _ = np.array(sp.signal.peak_widths(self.ydata, | |
self.peak_is))*self.inc | |
else: | |
peak_is, _ = \ | |
sp.signal.find_peaks(self.ydata_smoothed, prominence=0.01) | |
self.peak_is = list(peak_is) | |
self.peak_ws, _, _, _ = np.array(sp.signal.peak_widths(self.ydata_smoothed, | |
self.peak_is))*self.inc | |
self.peak_is.sort(key=lambda i: self.xdata[i]) | |
self.peak_xs = np.array([self.xdata[i] for i in self.peak_is]) | |
self.peak_ys = np.array([self.ydata[i] for i in self.peak_is]) | |
self.peak_xerrs = 1000*self.peak_ws**2*self.noise / (2*self.peak_ys) + self.inc | |
if len(self.peak_is) == 1: | |
self.split_err = 0 | |
self.split = 0 | |
else: | |
self.split_err = np.sum(self.peak_xerrs)-self.inc*2 | |
self.split = self.peak_xs[1]-self.peak_xs[0] | |
self.b_split = self.split/9.328e-8/self.intended_peak**2 | |
self.g_eff = self.factor*self.split/2 | |
self.e_per_m_times_b = -2*math.pi*2.998e17*self.split \ | |
/ (np.mean(self.intended_g_effs)*self.intended_peak**2) | |
self.avg_peak_x = np.mean(self.peak_xs) | |
self.ydata_simulated = np.zeros_like(self.ydata) | |
for g_eff in self.intended_g_effs: | |
split_w = 2*g_eff/self.factor | |
for x in (self.avg_peak_x-split_w/2, self.avg_peak_x+split_w/2): | |
to_add = 1/(math.pi*FWHM/2*(1+((self.xdata-x)/FWHM*2)**2)) | |
self.ydata_simulated += to_add | |
self.ydata_simulated /= np.amax(self.ydata_simulated) | |
class MagnetFit: | |
def __init__(self, spectra): | |
print('Magnet fit for', spectra[0].gas, 'at', spectra[0].intended_peak) | |
self.spectra = spectra | |
self.spectra.sort(key=lambda s:s.current) | |
self.data = np.array([[s.b, s.b_split] for s in spectra]) | |
self.xdata = self.data.T[0] | |
self.ydata = self.data.T[1] | |
self.errs = np.array([[s.b_err, s.split_err] for s in spectra]) | |
self.xerrs = self.errs.T[0] | |
self.yerrs = self.errs.T[1]*50 | |
m, b, R, p, sigma = sp.stats.linregress(self.xdata, self.ydata) | |
print('m:',m,'b:',b) | |
print('R:',R,'sigma:',sigma) | |
self.m, self.b, self.R, self.p, self.sigma = m, b, R, p, sigma | |
self.fit_xdata = self.xdata | |
self.fit_ydata = self.xdata*m+b | |
class MagnetEPerMFit: | |
def __init__(self, spectra): | |
print('Magnet e/m fit for', spectra[0].gas, 'at', spectra[0].intended_peak) | |
self.spectra = spectra | |
self.spectra.sort(key=lambda s:s.current) | |
self.data = np.array([[s.b, s.e_per_m_times_b] for s in spectra]) | |
self.xdata = self.data.T[0] | |
self.ydata = self.data.T[1] | |
self.errs = np.array([[s.b_err, s.split_err] for s in spectra]) | |
self.xerrs = self.errs.T[0] | |
self.yerrs = self.errs.T[1]*50 | |
m, b, R, p, sigma = sp.stats.linregress(self.xdata, self.ydata) | |
print('m:',m,'b:',b) | |
print('R:',R,'sigma:',sigma) | |
self.m, self.b, self.R, self.p, self.sigma = m, b, R, p, sigma | |
self.fit_xdata = self.xdata | |
self.fit_ydata = self.xdata*m+b | |
def plot_c_curve(): | |
plt.figure() | |
plt.plot(c_curve.T[0], c_curve.T[1], 'ko', | |
c_curve.T[0], c_curve.T[1], 'k--') | |
plt.xlabel('Current (A)') | |
plt.ylabel('Magnetic field (T)') | |
plt.tight_layout() | |
plt.savefig('new_plots/c_curve.eps') | |
return latex.figure( | |
'images/c_curve.eps', | |
'Hysteresis loop for strength of magnets as a function of applied current.') | |
def plot_magnet_spectrum(s, out_path, description=''): | |
plt.figure() | |
plt.plot(s.xdata, s.ydata, 'k-', | |
s.xdata, s.ydata_simulated, 'k--') | |
plt.xlabel('Wavelength (nm)') | |
plt.ylabel('Intensity (normalized)') | |
plt.savefig('new_plots/'+out_path) | |
return latex.figure( | |
'images/'+out_path, | |
description) | |
def plot_magnet_fit_spectra(m, out_path, description=''): | |
plt.figure() | |
n = len(m.spectra) | |
_, ax = plt.subplots(n, 1, figsize=(4.5,n)) | |
s_ax = None | |
for i, s in enumerate(m.spectra): | |
s_ax = ax[i] | |
s_ax.plot(s.xdata, s.ydata, 'k-', | |
s.xdata, s.ydata_simulated, 'k--') | |
s_ax.set_title(f'{s.current} A') | |
if i != n-1: | |
s_ax.set_xticklabels([]) | |
s_ax.set_yticklabels([]) | |
s_ax.set(xlabel='Wavelength (nm)') | |
s_ax.set(ylabel='Intensity') | |
plt.tight_layout() | |
plt.savefig('new_plots/'+out_path) | |
return latex.figure( | |
'images/'+out_path, | |
description) | |
def plot_magnet_fit(m, out_path, description=''): | |
plt.figure() | |
plt.plot(m.fit_xdata, m.fit_ydata, 'k-', | |
[0, 1.5], [0, 1.5*np.mean(m.spectra[-1].intended_g_effs)], 'k--') | |
plt.errorbar(m.xdata, m.ydata, m.yerrs, m.xerrs, 'ko') | |
plt.xlabel('Magnetic field (T)') | |
plt.ylabel('Split size (T)') | |
plt.savefig('new_plots/'+out_path) | |
return latex.figure( | |
'images/'+out_path, | |
description) | |
def plot_magnet_e_per_m_fit(m, out_path, description=''): | |
plt.figure() | |
plt.plot(m.fit_xdata, m.fit_ydata, 'k-', | |
[0, 1.5], [0, -1.5*1.7588e11], 'k--') | |
plt.errorbar(m.xdata, m.ydata, m.yerrs, m.xerrs, 'ko') | |
plt.xlabel('Magnetic field (T)') | |
plt.ylabel('B‧e/m (Hz)') | |
plt.savefig('new_plots/'+out_path) | |
return latex.figure( | |
'images/'+out_path, | |
description) | |
first_group = ['hg-404.7-4s-24deg-0A.csv', 'hg-404.7-4s-24deg-10A.csv', | |
'hg-404.7-4s-24deg-1A.csv', 'hg-404.7-4s-24deg-2A.csv', | |
'hg-404.7-4s-24deg-3A.csv', 'hg-404.7-4s-24deg-4A.csv', | |
'hg-404.7-4s-24deg-5A.csv', 'hg-404.7-4s-24deg-6A.csv', | |
'hg-404.7-4s-24deg-7A.csv', 'hg-404.7-4s-24deg-8A.csv', | |
'hg-404.7-4s-24deg-9A.csv'] | |
first_group_magnet_fit = MagnetFit([MagnetSpectrum(path) for path in first_group]) | |
first_group_magnet_e_per_m_fit = MagnetEPerMFit([MagnetSpectrum(path) for path in first_group]) | |
second_group = ['ne-585.3-4s-24deg-0A.csv', 'ne-585.3-4s-24deg-10A.csv', | |
'ne-585.3-4s-24deg-1A.csv', 'ne-585.3-4s-24deg-2A.csv', | |
'ne-585.3-4s-24deg-3A.csv', 'ne-585.3-4s-24deg-4A.csv', | |
'ne-585.3-4s-24deg-5A.csv', 'ne-585.3-4s-24deg-6A.csv', | |
'ne-585.3-4s-24deg-7A.csv', 'ne-585.3-4s-24deg-8A.csv', | |
'ne-585.3-4s-24deg-9A.csv'] | |
second_group_magnet_fit = MagnetFit([MagnetSpectrum(path) for path in second_group]) | |
if __name__ == '__main__': | |
figures = [ | |
plot_c_curve(), | |
plot_magnet_spectrum(first_group_magnet_fit.spectra[0], 'hg-404_7-114deg.eps'), | |
plot_magnet_spectrum(MagnetSpectrum('hg-435.8-2s-24deg-10A.csv'), 'hg-435_8.eps'), | |
plot_magnet_fit_spectra(first_group_magnet_fit, 'hg-404_7-spectra.eps'), | |
plot_magnet_fit(first_group_magnet_fit, 'hg-404_7-fit.eps'), | |
plot_magnet_fit_spectra(second_group_magnet_fit, 'ne-585_3-spectra.eps'), | |
plot_magnet_fit(second_group_magnet_fit, 'ne-585_3-fit.eps'), | |
plot_magnet_e_per_m_fit(first_group_magnet_e_per_m_fit, 'hg-404_7-e-per-m-fit.eps')] | |
open('new_plots/figures.tex','w').write('\n'.join(figures)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment