29 from xboa.core
import Hitcore
33 from numpy
import matrix
39 BadEventError is raised if Hit reads a bad
50 Represents a particle at a point in some phase space. Hit contains functions for i/o,
51 as well as accessors for rectangular or cylindrical coordinate systems and functions to
52 perform translations, abelian transformations etc.
54 Hit has the following variables (stored for real in C struct Hitcore)
56 - **x** transverse horizontal position
57 - **y** transverse vertical position
58 - **z** longitudinalposition
60 - **px** transverse horizontal component of momentum
61 - **py** transverse vertical component of momentum
62 - **pz** longitudinal component of momentum
63 - **energy** total energy
64 - **local_weight** local statistical weight (for a particular hit)
65 - **mass** particle mass
66 - **bx** horizontal component of magnetic field
67 - **by** vertical component of magnetic field
68 - **bz** longitudinal component of magnetic field
69 - **ex** x component of electric field
70 - **ey** y component of electric field
71 - **ez** z component of electric field
72 - **sx** x component of spin vector
73 - **sy** y component of spin vector
74 - **sz** z component of spin vector
75 - **path_length** total distance traversed by a particle
76 - **proper_time** proper time of the particle
77 - **e_dep** energy deposited, as registered by a Monte Carlo code
78 - **charge** particle charge, in units of electron charge
79 - **station** output plane index
80 - **pid** PDG particle ID (am I an electron? am I a proton?)
81 - **status** is the particle track okay? (code dependent)
82 - **spill** indexes the spill (for MICE)
83 - **event_number** indexes the event
84 - **particle_number** indexes the particle track within the event
88 - global_weight is a global statistical weight (for a particular particle).
89 All hits with the same (spill, event_number, particle_number) will register
90 the same global weight.
93 __slots__ = [
'__hitcore']
96 """Initialise to an empty event. Alternatively use static initialisers defined below - I prefer static initialisers"""
100 """Formatting for print command"""
104 """Shallow copy i.e. copy as reference"""
109 """Deep copy i.e. copy as data"""
113 def __eq__(self, target, float_tolerance=Common.float_tolerance):
114 """Test for equality of data values between self and target"""
115 if type(self) != type(target):
return False
116 for key
in self.__hitcore.get_variables():
117 if abs(self.__hitcore.get(key) - target.__hitcore.get(key)) > float_tolerance:
return False
120 def __ne__(self, target, float_tolerance=Common.float_tolerance):
121 """Test for inequality of data values between self and target"""
122 return not self.
__eq__(target, float_tolerance)
125 """Mimic some aspects of dict"""
126 return self.
get(variable)
129 """Mimic some aspects of dict"""
130 return self.
set(variable, value)
139 Static function returns a new hit object, setting data using string:value dict. Then forces E^2=p^2+m^2 by changing mass_shell_string.
141 - set_dict = dict of string:value pairs where strings are from set_variables()
142 - mass_shell_string = string from list mass_shell_variables that references the value that will be changed to force E^2=p^2+m^2
144 e.g. myHit = Hit.new_from_dict({'x':5, 'y':0, 'z':100, 'px':0, 'py':5, 'pz':200, 'pid':-13}, 'energy' )
147 for k,v
in set_dict.iteritems():
149 if(mass_shell_string !=
''):
150 my_hit.mass_shell_condition(mass_shell_string)
152 new_from_dict = staticmethod(new_from_dict)
156 Static function returns a new hit object, read from filehandle with a built-in format
158 - format = string from the list file_types() that defines the format of the input
159 - filehandle = filehandle from which the hit object will be read
161 e.g. myHit = Hit.new_from_read_builtin('zgoubi', myfile)
162 Note that this will read one event, typically corresponding to one line in <filehandle>
164 if format ==
'opal_loss':
166 opal_read = hit.__read_opal_loss_file(filehandle)
170 new_from_read_builtin = staticmethod(new_from_read_builtin)
172 def new_from_read_user(format_list, format_units_dict, filehandle, mass_shell_condition=''):
174 Static function returns a new hit object sets data using string/value pairs from set_dict and forces E^2=p^2+m^2 by changing mass_shell_string
176 - format_list = ordered list of variables from get_variables() that contains the particle variables on each line of your input file
177 - format_units_dict = dict of variables:units that are used to transform to internal system of units
178 - filehandle = file handle, created using e.g. filehandle = open('for009.dat')
180 e.g. myHit = Hit.new_from_read_user(['x','y','z','px','py','pz'], {'x':'mm', 'y':'mm', 'z':'mm', 'px':'MeV/c', 'py':'MeV/c', 'pz':'MeV/c'}, my_input_file)
188 new_from_read_user = staticmethod(new_from_read_user)
193 Static function returns a list of hit objects found in the spill
195 - format = type to take from the maus file.
196 - root_tree = TTree containing maus spill data, of type ROOT.TTree
197 - entry_number = index of the spill entry in the TTree
199 Returns a list of hit objects. Station number will be taken from the relevant maus_type. event_number will be given by the spill_number. track_number will be given by
200 the index on mc_events or recon_events
202 fac = xboa.hit.factory.factory.MausRootHitFactory(format, root_tree, entry_number)
203 hit_list = [hit
for hit
in fac.hit_generator()]
209 Static function returns a list of hit objects found in the spill
211 - format = type to take from the maus file.
212 - filehandle = filehandle containing json formatted data
214 Returns a list of hit objects. Station number will be taken from the
215 relevant maus_type. event_number will be given by the spill_number.
216 track_number will be given by the index on mc_events or recon_events.
218 fac = xboa.hit.factory.factory.MausJsonHitFactory(format, file_handle)
219 hit_list = [hit
for hit
in fac.hit_generator()]
223 """Return a shallow copy of self (copying data as references)"""
227 """Return a deep copy of target (deep copying target's data to self as well)"""
229 target = copy.deepcopy(self)
235 Return a numpy vector of data values taking data from get_variable_list, relative to some origin
237 - get_variable_list = list of variable strings from get_variables()
238 - origin_dict = dict of variable strings to origin value; if not set, assumes 0
240 e.g. transverse_vector = myHit.get_vector(['x', 'y', 'px', 'py'])
244 for key
in get_variable_list:
245 if key
in origin_dict: origin = origin_dict[key]
247 my_list.append(self.
get(key) - origin)
248 return matrix(numpy.array(my_list))
250 def translate(self, translation_dict, mass_shell_string):
252 Iterate over translation_dict and add the value in the dict to the value stored in Hit. Then force E^2 = p^2 + m^2
254 - translation_dict = dict of strings from list set_variables() to floats
255 - mass_shell_string = string from list mass_shell_variables()
257 for k,v
in translation_dict.iteritems():
258 self.
set(k, v+self.
get(k))
261 def abelian_transformation(self, rotation_list, rotation_matrix, translation_dict={}, origin_dict={}, mass_shell_variable=''):
263 Perform an abelian transformation about the origin, i.e. V_out - O = R*(V_in-O) + T.
264 Then force E^2 = p^2 + m^2
266 - rotation_list = list of variables to be rotated
267 - rotation_matrix = matrix R
268 - translation_dict = dict of strings from set_variables() to floats. Becomes O
269 - mass_shell_variable = string from list mass_shell_variables()
270 - origin_dict = dict of strings from set_variables() to floats. Becomes t
272 e.g. hit.abelian_transformation(['x','px'], array[[1,0.5],[0,1]],{'x':10},'energy') will
273 look like a drift space plus a translation
275 vector = (self.
get_vector(rotation_list)).transpose()
276 origin = copy.deepcopy(origin_dict)
277 trans = copy.deepcopy(translation_dict)
278 for key
in rotation_list:
279 if not key
in origin: origin[key] = 0
280 if not key
in trans: trans [key] = 0
281 for i
in range( len(rotation_list) ):
282 vector[i,0] -= origin[rotation_list[i]]
283 vector = rotation_matrix*vector
284 for i
in range( len(rotation_list) ):
285 self.
set(rotation_list[i], float(vector[i,0]+trans[rotation_list[i]]+origin[rotation_list[i]]))
291 Change variable represented by variable_string to force E^2 = p^2 + m^2
293 - variable_string = string which should be one of the list mass_shell_variables().
295 if(variable_string ==
''):
300 e = self.
get(
'energy')
302 if(variable_string ==
'p'):
303 self.
set(
'p', ( (e-m)*(e+m) )**0.5 )
304 elif(variable_string ==
'px'):
305 val = (e*e-m*m-py*py-pz*pz)
306 if val>float_tolerance: self.
set(
'px', abs(val)**1.5/val )
307 else: self.
set(
'px', 0.)
308 elif(variable_string ==
'py'):
309 val = (e*e-m*m-px*px-pz*pz)
310 if val>float_tolerance: self.
set(
'py', abs(val)**1.5/val )
311 else: self.
set(
'py', 0.)
312 elif(variable_string ==
'pz'):
313 val = (e*e-m*m-px*px-py*py)
314 if val>float_tolerance: self.
set(
'pz', abs(val)**1.5/val )
315 else: self.
set(
'pz', 0.)
316 elif(variable_string ==
'energy'):
317 self.
set(
'energy', (m*m+px*px+py*py+pz*pz) **0.5 )
319 raise IndexError(
'mass_shell_condition did not recognise \''+str(variable_string)+
'\'. Options are '+str(self.
__mass_shell_variables))
325 Return the value referenced by key
327 - key = string which should be one of the list get_variables()
330 return self.__hitcore.get(key)
336 raise IndexError(
'Key \''+str(key)+
'\' could not be found for Hit.get() - should be one of '+str(Hit.get_variables()))
338 def set(self, key, value):
340 Set the value referenced by key
342 - key = string which should be one of the list get_variables()
346 self.__hitcore.set(key, value)
352 raise IndexError(
'Key \''+str(key)+
'\' could not be found for Hit.set() - should be one of '+str(Hit.set_variables()))
354 def check(self, tolerance_float=1e-3):
355 """Return True if mass shell condition is obeyed and pid is correct for the mass else return False"""
356 pid = self.
get(
'pid')
357 if (
not abs(pid)
in Common.pdg_pid_to_mass)
and (
not pid
in Hit.__bad_pids)
and (
not pid == 0):
358 print 'pid not recognised',self.
get(
'pid')
360 if abs(pid)
in Common.pdg_pid_to_mass.keys():
361 if abs(self.
get(
'mass')-Common.pdg_pid_to_mass[abs(pid)]) > tolerance_float:
362 print 'Mass',self.
get(
'mass'),
'does not match pid',self.
get(
'pid')
364 if abs(round(self.
get(
'p')**2 + self.
get(
'mass')**2) - round(self.
get(
'energy')**2)) > tolerance_float :
370 Return a dict that uniquely defines the hit, so that new_from_dict(dict_from_hit(hit)) returns a copy of hit
373 for key
in self.__hitcore.set_variables():
374 my_dict[key] = self.__hitcore.get(key)
381 Write to a file formatted according to built-in file_type format
383 - format = string from file_types
384 - file_handle = file handle made using e.g. open() command
386 e.g. aHit.write_builtin_formatted('icool_for009', for009_dat) would write aHit in icool_for009 format to for009_dat
388 if( format.find(
'maus') > -1 ):
389 raise IOError(
"Can't write single maus hits, only lists of hits")
390 if( format.find(
'icool') > -1 ):
391 self.
set(
'pid', Common.pdg_pid_to_icool[self.
get(
'pid')])
392 if( format.find(
'mars') > -1 ):
393 self.
set(
'pid', Common.pdg_pid_to_mars [self.
get(
'pid')])
395 if( format.find(
'icool') > -1 ):
396 self.
set(
'pid', Common.icool_pid_to_pdg[self.
get(
'pid')])
397 if( format.find(
'mars') > -1 ):
398 self.
set(
'pid', Common.mars_pid_to_pdg [self.
get(
'pid')])
402 Write a list of hits to a file formatted according to built-in file_type format
404 - format = string from file_types
405 - file_handle = file handle made using e.g. open() command
406 - user_comment = comment included in some output formats (e.g. problem title, etc)
409 aHit.write_list_builtin_formatted([hit1, hit2] 'icool_for009', 'for009_dat')
410 would write hit1, hit2 in icool_for009 format to for009_dat
412 if( file_type_string.find(
'maus_root') > -1 ):
413 raise IOError(
"Can't write maus_root formats")
414 filehandle = Hit.open_filehandle_for_writing(file_type_string, file_name, user_comment)
415 if( file_type_string.find(
'maus') > -1 ):
417 maus_tree = Hit.get_maus_tree(list_of_hits, file_type_string)
418 for spill_number, item
in enumerate(maus_tree):
419 item[
"maus_event_type"] =
"Spill"
420 item[
"spill_number"] = spill_number
421 print >>filehandle,json.dumps(item)
423 comptor = (Hit.__station_cmp)
424 list_of_hits.sort(comptor)
427 for hit_in
in list_of_hits:
428 if old_hit ==
None or comptor(hit_in, old_hit) == 0:
429 current_hits.append(hit_in)
431 for hit_out
in current_hits:
432 try: hit_out.write_builtin_formatted(file_type_string, filehandle)
434 current_hits = [hit_in]
436 for hit_out
in current_hits:
438 hit_out.write_builtin_formatted(file_type_string, filehandle)
440 print 'Warning - failed to write ',hit_out
443 write_list_builtin_formatted = staticmethod(write_list_builtin_formatted)
447 Open a file handle of the specified type for writing. Some filehandles need special care, e.g. some are gzipped etc
449 - file_type_string = open filehandle for this file type
450 - file_name = string name of the file
453 filehandle = open(file_name,
'w')
454 filehandle.write(Hit.file_header(file_type_string, user_comment))
456 open_filehandle_for_writing = staticmethod(open_filehandle_for_writing)
458 def file_header(file_type_string, user_comment=None):
460 Return the file_header for the given file_type. Optionally, can add a user comment
462 - file_type_string = header returned for this file type. Select from file_types()
463 - user_comment = add a user comment - default is 'File generated by xboa'
465 e.g. Hit.file_header('icool_for009', 'This is my for009 file') would set 'This is my for009 file'
466 as a user comment and return the header string
468 if user_comment ==
None: file_header = Hit.__file_headers[file_type_string].replace(str(
'<user>'), str(Hit.__default_user_string))
469 else: file_header = Hit.__file_headers[file_type_string].replace(str(
'<user>'), str(user_comment))
471 file_header = staticmethod(file_header)
475 Write to a file formatted according to built-in file_type format
477 - format_list = ordered list of strings from get_variables()
478 - format_units_dict = dict of formats from format_list to units
479 - file_handle = file handle made using e.g. open() command
481 e.g. aHit.write_user_formatted(['x','px','y','py'], ['x':'m','y':'m','px':'MeV/c','py':'MeV/c'], some_file, '@') would make output like
482 0.001@0.002@0.001@0.002 in some_file
487 """Static function returns a list of available file types"""
488 return Hit.__file_types
489 file_types = staticmethod(file_types)
493 Convert from hit to a maus dict for MAUS IO
495 - type_name = name of the maus type to generate
497 Returns a tuple of (maus_dict, spill_number)
500 three_vec_conversions = Hit.__maus_three_vec_conversions[type_name]
501 conversion_dict = Hit.__maus_variable_conversions[type_name]
502 for maus_name, xboa_suffix
in three_vec_conversions.iteritems():
503 maus_dict[maus_name] = {}
504 for xyz
in [
'x',
'y',
'z']:
505 maus_dict[maus_name][xyz] = self[xboa_suffix+xyz]
506 for maus_key, xboa_key
in conversion_dict.iteritems():
507 maus_dict[maus_key] = self[xboa_key]
508 for key, value
in Hit._Hit__file_units[type_name]:
509 xboa_dict[key] *= Hit._Hit__file_units[type_name][key]
510 return (maus_dict, self[
'event_number'])
515 Convert from list of hits to a tree of maus objects
517 - list_of_hits = list of hits to be converted
518 - type_name = maus type, used to define position in the maus tree
520 Return value is a list of maus spills (each of which is a data tree)
525 return Hit.__get_maus_tree_recursive(list_of_hits, [[
"event_number"]]+Hit.__maus_paths[type_name], type_name)
526 get_maus_tree = staticmethod(get_maus_tree)
531 """Static function returns a list of variables suitable for mass_shell_condition calls"""
532 return Hit.__mass_shell_variables
533 mass_shell_variables = staticmethod(mass_shell_variables)
536 """Static function returns a list of variable suitable for get calls"""
537 return Hit.__get_keys
538 get_variables = staticmethod(get_variables)
541 """Static function returns a list of variable suitable for set calls"""
542 return Hit.__set_keys
543 set_variables = staticmethod(set_variables)
548 """Returns total momentum of the hit"""
549 return (self.
get(
'px')**2+self.
get(
'py')**2+self.
get(
'pz')**2)**0.5
552 """Returns transverse distance (i.e. in x,y space) from 0,0"""
553 return (self.
get(
'x')**2+self.
get(
'y')**2)**0.5
556 """Returns transverse angle (i.e. in x,y space) in range (-pi, pi); phi = 0. is positive y and phi = pi/2 is positive x"""
557 return math.atan2(self[
'y'], self[
'x'])
560 """Returns transverse momentum of the hit"""
561 return (self[
'px']**2+self[
'py']**2)**0.5
564 """Returns transverse angle of momentum (i.e. in px,py space) in range (-pi, pi); phi = 0. is positive py and phi = pi/2 is positive px"""
565 return math.atan2(self[
'py'], self[
'px'])
568 """Returns x divergence i.e. px/pz of the hit"""
569 return (self[
'x']**2+self[
'y']**2)
572 """Returns x divergence i.e. px/pz of the hit"""
573 return (self[
'px']/self[
'pz'])
576 """Returns y divergence i.e. py/pz of the hit"""
577 return (self[
'py']/self[
'pz'])
580 """Returns t \'divergence\' i.e. E/pz of the hit"""
581 return (-self[
'energy']/self[
'pz'])
584 """Returns dr/dz = pt/pz of the hit"""
585 return (self.
get(
'pt')/self[
'pz'])
588 """Returns absolute value of the spin"""
589 return (self.
get(
'sx')**2+self.
get(
'sy')**2+self.
get(
'sz')**2)**0.5
592 """Returns speed_of_light*t of the hit"""
593 return (self[
't']*Common.constants[
'c_light'])
596 """Returns total energy - mass, ie kinetic energy of the hit"""
597 return self[
'energy'] - self.
get(
'mass')
599 def set_ek (self, value_float):
600 """Sets kinetic energy = total energy - mass of the hit"""
601 self[
'energy'] = value_float + self.
get(
'mass')
604 """Returns kinetic angular momentum about the z-axis.
605 To use a different axis, you will have to perform your own transformation"""
606 return self[
'x']*self[
'py'] - self[
'y']*self[
'px']
608 def set_ct (self, value_float):
609 """Sets t = value_float/c_light"""
610 self[
't'] = value_float/Common.constants[
'c_light']
612 def set_p(self, value_float):
613 """Set p to value_float keeping momentum direction constant"""
617 scale = value_float/self.
get_p()
622 def set_xP (self, value_float):
623 """Set x\' to value_float keeping pz constant"""
624 if(math.fabs(self[
'pz']) < 1e-9):
raise FloatingPointError(
'Cant set x\' while pz is 0')
625 self[
'px'] = value_float*self[
'pz']
627 def set_yP (self, value_float):
628 """Set y\' to value_float keeping pz constant"""
629 if(math.fabs(self[
'pz']) < 1e-9):
raise FloatingPointError(
'Cant set y\' while pz is 0')
630 self[
'py'] = value_float*self[
'pz']
632 def set_tP (self, value_float):
633 """Set t\' (dt/dz=-E/pz) to value_float keeping pz constant; note sign of pz may change"""
634 if(math.fabs(self[
'pz']) < 1e-9):
raise FloatingPointError(
'Cant set t\' while pz is 0')
635 self[
'energy'] = -value_float*self[
'pz']
637 self[
'energy'] *= -1.
639 if self[
'energy'] < self.
get(
'mass'):
raise FloatingPointError(
'Energy less than muon mass')
642 """Returns total weight for this Hit"""
643 return self.
get(
'global_weight')*self.
get(
'local_weight')
646 """Set all global weights to 1"""
647 Hitcore.clear_global_weights()
648 clear_global_weights = staticmethod(clear_global_weights)
651 """Clear memory allocated to global weights - also resets global weights to 1"""
652 raise NotImplementedError(
"delete_global_weights is deprecated - please use clear_global_weights")
653 delete_global_weights = staticmethod(delete_global_weights)
656 """Returns local weight for this Hit"""
657 return self.
get(
'local_weight')
660 """Set local weight for this Hit to be value"""
661 self.
set(
'local_weight', value)
664 """Returns global weight for this Hit"""
665 return self.
get(
'global_weight')
668 """Set global weight for this Hit to be value"""
669 self.
set(
'global_weight', value)
673 g4beamline_track_file can take different units for length - set the unit here
675 - unit = string that is a unit of length
677 e.g. set_g4bl_unit('m') would set the length unit to metres
679 Hit.__file_units[
'g4beamline_bl_track_file'][
'x'] = unit
680 Hit.__file_units[
'g4beamline_bl_track_file'][
'y'] = unit
681 Hit.__file_units[
'g4beamline_bl_track_file'][
'z'] = unit
682 set_g4bl_unit = staticmethod(set_g4bl_unit)
685 def __write_formatted(self, format_list, format_units_dict, file_handle, separator=' '):
686 for key
in format_list:
687 if key ==
'': value = 0
688 else: value = Hit._default_var_types[key](self.
get(key)/Common.units[ format_units_dict[key] ])
689 file_handle.write( str( value )+separator)
690 file_handle.write(
'\n')
695 for i
in range(mc_event.GetVirtualHitsSize()):
696 maus_hit = mc_event.GetAVirtualHit(i)
697 pid = maus_hit.GetParticleId()
698 hit_dict = {
'pid':pid,
't':maus_hit.GetTime(),
'charge':maus_hit.GetCharge(),
'proper_time':maus_hit.GetProperTime(),
699 'path_length':maus_hit.GetPathLength(),
'station':maus_hit.GetStationId(),
700 'x':maus_hit.GetPosition().x(),
'y':maus_hit.GetPosition().y(),
'z':maus_hit.GetPosition().z(),
701 'px':maus_hit.GetMomentum().x(),
'py':maus_hit.GetMomentum().y(),
'pz':maus_hit.GetMomentum().z(),
702 'bx':maus_hit.GetBField().x(),
'by':maus_hit.GetBField().y(),
'bz':maus_hit.GetBField().z(),
703 'ex':maus_hit.GetEField().x(),
'ey':maus_hit.GetEField().y(),
'ez':maus_hit.GetEField().z(),
704 'particle_number':maus_hit.GetTrackId()}
705 hit_dict[
'mass'] = Common.pdg_pid_to_mass[abs(pid)]
706 if hit_dict[
'pid'] != 0:
707 hit_list.append(Hit.new_from_dict(hit_dict,
'energy'))
709 print 'Warning - pid 0 detected in maus_root_virtual_hit; hit will not be loaded'
711 __get_maus_root_virtual_hits = staticmethod(__get_maus_root_virtual_hits)
714 maus_hit = mc_event.GetPrimary()
715 pid = maus_hit.GetParticleId()
716 hit_dict = {
'pid':pid,
'energy':maus_hit.GetEnergy(),
't':maus_hit.GetTime(),
717 'x':maus_hit.GetPosition().x(),
'y':maus_hit.GetPosition().y(),
'z':maus_hit.GetPosition().z(),
718 'px':maus_hit.GetMomentum().x(),
'py':maus_hit.GetMomentum().y(),
'pz':maus_hit.GetMomentum().z()}
719 hit_dict[
'particle_number'] = 0
720 hit_dict[
'charge'] = Common.pdg_pid_to_charge[abs(pid)]
721 hit_dict[
'mass'] = Common.pdg_pid_to_mass[abs(pid)]
722 return [Hit.new_from_dict(hit_dict,
'energy')]
723 __get_maus_root_primary_hits = staticmethod(__get_maus_root_primary_hits)
729 value = item[sort_attribute]
730 if not value
in a_dict: a_dict[value] = []
731 a_dict[value].append(item)
732 return a_dict.values()
733 __split_list_by_equality = staticmethod(__split_list_by_equality)
737 if len(maus_path) == 1:
738 if type(maus_path[0]) == type(
""):
739 if len(list_of_hits) > 1:
740 for hit
in list_of_hits:
742 raise IOError(
"More than one hit for maus key")
744 if type(maus_path[0]) == type([]):
745 return [hit.get_maus_dict(format)[0]
for hit
in list_of_hits]
746 if type(maus_path[0]) == type([]):
747 list_of_hits_new = Hit.__split_list_by_equality(list_of_hits, maus_path[0][0])
748 my_output = [Hit.__get_maus_tree_recursive(x, maus_path[1:], format)
for x
in list_of_hits_new]
749 if len(maus_path) == 1:
751 for out
in my_output: output += out
752 else: output = my_output
754 if type(maus_path[0]) == type(
""):
755 return {maus_path[0]:Hit.__get_maus_tree_recursive(list_of_hits, maus_path[1:], format)}
756 __get_maus_tree_recursive = staticmethod(__get_maus_tree_recursive)
762 value = item[sort_attribute]
763 if not value
in a_dict: a_dict[value] = []
764 a_dict[value].append(item)
765 return a_dict.values()
766 __split_list_by_equality = staticmethod(__split_list_by_equality)
776 __file_types = [
'icool_for009',
'icool_for003',
'g4beamline_bl_track_file',
'mars_1']
779 __file_types += [
'maus_json_virtual_hit',
'maus_json_primary']
784 __file_types += [
'maus_root_virtual_hit',
'maus_root_primary']
788 __mass_shell_variables = [
'',
'p',
'px',
'py',
'pz',
'energy']
789 __get_variables = {
'p':get_p,
'r':get_r,'phi':get_phi,'pt':get_pt,'pphi':get_pphi,'x\'':get_xP,'y\'':get_yP,'t\'':get_tP, 'ct\'':get_tP,'r\'':get_rP,'spin':get_spin,
790 'weight':get_weight,
'ct':get_ct,
'r_squared':get_r_squared,
'z\'':__return_one,
'kinetic_energy':get_ek,
791 'l_kin':get_l_kin,
'':__do_nothing}
792 __set_variables = {
'p':set_p,
'x\'':set_xP,
'y\'':set_yP,
't\'':set_tP,
'ct':set_ct,
'kinetic_energy':set_ek,
'':__do_nothing}
793 _default_var_types = {
'x':float,
'y':float,
'z':float,
't':float,
'px':float,
'py':float,
'pz':float,
'energy':float,
'bx':float,
'by':float,
'bz':float,
794 'ex':float,
'ey':float,
'ez':float,
'eventNumber':int,
'event_number':int,
'particleNumber':int,
'particle_number':int,
'pid':int,
'status':int,
'station':int,
'local_weight':float,
795 'sx':float,
'sy':float,
'sz':float,
'mass':float,
'path_length':float,
'proper_time':float,
'e_dep':float,
'charge':float}
799 for key
in Hitcore.get_variables():
800 __get_keys.append(key)
801 for key
in Hitcore.set_variables():
802 __set_keys.append(key)
803 for key, value
in __get_variables.iteritems():
804 __get_keys.append(key)
805 for key, value
in __set_variables.iteritems():
806 __set_keys.append(key)
807 for key, value
in __get_variables.iteritems():
808 if not key
in _default_var_types:
809 _default_var_types[key] = float
812 __maus_three_vec_conversions = {
813 "maus_json_virtual_hit":{
"position":
"",
"momentum":
"p",
"b_field":
"b",
"e_field":
"e"},
814 "maus_json_primary":{
"position":
"",
"momentum":
"p"}
817 __maus_variable_conversions = {
818 "maus_json_virtual_hit":{
"station_id":
"station",
"particle_id":
"pid",
"track_id":
"particle_number",
"time":
"t",
"mass":
"mass",
"charge":
"charge",
"proper_time":
"proper_time",
"path_length":
"path_length"},
819 "maus_json_primary":{
"particle_id":
"pid",
"time":
"t",
"energy":
"energy"}
823 "maus_json_virtual_hit":[
"mc_events", [
"particle_number"],
"virtual_hits", [
"station"]],
824 "maus_json_primary":[
"mc_events", [
"particle_number"],
"primary"],
827 __maus_root_mc_types = {
828 "maus_root_virtual_hit":
lambda x, y: Hit.__get_maus_root_virtual_hits(x, y),
829 "maus_root_primary":
lambda x, y: Hit.__get_maus_root_primary_hits(x, y)
831 __maus_root_recon_types = {}
835 'icool_for009' : [
'eventNumber',
'particleNumber',
'pid',
'status',
'station',
't',
'x',
'y',
'z',
'px',
'py',
'pz',
'bx',
'by',
'bz',
'local_weight',
836 'ex',
'ey',
'ez',
'',
'sx',
'sy',
'sz'],
837 'icool_for003' : [
'eventNumber',
'particleNumber',
'pid',
'status',
't',
'local_weight',
'x',
'y',
'z',
'px',
'py',
'pz',
'sx',
'sy',
'sz'],
838 'g4beamline_bl_track_file' : [
'x',
'y',
'z',
'px',
'py',
'pz',
't',
'pid',
'eventNumber',
'particleNumber',
'',
'local_weight'],
842 'mars_1' : [
'eventNumber',
'pid',
'x',
'y',
'z',
'px',
'py',
'pz',
'energy',
'ct',
'local_weight']
845 'icool_for009' : {
'eventNumber':
'',
'particleNumber':
'',
'pid':
'',
'status':
'',
'station':
'',
't':
's',
'x':
'm',
'y':
'm',
'z':
'm',
'px':
'GeV/c',
'py':
'GeV/c',
846 'pz':
'GeV/c',
'bx':
'T',
'by':
'T',
'bz':
'T',
'local_weight':
'',
847 'ex':
'GV/m',
'ey':
'GV/m',
'ez':
'GV/m',
'sx':
'',
'sy':
'',
'sz':
'',
'':
''},
848 'icool_for003' : {
'eventNumber':
'',
'particleNumber':
'',
'pid':
'',
'status':
'',
't':
's',
'local_weight':
'',
'x':
'm',
'y':
'm',
'z':
'm',
'px':
'GeV/c',
'py':
'GeV/c',
'pz':
'GeV/c',
'sx':
'',
'sy':
'',
'sz':
''},
849 'g4beamline_bl_track_file' : {
'x':
'mm',
'y':
'mm',
'z':
'mm',
'px':
'MeV/c',
'py':
'MeV/c',
'pz':
'MeV/c',
't':
'ns',
'pid':
'',
'eventNumber':
'',
'station':
'',
'local_weight':
'',
'particleNumber':
''},
853 'mars_1' : {
'eventNumber':
'',
'pid':
'',
'x':
'mm',
'y':
'mm',
'z':
'mm',
'px':
'GeV/c',
'py':
'GeV/c',
'pz':
'GeV/c',
'energy':
'GeV',
'ct':
'cm',
'local_weight':
''},
854 'maus_json_virtual_hit': {},
855 'maus_json_primary': {},
859 'icool_for003':
'<user>\n0. 0. 0. 0. 0. 0. 0. 0.\n',
860 'icool_for009':
'#<user>\n# units = [s] [m] [GeV/c] [T] [V/m]\nevt par typ flg reg time x y z Px Py Pz Bx By Bz wt Ex Ey Ez arclength polX polY polZ\n',
861 'g4beamline_bl_track_file':
'#BLTrackFile <user>\n#x y z Px Py Pz t PDGid EvNum TrkId Parent weight\n',
866 'maus_json_virtual_hit':
'',
867 'maus_json_primary':
'',
869 __default_user_string =
'File generated by X_BOA'
872 return cmp(lhs.get(
'eventNumber'), rhs.get(
'eventNumber'))
873 __event_cmp = staticmethod(__event_cmp)
876 return cmp(lhs.get(
'station'), rhs.get(
'station'))
877 __station_cmp = staticmethod(__station_cmp)
880 __hit_sort_comparator = {
881 'icool_for009': __event_cmp,
882 'icool_for003': __event_cmp,
883 'g4beamline_bl_track_file': __event_cmp,
884 'ZGoubi': __event_cmp,
885 'Turtle': __event_cmp,
887 'maus_json_virtual_hit': __event_cmp,
888 'maus_json_primary': __event_cmp,
889 'mars_1': __event_cmp,
892 __angular_momentum_centroid = (0.,0.,0.)
893 __angular_momentum_vector = (0.,0.,1.)
896 __maus_root_mc_types = {
897 "maus_root_virtual_hit":
lambda x, y: Hit.__get_maus_root_virtual_hits(x, y),
898 "maus_root_primary":
lambda x, y: Hit.__get_maus_root_primary_hits(x, y)
900 __maus_root_recon_types = {}
902 __opal_ignore_probes = [
"RING"]
907 """Creates some summary documentation for the Hit class. If verbose is True then will also print any functions or data not included in summary"""
908 name_list = [
'initialise',
'get',
'set',
'transform',
'io',
'ancillary']
910 'initialise' : [
'new_from_dict',
'new_from_read_builtin',
'new_from_read_user',
'copy',
'deepcopy'],
911 'get' : [
'get',
'get_ct',
'get_ek',
'get_global_weight',
'get_l_kin',
'get_local_weight',
'get_p',
'get_phi',
'get_pphi',
'get_pt',
'get_r',
'get_rP',
'get_r_squared',
'get_spin',
'get_tP',
'get_vector',
'get_weight',
'get_xP',
'get_yP'],
912 'set' : [
'set',
'set_ct',
'set_ek',
'set_local_weight',
'set_p',
'set_tP',
'set_variables',
'set_xP',
'set_yP',
'set_global_weight'],
913 'transform' : [
'abelian_transformation',
'translate',
'mass_shell_condition'],
914 'io' : [
'file_header',
'file_types',
'set_g4bl_unit',
'write_builtin_formatted',
'write_list_builtin_formatted',
'write_user_formatted',
'open_filehandle_for_writing',
'get_maus_dict',
'get_maus_paths',
'get_maus_tree'],
915 'ancillary' : [
'check',
'clear_global_weights',
'delete_global_weights',
'get_bad_pids',
'set_bad_pids',
'dict_from_hit',
'mass_shell_variables',
'get_variables']
918 'initialise':
'Functions that can be used to initialise a Hit in various different ways:',
919 'get' :
'Functions to get Hit data',
920 'set' :
'Functions to set Hit data',
921 'transform' :
'Functions that transform a Hit in some way:',
922 'io' :
'Output and some input helper functions:',
923 'ellipse':
'Functions to calculate beam ellipses based on Twiss parameters etc:',
924 'ancillary':
'Some other useful functions'
926 hit_doc =
'\nHit class stores all data for a Hit on e.g. a detector - so for example, (x,y,z) and (px,py,pz) data. Mimics a string-indexed dict; full documentation for internal variables is given below under Hitcore. In brief, gettable variables are\n'+str(Hit.get_variables())+
'\n and settable variables are\n'+str(Hit.set_variables())+
'.\n Call using e.g. my_hit[\'x\'] = 3. Also has IO functions and a few other useful functions.\n'
929 print 'The following functions and data are in Bunch but not in overview_doc:'
932 for func_sublist
in function_list.values():
933 if func
in func_sublist: found =
True
934 if not found:
print func,
937 print 'The following functions and data are in bunch_overview_doc but not in Bunch:'
938 for func_sublist
in function_list.values():
939 for func
in func_sublist:
940 if func
not in dir_hit:
945 for key
in name_list:
946 doc = doc + function_doc[key]+
'\n'
947 for item
in function_list[key]:
948 doc = doc+
' '+item+
'\n'
950 hit_overview_doc = staticmethod(hit_overview_doc)
952 __doc__ = Hit.hit_overview_doc()
def get_phi
Returns transverse angle (i.e.
dictionary __file_formats
def __setitem__
Mimic some aspects of dict.
The hit factory module defines a number of factory classes used for generating hit objects...
def __ne__
Test for inequality of data values between self and target.
def get_local_weight
Returns local weight for this Hit.
def dict_from_hit
Return a dict that uniquely defines the hit, so that new_from_dict(dict_from_hit(hit)) returns a copy...
tuple __split_list_by_equality
def __repr__
Formatting for print command.
Factory class for line by line reads of output files using a user-defined format. ...
def clear_global_weights
Set all global weights to 1.
def get_xP
Returns x divergence i.e.
def get_weight
Returns total weight for this Hit.
tuple __get_maus_root_virtual_hits
def abelian_transformation
Perform an abelian transformation about the origin, i.e.
BadEventError is raised if Hit reads a bad.
def translate
Iterate over translation_dict and add the value in the dict to the value stored in Hit...
tuple new_from_read_builtin
def copy
Return a shallow copy of self (copying data as references)
def set_ek
Sets kinetic energy = total energy - mass of the hit.
def write_user_formatted
Write to a file formatted according to built-in file_type format.
def set_tP
Set t\' (dt/dz=-E/pz) to value_float keeping pz constant; note sign of pz may change.
def check
Return True if mass shell condition is obeyed and pid is correct for the mass else return False...
def get_tP
Returns t \'divergence\' i.e.
def __eq__
Test for equality of data values between self and target.
def get_rP
Returns dr/dz = pt/pz of the hit.
tuple __get_maus_tree_recursive
def get_pphi
Returns transverse angle of momentum (i.e.
def write_builtin_formatted
Write to a file formatted according to built-in file_type format.
Factory class for line by line reads of output files.
def __deepcopy__
Deep copy i.e.
def get_pt
Returns transverse momentum of the hit.
def get_vector
Return a numpy vector of data values taking data from get_variable_list, relative to some origin...
common module defines common utility data and functions that are used elsewhere
def new_list_from_maus_root
Static function returns a list of hit objects found in the spill.
def __getitem__
Mimic some aspects of dict.
def set_local_weight
Set local weight for this Hit to be value.
list __mass_shell_variables
tuple __get_maus_root_primary_hits
def mass_shell_condition
Change variable represented by variable_string to force E^2 = p^2 + m^2.
def set_ct
Sets t = value_float/c_light.
dictionary __set_variables
def __init__
Initialise to an empty event.
def new_list_from_maus_json
Static function returns a list of hit objects found in the spill.
def file_types
Static function returns a list of available file types.
def get_r
Returns transverse distance (i.e.
def mass_shell_variables
Static function returns a list of variables suitable for mass_shell_condition calls.
def set_variables
Static function returns a list of variable suitable for set calls.
dictionary __get_variables
Represents a particle at a point in some phase space.
def get_l_kin
Returns kinetic angular momentum about the z-axis.
tuple write_list_builtin_formatted
def set_global_weight
Set global weight for this Hit to be value.
def get_ct
Returns speed_of_light*t of the hit.
def get_spin
Returns absolute value of the spin.
def delete_global_weights
Clear memory allocated to global weights - also resets global weights to 1.
def deepcopy
Return a deep copy of target (deep copying target's data to self as well)
tuple open_filehandle_for_writing
def get_maus_dict
Convert from hit to a maus dict for MAUS IO.
def get_ek
Returns total energy - mass, ie kinetic energy of the hit.
def get_p
Returns total momentum of the hit.
def __copy__
Shallow copy i.e.
def get
Return the value referenced by key.
def set_xP
Set x\' to value_float keeping pz constant.
def get_r_squared
Returns x divergence i.e.
def get_variables
Static function returns a list of variable suitable for get calls.
def set_yP
Set y\' to value_float keeping pz constant.
def get_global_weight
Returns global weight for this Hit.
def get_yP
Returns y divergence i.e.
def set_p
Set p to value_float keeping momentum direction constant.
def set
Set the value referenced by key.