Newer
Older
import numpy as np
import pandas as pd
from scipy.optimize import curve_fit
lorenzennio
committed
This class computes mean and error on the detector output.
It then fits the exact equations of motions for a particle
in a magnetic field to the input data.
The results can then be visualized with plots.
def __init__(self):
...
def fill(self, bounds):
self.xBounds = pd.Series({'High' : bounds[:,0,0],
'Low' : bounds[:,0,1]})
self.yBounds = pd.Series({'High' : bounds[:,1,0],
'Low' : bounds[:,1,1]})
self.results = pd.DataFrame({'w' : np.zeros(2),
'vx' : np.zeros(2),
'vy' : np.zeros(2),
'vz' : np.zeros(2)})
lorenzennio
committed
self.xPoints = pd.DataFrame({'Mean': (bounds[1:,0,0] + bounds[1:,0,1])/2.,
'Error': (bounds[1:,0,0] - bounds[1:,0,1])/np.sqrt(12.)})
lorenzennio
committed
self.yPoints = pd.DataFrame({'Mean': (bounds[1:,1,0] + bounds[1:,1,1])/2.,
lorenzennio
committed
'Error': (bounds[1:,1,0] - bounds[1:,1,1])/np.sqrt(12.)})
lorenzennio
committed
self.zPoints = pd.DataFrame({'Mean': (bounds[1:,2,0] + bounds[1:,2,1])/2.,
lorenzennio
committed
'Error': (bounds[1:,2,0] - bounds[1:,2,1])/np.sqrt(12.)})
self.tPoints = pd.DataFrame({'Mean': bounds[1:,3,0],
'Error': 1e-9})
print(self.xPoints)
print(self.yPoints)
print(self.zPoints)
lorenzennio
committed
print(self.tPoints)
#print(self.xBounds['High'])
self.xBounds['High'] = np.array([x for x in self.xBounds['High'] if x is not None])
self.xBounds['Low'] = np.array([x for x in self.xBounds['Low'] if x is not None])
self.yBounds['High'] = np.array([x for x in self.yBounds['High'] if x is not None])
self.yBounds['Low'] = np.array([x for x in self.yBounds['Low'] if x is not None])
lorenzennio
committed
"""----------------------------------------------------------------------------
FITTING
Here we fit the data. As a fitting procedure we use ORTHOGONAL DISTANCE REGRESSION.
We fit all three spacial dimensions with respect to time, which is the same as fitting
path length for non-relativistic paricles.
The fitting functions / equations of motion are xEOM, yEOM, zEOM.
The actual fits are performed by the functions xFit, yFit, zFit.
The fitting functions are called by the function Fit. It also collects
all the results and fills them into the results dataframe.
"""
def Fit(self):
This function performs all the fits. The most stable are xFit and
zFit, so we use the results of those.
As the fitting functions are non-trivial and the signs of the
parameters can get mixed up, the correct signs are also determined
within this function.
lorenzennio
committed
xResults = self.xFit()
yResults = self.yFit()
zResults = self.zFit()
print(xResults.beta)
print(yResults.beta)
print(zResults.beta)
#Determine correct signs
wSgn = 1
vySgn = 1
if yResults.beta[0] < 0 or yResults.beta[2] < 0:
wSgn = -1
if yResults.beta[1] < 0:
vySgn = -1
#Extract correct results from fitting and fill to results container
self.results['vx'] = np.array([xResults.beta[0], xResults.sd_beta[0]])
#w = (np.abs(yResults.beta[0]) + np.abs(zResults.beta[0]))/2.
#wStd = np.sqrt(yResults.sd_beta[0]**2 + zResults.sd_beta[0]**2)
w = wSgn*np.abs(zResults.beta[0])
wStd = zResults.sd_beta[0]
self.results['w'] = np.array([w , wStd])
lorenzennio
committed
#vy = ySgn*(np.abs(yResults.beta[1]) + np.abs(zResults.beta[1]))/2.
#vyStd = np.sqrt(yResults.sd_beta[1]**2 + zResults.sd_beta[1]**2)
vy = vySgn*np.abs(zResults.beta[1])
vyStd = zResults.sd_beta[1]
lorenzennio
committed
#vz = zSgn*(np.abs(yResults.beta[2]) + np.abs(zResults.beta[2]))/2.
#vzStd = np.sqrt(yResults.sd_beta[2]**2 + zResults.sd_beta[2]**2)
vz = np.abs(zResults.beta[2])
vzStd = zResults.sd_beta[2]
lorenzennio
committed
"""
Equations of motion:
w = qB/m, where q is the charge [C], B the magnetic field [T] and
m the particle mass.
Vx = initial x velocity of the particle
Vy = initial y velocity of the particle
Vz = initial z velocity of the particle
"""
lorenzennio
committed
def xEOM(self, B, t):
lorenzennio
committed
B = [Vx]
lorenzennio
committed
x = B[0]*t
return x
lorenzennio
committed
def yEOM(self, B, t):
"""
B = [w, Vy, Vz]
"""
#y = B[1] + np.sqrt(B[0]**2 - (z-B[2])**2)
y = (1/B[0])*(B[2]*(1-np.cos(t*B[0])) + B[1]*np.sin(t*B[0]))
return y
lorenzennio
committed
def zEOM(self, B, t):
"""
B= [w, Vy, Vz]
"""
z = (1/B[0])*(-B[1]*(1-np.cos(t*B[0])) + B[2]*np.sin(t*B[0]))
return z
lorenzennio
committed
def pol(self, B, x):
return B[0] + B[1]*x + B[2]*(x**2) + B[3]*(x**3)
"""
Functions running the ODR fits:
We fit the collision points of the particle with the detector plate
with respect to time.
The fits are performed by the scipy.odr package. Initial guesses for
parameters are specified by beta[0]. See fitting functions for a
description of the parameters.
"""
lorenzennio
committed
xModel = odr.Model(self.xEOM)
xData = odr.RealData(self.tPoints['Mean'],
lorenzennio
committed
self.xPoints['Mean'],
lorenzennio
committed
sx = self.tPoints['Error'],
lorenzennio
committed
sy = self.xPoints['Error'])
xODR = odr.ODR(xData, xModel,beta0=[1])# beta0=[1, 100, 100, 100])
lorenzennio
committed
#xOUT.pprint()
print('The x fit was performend with chi2 = ', xOUT.res_var)
#print(xOUT.sd_beta)
return xOUT
"""
lorenzennio
committed
print('x ', xOUT.res_var)
lorenzennio
committed
plt.plot(self.tPoints['Mean'],self.xEOM(xOUT.beta, self.tPoints['Mean']))
plt.plot(self.tPoints['Mean'], self.xPoints['Mean'], 'o')
plt.xlabel('t')
lorenzennio
committed
plt.ylabel('x')
lorenzennio
committed
plt.savefig('x.pdf', format='pdf')
lorenzennio
committed
plt.gcf().clear()
lorenzennio
committed
lorenzennio
committed
yModel = odr.Model(self.yEOM)
yData = odr.RealData(self.tPoints['Mean'],
lorenzennio
committed
sx = self.tPoints['Error'],
lorenzennio
committed
yODR = odr.ODR(yData, yModel, beta0=[1, 10, 100])
lorenzennio
committed
print('The y fit was performend with chi2 = ', yOUT.res_var)
#yOUT.pprint()
return yOUT
"""
lorenzennio
committed
print('y :', yOUT.res_var)
lorenzennio
committed
plt.plot(self.tPoints['Mean'], self.yEOM(yOUT.beta, self.tPoints['Mean']))
plt.plot(self.tPoints['Mean'], self.yPoints['Mean'], 'o')
plt.xlabel('t')
lorenzennio
committed
plt.ylabel('y')
lorenzennio
committed
plt.savefig('y.pdf', format='pdf')
lorenzennio
committed
plt.gcf().clear()
lorenzennio
committed
def zFit(self):
zModel = odr.Model(self.zEOM)
zData = odr.RealData(self.tPoints['Mean'],
self.zPoints['Mean'],
sx = self.tPoints['Error'],
sy = self.zPoints['Error'])
zODR = odr.ODR(zData, zModel, beta0=[1, 1, 100])
lorenzennio
committed
zOUT = zODR.run()
print('The z fit was performend with chi2 = ', zOUT.res_var)
#zOUT.pprint()
#print('z :', zOUT.res_var)
return zOUT
"""
plt.plot(self.tPoints['Mean'], self.zEOM(zOUT.beta, self.tPoints['Mean']))
plt.plot(self.tPoints['Mean'], self.zPoints['Mean'], 'o')
plt.xlabel('t')
plt.ylabel('z')
plt.savefig('z.pdf', format='pdf')
plt.gcf().clear()
def output(self):
print(self.results)