In [65]:
#pylab mode
#remove the option inline to open plot windows using the selected gui backend. Induvidual graphs can stille be embedded using display(youfigure)
%pylab inline
#some imports for convenience
from __future__ import division
import sys
sys.path.append("../")
sys.path.append("../lmfit")
from lmfit import lmfit
import scipy.constants as const
#import the real thing
from tof_analysis import *
from helper import Moments
#some typesetting preferences
matplotlib.rcParams.update({'font.size': 14, 'font.family': 'serif'})
Assuming we have measured the transmitted IR Laser Power $I$ as a function of the Surface Position $Y_\mathrm{S}$.
The "SurfacePosMeas" class is designed to handle such a dataset. Its constructor's call signature is
where IRPos is the horizontal Position of the IR Laser on the Beamtool (in div) during the Surface Position Measurement.
In [66]:
Y = np.linspace(33, 35, 11) #Create a list of 11 equally spaced numbers from 33 to 35.
Power = [16.9, 16.9, 16.8, 16.6, 16.1, 13, 6.9, 2.5, 1.12, 0.63, 0.4] #Create a list of the measured IR Power corresponding to Y
PosMeas1 = SurfacePosMeas(Y, Power) #Create an instance of the SurfacePosMeas class
As one can see, the class automatically normalizes the data and fits it to a conjugate errorfunction yielding the surface position. Called like above, the Constructor recieves an IR Laser position of +7 div on the beamtool as default value. This can be changed easily:
In [67]:
PosMeas2 = SurfacePosMeas(Y, Power, IRPos=6)
Of course nothing changes in the plot or the fit since IRPos does not matter here, it comes into play when calculating the different distances occuring in the actual experiment.
In [68]:
print PosMeas1.Y0 #The Surface Position determined from the fit
print PosMeas1.IRPos
print PosMeas1.Y
In [69]:
print PosMeas1.Irel
The SurfacePosMeas class instance contains its own lmfit instance from which all attributes and properties are available:
In [70]:
print PosMeas1.fit.P #print the fit parameters ...
print PosMeas1.fit.StdDev #and their standard deviations
In [71]:
PosMeas1.fit.report()
In [72]:
print PosMeas1.fit.full_results
print 'RMS of Chi^2: %f' % PosMeas1.fit.full_results['RMSChi2'] # access Dictionary value for key 'RMSChi2'
In [73]:
PosMeas1.fit.plot() #Analysis Plots for the fit (kind of silly here...)
The Positions and finally the distances in the tagging experiment are calculated by the "TaggingSetup" class. It is constructed as
The "Position" argument is a dictionary containing all relevant Positions. If "SurfacePosMeas" stays "None", then tagging of the molecules on the way back is assumed and the direct distance between IR and REMPI Laser is calculated.
If "SurfacePosMeas" argument is an instance of the SurfacePosMeas class (like the one in the upper section) then the actual Surface Position is and all other distances are calculated.
In [74]:
Positions={'IR': (7,0), 'REMPI': 0, 'Center ZRM': 5.1, 'ZRM': 3.5, 'Surface Y': 33.6} #Create dictionary with Positions
Setup1 = TaggingSetup(Positions, SurfacePosMeas=PosMeas1, visualize=True) #Create instance of TaggingSetup class
In [75]:
Setup1.savefig('Setup1.pdf') # save the graph
In [76]:
print Setup1.FlightLength #the actual flight distance
In [77]:
Setup1.show() #write everything to the standard output
In [78]:
print Setup1.distances
print Setup1.distances['IR-S-MPI'] == Setup1.FlightLength
We will now look at some data from June 4th 2013
First the Setup:
In [79]:
Positions={'IR': (7,0), 'REMPI': -4, 'Center ZRM': 5.1, 'ZRM': 3.5} #Create dictionary with Positions
Setup = TaggingSetup(Positions, visualize=True) #Create instance of TaggingSetup class
The TOFSpectrum class is designed to handle one TOF data file and analyze it. It's constructor's signatur is
verbose and plot simply trigger the the report and the plot from the lmfit class, fit argument controls whether the Data is automatically fitted or not.
Also available as modes are: 'Flux_vs_TOF', 'Flux_vs_v', 'Flux_vs_E', 'Density_vs_v'
The Data is treated as follows:
Fitting:
Data is fit through the Levenberg-Marquardt algorithm. The following functions are used depending on the mode:
$$F(t) = F_0 \ \left( \frac{l}{t} \right)^4\mathrm{e}^{- \left(\frac{l}{\alpha}\right)^2 \left(\frac{1}{t} - \frac{1}{t_0} \right)^2}$$$$F(v) = F_0\ v^3\ \mathrm{e}^{-(v-v_0)^2/\alpha} $$$$ F(E) = \frac{F_0}{m^2} E\ \mathrm{e}^{- \frac{2}{m\alpha^2} \left( \sqrt{E} - \sqrt{E_0} \right)}$$$$ I(v) = I_0\ v^2\ \mathrm{e}^{-(v-v_0)^2/\alpha} $$
In [80]:
file0406002 = TaggingTOF(Setup, '../testdata/0406002.dat', 663, plot=True, verbose=True)
The Setup is also always available...
In [81]:
file0406002.Setup.visualize()
Same is true for the fit...
In [82]:
file0406002.Fit.P
Out[82]:
In [83]:
file0406002.plot() #The plot function of TOFSpectrum class ...
In [84]:
file0406002.Fit.plot() #vs. the plot function of lmfit class
Same file, different mode...
In [85]:
file0406002 = TaggingTOF(Setup, '../testdata/0406002.dat', 663, mode='Flux_vs_E')
file0406002.plot()
The TOFSpectrum class also holds an instance of the figure and axes objects from matplotlib...
In [86]:
file0406002.savefig('file0406002.svg') #save graph as svg vector image
file0406002.savefig('file0406002.pdf') # or pdf ... or eps... or... c.f. matplotlib reference for available graphic formats
In [87]:
file0406002.set_mode('Flux_vs_v') #change mode (but its better to create a new TOFSpectrum instance for that)
file0406002.fit()
file0406002.plot()
In [88]:
file0406002.set_mode('Flux_vs_E') #switch back to Energy
file0406002.fit()
file0406002.plot() #instances of matplotlib.figure and axes exist only when TOFSpectrum.plot() was calles before at some point
file0406002.axes.set_xlim((0,3)) #set xaxis limits. TOFSpectrum.axes gives you full access to the graphs properties
display(file0406002.fig) # show figure object in inline mode
The first three moments around 0 of the fit function can be calculated. Those are derived by numerical integration from 0 to $\infty$ using scipy.integrate.quad(). $$ \langle x^n \rangle = \int\limits_0^\infty x^n f(x) \ \mathrm{d} x $$ where $n=0,1,2$.
In [89]:
moments, mean, variance = file0406002.Moments
print moments # moments with numerical integration errors
The Mean and the Mean Squared values of the distributions can be calculated:
$$\langle x \rangle = \frac{\int\limits_0^\infty xf(x) \ \mathrm{d} x}{\int\limits_0^\infty f(x) \ \mathrm{d}x} $$$$\langle x^2 \rangle = \frac{\int\limits_0^\infty x^2f(x) \ \mathrm{d} x}{\int\limits_0^\infty f(x) \ \mathrm{d}x} $$
In [90]:
print mean
print variance
RMS = sqrt(variance)
print RMS
This works as well in other modes...
In [91]:
file0406002_v = TaggingTOF(Setup, '../testdata/0406002.dat', 663, mode='Flux_vs_v')
file0406002_v.plot()
In [92]:
print file0406002_v.Moments[1]
print sqrt(file0406002_v.Moments[2])
In [93]:
file0406002_E = TaggingTOF(Setup, '../testdata/0406002.dat', 663, mode='Flux_vs_E')
file0406002_E.plot()
file0406002_E.axes.set_xlim((0,1.5)) #set xaxis limits. TOFSpectrum.axes gives you full access to the graphs properties
display(file0406002_E.fig) # show figure object in inline mode
In [94]:
print file0406002_E.Fit.P
print file0406002_E.Fit.StdDev
In [95]:
P_Mean, P_StdDev, outlist = file0406002_E.Fit.bootstrap(n=500, plot=True)
print P_Mean
print P_StdDev
fitfunc = file0406002.get_fitfunc() #get the current fitfunction
E_Mean = np.array([None for i in outlist])
E_RMS = np.array([None for i in outlist])
i = 0
for finalParamsDict in outlist: # iterate over the final parameters of the bootstrap fits
zeroth, first, second = Moments(fitfunc, [0,1,2], args=finalParamsDict)
E_Mean[i] = first[0]/zeroth[0]
E_RMS[i] = second[0]/zeroth[0]
i += 1
print 'Mean Energy: (%f +/- %f) eV' %(E_Mean.mean(), E_Mean.std()) # maybe you want to use the standard error of the mean here instead of the standard deviation
print 'RMS Energy: (%f +/- %f) eV' %(E_RMS.mean(), E_RMS.std())
In [96]:
file0406003 = TaggingTOF(Setup, '../testdata/0406003.dat', 663)
file0406003.plot()
Using TOFSpectrum for manual analysis:
In [97]:
TOF, Flux = file0406003.get_values()
TOFslice, Fluxslice = file0406003.get_values(limits=(10,30))
plot(TOF, Flux, 'bo')
plot(TOFslice, Fluxslice, 'ro')
fitfunc = file0406003.get_fitfunc()
print fitfunc.func_code.co_varnames #inspect live object to see the variable names
In [98]:
file0406003fit = lmfit(fitfunc, TOFslice, Fluxslice, p0={'F0':1, 'alpha': -0.2, 'x0':20}, verbose=False, plot=True, plot_options={'acf':False, 'lagplot':False})
In [99]:
zeroth, first, second = Moments(file0406003fit, [0,1,2])
mean = first[0]/zeroth[0]
In [100]:
fig1 = figure(1)
plot(TOF, Flux, 'bo')
ylim((-0.01, 1.05))
xlim((0,50))
xlabel(r'$\mathrm{TOF}\ / \ \mu\mathrm{s}$')
ylabel(r'$\mathrm{Normalized\ Flux}$')
plot(TOFslice, Fluxslice, 'ro')
x = linspace(TOF[0], TOF[-1], 1000)
plot(x, file0406003fit(x), 'r-', label=r'Fit')
legend(loc='best')
bar(mean, file0406003fit(mean), width=0.01)
string = r'$\langle \mathrm{TOF} \rangle =\ %2.2f\ \mu\mathrm{s}$' % mean
annotate(string, xy=(25,0.6), xycoords='data')
savefig('0406003manual.pdf')
plt.show()
Dealing with Background:
In [101]:
Positions={'IR': (7,0), 'REMPI': -4, 'Center ZRM': 5.1, 'ZRM': 3.5, 'Surface Y': 33.6} #Create dictionary with Positions
Setup3 = TaggingSetup(Positions, visualize=True) #Create instance of TaggingSetup class
file0606028 = TaggingTOF(Setup, '../testdata/0606028.dat', 654, fit=False)
file0606029 = TaggingTOF(Setup, '../testdata/0606029.dat', 654, fit=False)
In [102]:
file0606028.RawData.plot()
In [103]:
file0606029.RawData.plot()
In [104]:
TOF = file0606029.RawData.TOF
SIG = file0606029.RawData.Baseline-file0606029.RawData.Signal
bgfit = polyfit(TOF, SIG, 5)
print bgfit
plot(TOF, SIG)
x = linspace(xlim()[0], xlim()[1], 1000)
plot(x, polyval(bgfit, x))
show()
In [105]:
Sig = file0606028.RawData.Baseline-file0606028.RawData.Signal - polyval(bgfit, file0606029.RawData.TOF)
plot(file0606028.RawData.TOF, Sig, 'k-')
show()
In [106]:
savetxt('temp.dat', transpose(array([file0606028.RawData.TOF, -Sig, zeros(len(Sig))]))) # save to file, third column with zeros must be appended
In [107]:
file0606028corr = TaggingTOF(Setup3, 'temp.dat', 654, fit=False)
In [108]:
TOF, Flux = file0606028corr.TOF
TOFslice, Fluxslice = file0606028corr.get_values(limits=(10,160))
plot(TOF, Flux, 'bo')
plot(TOFslice, Fluxslice, 'ro')
show()
In [109]:
fitfunc = file0606028.get_fitfunc()
file0606028corr_fit = lmfit(fitfunc, TOFslice, Fluxslice, p0={'F0':1, 'alpha':-0.2, 'x0':20}, verbose=False, plot=True)
In [110]:
file0606028corr2 = TaggingTOF(Setup3, 'temp.dat', 654, fit=False)
file0606028corr2.fit(p0={'F0':1, 'alpha':-0.2, 'x0':20}, plot=False)
file0606028corr2.plot()
In [111]:
files = [u'../testdata/0406012.dat',\
u'../testdata/0406013.dat',\
u'../testdata/0406014.dat',\
u'../testdata/0406015.dat',\
u'../testdata/0406016.dat',\
u'../testdata/0406017.dat',\
u'../testdata/0406018.dat',\
u'../testdata/0406019.dat',\
u'../testdata/0406020.dat',\
u'../testdata/0406021.dat',\
u'../testdata/0406022.dat',\
u'../testdata/0406023.dat']
descriptions = [r'$100\ ^\circ \mathrm{C}$',\
r'$200\ ^\circ \mathrm{C}$',\
r'$400\ ^\circ \mathrm{C}$',\
r'$600\ ^\circ \mathrm{C}$',\
r'$700\ ^\circ \mathrm{C}$',\
r'$500\ ^\circ \mathrm{C}$',\
r'$300\ ^\circ \mathrm{C}$',\
r'$-180\ ^\circ \mathrm{C}$',\
r'$-100\ ^\circ \mathrm{C}$',\
r'$-50\ ^\circ \mathrm{C}$',\
r'$0\ ^\circ \mathrm{C}$',\
r'$30\ ^\circ \mathrm{C}$']
R6Tagging = MultiTOF(files, descriptions, Setup, 663, mode='Flux_vs_E')
In [112]:
R6Tagging.plot(xlim=(0,3))
In [113]:
R6_300deg = R6Tagging[3]
R6_300deg.plot()
In [114]:
R6_300deg.Fit.plot()
In [115]:
moments, mean, variance = R6_300deg.Moments
print mean, sqrt(variance)
In [116]:
from helper import SelectFileDialog
In [117]:
#files = SelectFileDialog()
#print files
In [118]:
from helper import construct_filename
In [119]:
print construct_filename('1607', 1)
In [120]:
print construct_filename('1607', range(10))
In [121]:
ls
In [122]:
rm -f file0406002.pdf
In [123]:
rm -f file0406002.svg
In [124]:
rm -f Setup1.pdf
In [125]:
rm -f temp.dat
In [126]:
rm -f 0406003manual.pdf
In [126]: