19 common contains some global physics and other parameters, plus some useful functions
20 - icool_pid_to_pdg = dict from icool particle identification indices to pdg indices
21 - pdg_pid_to_icool = inverse of above
22 - constants = string to number dict of physical constants
23 - units = string to number dict of some units
24 Functions documented below
41 xboa_version =
'0.16.2'
42 float_tolerance = 1.e-9
43 kill_subprocesses_at_exit =
True
50 print 'Maus library not detected'
55 ROOT.gStyle.SetPalette(1)
57 print 'PyRoot not detected - ROOT graphing functions will not be available'
64 print 'SciPy not detected - a few analysis functions will not be available'
71 from numpy
import linalg
72 from numpy
import matrix
74 print 'NumPy not detected - many analysis functions will not be available'
81 from matplotlib
import pyplot
83 print 'MatPlotLib not detected - matplotlib graphing functions will not be available'
86 __has_multiprocessing =
True
88 import multiprocessing
90 print 'multiprocessing library not detected - subprocess library will not be available'
91 __has_multiprocessing =
False
97 print 'json library not detected - maus import will not be available'
100 pdg_pid_to_muon1 = {-13:
'mu+'}
101 muon1_pid_to_pdg = {}
102 for k,v
in pdg_pid_to_muon1.iteritems():
103 muon1_pid_to_pdg[v] = k
105 icool_pid_to_pdg = {0:0, 1:-11, 2:-13, 3:211, 4:321, 5:2212, -1:11, -2:13, -3:-211, -4:-321, -5:-2212};
106 pdg_pid_to_icool = {};
107 for k,v
in icool_pid_to_pdg.iteritems():
108 pdg_pid_to_icool[v] = k;
116 mars_pid_to_pdg = {1:2212, 2:2112, 3:211, 4:-211, 5:321, 6:-321, 7:-13, 8:13, 9:22, 10:11, 11:-11, 12:-2212, 13:111, 14:1000010020, 15:1000010030, 16:1000020030, 17:1000020040, 18:14, 19:-14, 20:12, 21:-12, 22:130, 23:310, 24:311, 25:-311,26:3122,27:-3122,28:0,29:0,30:0,31:-2112,32:0,33:0,34:0,35:0,36:0,38:0,39:0,40:0};
118 for k,v
in mars_pid_to_pdg.iteritems():
119 pdg_pid_to_mars[v] = k;
121 pdg_pid_to_mass = {0:0, 11:0.510998910, 12:0., 13:105.6583668, 14:0., 22:0., 111:134.9766, 211:139.57018, 321:493.667, 2112:939.56536, 2212:938.271996, 1000010020:1876.1239, 1000010030:2809.432, 1000020030:2809.41346, 1000020040: 3728.4001, 130:497.614, 310:497.614, 311:497.614, 3122:1115.683}
122 pdg_pid_to_name = {0:
'none', 11:
'e-', 12:
'electron neutrino', 13:
'mu-', 14:
'muon neutrino', 22:
'photon', 111:
'pi0', 211:
'pi+', 321:
'K+', 2112:
'neutron', 2212:
'proton', 1000010020:
'deuterium', 1000010030:
'tritium', 1000020030:
'3He', 1000020040:
'4He', 130:
'K0L', 310:
'K0S', 311:
'K0', 3122:
'lambda',
123 -11:
'e+', -12:
'electron antineutrino', -13:
'mu+', -14:
'muon antineutrino', -211:
'pi-', -321:
'K-', -2112:
'antineutron', -2212:
'antiproton', -3122:
'antilambda'}
125 pdg_pid_to_charge = {0:0, 11:-1, 12:0, 13:-1, 14:0, 22:0, 111:0, 211:+1, 321:+1, 2112:0, 2212:+1, 1000010020:0, 1000010030:0, 1000020030:0, 1000020040:0, 130:0, 310:0, 311:0, 3122:0, -11:+1, -12:0, -13:+1, -14:0, -211:-1, -321:-1, -2112:0, -2212:-1, -3122:0}
128 constants = {
'c_light':299.792458,
'pi':3.14159265,
'echarge':1}
130 'mum':1.e-3,
'mm':1.,
'cm':10.,
'm':1.e3,
'km':1.e6,
131 'ns':1.,
'mus':1.e3,
'ms':1e6,
's':1.e9,
132 'eV':1e-6,
'keV':1e-3,
'MeV':1.,
'GeV':1.e3,
'TeV':1e6,
133 'eV/c':1e-6,
'keV/c':1e-3,
'MeV/c':1.,
'GeV/c':1.e3,
'TeV/c':1e6,
134 'eV/c2':1e-6,
'keV/c2':1e-3,
'MeV/c2':1.,
'GeV/c2':1.e3,
'TeV/c2':1e6,
135 'Gauss':1.e-7,
'mT':1.e-6,
'T':1.e-3,
'kT':1.,
136 'V':1.e-6,
'kV':1.e-3,
'MV':1.,
'GV':1.e3,
137 'kHz':1.e-6,
'MHz':1.e-3,
'GHz':1.,
138 'GV/m':1.,
'GV/mm':1.e3,
139 'kW':6.24150974e6,
'MW':6.24150974e9,
'GW':6.24150974e12,
140 'degrees':2.*constants[
'pi']/360.,
'radians':1.,
'deg':2.*constants[
'pi']/360.,
'rad':1.,
'degree':2.*constants[
'pi']/360.,
'radian':1.,
141 'echarge':1.,
'Coulomb':6.24150974*10.**18.
148 Container to hold some details of root global style information
150 canvas_border_mode = 0
151 canvas_highlight_color = 2
152 canvas_fill_color = 10
153 hist_fill_color = canvas_fill_color
158 graph_fill_color = 10
166 _canvas_persistent = []
167 _hist_persistent = []
168 _graph_persistent = []
169 _legend_persistent = []
170 _function_persistent = []
177 Read in file_name_in and write to file_name_out, replacing key with value in switch_dict. Must be a built in function somewhere to do same...
179 - file_name_in = string name of the input file
180 - file_name_out = string name of the output file
181 - switch_dict = dict of values to be swapped to the values they will be swapped for
183 e.g. common.substitute('file.in', 'file.out', {'energy':'momentum'})
185 fin = open(file_name_in,
'r')
186 fout = open(file_name_out, 'w')
188 for key, value
in switch_dict.iteritems():
189 line = line.replace(str(key), str(value))
194 wrapped_y_function =
None
196 global wrapped_y_function
201 def nd_newton_raphson1(y_function, y_tolerances_list, x_start_values_list, x_deltas_list, max_iteration=10, x_upper_limits=None, x_lower_limits = None, verbose=True):
203 Root finding in an arbitrary dimensional system. Returns x-value for y(x) = 0; caveat is dimension of y must equal dimension of x.
204 If you use this, you might find more and better root finding functions in SciPy module
206 - y_function is a reference to the function to be minimised i.e. y(x); it takes a list of x-values; and returns a list of y-values
207 - y_tolerances_list is a list of tolerances; the iteration will stop when abs(value) < value_tolerance
208 _ x_start_values_list is a list of the values I will try to start with
209 - x_deltas_list is a list of the initial estimates of the error on x
210 - max_iteration is the maximum number of iterations allowed
211 - x_upper_limits is for future development
212 - x_lower_limits is for future development
214 e.g. nd_newton_raphson(some_function, [0.1, 0.1], [0,0], [1,1]) will find root to y(x) < (0.1,0.1); starting at x=(0,0); initial error estimated to be [1,1].
215 some_function would be called like some_function([x_0, x_1]) and should return a list like [y_0,y_1]
217 global wrapped_y_function
218 wrapped_y_function = y_function
219 return nd_newton_raphson2( __y_function_wrapper, y_tolerances_list, x_start_values_list, x_deltas_list, max_iteration, x_upper_limits, x_lower_limits, verbose)
221 def nd_newton_raphson2(y_function, y_tolerances_list, x_start_values_list, x_deltas_list, max_iteration=10, x_upper_limits=None, x_lower_limits = None, verbose=True):
223 Alternative version of nd_newton_raphson1. Here y_function takes a list of lists of x_values, of length dimension+1 and returns a list of lists of y_values
224 Optimisation for when y_function can be made faster by running several jobs at once...
226 - y_function is a reference to the function to be minimised i.e. y(x); it takes a list of lists of x-values; and returns a list of lists y-values
227 - y_tolerances_list is a list of tolerances; the iteration will stop when abs(value) < value_tolerance
228 - x_start_values_list is a list of the values I will try to start with
229 - x_deltas_list is a list of the initial estimates of the error on x
230 - max_iteration is the maximum number of iterations allowed
231 - x_upper_limits is for future development
232 - x_lower_limits is for future development
234 e.g. nd_newton_raphson(some_function, [0.1, 0.1], [0,0], [1,1]) will find root to y(x) < (0.1,0.1); starting at x=(0,0); initial error estimated to be [1,1].
235 some_function would be called like some_function([[x_00, x_01] ,[x_10, x_11], [x_20, x_21]) and should return a list like [[y_00,y_01],[y_10,y_11],[y_20,y_21]]
240 for key
in range( len(x_start_values_list)+1 ):
241 x_list.append( copy.deepcopy(x_start_values_list) )
242 delta_x = numpy.matrix( str(x_deltas_list) )
243 count = copy.deepcopy(max_iteration)
244 limits = type(x_upper_limits) == type([])
and type(x_lower_limits) == type([])
247 for i
in range(len(x_start_values_list)): delta_limit.append(x_upper_limits[i]-x_lower_limits[i])
248 while not done
and count > 0:
250 jacobian = numpy.matrix( numpy.zeros( (len(x_start_values_list), len(x_start_values_list)) ) )
251 for i
in range( len(x_start_values_list) ):
253 x_list[0][i] -= delta_limit[i]*math.floor(x_list[0][i]/delta_limit[i]-x_lower_limits[i]);
254 for i
in range( len(x_start_values_list) ):
255 x_list[i+1] = copy.deepcopy(x_list[0])
256 x_list[i+1][i] += delta_x[0,i]
257 y_x = y_function(x_list)
259 y_x0 = numpy.matrix( str(y_x[0]) )
261 raise RuntimeError(
'Newton-Raphson failed to evaluate function with input '+str(x_list)+
' and output '+str(y_x))
263 y_magnitude_squared = numpy.vdot(y_x0, y_x0)
264 for i
in range( len(x_start_values_list) ):
265 if abs(delta_x[0,i]) < float_tolerance:
266 print 'Warning - returned without convergence; delta_x',str(delta_x),
'is below float tolerance'
268 for j
in range( len(y_tolerances_list) ):
269 jacobian[j,i] = (y_x[i+1][j] - y_x[0][j])/delta_x[0,i]
270 x_list[i+1][i] -= delta_x[0,i]
272 delta_x = -(linalg.inv(jacobian)*y_x0.transpose()).transpose()
274 print 'Newton-Raphson failed with (singular?) jacobian\n',jacobian,
'\nbailing out'
275 print 'x:',x_list[0],
' y(x):',y_x[0],
' dx:',delta_x
278 if verbose:
print 'x:',x_list[0],
' y(x):',y_x[0],
' dx:',delta_x
279 for i
in range( len(x_start_values_list) ):
280 if abs(y_x[0][i]) > y_tolerances_list[i]:
282 x_list[0][i] += delta_x[0,i]
283 y_x0 = y_function([x_list[0]])
287 """Raise an exception if multiprocessing libraries have not been imported properly"""
288 if not __has_multiprocessing:
289 raise ImportError(
"Attempt to use multiprocessing when library has not been imported - multiprocessing requires matplot >= 2.6")
293 """Raise an exception if MAUS tracking library has not been imported properly"""
295 raise ImportError(
"Attempt to use maus when library has not been imported - check your maus installation")
299 """Raise an exception if ROOT graphics libraries have not been imported properly"""
301 raise ImportError(
"Attempt to use root when library has not been imported - check your root installation")
305 """Raise an exception if NumPy numerical algebra libraries have not been imported properly"""
307 raise ImportError(
"Attempt to use numpy when library has not been imported - check your numpy installation")
311 """Raise an exception if SciPy math/analysis libraries have not been imported properly"""
313 raise ImportError(
"Attempt to use scipy when library has not been imported - check your scipy installation")
318 """Raise an exception if NumPy numerical algebra libraries have not been imported properly"""
319 if(
not __has_matplot):
320 raise ImportError(
"Attempt to use matplotlib when library has not been imported - check your matplotlib installation")
324 """Raise an exception if json data libraries have not been imported properly"""
326 raise ImportError(
"Attempt to use json when library has not been imported - check your json installation (python >= 2.6)")
330 def min_max(x_float_list, weight_list=[], margin = 0.1, xmin=None, xmax=None):
332 Return minimum and maximum of a list (i) discarding values with ~0 weight and (ii) adding a margin. For making histograms.
334 - x_float_list = return minimum and maximum of this list of floats
335 - weight_list = ignore items in x_float_list if weight is 0. Ignored if weight_list is not same length as x_float_list
336 - margin = add a margin given by (x_max-x_min)*margin
337 - xmin = if set, will override the xmin value
338 - xmax = if set, will override the xmax value
340 e.g. common.min_max([0.1,0.2,0.3,0.4], [0,1,1,1], 0.2) will return [0.16,0.44]
342 new_floats = x_float_list
343 if len(weight_list) == len(x_float_list):
345 for ind
in range(len(weight_list)):
346 if weight_list[ind] > 1e-6:
347 new_floats.append(x_float_list[ind])
348 if len(new_floats) == 0: x = [0.,0.]
349 else: x = [min(new_floats), max(new_floats)]
350 delta = (x[1]-x[0])*margin
353 if(x[1] - x[0] < 1e-9):
356 if xmin!=
None: x[0] = xmin
357 if xmax!=
None: x[1] = xmax
361 """Sort a list of lists by the first list"""
364 for i
in range( len(list_of_lists[0]) ):
365 horizontal_list.append([])
366 for j
in range( len(list_of_lists) ):
367 horizontal_list[-1].append(list_of_lists[j][i])
369 getitem = operator.itemgetter(0)
370 horizontal_list = sorted(horizontal_list, key=getitem)
372 for i
in range( len(list_of_lists) ):
373 for j
in range( len(list_of_lists[0]) ):
374 list_of_lists[i][j] = horizontal_list[j][i]
377 def n_bins(n_points, nx_bins=None, ny_bins=None, nz_bins=None, n_dimensions=1):
379 Dynamically decide a number of bins depending on the number of points in the histogram
381 - n_points = number of data points in the histogram
382 - nx_bins = set to an integer to override the automatic selection for number of x bins
383 - ny_bins = set to an integer to override the automatic selection for number of y bins
384 - n_dimensions = set to number of dimensions in the histogram
386 Return value is a tuple (nx_bins, ny_bins, nz_bins), setting 0 to values that are out of the dimension range
388 out = [nx_bins, ny_bins, nz_bins]
389 num_events = float(n_points)
390 if nx_bins==
None and n_dimensions==1: out[0] = int(num_events/10.)+1
391 if nx_bins==
None and n_dimensions==2: out[0] = int(num_events**0.7/10.)+1
392 if ny_bins==
None and n_dimensions==2: out[1] = int(num_events**0.7/10.)+1
393 if nx_bins==
None and n_dimensions==3: out[0] = int(num_events**0.5/10.)+1
394 if ny_bins==
None and n_dimensions==3: out[1] = int(num_events**0.5/10.)+1
395 if nz_bins==
None and n_dimensions==3: out[2] = int(num_events**0.5/10.)+1
397 if out[i] ==
None: out[i]= 0
400 def histogram(x_values, x_bins, y_values=None, y_bins=None, weights=None):
402 Get a 1d or 2d list of bin weights from a set of data, weights and bin edges
404 - x_values = list of x values to be binned
405 - x_bins = list of x bin edges
406 - y_values = list of y values to be binned. Set to None to make a 1d binning
407 - y_bins = list of y bin edges of same length as x_values
408 - weights = list of statistical weights of same length as x_values. Set to None to make all weights default to 1.
410 Return value is a tuple of (bin_weights, x_bins, y_bins)
415 weights = [1.]*len(x_values)
418 y_values = [0.]*len(x_values)
420 contents = numpy.zeros((len(x_bins)-1, len(y_bins)-1), )
421 for i,x
in enumerate(x_values):
422 p = bisect.bisect_right(x_bins,x_values[i])-1
423 q = bisect.bisect_right(y_bins,y_values[i])-1
424 if p>=0
and p<len(x_bins)-1
and q>=0
and q<len(y_bins)-1:
425 contents[p,q] += weights[i]
426 out = (contents, x_bins, y_bins)
427 if is_1d:
return (contents, x_bins, [])
428 else:
return (contents, x_bins, y_bins)
430 def get_bin_edges(list_of_variables, number_of_bins, xmin=None, xmax=None):
432 Get a sorted list of equally spaced bin edges from a list of floats
434 - list_of_variables = list of floats to be binned
435 - number_of_bins = number of bins to make; note that there will be number_of_bins+1 edges
436 - xmin = lower edge of all the bins (set to None to auto-detect)
437 - xmax = upper edge of all the bins (set to None to auto-detect)
440 mm =
min_max(list_of_variables, margin=0.0)
441 if xmin!=
None: mm[0]=xmin
442 if xmax!=
None: mm[1]=xmax
443 delta = (mm[1] - mm[0])/float(number_of_bins)
444 for i
in range(number_of_bins+1):
445 my_bins.append(mm[0]+delta*i)
448 def make_root_canvas(name_string, title_string=None, bg_color=rg.canvas_fill_color, highlight_color=rg.canvas_highlight_color,
449 border_mode=rg.canvas_border_mode, frame_fill_color=rg.hist_fill_color):
451 Make a root canvas with name canvas_name_string-<index> where <index> is a unique integer starting from 0
453 - name_string = Name of the canvas. Due to a ROOT bug, xboa adds a unique identifier to the name_string to ensure the canvas is drawn.
454 - title_string = Title of the canvas (as displayed in canvas window title bar); if set to None will use the name_string.
455 - bg_color = Fill color of the canvas.
456 - highlight_color = When a canvas is selected, ROOT draws a border with a particular color to indicate that the canvas is selected.
457 - border_mode = When a canvas is selected, ROOT draws a border if border mode is not set to 0.
458 - frame_fill_color = Fill color of frames drawn on the canvas (e.g. histograms).
461 canvas_name_string = name_string+
"-"+str(len(_canvas_persistent))
462 if title_string ==
None: title_string = name_string
463 canvas = ROOT.TCanvas(canvas_name_string, title_string)
464 canvas.SetHighLightColor(highlight_color)
465 canvas.SetFillColor(bg_color)
466 canvas.SetBorderMode(border_mode)
467 canvas.SetFrameFillColor(frame_fill_color)
468 _canvas_persistent.append(canvas)
471 def make_root_histogram(name_string, x_float_list, x_axis_string, n_x_bins, y_float_list=[], y_axis_string='', n_y_bins=0, weight_list=[], xmin=None, xmax=None, ymin=None, ymax=None,
472 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=
''):
474 Make a root histogram with data taken from float lists and axes named after the axis strings.
476 - name_string = name given to the histogram
477 - x_float_list = list of x-data
478 - x_axis_string = string used to label the x-axis
479 - n_x_bins = number of bins in x direction
480 - y_float_list = list of y-data. If number of items in y list not equal to number in x list, will build 1d histogram
481 - y_axis_string = string used to label the y-axis
482 - n_y_bins = number of y bins
483 - weight_list = if present, each item will be filled with weight taken from this list
484 - xmin = float that overrides auto-detection of minimum x-axis value
485 - xmax = float that overrides auto-detection of maximum x-axis value
486 - ymin = float that overrides auto-detection of minimum y-axis value
487 - ymax = float that overrides auto-detection of maximum y-axis value
488 - line_color = int that sets the line colour of the histogram
489 - line_style = int that sets the line style of the histogram
490 - line_width = int that sets the line width of the histogram
491 - fill_color = int that sets the fill color of the histogram
492 - stats = set to True to plot a stats box on the histogram
493 - hist_title_string = specify the string that will appear as a title on the canvas
495 Return value is the histogram
498 name_string +=
" "+str(len(_hist_persistent))
499 if len(y_float_list) == len(x_float_list):
500 x_min_max =
min_max(x_float_list, weight_list, margin=rg.histo_margin, xmin=xmin, xmax=xmax)
501 y_min_max =
min_max(y_float_list, weight_list, margin=rg.histo_margin, xmin=ymin, xmax=ymax)
502 hist = ROOT.TH2D(name_string, hist_title_string+
';'+x_axis_string+
';'+y_axis_string, n_x_bins, x_min_max[0], x_min_max[1], n_y_bins, y_min_max[0], y_min_max[1])
503 if(len(weight_list) == len(x_float_list)):
504 for i
in range( len(x_float_list) ):
505 hist.Fill(x_float_list[i], y_float_list[i], weight_list[i])
507 for i
in range( len(x_float_list) ):
508 hist.Fill(x_float_list[i], y_float_list[i])
510 x_min_max =
min_max(x_float_list, weight_list, margin=rg.histo_margin, xmin=xmin, xmax=xmax)
511 hist = ROOT.TH1D(name_string, hist_title_string+
';'+x_axis_string, n_x_bins, x_min_max[0], x_min_max[1])
512 if(len(weight_list) == len(x_float_list)):
513 for i
in range( len(x_float_list) ):
514 hist.Fill(x_float_list[i], weight_list[i])
516 for i
in range( len(x_float_list) ):
517 hist.Fill(x_float_list[i])
518 _hist_persistent.append(hist)
519 hist.SetLineColor(line_color)
520 hist.SetLineStyle(line_style)
521 if fill_color!=
None: hist.SetFillColor(fill_color)
527 Build a legend for the canvas
530 if len(root_item_list) == 0:
531 raise KeyError(
"No items for ROOT legend")
534 for index, leg
in enumerate(root_item_list):
535 leg_min = 0.89-0.08*len(root_item_list)
538 leg = ROOT.TLegend(0.0, leg_min, 0.4, 0.90)
539 leg.SetEntrySeparation(0.6)
540 for i, hist
in enumerate(root_item_list):
541 leg.AddEntry(hist, root_item_list[i].GetName())
546 _legend_persistent.append(leg)
600 def make_matplot_histogram(x_float_list, x_axis_string, n_x_bins, y_float_list=[], y_axis_string='', n_y_bins=0, weight_list=[]):
602 Make a matplot graph with data taken from float lists and axes naemd after the axis strings. Return value is a tuple of (hist, graph)
603 matplot can format using tex expressions - use '$some math expression$' to include math text in your labels
605 - x_float_list = list of x-data
606 - x_axis_string = string used to label the x-axis
607 - y_float_list = list of y-data
608 - y_axis_string = string used to label the y-axis
610 After building the graph, use matplotlib.pyplot.show() to show something on the screen
615 pyplot.figure(_figure_index)
617 if(len(x_float_list) == 0):
618 raise IndexError(
'Attempt to draw histogram with no x-points')
619 if not len(y_float_list) == len(x_float_list):
623 if(weight_list == []):
624 (n, my_bins) = numpy.histogram(a=x_float_list, bins=n_x_bins)
626 (n, my_bins) = numpy.histogram(a=x_float_list, bins=n_x_bins, weights=weight_list)
630 while(abs(n[index])<1.e-9
and index < len(n)): index += 1
631 for i
in range(index, len(n)-1):
632 new_bins.append((my_bins[i] + my_bins[i+1])/2.)
634 hist = pylab.plot(new_bins, new_n)
635 pylab.xlabel(x_axis_string)
637 if len(weight_list) == len(x_float_list): hist = pyplot.hexbin(x_float_list, y_float_list, weight_list, gridsize=(n_x_bins,n_y_bins))
638 else: hist = pyplot.hexbin(x_float_list, y_float_list, gridsize=(n_x_bins,n_y_bins))
639 pylab.xlabel(x_axis_string)
640 pylab.ylabel(y_axis_string)
643 def make_root_graph(name_string, x_float_list, x_axis_string, y_float_list, y_axis_string, sort=True, xmin=None, xmax=None, ymin=None, ymax=None,
644 line_color=rg.line_color, line_style=rg.line_style, line_width=rg.line_width, fill_color=rg.graph_fill_color, hist_title_string=
''):
646 Make a root graph with data taken from float lists and axes named after the axis strings. Return value is a tuple of (hist, graph)
648 - name_string = name given to the histogram
649 - x_float_list = list of x-data
650 - x_axis_string = string used to label the x-axis
651 - y_float_list = list of y-data
652 - y_axis_string = string used to label the y-axis
653 - sort = boolean - set to true to automatically sort input data
654 - xmin = float that overrides auto-detection of minimum x-axis value
655 - xmax = float that overrides auto-detection of maximum x-axis value
656 - ymin = float that overrides auto-detection of minimum y-axis value
657 - ymax = float that overrides auto-detection of maximum y-axis value
658 - line_color = int that sets the line colour of the graph
659 - line_style = int that sets the line style of the graph
660 - line_width = int that sets the line width of the graph
661 - fill_color = graphs dont usually get a fill, but sometimes the fill colour turns up in e.g. legend drawing
662 - hist_title_string = specify the string that will appear as a title
664 Return value is a tuple of (histogram, graph)
667 x_float_list = copy.deepcopy(x_float_list)
668 y_float_list = copy.deepcopy(y_float_list)
669 if(len(x_float_list) == 0
or len(x_float_list) != len(y_float_list)):
670 raise IndexError(
'Attempt to draw graph with no x-points, or different number of x to y points')
672 multilist = [x_float_list, y_float_list]
674 x_min_max =
min_max(multilist[0], margin=rg.graph_margin, xmin=xmin, xmax=xmax)
675 y_min_max =
min_max(multilist[1], margin=rg.graph_margin, xmin=ymin, xmax=ymax)
676 hist =
make_root_histogram(name_string, [], x_axis_string, 1000, [], y_axis_string, 1000, [], x_min_max[0], x_min_max[1], y_min_max[0], y_min_max[1],
677 line_color=rg.line_color, line_style=rg.line_style, line_width=0, fill_color=
None, stats=
False, hist_title_string=hist_title_string)
678 graph = ROOT.TGraph(len(x_float_list))
679 graph.SetTitle(name_string)
680 graph.SetName(name_string)
681 graph.SetLineColor(line_color)
682 graph.SetLineStyle(line_style)
683 graph.SetLineWidth(line_width)
684 graph.SetFillColor(fill_color)
685 for i
in range(len(x_float_list)):
686 graph.SetPoint(i, x_float_list[i], y_float_list[i])
687 _graph_persistent.append(graph)
690 def make_matplot_graph(x_float_list, x_axis_string, y_float_list, y_axis_string, sort=True):
692 Make a matplot graph with data taken from float lists and axes naemd after the axis strings. Return value is a tuple of (hist, graph)
693 matplot can format using tex expressions - use '$some math expression$' to include math text in your labels
695 - x_float_list = list of x-data
696 - x_axis_string = string used to label the x-axis
697 - y_float_list = list of y-data
698 - y_axis_string = string used to label the y-axis
699 - sort = boolean - set to true to automatically sort input data
701 After building the graph, use matplotlib.pyplot.show() to show something on the screen
705 pyplot.figure(_figure_index)
707 if(len(x_float_list) == 0
or len(x_float_list) != len(y_float_list)):
708 raise IndexError(
'Attempt to draw graph with no x-points, or different number of x to y points')
709 multilist = [x_float_list, y_float_list]
711 x_min_max =
min_max(multilist[0], margin=rg.graph_margin)
712 y_min_max =
min_max(multilist[1], margin=rg.graph_margin)
713 myplot = pylab.plot(x_float_list, y_float_list)
714 pylab.xlabel(x_axis_string)
715 pylab.ylabel(y_axis_string)
716 pylab.xlim (x_min_max[0], x_min_max[1])
717 pylab.ylim (y_min_max[0], y_min_max[1])
718 matplotlib.pyplot.draw()
720 def make_root_multigraph(name_string, x_float_list_of_lists, x_axis_string, y_float_list_of_lists, y_axis_string):
722 Print several different graphs on the same canvas. Some default colour scheme is applied, but it may not be the best...
724 - name_string = name that will be given to the axes (histogram)
725 - x_float_list_of_lists = list of lists. Each list will be used as the x-axis for a graph
726 - x_axis_string = string that will be used to label the x_axis
727 - y_float_list_of_lists = list of lists. Each list will be used as the y-axis for a graph
728 - y_axis_string = string that will be used to label the y_axis
730 E.g. common.make_root_multigraph('example', [[1.,2.,3.,4.], [1.,4.,9.,16.]], 'x', [[1.,2.,3.,4.],[1.,2.,3.,4.]], 'f(x)') will make a graph of f = x and f = x^0.5
733 name_string +=
" "+str(len(_hist_persistent))
736 for a_list
in x_float_list_of_lists: total_x_list += a_list
737 for a_list
in y_float_list_of_lists: total_y_list += a_list
738 x_min_max =
min_max(total_x_list, margin=rg.graph_margin)
739 y_min_max =
min_max(total_y_list, margin=rg.graph_margin)
740 hist = ROOT.TH2D(name_string,
';'+x_axis_string+
';'+y_axis_string, 1000, x_min_max[0], x_min_max[1], 1000, y_min_max[0], y_min_max[1])
742 for index
in range( len(x_float_list_of_lists) ):
743 graphs.append(ROOT.TGraph( len(x_float_list_of_lists[index]) ))
744 ROOT.gStyle.SetPalette(int(len(x_float_list_of_lists)*1.25))
745 graphs[-1].SetLineColor(ROOT.gStyle.GetColorPalette(index + int(len(x_float_list_of_lists)*0.25) ))
746 for i
in range(len(x_float_list_of_lists[index])):
747 graphs[-1].SetPoint(i, x_float_list_of_lists[index][i], y_float_list_of_lists[index][i])
748 _graph_persistent.append(graphs[-1])
749 _hist_persistent.append(hist)
751 return (hist, graphs)
755 Print several different graphs on the same axes. Some default colour scheme is applied, but it may not be the best...
757 - x_float_list_of_lists = list of lists. Each list will be used as the x-axis for a graph
758 - x_axis_string = string that will be used to label the x_axis
759 - y_float_list_of_lists = list of lists. Each list will be used as the y-axis for a graph
760 - y_axis_string = string that will be used to label the y_axis
762 E.g. common.make_matplot_multigraph('example', [[1.,2.,3.,4.], [1.,4.,9.,16.]], 'x', [[1.,2.,3.,4.],[1.,2.,3.,4.]], 'f(x)') will make a graph of f = x and f = x^0.5
766 pyplot.figure(_figure_index)
770 for a_list
in x_float_list_of_lists: total_x_list += a_list
771 for a_list
in y_float_list_of_lists: total_y_list += a_list
772 x_min_max =
min_max(total_x_list, margin=rg.graph_margin)
773 y_min_max =
min_max(total_y_list, margin=rg.graph_margin)
774 for index
in range( len(x_float_list_of_lists) ):
775 multilist = [x_float_list_of_lists[index], y_float_list_of_lists[index]]
777 myplot = pylab.plot(multilist[0], multilist[1])
778 pylab.xlabel(x_axis_string)
779 pylab.ylabel(y_axis_string)
780 pylab.xlim (x_min_max[0], x_min_max[1])
781 pylab.ylim (y_min_max[0], y_min_max[1])
782 matplotlib.pyplot.draw()
786 Make a matplot scatter graph with data taken from float lists and axes naemd after the axis strings.
787 matplot can format using tex expressions - use '$some math expression$' to include math text in your labels
789 - x_float_list = list of x-data
790 - x_axis_string = string used to label the x-axis
791 - y_float_list = list of y-data
792 - y_axis_string = string used to label the y-axis
794 After building the graph, use matplotlib.pyplot.show() to show something on the screen
798 pyplot.figure(_figure_index)
800 if(len(x_float_list) == 0):
801 raise IndexError(
'Attempt to draw histogram with no x-points')
802 hist = pyplot.scatter(x_float_list, y_float_list, s=1)
803 pylab.xlabel(x_axis_string)
804 pylab.ylabel(x_axis_string)
809 Force python to halt processing until ROOT windows are closed
811 print 'Close ROOT windows to continue'
815 for canvas
in _canvas_persistent:
816 if not canvas ==
None:
823 Close root plots (and free memory)
825 global _canvas_persistent, _hist_persistent, _graph_persistent
826 for canv
in _canvas_persistent: del(canv)
827 for hist
in _hist_persistent: del(hist)
828 for graph
in _graph_persistent: del(graph)
829 _canvas_persistent = []
830 _hist_persistent = []
831 _canvas_persistent = []
834 """Show any plots made using matplotlib on the screen"""
836 matplotlib.pyplot.show()
839 """Show matplotlib plots and return to the script"""
844 raise ImportError(
'matplot_show_and_continue is only available is (i) ROOT is not installed or (ii) you have python > 2.6')
846 __mp_subprocesses = []
847 __fk_subprocesses = []
850 Make a function call in a subprocess; return the subprocess pid
851 - This uses the multiprocessing libary in the first instance - if multiprocessing is not available
852 the function tries to use os.fork(); however, os.fork is not compatible with ROOT. If
853 - multiprocessing is not available and ROOT is installed, this routine will throw an ImportError
857 __mp_subprocesses.append( multiprocessing.Process(target=function, args=args) )
858 __mp_subprocesses[-1].start()
859 return __mp_subprocesses[-1]
863 raise ImportError(
'Error - attempt to make a subprocess using fork when ROOT library is active')
871 __fk_subprocesses.append(pid)
876 Kill all subprocesses generated by common.subprocess call; automatically called at exit unless kill_subprocesses_at_exit is set to False
877 Note that this makes a call to the os, which may take a bit of time to respond.
879 for ps
in __mp_subprocesses:
882 for pid
in __fk_subprocesses:
883 os.kill(pid, signal.SIGKILL)
887 Convenience wrapper for ROOT kolmogorov-smirnov test.
888 - list_1 = list of floats that are sampled from some parent probability distribution
889 - list_2 = list of floats that are sampled from other some parent distribution
890 Returns double between 0. and 1. giving probability that list_1 and list_2 have the same parent distribution.
892 list_1 = sorted(list_1)
893 list_2 = sorted(list_2)
894 c_array_1 = ctypes.c_double*len(list_1)
895 c_array_2 = ctypes.c_double*len(list_2)
898 for i
in range(len(list_1)): ca1[i]=ctypes.c_double(list_1[i])
899 for i
in range(len(list_2)): ca2[i]=ctypes.c_double(list_2[i])
900 ks = ROOT.TMath.KolmogorovTest(len(list_1), ca1, len(list_2), ca2,
'')
904 """Calls some functions automatically at exit"""
905 if(kill_subprocesses_at_exit):
907 atexit.register(__atexit)
912 Make a rectangular n_dimensional grid of points evenly spaced between [-1,1] in each
915 - n_dimensions = number of dimensions
916 - n_per_dimension = number of points in each dimension; total number of points will be
917 n_per_dimension^n_dimensions
919 Return value is a list of numpy.matrices with shape (n_dimensions, 1)
922 pos_vector = [numpy.matrix( [-1.]*n_dimensions )]
923 for i
in range(n_dimensions):
924 pos_vector_copy = copy.deepcopy(pos_vector)
925 for j
in range(1, n_per_dimension):
926 pos = (2.*j)/float(n_per_dimension-1)-1.
927 for vec
in pos_vector_copy:
928 vec = copy.deepcopy(vec)
930 pos_vector.append(vec)
935 Make a shell of points that sit on a hyper-ellipsoid defined by ellipse matrix
937 - n_per_dimension = number of points in each dimension; total number of points will be
938 n_per_dimension^n_dimensions if n_per_dimension is even or
939 n_per_dimension^n_dimensions-1 if n_per_dimension is odd
940 - ellipse = matrix that defines the ellipse on which vector sits; should be a
941 numpy.matrix with shape (vec_length, vec_length)
943 Points are defined on a (hyper-)cuboidal grid and then compressed so that lengths are
944 all 1. Doesn't necessarily mean points are evenly spaced. Return value is a list of
945 numpy.matrices with shape (n_dimensions, 1)
948 n_dimensions = numpy.shape(ellipse)[0]
949 grid =
make_grid(n_dimensions, n_per_dimension)
951 ellipse_inv = numpy.linalg.inv(ellipse)
953 if numpy.vdot(vector,vector) > float_tolerance:
959 Normalise vector so that vector.T() * matrix.inverse * vector = 1
961 - vector = the vector to normalise; should be a numpy.matrix with shape (vec_length,1)
962 - matrix_inverse = inverse of matrix that defines the ellipse on which vector sits; should be a
963 numpy.matrix with shape (vec_length, vec_length)
965 Return value is a list of numpy.matrices with shape (vec_length,1)
968 scale = 1./(vector * matrix_inverse * vector.transpose())[0,0]**0.5
969 if scale != scale: raise(ValueError(
"Bad input - vector or matrix magnitude 0"))
970 vector = vector*scale
975 Wrapper function to put multiprocessing output into a queue
977 - args tuple of (function_call, queue, function_arg) where
978 - function_call is a reference to the function that we want to wrap\n
979 - queue is the queue that will hold return values from the function\n
980 - function_arg is the argument to function_call\n
981 - index is an index indicating function_arg's position in the inputs
983 tuple of (index, Output) is placed into queue; if function_call throws an
984 exception, the exception is placed on the queue instead
986 (function_call, queue, function_arg, index) = args
988 queue.put((index, function_call(*function_arg)))
990 queue.put((index, sys.exc_info()[1]))
992 def process_list(function_call, list_of_args, max_n_processes):
994 Run multiprocessing on a list of arguments
996 - function_call multiprocess this function call
997 - list_of_args list of tuples of arguments for function_call
998 - max_n_processes maximum number of concurrent processes to use
1000 Returns list of return values, one for each function call. List is always
1001 sorted into same order as input.
1003 e.g. process_list(time.sleep, [(3, ), (6, ), (2, )], 2) will multiprocess
1004 the time.sleep function with inputs 3, 6 and 2 across 2 cores and return
1005 list like [None, None, None].
1007 manager = multiprocessing.Manager()
1008 queue = manager.Queue()
1009 pool = multiprocessing.Pool(max_n_processes)
1014 new_list_of_args = [(function_call, queue, x, i)
for i,x
in enumerate(list_of_args)]
1016 pool.map(__function_with_queue, new_list_of_args)
1019 while not queue.empty():
1020 out_list.append(queue.get())
1022 for i,item
in enumerate(out_list):
1023 out_list[i] = item[1]
1029 n_points = len(in_cut)
1030 return sum([weights[i]
for i
in range(n_points)
if in_cut[i]])
1033 n_points = len(points)
1035 dimension = len(points[0])
1036 mean = numpy.zeros(dimension)
1037 cov = numpy.zeros([dimension, dimension])
1038 for i
in range(n_points):
1041 for j
in range(dimension):
1042 mean[j] += a_point[j]/sum_weight*weights[i]
1043 for k
in range(dimension):
1044 cov[j, k] += a_point[j]*a_point[k]/sum_weight*weights[i]
1045 for i
in range(dimension):
1046 for j
in range(dimension):
1047 cov[i, j] -= mean[i]*mean[j]
1051 n_points = len(points)
1053 in_cut = [
True for i
in range(n_points)]
1054 sqrt_det_inv = numpy.linalg.det(cov_inv)**(1./float(n_dim))
1055 for i
in range(n_points):
1056 vec = numpy.array(points[i])-mean
1057 vec_t = numpy.transpose(vec)
1058 eps = numpy.dot(vec_t, numpy.dot(cov_inv, vec))/sqrt_det_inv
1059 in_cut[i] = eps < eps_cut
1062 def fit_ellipse(points, eps_cut, weights=None, max_number_of_iterations = 10, verbose = True):
1064 Fit an ellipse of arbitrary dimension n to a set of points
1066 - points iterable of points; each point should be an iterable of floats of
1068 - eps_cut float cut value; only particles with
1069 eps = x^T*V^{-1}*x*|V|**{1/n} < eps_{cut}
1070 are considered. The cut value is a normalised chi-squared. It
1072 - weights list of floats, one for each point; use statistically weighted
1073 particles for the fit. Set to None to ignore weights.
1074 - max_number_of_iterations integer number of iterations; the ellipse fitting
1075 procedure is repeated several times to attempt to improve the
1076 fit of the ellipse. This sets a maximum number of repetitions.
1077 - verbose set to True to provide some verbose output during fitting
1079 Returns ellipse centre vector <x> and defining matrix V. The ensemble of
1080 points on the ellipse is given by (x-<x>)^T*V^{-1}*(x-<x>) where x is a
1081 particle vector and V is the defining matrix.
1083 n_points = len(points)
1085 mean, cov = numpy.ones([2]), numpy.ones([2, 2])
1086 in_cut = [
True for i
in range(n_points)]
1088 weights = [1.,]*n_points
1091 while abs(numpy.linalg.det(cov)-old_det) > float_tolerance
and \
1092 iterations < max_number_of_iterations:
1098 old_det = numpy.linalg.det(cov)
1100 mat_inv = numpy.linalg.inv(cov)
1104 print "xboa.common.fit_ellipse(...) failed to converge; final iteration as follows."
1105 sys.excepthook(*sys.exc_info())
1107 print 'Weight in cut:\n',
_sum_weight(weights, in_cut)
1108 print "Means:\n", mean
1109 print "Ellipse:\n", cov
1110 print "Number of iterations:\n", iterations
1115 Make a ROOT TFunction for a given beam ellipse
1117 - mean sequence type of length>=2 (must allow reference by integer [index])
1118 - cov ellipse >= 2x2 symmetric numpy.array (must allow referencing by integer
1119 indices like [a, b])
1120 - contours iterable; draw contours at values of x^T V^{-1} x given by
1121 elements. Uses ROOT default if equal to None.
1123 Returns a ROOT TFunction. Note ROOT TFunction does not like drawing
1124 small ellipses if the ellipse matrix is highly correlated (i.e. determinant
1125 near zero). A workaround is to make a TGraph with appropriate points (using
1126 e.g. formula given by this function). May be possible to fix by increasing
1127 the number of points in plot (func.SetNpy).
1130 mat_inv = numpy.linalg.inv(cov)
1131 fit_func_str =
"[2]*(x-[0])**2+[4]*(y-[1])**2+2*[3]*(x-[0])*(y-[1])"
1132 fit_func = ROOT.TF2(
"ellipse", fit_func_str)
1133 if contours !=
None:
1134 fit_func.SetContour(len(contours))
1135 for i, contour
in enumerate(contours):
1136 fit_func.SetContourLevel(i, contour)
1137 if xmax ==
None or xmin ==
None or ymax ==
None or ymin ==
None:
1143 fit_func.SetRange(xmin, ymin, xmax, ymax)
1144 fit_func.SetParameter(0, mean[0])
1145 fit_func.SetParameter(1, mean[1])
1146 fit_func.SetParameter(2, mat_inv[0, 0])
1147 fit_func.SetParameter(3, mat_inv[0, 1])
1148 fit_func.SetParameter(4, mat_inv[1, 1])
1149 fit_func.SetLineColor(rg.fit_color)
1150 fit_func.SetLineStyle(rg.fit_style)
1151 _function_persistent.append(fit_func)
1156 """Creates some summary documentation for the common module. If verbose is True then will also print any functions or data not included in summary"""
1157 common_doc =
'\cCommon module contains a number of useful interfaces, defaults, data and ancillary functions that support the rest of the XBOA package.\n'
1159 name_list = [
'math',
'root',
'matplot',
'data',
'defaults',
'other_stuff']
1161 'math' : [
'min_max',
'multisort',
'nd_newton_raphson1',
'nd_newton_raphson2'],
1162 'root' : [
'has_root',
'make_root_graph',
'make_root_histogram',
'make_root_multigraph',
'clear_root',
'wait_for_root',
'make_root_canvas'],
1163 'matplot' : [
'has_matplot',
'make_matplot_graph',
'make_matplot_histogram',
'make_matplot_multigraph',
'make_matplot_scatter',
'wait_for_matplot',
'matplot_show_and_continue'],
1164 'other_stuff' : [
'get_bin_edges',
'histogram',
'substitute',
'has_numpy',
'build_installation',
'make_grid',
'make_shell',
'normalise_vector',
'kolmogorov_smirnov_test',
'kill_all_subprocesses',
'has_multiprocessing',
'has_json'],
1165 'data' : [
'constants',
'pdg_pid_to_icool',
'pdg_pid_to_mars',
'pdg_pid_to_mass',
'pdg_pid_to_name',
'pdg_pid_to_charge',
'icool_pid_to_pdg',
'mars_pid_to_pdg',
'units'],
1166 'defaults' : [
'canvas_fill_color',
'canvas_highlight_color',
'default_margin',
'float_tolerance',
'graph_margin',
'histo_margin',
'python_version',
'xboa_version',
'kill_subprocesses_at_exit']
1170 'math' :
'Maths functions:',
1171 'root' :
'Interfaces to ROOT plotting library:',
1172 'matplot' :
'Interfaces to matplotlib plotting library:',
1173 'other_stuff' :
'Some other useful functions:',
1174 'data' :
'Physics data:',
1175 'defaults' :
'Defaults for e.g. root canvases, etc:',
1179 dir_common = dir(sys.modules[__name__])
1180 print 'The following functions and data are in common but not in common_overview_doc:'
1181 for func
in dir_common:
1183 for func_sublist
in function_list.values():
1184 if func
in func_sublist: found =
True
1185 if not found:
print func,
1188 print 'The following functions and data are in common_overview_doc but not in Common:'
1189 for func_sublist
in function_list.values():
1190 for func
in func_sublist:
1191 if func
not in dir_common:
1196 for key
in name_list:
1197 doc = doc + function_doc[key]+
'\n'
1198 for item
in function_list[key]:
1199 doc = doc+
' '+item+
'\n'
def has_json
Raise an exception if json data libraries have not been imported properly.
def has_root
Raise an exception if ROOT graphics libraries have not been imported properly.
def __function_with_queue
Wrapper function to put multiprocessing output into a queue.
def multisort
Sort a list of lists by the first list.
def make_root_histogram
Make a root histogram with data taken from float lists and axes named after the axis strings...
def normalise_vector
Normalise vector so that vector.T() * matrix.inverse * vector = 1.
def make_root_multigraph
Print several different graphs on the same canvas.
def make_matplot_multigraph
Print several different graphs on the same axes.
def substitute
Read in file_name_in and write to file_name_out, replacing key with value in switch_dict.
def kill_all_subprocesses
Kill all subprocesses generated by common.subprocess call; automatically called at exit unless kill_s...
def make_matplot_scatter
Make a matplot scatter graph with data taken from float lists and axes naemd after the axis strings...
def wait_for_matplot
Show any plots made using matplotlib on the screen.
def has_maus
Raise an exception if MAUS tracking library has not been imported properly.
def make_shell
Make a shell of points that sit on a hyper-ellipsoid defined by ellipse matrix.
def min_max
Return minimum and maximum of a list (i) discarding values with ~0 weight and (ii) adding a margin...
def _update_fit_ellipse_cut
def kolmogorov_smirnov_test
Convenience wrapper for ROOT kolmogorov-smirnov test.
def make_grid
Make a rectangular n_dimensional grid of points evenly spaced between [-1,1] in each dimension...
def histogram
Get a 1d or 2d list of bin weights from a set of data, weights and bin edges.
def nd_newton_raphson1
Root finding in an arbitrary dimensional system.
def has_multiprocessing
Raise an exception if multiprocessing libraries have not been imported properly.
def fit_ellipse
Fit an ellipse of arbitrary dimension n to a set of points.
def has_numpy
Raise an exception if NumPy numerical algebra libraries have not been imported properly.
def common_overview_doc
Creates some summary documentation for the common module.
def nd_newton_raphson2
Alternative version of nd_newton_raphson1.
def has_matplot
Raise an exception if NumPy numerical algebra libraries have not been imported properly.
def has_scipy
Raise an exception if SciPy math/analysis libraries have not been imported properly.
def make_root_legend
Build a legend for the canvas.
def wait_for_root
Force python to halt processing until ROOT windows are closed.
def make_root_graph
Make a root graph with data taken from float lists and axes named after the axis strings.
def n_bins
Dynamically decide a number of bins depending on the number of points in the histogram.
def make_root_ellipse_function
Make a ROOT TFunction for a given beam ellipse.
def _get_fit_ellipse_covariance_matrix
def clear_root
Close root plots (and free memory)
def make_root_canvas
Make a root canvas with name canvas_name_string-<index> where <index> is a unique integer starting fr...
def matplot_show_and_continue
Show matplotlib plots and return to the script.
def process_list
Run multiprocessing on a list of arguments.
def __atexit
Calls some functions automatically at exit.
def get_bin_edges
Get a sorted list of equally spaced bin edges from a list of floats.
def make_matplot_histogram
Make a matplot graph with data taken from float lists and axes naemd after the axis strings...
def make_matplot_graph
Make a matplot graph with data taken from float lists and axes naemd after the axis strings...
root globals line_color_int=1, line_style_int=1, line_width_int=2, fill_color_int=None, stats_bool=False, hist_title_string=''
def subprocess
Make a function call in a subprocess; return the subprocess pid.