def simplify_blocks(self, block, history_nodes=None): ''' Block: a block which contains list of element ids and set of edges that connect them history_nodes: optional dictionary of Nodes with element identifiers in each node returns a dictionary of new split blocks The goal is to remove, if needed, some links from the block so that each track links to at most one hcal within a block. In some cases this may separate a block into smaller blocks (splitblocks). The BlockSplitter is used to return the new smaller blocks. If history_nodes are provided then the history will be updated. Split blocks will have the tracks and cluster elements as parents, and also the original block as a parent ''' ids = block.element_uniqueids #create a copy of the edges and unlink some of these edges if needed newedges = copy.deepcopy(block.edges) if len(ids) > 1 : for uid in ids : if Identifier.is_track(uid): # for tracks unlink all hcals except the closest hcal linked_ids = block.linked_ids(uid, "hcal_track") # NB already sorted from small to large distance if linked_ids != None and len(linked_ids) > 1: first_hcal = True for id2 in linked_ids: newedge = newedges[Edge.make_key(uid, id2)] if first_hcal: first_dist = newedge.distance first_hcal = False else: if newedge.distance == first_dist: pass newedge.linked = False #create new block(s) splitblocks = BlockSplitter(block.uniqueid, ids, newedges, len(self.splitblocks), 's', history_nodes).blocks return splitblocks
def __init__(self, element_ids, edges, pfevent): ''' 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 pfevent: allows access to the underlying elements given a uniqueid must provide a get_object function ''' #make a uniqueid for this block self.uniqueid = Identifier.make_id(Identifier.PFOBJECTTYPE.BLOCK) self.is_active = True # if a block is subsequently split it will be deactivated #allow access to the underlying objects self.pfevent=pfevent #order the elements by element type (ecal, hcal, track) and then by energy #this is a bit yucky but needed to make sure the order returned is consistent #maybe should live outside of this class self.element_uniqueids = sorted(element_ids, key = lambda x: (Identifier.type_short_code(x),-self.pfevent.get_object(x).energy) ) #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 __init__(self, element_ids, edges, pfevent): ''' 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 pfevent: allows access to the underlying elements given a uniqueid must provide a get_object function ''' #make a uniqueid for this block self.uniqueid = Identifier.make_id(Identifier.PFOBJECTTYPE.BLOCK) self.is_active = True # if a block is subsequently split it will be deactivated #allow access to the underlying objects self.pfevent = pfevent #comment out energy sorting for now as not available C++ sortby = lambda x: Identifier.type_short_code(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 simplify_blocks(self, block, history_nodes=None): ''' Block: a block which contains list of element ids and set of edges that connect them history_nodes: optional dictionary of Nodes with element identifiers in each node returns a dictionary of new split blocks The goal is to remove, if needed, some links from the block so that each track links to at most one hcal within a block. In some cases this may separate a block into smaller blocks (splitblocks). The BlockSplitter is used to return the new smaller blocks. If history_nodes are provided then the history will be updated. Split blocks will have the tracks and cluster elements as parents, and also the original block as a parent ''' ids = block.element_uniqueids #create a copy of the edges and unlink some of these edges if needed newedges = copy.deepcopy(block.edges) if len(ids) > 1 : for uid in ids : if IdCoder.is_track(uid): # for tracks unlink all hcals except the closest hcal linked_ids = block.linked_ids(uid, "hcal_track") # NB already sorted from small to large distance if linked_ids != None and len(linked_ids) > 1: first_hcal = True for id2 in linked_ids: newedge = newedges[Edge.make_key(uid, id2)] if first_hcal: first_dist = newedge.distance first_hcal = False else: if newedge.distance == first_dist: pass newedge.linked = False #create new block(s) splitblocks = BlockSplitter(block.uniqueid, ids, newedges, len(self.splitblocks), 's', history_nodes).blocks return splitblocks
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 __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 = IdCoder.make_id(IdCoder.PFOBJECTTYPE.BLOCK, index, subtype, len(element_ids)) #this will sort by type eg ecal, hcal, track and then by energy (biggest first) self.element_uniqueids = sorted(element_ids, reverse=True) #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 __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) self.element_uniqueids = sorted(element_ids, reverse=True) #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 get_edge(self, id1, id2): ''' Find the edge corresponding to e1 e2 Note that make_key deals with whether it is get_edge(e1, e2) or get_edge(e2, e1) (either order gives same result) ''' return self.edges[Edge.make_key(id1, id2)]
def get_edge(self, id1, id2): ''' Find the edge corresponding to e1 e2 Note that make_key deals with whether it is get_edge(e1, e2) or get_edge(e2, e1) (either order gives same result) ''' return self.edges[Edge.make_key(id1,id2)]