(momentum variables)
- L = *( - ) (geometric variables)
- rotation_axis_dict = dict that defines the axis of rotation
"""
if not Bunch.__geometric_momentum:
return self.moment(['x','py'], rotation_axis_dict) - self.moment(['y','px'], rotation_axis_dict)
else:
return (self.moment(['x','y\''], rotation_axis_dict) - self.moment(['y','x\''], rotation_axis_dict)) * self.mean(['pz'])['pz']
def get_canonical_angular_momentum(self, bz=None, field_axis_dict={'x':0, 'y':0}, rotation_axis_dict={'x':0,'y':0,'px':0,'py':0}):
"""
Return the bunch canonical angular momentum about some arbitrary axis, defined by
- L = - + e Bz (+y^2) (momentum variables)
- L = *( - ) + e Bz (+y^2) (geometric variables)
- bz = nominal on-axis magnetic field - where axis is as; defaults to the field of the 1st particle in the bunch
- field_axis_dict = dict that defines the nominal solenoid axis
- rotation_axis_dict = dict that defines the axis of rotation
"""
if bz==None:
bz = (self[0]['bz'])
return self.get_kinetic_angular_momentum(rotation_axis_dict) + \
Common.constants['c_light']*bz*(self.moment(['x','x'], field_axis_dict) + self.moment(['y','y'], field_axis_dict))/2.
def momentum_variable(axis_variable, geometric_momentum):
"""
Return the momentum conjugate for axis_variable
"""
if not axis_variable in Bunch.__axis_list:
raise IndexError(str(axis_variable)+' does not appear to be an axis variable. Options are '+str(Bunch.get_axes()))
if type(axis_variable) == int:
if geometric_momentum:
return Hit.get_variables()[axis_variable]+'\''
else:
return Hit.get_variables()[axis_variable+4]
if geometric_momentum:
return axis_variable+'\''
elif axis_variable == 't' or axis_variable == 'ct' or axis_variable==3:
return 'energy'
else:
return 'p'+axis_variable
momentum_variable = staticmethod(momentum_variable)
def get_amplitude (bunch, hit, axis_list, covariance_matrix=None, mean_dict={}, geometric=None):
"""
Return the particle amplitude for a hit relative to a bunch, defined by
- amplitude = emittance*x^T.V^-1.x
where x is a vector of particle coordinates and V is a covariance matrix
- bunch = bunch from which the covariance matrix is calculated
- hit = hit from which the particle vector is taken
- axis_list = list of axes that defines the covariance matrix and particle vector
- covariance_matrix = if this is not set to None, will use this covariance_matrix
for the calculation rather than taking one from bunch. Should be a numpy matrix
like "x","px","y","py"
E.g.
~~~~~~~{.py}
Bunch.get_amplitude(my_bunch, my_hit, ['x','y'])
~~~~~~~
will return
emittance*(x,px,y,py)^T*V^{-1}(x,px,y,py)*(x,px,y,py)
"""
if geometric == None: geometric = Bunch.__geometric_momentum
cov_list = Bunch.axis_list_to_covariance_list(axis_list, geometric)
if mean_dict == {}:
mean_dict = bunch.__mean_picker(axis_list)
if mean_dict == {}:
mean_dict = bunch.mean(cov_list)
my_vector = hit.get_vector(cov_list, mean_dict)
my_cov = copy.deepcopy( covariance_matrix )
if my_cov == None:
my_cov = bunch.__cov_mat_picker(axis_list)
if my_cov == None:
my_cov = bunch.covariance_matrix(cov_list)
my_amp = my_vector*linalg.inv(my_cov)*my_vector.T
return float(my_amp[0,0])*bunch.get_emittance(axis_list, my_cov)
get_amplitude = staticmethod(get_amplitude)
def axis_list_to_covariance_list(axis_list, geometric=None):
"""
Convert from a list of position variables to a list of position
and conjugate momentum variables
- axis_list = list of strings from get_axes()
"""
if geometric == None: geometric = Bunch.__geometric_momentum
cov_list = []
for axis in axis_list:
cov_list.append(axis)
cov_list.append(Bunch.momentum_variable(axis, geometric))
return cov_list
axis_list_to_covariance_list = staticmethod(axis_list_to_covariance_list)
def convert_string_to_axis_list(axis_string):
"""
Return a list of axes from a string.
- axis_string = string that contains a list of axis. Either format
as axis_strings separated by white space or as a python list
of axis_strings
"""
axis_list = []
try:
axis_list = eval(axis_string) #try to evaluate it as a list
except:
axis_list = axis_string.split(' ') #assume it is a white space separated dataset instead
for key in axis_list:
if not key in Bunch.__axis_list:
raise KeyError('Could not resolve '+str(axis_string)+' into a list of axes.')
return axis_list
convert_string_to_axis_list = staticmethod(convert_string_to_axis_list)
def set_geometric_momentum(new_value_bool):
"""
Set the default for conjugate momenta; either geometric (x', y', etc) or kinetic (px, py, etc)
- new_value_bool = if True, use geometric momenta. If False, use kinetic momenta (default)
"""
Bunch.__geometric_momentum = new_value_bool
set_geometric_momentum = staticmethod(set_geometric_momentum)
def get_geometric_momentum():
"""
Set the default for conjugate momenta; either geometric (x', y', etc) or kinetic (px, py, etc)
- new_value_bool = if True, use geometric momenta. If False, use kinetic momenta (default)
"""
return Bunch.__geometric_momentum
get_geometric_momentum = staticmethod(get_geometric_momentum)
def get_axes():
"""Return list of axis variables (position-type variables)"""
return Bunch.__axis_list
get_axes = staticmethod(get_axes)
def get_hit_variable(self, hit, variable_name, covariance_matrix=None, mean_dict={}):
"""
Return axis variable for hit. Special power is that it can calculate amplitude, unlike hit.get(blah)
- hit = a Hit object
- variable_name = either a variable from Hit.get_variables() or an amplitude variable.
amplitude variables should be formatted like 'amplitude x y' or 'amplitude x y t'
- covariance_matrix = use a pre-calculated covariance matrix, or calculate if set to None
"""
if type(variable_name) == str:
if variable_name.find('amplitude') > -1:
axis_list = Bunch.convert_string_to_axis_list(variable_name[10:len(variable_name)])
return Bunch.get_amplitude(self, hit, axis_list, covariance_matrix, mean_dict)
return hit.get(variable_name)
def list_get_hit_variable(self, list_of_variables, list_of_units=[], covariance_matrix = None, mean_dict = {}):
"""
Return a list of get_hit_variable results, one element for each hit in the bunch
- variable_name = either a variable from Hit.get_variables() or an amplitude variable.
amplitude variables should be formatted like 'amplitude x y' or 'amplitude x y t'
i.e. amplitude followed by a list of axes separated by white space
- covariance_matrix = use a pre-calculated covariance matrix, or calculate if set to None
"""
values = []
for dummy in list_of_variables:
values.append([])
for i in range(len(list_of_variables)):
var = list_of_variables[i]
if type(var) is str:
if(var.find('amplitude') > -1):
axis_list = Bunch.convert_string_to_axis_list(var[10:len(var)])
if covariance_matrix == None:
covariance_matrix = self.covariance_matrix( Bunch.axis_list_to_covariance_list(axis_list) )
if mean_dict == {}:
mean_dict = self.mean(Bunch.axis_list_to_covariance_list(axis_list))
for hit in self.__hits:
values[i].append( self.get_hit_variable(hit, var, covariance_matrix, mean_dict) )
if not list_of_units == []:
values[i][-1] /= Common.units[list_of_units[i]]
return values
def get(self, variable_string, variable_list):
"""
Return a bunch variable taken from the list Bunch.get_variables()
- variable_string = string variable from Bunch.get_variables()
- variable_list = list of variables (see below, a bit complicated)
For 'bunch_weight', axis_list is ignored
For 'dispersion', 'dispersion_prime' the first value of variable_list is used. It should be taken from the list Bunch.get_axes()
For 'mean', the first value in variable_list is used. It should be taken from the list Bunch.hit_get_variables()
For others, variable_list should be a list taken from Bunch.get_axes()
E.g. bunch.get('emittance', ['x','y']) would get emittance x y
E.g. bunch.get('mean', ['x','px','z']) would return mean of x; px and z are ignored
"""
if not variable_string in Bunch.__get_dict:
raise KeyError(variable_string+' not available. Options are '+str(Bunch.get_variables()))
else:
return self.__get_dict[variable_string](self, variable_list)
def list_get(dict_of_bunches, list_of_variables, list_of_axis_lists):
"""
Get a list of lists of variables from each bunch in the dict_of_bunches
- dict_of_bunches = dict of bunches from which the lists will be taken
- list_of_variables = list of variables that will be used in the calculation
- list_of_axis_lists = axis_list that will be used in the calculation of the
corresponding variable
E.g. list_get(my_dict_of_bunches, ['mean', 'emittance'], [['z'],['x','y']])
would calculate a list of two arrays: (i) mean z; (ii) emittance x y
Output is sorted by the first variable in the list. This might be useful to interface
with E.g. a plotting package
"""
values = []
for dummy in list_of_variables:
values.append([])
for key, bunch in dict_of_bunches.iteritems():
for i in range(len(list_of_variables)):
values[i].append(bunch.get(list_of_variables[i], list_of_axis_lists[i]))
Common.multisort(values)
return values
list_get = staticmethod(list_get)
def get_variables():
"""Return a list of variables suitable for calls to Bunch.get"""
return Bunch.__get_list
get_variables = staticmethod(get_variables)
def hit_get_variables():
"""Return a list of variables suitable for calls to Bunch.get"""
return Hit.get_variables()+['amplitude x', 'amplitude y', 'amplitude x y', 'amplitude ct', 'amplitude x y ct']
hit_get_variables = staticmethod(hit_get_variables)
def hit_write_builtin(self, file_type_string, file_name, user_comment=None):
"""
Write the hits in the bunch using some built-in format to the file file_name
- file_type_string = string that controls which predefined file type will be used
- file_name = string that defines the file name
- user_comment = comment to be included in file header (e.g. problem title)
e.g. my_bunches.hit_write_builtin('g4mice_special_hit', 'Sim.out.gz') would write all hits
from my_bunches formatted in the old G4MICE Special Virtual style in file Sim.out.gz
"""
if not file_type_string in Hit.file_types(): raise IOError('Attempt to write file of unknown file type '+str(file_type_string)+' - try one of '+str(Hit.file_types()))
Hit.write_list_builtin_formatted(self.__hits, file_type_string, file_name, user_comment)
return
def hit_write_builtin_from_dict(dict_of_bunches, file_type_string, file_name, user_comment=None):
"""
Write the hits in the dict of bunches using some built-in format to the file file_name
- dict_of_bunches = list of hits
- file_type_string = string that controls which predefined file type will be used
- file_name = string that defines the file name
- user_comment = comment to be included in file header (e.g. problem title)
e.g. Bunch.hit_write_builtin_from_dict(my_bunches, 'g4mice_special_hit', 'Sim.out.gz') would write all hits
from my_bunches formatted in the G4MICE Special Virtual style in file Sim.out.gz
"""
if not file_type_string in Hit.file_types(): raise IOError('Attempt to write file of unknown file type '+str(file_type_string)+' - try one of '+str(Hit.file_types()))
all_hits = []
for key,value in dict_of_bunches.iteritems():
all_hits += value.hits()
Hit.write_list_builtin_formatted(all_hits, file_type_string, file_name)
hit_write_builtin_from_dict = staticmethod(hit_write_builtin_from_dict)
def hit_write_user(self, format_list, format_units_dict, file_handle, separator=' ', comparator=None):
"""
Write the hits in the bunch in some user defined format to file_handle, in an order defined by comparator
- format_list = ordered list of strings from get_variables()
- format_units_dict = dict of formats from format_list to units
- file_handle = file handle made using e.g. open() command to which hits are written
- separator = separator that is used to separate hits
- comparator = comparator that is used for sorting prior to writing the file; if left as None, no sorting is performed
e.g. aBunch.hit_write_user(['x','px','y','py'], ['x':'m','y':'m','px':'MeV/c','py':'MeV/c'], some_file, '@') would make output like
0.001@0.002@0.001@0.002
0.003@0.004@0.003@0.004
in some_file
"""
if not comparator==None:
self.__hits.sort(comparator)
for hit in self.__hits:
hit.write_user_formatted(format_list, format_units_dict, file_handle, separator)
def build_ellipse_2d(beta, alpha, emittance, p, mass, geometric):
"""
Build a 2x2 ellipse matrix, given by
For geometric = true
- var(x, x) = beta*emittance
- var(x, x') = alpha*emittance
- var(x',x') = gamma*emittance
For geometric = false
- var(x, x ) = beta*emittance*mass/p
- var(x, px) = alpha*emittance*mass
- var(px,px) = gamma*emittance*mass*p
"""
Common.has_numpy()
cov = matrix(numpy.zeros((2,2)))
gamma = (1.+alpha**2)/beta
if beta <= 0.:
raise ValueError("Beta "+str(beta)+" must be positive")
if emittance <= 0.:
raise ValueError("Emittance "+str(emittance)+" must be positive")
if geometric:
cov[0,0] = beta *emittance
cov[1,0] = -alpha*emittance
cov[0,1] = cov[1,0]
cov[1,1] = gamma*emittance
if not geometric:
cov[0,0] = beta *emittance*mass/p
cov[1,0] = -alpha*emittance*mass
cov[0,1] = cov[1,0]
cov[1,1] = gamma*emittance*mass*p
return cov
build_ellipse_2d = staticmethod(build_ellipse_2d)
def build_MR_ellipse():
"""
Not implemented
"""
# Build a 6x6 ellipse using the Mais-Ripken parameterisation - not implemented
raise NotImplementedError('Mais-Ripken methods will be released later')
build_MR_ellipse = staticmethod(build_MR_ellipse)
def build_ET_ellipse():
"""
Not implemented
"""
# Build a 6x6 ellipse using the Edwards-Teng parameterisation
raise NotImplementedError('Edwards-Teng methods will be released later')
build_ET_ellipse = staticmethod(build_ET_ellipse)
def build_ellipse_from_transfer_matrix( M ):
"""
Not implemented
"""
# Build an ellipse using the transfer matrix M such that M.T() * ellipse * M = ellipse
raise NotImplementedError('This function not ready yet')
build_ellipse_from_transfer_matrix = staticmethod(build_ellipse_from_transfer_matrix)
def build_penn_ellipse(emittance_t, mass, beta_t, alpha_t, p, Ltwiddle_t, bz, q):
"""
Build an ellipse using Penn formalism for solenoids.
- emittance_t = nominal beam emittance
- mass = particle mass
- beta_t = transverse beta function
- alpha_t = transverse alpha function
- p = reference momentum
- Ltwiddle_t = normalised canonical angular momentum
- bz = magnetic field strength
- q = particle charge
Output ellipse is a 4*4 matrix with elements v_ij where i,j indexes the vector (x,px,y,py)
"""
if beta_t <= 0.:
raise ValueError("Beta "+str(beta_t)+" must be positive")
if emittance_t <= 0.:
raise ValueError("Emittance "+str(emittance_t)+" must be positive")
if mass <= 0.:
raise ValueError("Mass "+str(mass)+" must be positive")
k = Common.constants['c_light']*bz/2./p
gamma_t = (1+alpha_t*alpha_t+(beta_t*k - Ltwiddle_t)*(beta_t*k-Ltwiddle_t))/beta_t
s_xx = emittance_t*mass*beta_t/p
s_xpx = -emittance_t*mass*alpha_t
s_pxpx = emittance_t*mass*p*gamma_t
s_xpy = -emittance_t*mass*(beta_t*k-Ltwiddle_t)*q
covariance_matrix = numpy.matrix([
[s_xx, s_xpx, 0., s_xpy],
[s_xpx, s_pxpx,-s_xpy, 0],
[ 0., -s_xpy, s_xx, s_xpx],
[s_xpy, 0., s_xpx, s_pxpx],
])
return covariance_matrix
build_penn_ellipse = staticmethod(build_penn_ellipse)
def histogram(self, x_axis_string, x_axis_units='', y_axis_string='', y_axis_units='', nx_bins=None, ny_bins=None, xmin=None, xmax=None, ymin=None, ymax=None):
"""
Returns a binned 1D or 2D histogram of hits in the bunch (but doesnt draw anything or call any plotting package).
- x_axis_string = string for call to get_hit_variables()
- x_axis_units = units for x axis
- y_axis_string = string for call to get_hit_variables(). If string is empty, makes a 1D histogram
- y_axis_units = units for y axis
- nx_bins = force histogram to use this number of bins for the x-axis rather than choosing number of bins itself
- ny_bins = force histogram to use this number of bins for the y-axis rather than choosing number of bins itself
- xmin = float that overrides auto-detection of minimum x-axis value
- xmax = float that overrides auto-detection of maximum x-axis value
- ymin = float that overrides auto-detection of minimum y-axis value
- ymax = float that overrides auto-detection of maximum y-axis value
Return value is a list of bin weights for a 1D histogram or a list of lists of bin weights for a 2D histogram
"""
Common.has_numpy()
weights = self.list_get_hit_variable(['weight'], [''])[0]
x_points = self.list_get_hit_variable([x_axis_string], [x_axis_units])[0]
y_bins = None
if xmin!=None: xmin*=Common.units[x_axis_units]
if xmax!=None: xmax*=Common.units[x_axis_units]
if ymin!=None: ymin*=Common.units[y_axis_units]
if ymax!=None: ymax*=Common.units[y_axis_units]
if y_axis_string=='':
(nx_bins, ny_bins, dummy) = Common.n_bins(len(x_points), nx_bins, 1)
else:
y_points = self.list_get_hit_variable([y_axis_string], [y_axis_units])[0]
(nx_bins, ny_bins, dummy) = Common.n_bins(len(y_points), nx_bins, ny_bins, 2)
y_bins = Common.get_bin_edges(y_points, ny_bins, ymin, ymax)
x_bins = Common.get_bin_edges(x_points, nx_bins, xmin, xmax)
return self.histogram_var_bins(x_axis_string, x_bins, x_axis_units, y_axis_string, y_bins, y_axis_units)
def histogram_var_bins(self, x_axis_string, x_bins, x_axis_units='', y_axis_string='', y_bins=None, y_axis_units=''):
"""
Returns a binned histogram of hits in the bunch.
Requires numpy
- x_axis_string = string for call to get_hit_variables()
- x_bins = list of bin edges used to generate the histogram
- x_axis_units = units for x axis
- y_axis_string = string for call to get_hit_variables()
- y_bins = list of bin edges used to generate the histogram
- y_axis_units = units for y axis
Return value is a tuple containing ((bin weights array),x_bins,y_bins). The bin weights array is always nx*ny, with ny defaulting to 1 in the case of a 1d histogram.
"""
Common.has_numpy()
weights = self.list_get_hit_variable(['weight'], [''])[0]
x_points = self.list_get_hit_variable([x_axis_string], [x_axis_units])[0]
if y_axis_string == '':
return Common.histogram(x_points, x_bins, weights=weights)
else:
y_points = self.list_get_hit_variable([y_axis_string], [y_axis_units])[0]
return Common.histogram(x_points, x_bins, y_points, y_bins, weights=weights)
def root_histogram(self, x_axis_string, x_axis_units='', y_axis_string='', y_axis_units='', nx_bins=None, ny_bins=None, canvas=None, xmin=None, xmax=None, ymin=None, ymax=None,
line_color=rg.line_color, line_style=rg.line_style, line_width=rg.line_width, fill_color=rg.fill_color, stats=rg.stats, hist_title_string='', draw_option=''):
"""
Prints a 1D or 2D histogram of hits in the bunch. Axes are automatically detected
to encapsulate all data.
Needs correct root installation.
- x_axis_string = string for call to get_hit_variables()
- x_axis_units = units for x axis
- y_axis_string = string for call to get_hit_variables(). If string is empty, makes a 1D histogram
- y_axis_units = units for y axis
- nx_bins = force root_histogram to use this number of bins for the x-axis rather than choosing number of bins itself
- ny_bins = force root_histogram to use this number of bins for the y-axis rather than choosing number of bins itself
- canvas = if canvas=None, root_histogram will create a new tcanvas and plot histograms on that
else will plot on the existing canvas, attempting to plot on existing axes
- xmin = float that overrides auto-detection of minimum x-axis value
- xmax = float that overrides auto-detection of maximum x-axis value
- ymin = float that overrides auto-detection of minimum y-axis value
- ymax = float that overrides auto-detection of maximum y-axis value
- line_color = int that sets the line colour of the histogram
- line_style = int that sets the line style of the histogram
- line_width = int that sets the line width of the histogram
- fill_color = int that sets the fill color of the histogram
- stats = set to True to plot a stats box on the histogram
- hist_title_string = specify the string that will appear as a title on the canvas
e.g. bunch.root_histogram('x', 'cm', 'py', 'GeV/c') will histogram x vs py.
Returns a tuple of the (canvas, histogram)
"""
weights = []
num_events = float(len(self))
x_points = self.list_get_hit_variable([x_axis_string], [x_axis_units])[0]
if y_axis_string == '' and nx_bins==None:
nx_bins = int(num_events/10.)
if not y_axis_string == '' and draw_option=='':
draw_option = 'COL'
y_points = self.list_get_hit_variable([y_axis_string], [y_axis_units])[0]
if nx_bins == None: nx_bins = int(num_events**0.7/10.)
if ny_bins == None: ny_bins = int(num_events**0.7/10.)
else: y_points = []
for key in self.__hits:
weights.append(key.get('weight'))
if not x_axis_units == '': x_axis_units = " ["+x_axis_units+"]"
if not y_axis_units == '': y_axis_units = " ["+y_axis_units+"]"
x_name = x_axis_string+x_axis_units
y_name = y_axis_string+y_axis_units
num_evts = 0.
for hit in self.__hits:
if abs(hit.get('weight')) > 0.: num_evts += 1.
name = x_axis_string
if not y_axis_string == '': name += ":"+y_axis_string
if canvas == '' or canvas == None: canvas = Common.make_root_canvas(name)
else:
draw_option += 'same'
canvas.cd()
hist = Common.make_root_histogram(name, x_points, x_name, nx_bins, y_points, y_name, ny_bins, weights, xmin, xmax, ymin, ymax,
line_color, line_style, line_width, fill_color, stats, hist_title_string)
hist.SetStats(False)
hist.Draw(draw_option)
canvas.Update()
return (canvas, hist)
def root_scatter_graph(self, x_axis_string, y_axis_string, x_axis_units='', y_axis_units='', include_weightless=True, canvas=None, xmin=None, xmax=None, ymin=None, ymax=None,
line_color=rg.line_color, line_style=rg.line_style, line_width=rg.line_width, fill_color=rg.graph_fill_color, hist_title_string=''):
"""
Prints a 2d scatter plot of Hit.get(...) data over a dict of bunches.
Needs correct root installation.
- x_axis_string = string for call to Bunch.get_hit_variable() used to calculate x-values
- x_axis_units = units for x axis
- y_axis_string = string for call to Bunch.get_hit_variable() used to calculate y-values
- y_axis_units = units for y axis
- include_weightless = set to True to plot hits with <= 0. weight
- canvas = if canvas=None, root_graph will create a new tcanvas and plot graphs on that
else will plot on the existing canvas, attempting to plot on existing axes
- xmin = float that overrides auto-detection of minimum x-axis value
- xmax = float that overrides auto-detection of maximum x-axis value
- ymin = float that overrides auto-detection of minimum y-axis value
- ymax = float that overrides auto-detection of maximum y-axis value
- line_color = int that sets the line colour of the histogram
- line_style = int that sets the line style of the histogram
- line_width = int that sets the line width of the histogram
- fill_color = int that sets the fill color of the histogram
- hist_title_string = specify the string that will appear as a title on the canvas
- fit_ellipse = set to True to draw a fitted ellipse corresponding to the relevant covariances matrix
e.g. bunch.root_scatter_graph('x', 'p', 'cm', 'MeV/c') will graph x vs p.
Returns a tuple of (canvas, histogram, graph) where the histogram contains
the axes.
"""
fit_ellipse=False # hard coded - I am not sure this is the right way
x_points = []
y_points = []
for hit in self:
if abs(hit['weight'])>Common.float_tolerance or include_weightless:
x_points.append(self.get_hit_variable(hit, x_axis_string)/Common.units[x_axis_units])
y_points.append(self.get_hit_variable(hit, y_axis_string)/Common.units[y_axis_units])
name = x_axis_string+":"+y_axis_string
if not x_axis_units == '': x_axis_string += " ["+x_axis_units+"]"
if not y_axis_units == '': y_axis_string += " ["+y_axis_units+"]"
graph = Common.make_root_graph(name, x_points, x_axis_string, y_points, y_axis_string, True, xmin, xmax, ymin, ymax,
line_color, line_style, line_width, fill_color, hist_title_string)
if canvas == '' or canvas==None:
canvas = Common.make_root_canvas(name)
graph[0].SetStats(False)
graph[0].Draw()
else:
canvas.cd()
graph[1].Draw('p')
if fit_ellipse:
points = [(x_points[i], y_points[i]) for i in range(len(x_points))]
mean, cov = Common.fit_ellipse(points, -1., self.list_get_hit_variable(['weight'])[0], 1, True)
func = Common.make_root_ellipse_function(mean, cov, [1.],
graph[0].GetXaxis().GetXmin(),
graph[0].GetXaxis().GetXmax(),
graph[0].GetYaxis().GetXmin(),
graph[0].GetYaxis().GetXmax())
func.Draw('SAME')
_function_persistent.append(fit_func)
canvas.Update()
return (canvas, graph[0], graph[1])
def root_graph(bunches, x_axis_string, x_axis_list, y_axis_string, y_axis_list, x_axis_units='', y_axis_units='', canvas='', comparator=None, xmin=None, xmax=None, ymin=None, ymax=None,
line_color=rg.line_color, line_style=rg.line_style, line_width=rg.line_width, fill_color=rg.graph_fill_color, hist_title_string=''):
"""
Prints a graph of Bunch.get(...) data over a set of bunches and returns the root canvas.
Needs correct root installation.
- bunches = either a dict or a list of bunches
- x_axis_string = string for call to Bunch.get() used to calculate x axis variables
- x_axis_list = list of variables for call to Bunch.get() used to calculate x axis variables
- x_axis_units = units for x axis
- y_axis_string = string for call to Bunch.get() used to calculate y axis variables
- y_axis_list = list of variables for call to Bunch.get() used to calculate y axis variables
- y_axis_units = units for y axis
- canvas = if canvas=None, root_graph will create a new tcanvas and plot graphs on that
else will plot on the existing canvas, attempting to plot on existing axes
- comparator = comparator of bunch1, bunch2 - if none given, will sort by x-axis value
- xmin = float that overrides auto-detection of minimum x-axis value
- xmax = float that overrides auto-detection of maximum x-axis value
- ymin = float that overrides auto-detection of minimum y-axis value
- ymax = float that overrides auto-detection of maximum y-axis value
- line_color = int that sets the line colour of the histogram
- line_style = int that sets the line style of the histogram
- line_width = int that sets the line width of the histogram
- fill_color = int that sets the fill color of the histogram
- hist_title_string = specify the string that will appear as a title on the canvas
e.g. root_graph(bunch_dict, 'mean', ['x'], 'emittance', ['x','y'], 'cm', 'mm') will graph mean x vs emittance x y.
Returns a tuple of (canvas, histogram, graph) where the histogram contains the axes
"""
x_points = []
y_points = []
list_of_bunches = []
try: list_of_bunches = bunches.values()
except: list_of_bunches = bunches
if comparator != None:
list_of_bunches.sort(comparator)
for i, bunch in enumerate(list_of_bunches):
try:
x_points.append(bunch.get(x_axis_string, x_axis_list)/Common.units[x_axis_units])
y_points.append(bunch.get(y_axis_string, y_axis_list)/Common.units[y_axis_units])
except Exception:
if len(x_points) > len(y_points):
x_points.pop(-1)
sys.excepthook(*sys.exc_info())
print 'Failed to get data from bunch', i
x_axis_string += "( "
y_axis_string += "( "
for value in x_axis_list: x_axis_string += value+" "
for value in y_axis_list: y_axis_string += value+" "
x_axis_string += ")"
y_axis_string += ")"
name = x_axis_string+":"+y_axis_string
if not x_axis_units == '': x_axis_string += " ["+x_axis_units+"]"
if not y_axis_units == '': y_axis_string += " ["+y_axis_units+"]"
graph = Common.make_root_graph(name, x_points, x_axis_string, y_points, y_axis_string, comparator==None, xmin, xmax, ymin, ymax,
line_color, line_style, line_width, fill_color, hist_title_string)
if canvas == '' or canvas == None:
canvas = Common.make_root_canvas(name)
graph[0].SetStats(False)
graph[0].Draw()
else:
canvas.cd()
graph[1].Draw('l')
canvas.Update()
return (canvas, graph[0], graph[1])
root_graph = staticmethod(root_graph)
def matplot_histogram(self, x_axis_string, x_axis_units='', y_axis_string='', y_axis_units='', canvas=None, comparator=None):
"""
Prints a 1D or 2D histogram of hits in the bunch. Axes are automatically detected
to encapsulate all data. Use Bunch.cut(...) to shrink the axes.
Needs correct matplot installation.
- x_axis_string = string for call to get_hit_variables()
- x_axis_units = units for x axis
- y_axis_string = string for call to get_hit_variables(). If string is empty, makes a 1D histogram
- y_axis_units = units for y axis
- comparator = comparator of bunch1, bunch2 - if none given, will sort by x-axis value
e.g. bunch.matplot_histogram('x', 'cm', 'py', 'GeV/c') will histogram x vs py.
To display plots, call Common.wait_for_matplot() - script waits until all matplot windows are closed
"""
weights = []
num_evts = 0.
for hit in self.__hits:
if abs(hit.get('weight')) > 0.: num_evts += 1.
n_bins = num_evts/10.+1.;
x_points = self.list_get_hit_variable([x_axis_string], [x_axis_units])[0]
if not y_axis_string == '':
y_points = self.list_get_hit_variable([y_axis_string], [y_axis_units])[0]
n_bins = num_evts**0.5/10.+1.;
else: y_points = []
for key in self.__hits:
weights.append(key.get('weight'))
if not x_axis_units == '': x_axis_units = " ["+x_axis_units+"]"
if not y_axis_units == '': y_axis_units = " ["+y_axis_units+"]"
x_name = x_axis_string+x_axis_units
y_name = y_axis_string+y_axis_units
sort = True
if comparator != None:
sort = False
Common.make_matplot_histogram( x_points, x_name, int(n_bins), y_points, y_name, int(n_bins), weight_list=weights)
def matplot_scatter_graph(self, x_axis_string, y_axis_string, x_axis_units='', y_axis_units='', include_weightless=True):
"""
Prints a 2d scatter plot of Hit.get(...) data over a dict of bunches.
Needs correct matplot installation.
- x_axis_string = string for call to Bunch.get_hit_variable() used to calculate x-values
- x_axis_units = units for x axis
- y_axis_string = string for call to Bunch.get_hit_variable() used to calculate y-values
- y_axis_units = units for y axis
- include_weightless = set to True to plot hits with <= 0. weight
e.g. bunch.matplot_scatter_graph('x', 'cm', 'p', 'MeV/c') will graph x vs p.
To display plots, call Common.wait_for_matplot() - script waits until all matplot windows are closed
"""
x_points = []
y_points = []
for hit in self:
if abs(hit['weight'])>Common.float_tolerance or include_weightless:
x_points.append(self.get_hit_variable(hit, x_axis_string)/Common.units[x_axis_units])
y_points.append(self.get_hit_variable(hit, y_axis_string)/Common.units[y_axis_units])
if not x_axis_units == '': x_axis_string += " ["+x_axis_units+"] "
if not y_axis_units == '': y_axis_string += " ["+y_axis_units+"] "
graph = Common.make_matplot_scatter(x_points, x_axis_string, y_points, y_axis_string)
def matplot_graph(bunches, x_axis_string, x_axis_list, y_axis_string, y_axis_list, x_axis_units='', y_axis_units='', comparator=None):
"""
Prints a graph of Bunch.get(...) data over a dict of bunches.
Needs correct matplot installation.
- x_axis_string = string for call to Bunch.get() used to calculate x axis variables
- x_axis_list = list of variables for call to Bunch.get() used to calculate x axis variables
- y_axis_string = string for call to Bunch.get() used to calculate y axis variables
- y_axis_list = list of variables for call to Bunch.get() used to calculate y axis variables
- x_axis_units = units for x axis
- y_axis_units = units for y axis
- comparator = comparator of bunch1, bunch2 - if none given, will sort by x-axis value
e.g. bunch.matplot_graph('mean', ['x'], 'cm', 'emittance', ['x','y'], 'mm') will graph mean x vs emittance x y.
To display plots, call Common.wait_for_matplot() - script waits until all matplot windows are closed
"""
x_points = []
y_points = []
try: list_of_bunches = bunches.values()
except: list_of_bunches = bunches
if comparator != None:
list_of_bunches.sort(comparator)
for bunch in list_of_bunches:
x_points.append(bunch.get(x_axis_string, x_axis_list)/Common.units[x_axis_units])
y_points.append(bunch.get(y_axis_string, y_axis_list)/Common.units[y_axis_units])
x_axis_string += "( "
y_axis_string += "( "
for value in x_axis_list: x_axis_string += value+" "
for value in y_axis_list: y_axis_string += value+" "
x_axis_string += ") "
y_axis_string += ") "
if not x_axis_units == '': x_axis_string += " ["+x_axis_units+"] "
if not y_axis_units == '': y_axis_string += " ["+y_axis_units+"] "
graph = Common.make_matplot_graph(x_points, x_axis_string, y_points, y_axis_string)
matplot_graph = staticmethod(matplot_graph)
#privates
def __mean_for_get(self, variable_list):
return self.mean(variable_list)[variable_list[0]]
def __weight_for_get(self, variable_list):
return self.bunch_weight()
def __ang_mom_for_get(self, variable_list):
return self.get_kinetic_angular_momentum()
def __dispersion_for_get(self, variable_list):
return self.get_dispersion(variable_list[0])
def __dispersion_prime_for_get(self, variable_list):
return self.get_dispersion_prime(variable_list[0])
def __cov_mat_picker(self, axis_list):
Common.has_numpy()
if self.__covs == None: return None
covs = numpy.zeros( (2*len(axis_list),2*len(axis_list) ))
ind = []
for axis in axis_list:
ind.append( Bunch.__axis_list.index( axis ) )
for i in range( len(ind) ):
for j in range( len(ind) ):
covs[2*i, 2*j] = self.__covs[2*ind[i], 2*ind[j]]
covs[2*i+1,2*j] = self.__covs[2*ind[i]+1, 2*ind[j]]
covs[2*i+1,2*j+1] = self.__covs[2*ind[i]+1, 2*ind[j]+1]
covs[2*i, 2*j+1] = self.__covs[2*ind[i], 2*ind[j]+1]
return covs
def __mean_picker(self, var_list):
if self.__means == None or self.__means == {}: return {}
means = {}
all_list = Bunch.axis_list_to_covariance_list(var_list)
try:
for var in all_list: means[var] = self.__means[var]
except:
return {}
return means
__g4mice_types = {'g4mice_special_hit':'SpecialHits', 'g4mice_virtual_hit':'VirtualHits'}
__number_of_header_lines = {'icool_for009':3, 'icool_for003':2, 'g4beamline_bl_track_file':0,'g4mice_special_hit':0,'g4mice_virtual_hit':0,'zgoubi':0, 'turtle':0, 'madx':0,'mars_1':0, 'maus_virtual_hit':0, 'maus_primary':0, 'opal_loss':1, 'muon1_csv':0}
__axis_list = ['x','y','z','t', 'ct']
__get_dict = {'angular_momentum':__ang_mom_for_get, 'emittance':get_emittance, 'dispersion':__dispersion_for_get,
'dispersion_prime':__dispersion_prime_for_get, 'beta':get_beta, 'alpha':get_alpha, 'gamma':get_gamma,
'moment':moment, 'mean':__mean_for_get, 'bunch_weight':__weight_for_get, 'standard_deviation':standard_deviation}
__geometric_momentum = False
__get_list = []
for key,value in __get_dict.iteritems():
__get_list.append(key)
def bunch_overview_doc(verbose = False):
"""Creates some summary documentation for the Bunch class. If verbose is True then will also print any functions or data not included in summary"""
name_list = ['initialise', 'transforms', 'hit', 'moments', 'weights', 'twiss', 'twiss_help', 'io', 'ellipse', 'root', 'matplotlib', 'generic graphics']
function_list = {
'initialise' : ['new_dict_from_read_builtin', 'new_from_hits', 'new_from_read_builtin', 'new_from_read_user', 'new_list_from_read_builtin', 'new_hit_shell', 'copy', 'deepcopy'],
'transforms' : ['abelian_transformation', 'period_transformation', 'transform_to', 'translate'],
'hit' : ['get', 'get_hit_variable', 'get_hits', 'hit_equality', 'list_get', 'list_get_hit_variable', 'append', 'hits', 'hit_get_variables', 'get_variables', 'get_amplitude'],
'moments' : ['mean', 'moment', 'covariance_matrix'],
'weights' : ['bunch_weight', 'clear_global_weights', 'clear_local_weights', 'clear_weights', 'cut', 'transmission_cut', 'conditional_remove'],
'twiss' : ['get_emittance', 'get_beta', 'get_alpha', 'get_gamma', 'get_emittance', 'get_canonical_angular_momentum', 'get_dispersion', 'get_dispersion_prime','get_dispersion_rsquared', 'get_kinetic_angular_momentum'],
'twiss_help' : ['convert_string_to_axis_list', 'covariances_set', 'means_set', 'momentum_variable', 'set_geometric_momentum', 'set_covariance_matrix', 'get_axes', 'get_geometric_momentum', 'axis_list_to_covariance_list'],
'io' : ['hit_write_builtin', 'hit_write_builtin_from_dict', 'hit_write_user', 'read_g4mice_file', 'setup_file', 'get_list_of_maus_dicts', 'read_maus_file'],
'ellipse' : ['build_ellipse_2d', 'build_ellipse_from_transfer_matrix', 'build_penn_ellipse'], #, 'build_ET_ellipse', 'build_MR_ellipse'
'root' : ['root_graph', 'root_histogram', 'root_scatter_graph'],
'matplotlib' : ['matplot_graph', 'matplot_histogram', 'matplot_scatter_graph'],
'generic graphics': ['histogram', 'histogram_var_bins'],
}
function_doc = {
'initialise':'Functions that can be used to initialise a Bunch in various different ways:',
'transforms':'Functions that transform all data in the bunch in some way:',
'hit':'Functions to examine individual hits within the bunch:',
'moments':'Functions to calculate beam moments:',
'weights':'Functions to access and modify statistical weights:',
'twiss':'Functions to calculate Twiss parameters, etc, in the bunch:',
'twiss_help':'Helper functions to aid Twiss parameter calculation:',
'io':'Output and some input helper functions:',
'ellipse':'Functions to calculate beam ellipses based on Twiss parameters etc:',
'root':'Interfaces to root plotting library:',
'matplotlib':'Interfaces to matplotlib plotting library:',
'generic graphics':'General algorithms to support graphics functions:',
}
bunch_doc = """
Bunch class is a container class for a set of hits. The main purpose is to store a set of hits that are recorded at an output station in some tracking code. Functions are provided to calculate Twiss parameters, RMS emittances etc for this bunch. List of functions:
"""
dir_bunch = dir(Bunch)
if verbose:
print 'The following functions and data are in Bunch but not in overview_doc:'
for func in dir_bunch:
found = False
for func_sublist in function_list.values():
if func in func_sublist: found = True
if not found: print func,
print '\n'
print 'The following functions and data are in bunch_overview_doc but not in Bunch:'
for func_sublist in function_list.values():
for func in func_sublist:
if func not in dir_bunch:
print func,
print
doc = bunch_doc
for key in name_list:
doc = doc + function_doc[key]+'\n'
for item in function_list[key]:
doc = doc+' '+item+'\n'
__doc__ = doc
return doc
bunch_overview_doc = staticmethod(bunch_overview_doc)
#summary documentation
__doc__ = Bunch.bunch_overview_doc()