def __init__(self, element_ids, edges, subtype): ''' element_ids: list of the uniqueids of the elements to go in this block [id1,id2,...] edges: is a dictionary of edges, it must contain at least all needed edges. It is not a problem if it contains additional edges as only the ones needed will be extracted subtype: used when making unique identifier, will normally be 'r' for reconstructed blocks and 's' for split blocks ''' #make a uniqueid for this block self.uniqueid = Identifier.make_id(Identifier.PFOBJECTTYPE.BLOCK, subtype) self.element_uniqueids = sorted( element_ids, key=lambda x: Identifier.type_letter(x)) #comment out energy sorting for now as not available C++ sortby = lambda x: Identifier.type_letter(x) self.element_uniqueids = sorted(element_ids, key=sortby) #sequential numbering of blocks, not essential but helpful for debugging self.block_count = PFBlock.temp_block_count PFBlock.temp_block_count += 1 #extract the relevant parts of the complete set of edges and store this within the block self.edges = dict() for id1, id2 in itertools.combinations(self.element_uniqueids, 2): key = Edge.make_key(id1, id2) self.edges[key] = edges[key]
def _edge_type(self): ''' produces an edge_type string eg "ecal_track" the order of id1 an id2 does not matter, eg for one track and one ecal the type will always be "ecal_track" (and never be a "track_ecal") ''' #consider creating an ENUM instead for the edge_type shortid1 = Identifier.type_letter(self.id1) shortid2 = Identifier.type_letter(self.id2) if shortid1 == shortid2: if shortid1 == "h": return "hcal_hcal" elif shortid1 == "e": return "ecal_ecal" elif shortid1 == "t": return "track_track" elif (shortid1 == "h" and shortid2 == "t" or shortid1 == "t" and shortid2 == "h"): return "hcal_track" elif (shortid1 == "e" and shortid2 == "t" or shortid1 == "t" and shortid2 == "e"): return "ecal_track" elif (shortid1 == "e" and shortid2 == "h" or shortid1 == "h" and shortid2 == "e"): return "ecal_hcal" return "unknown"
def short_elements_string(self): ''' Construct a string description of each of the elements in a block. The elements are given a short name E/H/T according to ecal/hcal/track and then sequential numbering starting from 0, this naming is also used to index the matrix of distances. The full unique id is also given. For example:- elements: { E0:1104134446736:SmearedCluster : ecal_in 0.57 0.33 -2.78 H1:2203643940048:SmearedCluster : hcal_in 6.78 0.35 -2.86 T2:3303155568016:SmearedTrack : 5.23 4.92 0.34 -2.63 } ''' count = 0 elemdetails = " elements:\n" for uid in self.element_uniqueids: elemdetails += "{shortname:>7}{count} = {strdescrip:9} value={val:5.1f} ({uid})\n".format( shortname=Identifier.type_letter(uid), count=count, strdescrip=Identifier.pretty(uid), val=Identifier.get_value(uid), uid=uid) count = count + 1 return elemdetails
def edge_matrix_string(self): ''' produces a string containing the the lower part of the matrix of distances between elements elements are ordered as ECAL(E), HCAL(H), Track(T) for example:- distances: E0 H1 T2 T3 E0 . H1 0.0267 . T2 0.0000 0.0000 . T3 0.0287 0.0825 --- . ''' # make the header line for the matrix count = 0 matrixstr = "" if len(self.element_uniqueids) > 1: matrixstr = " distances:\n " for e1 in self.element_uniqueids: # will produce short id of form E2 H3, T4 etc in tidy format elemstr = Identifier.type_letter(e1) + str(count) matrixstr += "{:>8}".format(elemstr) count += 1 matrixstr += "\n" #for each element find distances to all other items that are in the lower part of the matrix countrow = 0 for e1 in self.element_uniqueids: # this will be the rows countcol = 0 rowstr = "" #make short name for the row element eg E3, H5 etc rowname = Identifier.type_letter(e1) + str(countrow) for e2 in self.element_uniqueids: # these will be the columns countcol += 1 if e1 == e2: rowstr += " ." break elif self.get_edge(e1, e2).distance is None: rowstr += " ---" elif not self.get_edge(e1, e2).linked: rowstr += " ---" else: rowstr += "{:8.4f}".format( self.get_edge(e1, e2).distance) matrixstr += "{:>8}".format(rowname) + rowstr + "\n" countrow += 1 return matrixstr
def edge_matrix_string(self): ''' produces a string containing the the lower part of the matrix of distances between elements elements are ordered as ECAL(E), HCAL(H), Track(T) for example:- distances: E0 H1 T2 T3 E0 . H1 0.0267 . T2 0.0000 0.0000 . T3 0.0287 0.0825 --- . ''' # make the header line for the matrix count = 0 matrixstr = "" if len(self.element_uniqueids) > 1: matrixstr = " distances:\n " for e1 in self.element_uniqueids : # will produce short id of form E2 H3, T4 etc in tidy format elemstr = Identifier.type_letter(e1) + str(count) matrixstr += "{:>8}".format(elemstr) count += 1 matrixstr += "\n" #for each element find distances to all other items that are in the lower part of the matrix countrow = 0 for e1 in self.element_uniqueids : # this will be the rows countcol = 0 rowstr = "" #make short name for the row element eg E3, H5 etc rowname = Identifier.type_letter(e1) +str(countrow) for e2 in self.element_uniqueids: # these will be the columns countcol += 1 if e1 == e2: rowstr += " ." break elif self.get_edge(e1, e2).distance is None: rowstr += " ---" elif not self.get_edge(e1, e2).linked: rowstr += " xxx" else : rowstr += "{:8.4f}".format(self.get_edge(e1, e2).distance) matrixstr += "{:>8}".format(rowname) + rowstr + "\n" countrow += 1 return matrixstr
def _edge_type(self): ''' produces an edge_type string eg "ecal_track" the order of id1 an id2 does not matter, eg for one track and one ecal the type will always be "ecal_track" (and never be a "track_ecal") ''' #consider creating an ENUM instead for the edge_type shortid1=Identifier.type_letter(self.id1); shortid2=Identifier.type_letter(self.id2); if shortid1 == shortid2: if shortid1 == "h": return "hcal_hcal" elif shortid1 == "e": return "ecal_ecal" elif shortid1 == "t": return "track_track" elif (shortid1=="h" and shortid2=="t" or shortid1=="t" and shortid2=="h"): return "hcal_track" elif (shortid1=="e" and shortid2=="t" or shortid1=="t" and shortid2=="e"): return "ecal_track" elif (shortid1=="e" and shortid2=="h" or shortid1=="h" and shortid2=="e"): return "ecal_hcal" return "unknown"
def __init__(self, element_ids, edges, index, subtype): ''' @param element_ids: list of the uniqueids of the elements to go in this block [id1,id2,...] @param edges: is a dictionary of edges, it must contain at least all needed edges. It is not a problem if it contains additional edges as only the ones needed will be extracted @param index: index into the collection of blocks into which new block will be added @param subtype: used when making unique identifier, will normally be 'r' for reconstructed blocks and 's' for split blocks ''' #make a uniqueid for this block self.uniqueid = Identifier.make_id(Identifier.PFOBJECTTYPE.BLOCK, index, subtype, len(element_ids)) #this will sort by type eg ecal, hcal, track and then by energy (biggest first) sortby = lambda x: (Identifier.type_letter(x), -Identifier.get_value(x)) self.element_uniqueids = sorted(element_ids, key=sortby) #sequential numbering of blocks, not essential but helpful for debugging self.block_count = PFBlock.temp_block_count PFBlock.temp_block_count += 1 #extract the relevant parts of the complete set of edges and store this within the block self.edges = dict() for id1, id2 in itertools.combinations(self.element_uniqueids, 2): key = Edge.make_key(id1, id2) self.edges[key] = edges[key]