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.15.1'
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'
63 from numpy
import linalg
64 from numpy
import matrix
66 print 'NumPy not detected - many analysis functions will not be available'
73 from matplotlib
import pyplot
75 print 'MatPlotLib not detected - matplotlib graphing functions will not be available'
78 __has_multiprocessing =
True
80 import multiprocessing
82 print 'multiprocessing library not detected - subprocess library will not be available'
83 __has_multiprocessing =
False
89 print 'json library not detected - maus import will not be available'
92 pdg_pid_to_muon1 = {-13:
'mu+'}
94 for k,v
in pdg_pid_to_muon1.iteritems():
95 muon1_pid_to_pdg[v] = k
97 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};
98 pdg_pid_to_icool = {};
99 for k,v
in icool_pid_to_pdg.iteritems():
100 pdg_pid_to_icool[v] = k;
108 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};
110 for k,v
in mars_pid_to_pdg.iteritems():
111 pdg_pid_to_mars[v] = k;
113 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}
114 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',
115 -11:
'e+', -12:
'electron antineutrino', -13:
'mu+', -14:
'muon antineutrino', -211:
'pi-', -321:
'K-', -2112:
'antineutron', -2212:
'antiproton', -3122:
'antilambda'}
117 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}
120 constants = {
'c_light':299.792458,
'pi':3.14159265,
'echarge':1}
122 'mum':1.e-3,
'mm':1.,
'cm':10.,
'm':1.e3,
'km':1.e6,
123 'ns':1.,
'mus':1.e3,
'ms':1e6,
's':1.e9,
124 'eV':1e-6,
'keV':1e-3,
'MeV':1.,
'GeV':1.e3,
'TeV':1e6,
125 'eV/c':1e-6,
'keV/c':1e-3,
'MeV/c':1.,
'GeV/c':1.e3,
'TeV/c':1e6,
126 'eV/c2':1e-6,
'keV/c2':1e-3,
'MeV/c2':1.,
'GeV/c2':1.e3,
'TeV/c2':1e6,
127 'Gauss':1.e-7,
'mT':1.e-6,
'T':1.e-3,
'kT':1.,
128 'V':1.e-6,
'kV':1.e-3,
'MV':1.,
'GV':1.e3,
129 'kHz':1.e-6,
'MHz':1.e-3,
'GHz':1.,
130 'GV/m':1.,
'GV/mm':1.e3,
131 'kW':6.24150974e6,
'MW':6.24150974e9,
'GW':6.24150974e12,
132 'degrees':2.*constants[
'pi']/360.,
'radians':1.,
'deg':2.*constants[
'pi']/360.,
'rad':1.,
'degree':2.*constants[
'pi']/360.,
'radian':1.,
133 'echarge':1.,
'Coulomb':6.24150974*10.**18.
140 Container to hold some details of root global style information
142 canvas_border_mode = 0
143 canvas_highlight_color = 2
144 canvas_fill_color = 10
145 hist_fill_color = canvas_fill_color
150 graph_fill_color = 10
156 _canvas_persistent = []
157 _hist_persistent = []
158 _graph_persistent = []
159 _legend_persistent = []
166 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...
168 - file_name_in = string name of the input file
169 - file_name_out = string name of the output file
170 - switch_dict = dict of values to be swapped to the values they will be swapped for
172 e.g. Common.substitute('file.in', 'file.out', {'energy':'momentum'})
174 fin = open(file_name_in,
'r')
175 fout = open(file_name_out, 'w')
177 for key, value
in switch_dict.iteritems():
178 line = line.replace(str(key), str(value))
183 wrapped_y_function =
None
185 global wrapped_y_function
190 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):
192 Root finding in an arbitrary dimensional system. Returns x-value for y(x) = 0; caveat is dimension of y must equal dimension of x.
193 If you use this, you might find more and better root finding functions in SciPy module
195 - 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
196 - y_tolerances_list is a list of tolerances; the iteration will stop when abs(value) < value_tolerance
197 _ x_start_values_list is a list of the values I will try to start with
198 - x_deltas_list is a list of the initial estimates of the error on x
199 - max_iteration is the maximum number of iterations allowed
200 - x_upper_limits is for future development
201 - x_lower_limits is for future development
203 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].
204 some_function would be called like some_function([x_0, x_1]) and should return a list like [y_0,y_1]
206 global wrapped_y_function
207 wrapped_y_function = y_function
208 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)
210 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):
212 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
213 Optimisation for when y_function can be made faster by running several jobs at once...
215 - 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
216 - y_tolerances_list is a list of tolerances; the iteration will stop when abs(value) < value_tolerance
217 - x_start_values_list is a list of the values I will try to start with
218 - x_deltas_list is a list of the initial estimates of the error on x
219 - max_iteration is the maximum number of iterations allowed
220 - x_upper_limits is for future development
221 - x_lower_limits is for future development
223 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].
224 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]]
229 for key
in range( len(x_start_values_list)+1 ):
230 x_list.append( copy.deepcopy(x_start_values_list) )
231 delta_x = numpy.matrix( str(x_deltas_list) )
232 count = copy.deepcopy(max_iteration)
233 limits = type(x_upper_limits) == type([])
and type(x_lower_limits) == type([])
236 for i
in range(len(x_start_values_list)): delta_limit.append(x_upper_limits[i]-x_lower_limits[i])
237 while not done
and count > 0:
239 jacobian = numpy.matrix( numpy.zeros( (len(x_start_values_list), len(x_start_values_list)) ) )
240 for i
in range( len(x_start_values_list) ):
242 x_list[0][i] -= delta_limit[i]*math.floor(x_list[0][i]/delta_limit[i]-x_lower_limits[i]);
243 for i
in range( len(x_start_values_list) ):
244 x_list[i+1] = copy.deepcopy(x_list[0])
245 x_list[i+1][i] += delta_x[0,i]
246 y_x = y_function(x_list)
248 y_x0 = numpy.matrix( str(y_x[0]) )
250 raise RuntimeError(
'Newton-Raphson failed to evaluate function with input '+str(x_list)+
' and output '+str(y_x))
252 y_magnitude_squared = numpy.vdot(y_x0, y_x0)
253 for i
in range( len(x_start_values_list) ):
254 if abs(delta_x[0,i]) < float_tolerance:
255 print 'Warning - returned without convergence; delta_x',str(delta_x),
'is below float tolerance'
257 for j
in range( len(y_tolerances_list) ):
258 jacobian[j,i] = (y_x[i+1][j] - y_x[0][j])/delta_x[0,i]
259 x_list[i+1][i] -= delta_x[0,i]
261 delta_x = -(linalg.inv(jacobian)*y_x0.transpose()).transpose()
263 print 'Newton-Raphson failed with (singular?) jacobian\n',jacobian,
'\nbailing out'
264 print 'x:',x_list[0],
' y(x):',y_x[0],
' dx:',delta_x
267 if verbose:
print 'x:',x_list[0],
' y(x):',y_x[0],
' dx:',delta_x
268 for i
in range( len(x_start_values_list) ):
269 if abs(y_x[0][i]) > y_tolerances_list[i]:
271 x_list[0][i] += delta_x[0,i]
272 y_x0 = y_function([x_list[0]])
276 """Raise an exception if multiprocessing libraries have not been imported properly"""
277 if not __has_multiprocessing:
278 raise ImportError(
"Attempt to use multiprocessing when library has not been imported - multiprocessing requires matplot >= 2.6")
282 """Raise an exception if MAUS tracking library has not been imported properly"""
284 raise ImportError(
"Attempt to use maus when library has not been imported - check your maus installation")
288 """Raise an exception if ROOT graphics libraries have not been imported properly"""
290 raise ImportError(
"Attempt to use root when library has not been imported - check your root installation")
294 """Raise an exception if NumPy numerical algebra libraries have not been imported properly"""
296 raise ImportError(
"Attempt to use numpy when library has not been imported - check your numpy installation")
300 """Raise an exception if NumPy numerical algebra libraries have not been imported properly"""
301 if(
not __has_matplot):
302 raise ImportError(
"Attempt to use matplotlib when library has not been imported - check your matplotlib installation")
306 """Raise an exception if json data libraries have not been imported properly"""
308 raise ImportError(
"Attempt to use json when library has not been imported - check your json installation (python >= 2.6)")
312 def min_max(x_float_list, weight_list=[], margin = 0.1, xmin=None, xmax=None):
314 Return minimum and maximum of a list (i) discarding values with ~0 weight and (ii) adding a margin. For making histograms.
316 - x_float_list = return minimum and maximum of this list of floats
317 - weight_list = ignore items in x_float_list if weight is 0. Ignored if weight_list is not same length as x_float_list
318 - margin = add a margin given by (x_max-x_min)*margin
319 - xmin = if set, will override the xmin value
320 - xmax = if set, will override the xmax value
322 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]
324 new_floats = x_float_list
325 if len(weight_list) == len(x_float_list):
327 for ind
in range(len(weight_list)):
328 if weight_list[ind] > 1e-6:
329 new_floats.append(x_float_list[ind])
330 if len(new_floats) == 0: x = [0.,0.]
331 else: x = [min(new_floats), max(new_floats)]
332 delta = (x[1]-x[0])*margin
335 if(x[1] - x[0] < 1e-9):
338 if xmin!=
None: x[0] = xmin
339 if xmax!=
None: x[1] = xmax
343 """Sort a list of lists by the first list"""
346 for i
in range( len(list_of_lists[0]) ):
347 horizontal_list.append([])
348 for j
in range( len(list_of_lists) ):
349 horizontal_list[-1].append(list_of_lists[j][i])
351 getitem = operator.itemgetter(0)
352 horizontal_list = sorted(horizontal_list, key=getitem)
354 for i
in range( len(list_of_lists) ):
355 for j
in range( len(list_of_lists[0]) ):
356 list_of_lists[i][j] = horizontal_list[j][i]
359 def n_bins(n_points, nx_bins=None, ny_bins=None, nz_bins=None, n_dimensions=1):
361 Dynamically decide a number of bins depending on the number of points in the histogram
363 - n_points = number of data points in the histogram
364 - nx_bins = set to an integer to override the automatic selection for number of x bins
365 - ny_bins = set to an integer to override the automatic selection for number of y bins
366 - n_dimensions = set to number of dimensions in the histogram
368 Return value is a tuple (nx_bins, ny_bins, nz_bins), setting 0 to values that are out of the dimension range
370 out = [nx_bins, ny_bins, nz_bins]
371 num_events = float(n_points)
372 if nx_bins==
None and n_dimensions==1: out[0] = int(num_events/10.)+1
373 if nx_bins==
None and n_dimensions==2: out[0] = int(num_events**0.7/10.)+1
374 if ny_bins==
None and n_dimensions==2: out[1] = int(num_events**0.7/10.)+1
375 if nx_bins==
None and n_dimensions==3: out[0] = int(num_events**0.5/10.)+1
376 if ny_bins==
None and n_dimensions==3: out[1] = int(num_events**0.5/10.)+1
377 if nz_bins==
None and n_dimensions==3: out[2] = int(num_events**0.5/10.)+1
379 if out[i] ==
None: out[i]= 0
382 def histogram(x_values, x_bins, y_values=None, y_bins=None, weights=None):
384 Get a 1d or 2d list of bin weights from a set of data, weights and bin edges
386 - x_values = list of x values to be binned
387 - x_bins = list of x bin edges
388 - y_values = list of y values to be binned. Set to None to make a 1d binning
389 - y_bins = list of y bin edges of same length as x_values
390 - weights = list of statistical weights of same length as x_values. Set to None to make all weights default to 1.
392 Return value is a tuple of (bin_weights, x_bins, y_bins)
397 weights = [1.]*len(x_values)
400 y_values = [0.]*len(x_values)
402 contents = numpy.zeros((len(x_bins)-1, len(y_bins)-1), )
403 for i,x
in enumerate(x_values):
404 p = bisect.bisect_right(x_bins,x_values[i])-1
405 q = bisect.bisect_right(y_bins,y_values[i])-1
406 if p>=0
and p<len(x_bins)-1
and q>=0
and q<len(y_bins)-1:
407 contents[p,q] += weights[i]
408 out = (contents, x_bins, y_bins)
409 if is_1d:
return (contents, x_bins, [])
410 else:
return (contents, x_bins, y_bins)
412 def get_bin_edges(list_of_variables, number_of_bins, xmin=None, xmax=None):
414 Get a sorted list of equally spaced bin edges from a list of floats
416 - list_of_variables = list of floats to be binned
417 - number_of_bins = number of bins to make; note that there will be number_of_bins+1 edges
418 - xmin = lower edge of all the bins (set to None to auto-detect)
419 - xmax = upper edge of all the bins (set to None to auto-detect)
422 mm =
min_max(list_of_variables, margin=0.0)
423 if xmin!=
None: mm[0]=xmin
424 if xmax!=
None: mm[1]=xmax
425 delta = (mm[1] - mm[0])/float(number_of_bins)
426 for i
in range(number_of_bins+1):
427 my_bins.append(mm[0]+delta*i)
430 def make_root_canvas(name_string, title_string=None, bg_color=rg.canvas_fill_color, highlight_color=rg.canvas_highlight_color,
431 border_mode=rg.canvas_border_mode, frame_fill_color=rg.hist_fill_color):
433 Make a root canvas with name canvas_name_string-<index> where <index> is a unique integer starting from 0
435 - 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.
436 - title_string = Title of the canvas (as displayed in canvas window title bar); if set to None will use the name_string.
437 - bg_color = Fill color of the canvas.
438 - highlight_color = When a canvas is selected, ROOT draws a border with a particular color to indicate that the canvas is selected.
439 - border_mode = When a canvas is selected, ROOT draws a border if border mode is not set to 0.
440 - frame_fill_color = Fill color of frames drawn on the canvas (e.g. histograms).
443 canvas_name_string = name_string+
"-"+str(len(_canvas_persistent))
444 if title_string ==
None: title_string = name_string
445 canvas = ROOT.TCanvas(canvas_name_string, title_string)
446 canvas.SetHighLightColor(highlight_color)
447 canvas.SetFillColor(bg_color)
448 canvas.SetBorderMode(border_mode)
449 canvas.SetFrameFillColor(frame_fill_color)
450 _canvas_persistent.append(canvas)
453 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,
454 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=
''):
456 Make a root histogram with data taken from float lists and axes named after the axis strings.
458 - name_string = name given to the histogram
459 - x_float_list = list of x-data
460 - x_axis_string = string used to label the x-axis
461 - n_x_bins = number of bins in x direction
462 - 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
463 - y_axis_string = string used to label the y-axis
464 - n_y_bins = number of y bins
465 - weight_list = if present, each item will be filled with weight taken from this list
466 - xmin = float that overrides auto-detection of minimum x-axis value
467 - xmax = float that overrides auto-detection of maximum x-axis value
468 - ymin = float that overrides auto-detection of minimum y-axis value
469 - ymax = float that overrides auto-detection of maximum y-axis value
470 - line_color = int that sets the line colour of the histogram
471 - line_style = int that sets the line style of the histogram
472 - line_width = int that sets the line width of the histogram
473 - fill_color = int that sets the fill color of the histogram
474 - stats = set to True to plot a stats box on the histogram
475 - hist_title_string = specify the string that will appear as a title on the canvas
477 Return value is the histogram
480 name_string +=
" "+str(len(_hist_persistent))
481 if len(y_float_list) == len(x_float_list):
482 x_min_max =
min_max(x_float_list, weight_list, margin=rg.histo_margin, xmin=xmin, xmax=xmax)
483 y_min_max =
min_max(y_float_list, weight_list, margin=rg.histo_margin, xmin=ymin, xmax=ymax)
484 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])
485 if(len(weight_list) == len(x_float_list)):
486 for i
in range( len(x_float_list) ):
487 hist.Fill(x_float_list[i], y_float_list[i], weight_list[i])
489 for i
in range( len(x_float_list) ):
490 hist.Fill(x_float_list[i], y_float_list[i])
492 x_min_max =
min_max(x_float_list, weight_list, margin=rg.histo_margin, xmin=xmin, xmax=xmax)
493 hist = ROOT.TH1D(name_string, hist_title_string+
';'+x_axis_string, n_x_bins, x_min_max[0], x_min_max[1])
494 if(len(weight_list) == len(x_float_list)):
495 for i
in range( len(x_float_list) ):
496 hist.Fill(x_float_list[i], weight_list[i])
498 for i
in range( len(x_float_list) ):
499 hist.Fill(x_float_list[i])
500 _hist_persistent.append(hist)
501 hist.SetLineColor(line_color)
502 hist.SetLineStyle(line_style)
503 if fill_color!=
None: hist.SetFillColor(fill_color)
509 Build a legend for the canvas
514 for index, leg
in enumerate(root_item_list):
515 leg_min = 0.89-0.08*len(root_item_list)
518 leg = ROOT.TLegend(0.0, leg_min, 0.4, 0.90)
519 leg.SetEntrySeparation(0.6)
520 for i, hist
in enumerate(root_item_list):
521 leg.AddEntry(hist, root_item_list[i].GetName())
526 _legend_persistent.append(leg)
580 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=[]):
582 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)
583 matplot can format using tex expressions - use '$some math expression$' to include math text in your labels
585 - x_float_list = list of x-data
586 - x_axis_string = string used to label the x-axis
587 - y_float_list = list of y-data
588 - y_axis_string = string used to label the y-axis
590 After building the graph, use matplotlib.pyplot.show() to show something on the screen
595 pyplot.figure(_figure_index)
597 if(len(x_float_list) == 0):
598 raise IndexError(
'Attempt to draw histogram with no x-points')
599 if not len(y_float_list) == len(x_float_list):
603 if(weight_list == []):
604 (n, my_bins) = numpy.histogram(a=x_float_list, bins=n_x_bins)
606 (n, my_bins) = numpy.histogram(a=x_float_list, bins=n_x_bins, weights=weight_list)
610 while(abs(n[index])<1.e-9
and index < len(n)): index += 1
611 for i
in range(index, len(n)-1):
612 new_bins.append((my_bins[i] + my_bins[i+1])/2.)
614 hist = pylab.plot(new_bins, new_n)
615 pylab.xlabel(x_axis_string)
617 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))
618 else: hist = pyplot.hexbin(x_float_list, y_float_list, gridsize=(n_x_bins,n_y_bins))
619 pylab.xlabel(x_axis_string)
620 pylab.ylabel(y_axis_string)
623 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,
624 line_color=rg.line_color, line_style=rg.line_style, line_width=rg.line_width, fill_color=rg.graph_fill_color, hist_title_string=
''):
626 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)
628 - name_string = name given to the histogram
629 - x_float_list = list of x-data
630 - x_axis_string = string used to label the x-axis
631 - y_float_list = list of y-data
632 - y_axis_string = string used to label the y-axis
633 - sort = boolean - set to true to automatically sort input data
634 - xmin = float that overrides auto-detection of minimum x-axis value
635 - xmax = float that overrides auto-detection of maximum x-axis value
636 - ymin = float that overrides auto-detection of minimum y-axis value
637 - ymax = float that overrides auto-detection of maximum y-axis value
638 - line_color = int that sets the line colour of the graph
639 - line_style = int that sets the line style of the graph
640 - line_width = int that sets the line width of the graph
641 - fill_color = graphs dont usually get a fill, but sometimes the fill colour turns up in e.g. legend drawing
642 - hist_title_string = specify the string that will appear as a title
644 Return value is a tuple of (histogram, graph)
647 x_float_list = copy.deepcopy(x_float_list)
648 y_float_list = copy.deepcopy(y_float_list)
649 if(len(x_float_list) == 0
or len(x_float_list) != len(y_float_list)):
650 raise IndexError(
'Attempt to draw graph with no x-points, or different number of x to y points')
652 multilist = [x_float_list, y_float_list]
654 x_min_max =
min_max(multilist[0], margin=rg.graph_margin, xmin=xmin, xmax=xmax)
655 y_min_max =
min_max(multilist[1], margin=rg.graph_margin, xmin=ymin, xmax=ymax)
656 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],
657 line_color=rg.line_color, line_style=rg.line_style, line_width=0, fill_color=
None, stats=
False, hist_title_string=hist_title_string)
658 graph = ROOT.TGraph(len(x_float_list))
659 graph.SetTitle(name_string)
660 graph.SetName(name_string)
661 graph.SetLineColor(line_color)
662 graph.SetLineStyle(line_style)
663 graph.SetLineWidth(line_width)
664 graph.SetFillColor(fill_color)
665 for i
in range(len(x_float_list)):
666 graph.SetPoint(i, x_float_list[i], y_float_list[i])
667 _graph_persistent.append(graph)
670 def make_matplot_graph(x_float_list, x_axis_string, y_float_list, y_axis_string, sort=True):
672 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)
673 matplot can format using tex expressions - use '$some math expression$' to include math text in your labels
675 - x_float_list = list of x-data
676 - x_axis_string = string used to label the x-axis
677 - y_float_list = list of y-data
678 - y_axis_string = string used to label the y-axis
679 - sort = boolean - set to true to automatically sort input data
681 After building the graph, use matplotlib.pyplot.show() to show something on the screen
685 pyplot.figure(_figure_index)
687 if(len(x_float_list) == 0
or len(x_float_list) != len(y_float_list)):
688 raise IndexError(
'Attempt to draw graph with no x-points, or different number of x to y points')
689 multilist = [x_float_list, y_float_list]
691 x_min_max =
min_max(multilist[0], margin=rg.graph_margin)
692 y_min_max =
min_max(multilist[1], margin=rg.graph_margin)
693 myplot = pylab.plot(x_float_list, y_float_list)
694 pylab.xlabel(x_axis_string)
695 pylab.ylabel(y_axis_string)
696 pylab.xlim (x_min_max[0], x_min_max[1])
697 pylab.ylim (y_min_max[0], y_min_max[1])
698 matplotlib.pyplot.draw()
700 def make_root_multigraph(name_string, x_float_list_of_lists, x_axis_string, y_float_list_of_lists, y_axis_string):
702 Print several different graphs on the same canvas. Some default colour scheme is applied, but it may not be the best...
704 - name_string = name that will be given to the axes (histogram)
705 - x_float_list_of_lists = list of lists. Each list will be used as the x-axis for a graph
706 - x_axis_string = string that will be used to label the x_axis
707 - y_float_list_of_lists = list of lists. Each list will be used as the y-axis for a graph
708 - y_axis_string = string that will be used to label the y_axis
710 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
713 name_string +=
" "+str(len(_hist_persistent))
716 for a_list
in x_float_list_of_lists: total_x_list += a_list
717 for a_list
in y_float_list_of_lists: total_y_list += a_list
718 x_min_max =
min_max(total_x_list, margin=rg.graph_margin)
719 y_min_max =
min_max(total_y_list, margin=rg.graph_margin)
720 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])
722 for index
in range( len(x_float_list_of_lists) ):
723 graphs.append(ROOT.TGraph( len(x_float_list_of_lists[index]) ))
724 ROOT.gStyle.SetPalette(int(len(x_float_list_of_lists)*1.25))
725 graphs[-1].SetLineColor(ROOT.gStyle.GetColorPalette(index + int(len(x_float_list_of_lists)*0.25) ))
726 for i
in range(len(x_float_list_of_lists[index])):
727 graphs[-1].SetPoint(i, x_float_list_of_lists[index][i], y_float_list_of_lists[index][i])
728 _graph_persistent.append(graphs[-1])
729 _hist_persistent.append(hist)
731 return (hist, graphs)
735 Print several different graphs on the same axes. Some default colour scheme is applied, but it may not be the best...
737 - x_float_list_of_lists = list of lists. Each list will be used as the x-axis for a graph
738 - x_axis_string = string that will be used to label the x_axis
739 - y_float_list_of_lists = list of lists. Each list will be used as the y-axis for a graph
740 - y_axis_string = string that will be used to label the y_axis
742 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
746 pyplot.figure(_figure_index)
750 for a_list
in x_float_list_of_lists: total_x_list += a_list
751 for a_list
in y_float_list_of_lists: total_y_list += a_list
752 x_min_max =
min_max(total_x_list, margin=rg.graph_margin)
753 y_min_max =
min_max(total_y_list, margin=rg.graph_margin)
754 for index
in range( len(x_float_list_of_lists) ):
755 multilist = [x_float_list_of_lists[index], y_float_list_of_lists[index]]
757 myplot = pylab.plot(multilist[0], multilist[1])
758 pylab.xlabel(x_axis_string)
759 pylab.ylabel(y_axis_string)
760 pylab.xlim (x_min_max[0], x_min_max[1])
761 pylab.ylim (y_min_max[0], y_min_max[1])
762 matplotlib.pyplot.draw()
766 Make a matplot scatter graph with data taken from float lists and axes naemd after the axis strings.
767 matplot can format using tex expressions - use '$some math expression$' to include math text in your labels
769 - x_float_list = list of x-data
770 - x_axis_string = string used to label the x-axis
771 - y_float_list = list of y-data
772 - y_axis_string = string used to label the y-axis
774 After building the graph, use matplotlib.pyplot.show() to show something on the screen
778 pyplot.figure(_figure_index)
780 if(len(x_float_list) == 0):
781 raise IndexError(
'Attempt to draw histogram with no x-points')
782 hist = pyplot.scatter(x_float_list, y_float_list, s=1)
783 pylab.xlabel(x_axis_string)
784 pylab.ylabel(x_axis_string)
789 Force python to halt processing until ROOT windows are closed
791 print 'Close ROOT windows to continue'
795 for canvas
in _canvas_persistent:
796 if not canvas ==
None:
801 Close root plots (and free memory)
803 for canv
in _canvas_persistent: del(canv)
804 for hist
in _hist_persistent: del(hist)
805 for graph
in _graph_persistent: del(graph)
808 """Show any plots made using matplotlib on the screen"""
810 matplotlib.pyplot.show()
813 """Show matplotlib plots and return to the script"""
818 raise ImportError(
'matplot_show_and_continue is only available is (i) ROOT is not installed or (ii) you have python > 2.6')
821 def make_doc(source_folder=os.getcwd(), target_folder=os.getcwd(), test=
True):
827 file_list = [
'Hit.html',
'Common.html',
'Bunch.html']
828 for docfile
in file_list:
829 try: os.remove(source_folder+
'/xboa.'+docfile)
834 for docfile
in file_list:
835 try: os.remove(target_folder+
'/doc/'+docfile)
837 shutil.move(source_folder+
'/xboa.'+docfile, target_folder+
'/doc/'+docfile)
841 Preliminaries to making a distribution:
843 - generate documentation
847 (passes, fails, warns) = Boa_Test.test_all()
848 print 'TEST RESULTS:\nPasses:',passes,
'\nFails:',fails,
'\nWarns:',warns,
'\n'
849 if fails > 0:
raise Exception(
'Some tests failed - aborting release')
852 __mp_subprocesses = []
853 __fk_subprocesses = []
856 Make a function call in a subprocess; return the subprocess pid
857 - This uses the multiprocessing libary in the first instance - if multiprocessing is not available
858 the function tries to use os.fork(); however, os.fork is not compatible with ROOT. If
859 - multiprocessing is not available and ROOT is installed, this routine will throw an ImportError
863 __mp_subprocesses.append( multiprocessing.Process(target=function, args=args) )
864 __mp_subprocesses[-1].start()
865 return __mp_subprocesses[-1]
869 raise ImportError(
'Error - attempt to make a subprocess using fork when ROOT library is active')
877 __fk_subprocesses.append(pid)
882 Kill all subprocesses generated by Common.subprocess call; automatically called at exit unless kill_subprocesses_at_exit is set to False
883 Note that this makes a call to the os, which may take a bit of time to respond.
885 for ps
in __mp_subprocesses:
888 for pid
in __fk_subprocesses:
889 os.kill(pid, signal.SIGKILL)
893 Convenience wrapper for ROOT kolmogorov-smirnov test.
894 - list_1 = list of floats that are sampled from some parent probability distribution
895 - list_2 = list of floats that are sampled from other some parent distribution
896 Returns double between 0. and 1. giving probability that list_1 and list_2 have the same parent distribution.
898 list_1 = sorted(list_1)
899 list_2 = sorted(list_2)
900 c_array_1 = ctypes.c_double*len(list_1)
901 c_array_2 = ctypes.c_double*len(list_2)
904 for i
in range(len(list_1)): ca1[i]=ctypes.c_double(list_1[i])
905 for i
in range(len(list_2)): ca2[i]=ctypes.c_double(list_2[i])
906 ks = ROOT.TMath.KolmogorovTest(len(list_1), ca1, len(list_2), ca2,
'')
910 """Calls some functions automatically at exit"""
911 if(kill_subprocesses_at_exit):
913 atexit.register(__atexit)
918 Make a rectangular n_dimensional grid of points evenly spaced between [-1,1] in each
921 - n_dimensions = number of dimensions
922 - n_per_dimension = number of points in each dimension; total number of points will be
923 n_per_dimension^n_dimensions
925 Return value is a list of numpy.matrices with shape (n_dimensions, 1)
928 pos_vector = [numpy.matrix( [-1.]*n_dimensions )]
929 for i
in range(n_dimensions):
930 pos_vector_copy = copy.deepcopy(pos_vector)
931 for j
in range(1, n_per_dimension):
932 pos = (2.*j)/float(n_per_dimension-1)-1.
933 for vec
in pos_vector_copy:
934 vec = copy.deepcopy(vec)
936 pos_vector.append(vec)
941 Make a shell of points that sit on a hyper-ellipsoid defined by ellipse matrix
943 - n_per_dimension = number of points in each dimension; total number of points will be
944 n_per_dimension^n_dimensions if n_per_dimension is even or
945 n_per_dimension^n_dimensions-1 if n_per_dimension is odd
946 - ellipse = matrix that defines the ellipse on which vector sits; should be a
947 numpy.matrix with shape (vec_length, vec_length)
949 Points are defined on a (hyper-)cuboidal grid and then compressed so that lengths are
950 all 1. Doesn't necessarily mean points are evenly spaced. Return value is a list of
951 numpy.matrices with shape (n_dimensions, 1)
954 n_dimensions = numpy.shape(ellipse)[0]
955 grid =
make_grid(n_dimensions, n_per_dimension)
957 ellipse_inv = numpy.linalg.inv(ellipse)
959 if numpy.vdot(vector,vector) > float_tolerance:
965 Normalise vector so that vector.T() * matrix.inverse * vector = 1
967 - vector = the vector to normalise; should be a numpy.matrix with shape (vec_length,1)
968 - matrix_inverse = inverse of matrix that defines the ellipse on which vector sits; should be a
969 numpy.matrix with shape (vec_length, vec_length)
971 Return value is a list of numpy.matrices with shape (vec_length,1)
974 scale = 1./(vector * matrix_inverse * vector.transpose())[0,0]**0.5
975 if scale != scale: raise(ValueError(
"Bad input - vector or matrix magnitude 0"))
976 vector = vector*scale
981 Wrapper function to put multiprocessing output into a queue
983 - args tuple of (function_call, queue, function_arg) where
984 - function_call is a reference to the function that we want to wrap\n
985 - queue is the queue that will hold return values from the function\n
986 - function_arg is the argument to function_call\n
987 - index is an index indicating function_arg's position in the inputs
989 tuple of (index, Output) is placed into queue; if function_call throws an
990 exception, the exception is placed on the queue instead
992 (function_call, queue, function_arg, index) = args
994 queue.put((index, function_call(*function_arg)))
996 queue.put((index, sys.exc_info()[1]))
998 def process_list(function_call, list_of_args, max_n_processes):
1000 Run multiprocessing on a list of arguments
1002 - function_call multiprocess this function call
1003 - list_of_args list of tuples of arguments for function_call
1004 - max_n_processes maximum number of concurrent processes to use
1006 Returns list of return values, one for each function call. List is always
1007 sorted into same order as input.
1009 e.g. process_list(time.sleep, [(3, ), (6, ), (2, )], 2) will multiprocess
1010 the time.sleep function with inputs 3, 6 and 2 across 2 cores and return
1011 list like [None, None, None].
1013 manager = multiprocessing.Manager()
1014 queue = manager.Queue()
1015 pool = multiprocessing.Pool(max_n_processes)
1020 new_list_of_args = [(function_call, queue, x, i)
for i,x
in enumerate(list_of_args)]
1022 pool.map(__function_with_queue, new_list_of_args)
1025 while not queue.empty():
1026 out_list.append(queue.get())
1028 for i,item
in enumerate(out_list):
1029 out_list[i] = item[1]
1035 """Creates some summary documentation for the Common module. If verbose is True then will also print any functions or data not included in summary"""
1036 common_doc =
'\nCommon module contains a number of useful interfaces, defaults, data and ancillary functions that support the rest of the XBOA package.\n'
1038 name_list = [
'math',
'root',
'matplot',
'data',
'defaults',
'other_stuff']
1040 'math' : [
'min_max',
'multisort',
'nd_newton_raphson1',
'nd_newton_raphson2'],
1041 'root' : [
'has_root',
'make_root_graph',
'make_root_histogram',
'make_root_multigraph',
'clear_root',
'wait_for_root',
'make_root_canvas'],
1042 'matplot' : [
'has_matplot',
'make_matplot_graph',
'make_matplot_histogram',
'make_matplot_multigraph',
'make_matplot_scatter',
'wait_for_matplot',
'matplot_show_and_continue'],
1043 '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'],
1044 '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'],
1045 'defaults' : [
'canvas_fill_color',
'canvas_highlight_color',
'default_margin',
'float_tolerance',
'graph_margin',
'histo_margin',
'python_version',
'xboa_version',
'kill_subprocesses_at_exit']
1049 'math' :
'Maths functions:',
1050 'root' :
'Interfaces to ROOT plotting library:',
1051 'matplot' :
'Interfaces to matplotlib plotting library:',
1052 'other_stuff' :
'Some other useful functions:',
1053 'data' :
'Physics data:',
1054 'defaults' :
'Defaults for e.g. root canvases, etc:',
1058 dir_common = dir(Common)
1060 print 'The following functions and data are in Common but not in common_overview_doc:'
1061 for func
in dir_common:
1063 for func_sublist
in function_list.values():
1064 if func
in func_sublist: found =
True
1065 if not found:
print func,
1068 print 'The following functions and data are in common_overview_doc but not in Common:'
1069 for func_sublist
in function_list.values():
1070 for func
in func_sublist:
1071 if func
not in dir_common:
1076 for key
in name_list:
1077 doc = doc + function_doc[key]+
'\n'
1078 for item
in function_list[key]:
1079 doc = doc+
' '+item+
'\n'