Beispiel #1
0
    def _make_edge(self, id1, id2, ruler):
        ''' id1, id2 are the unique ids of the two items
            ruler is something that measures distance between two objects eg track and hcal
            (see Distance class for example)
            it should take the two objects as arguments and return a tuple
            of the form
                link_type = 'ecal_ecal', 'ecal_track' etc
                is_link = true/false
                distance = float
            an edge object is returned which contains the link_type, is_link (bool) and distance between the 
            objects. 
        '''
        #find the original items and pass to the ruler to get the distance info
        obj1 = self.pfevent.get_object(id1)
        obj2 = self.pfevent.get_object(id2)
        link_type, is_linked, distance = ruler(
            obj1, obj2
        )  #some redundancy in link_type as both distance and Edge make link_type
        #not sure which to get rid of

        #for the event we do not want ehal_hcal links
        if link_type == "ecal_hcal":
            is_linked = False

        #make the edge
        return Edge(id1, id2, is_linked, distance)
Beispiel #2
0
    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]
Beispiel #3
0
 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 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
Beispiel #5
0
 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
Beispiel #6
0
    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, clusters, ruler, history_nodes = None):
        '''
        clusters a dictionary : {id1:ecal1, id2:ecal2, ...}
        ruler is something that measures distance between two objects eg track and hcal
            (see Distance class for example)
            it should take the two objects as arguments and return a tuple
            of the form
                link_type = 'ecal_ecal', 'ecal_track' etc
                is_link = true/false
                distance = float
        hist_nodes is an optional dictionary of Nodes : { id:Node1, id: Node2 etc}
            it could for example contain the simulation history nodes
            A Node contains the id of an item (cluster, track, particle etc)
            and says what it is linked to (its parents and children)
            if hist_nodes is provided it will be added to with the new block information
            If hist_nodes is not provided one will be created, it will contain nodes
            corresponding to each of the tracks, ecal etc and also for the blocks that
            are created by the event block builder.
        '''
        self.clusters = clusters
        
        # the merged clusters will be stored here
        self.merged = dict()

        # collate ids of clusters
        uniqueids = list(clusters.keys())         
             
        #make the edges match cpp by using the same approach as cpp
        edges = dict()
        for obj1 in  clusters.values():
            for obj2 in  clusters.values():
                if obj1.uniqueid < obj2.uniqueid :
                    link_type, is_linked, distance = ruler(obj1, obj2)
                    edge = Edge(obj1.uniqueid, obj2.uniqueid, is_linked, distance)
                    #the edge object is added into the edges dictionary
                    edges[edge.key] = edge

        #make the subgraphs of clusters
        super(MergedClusterBuilder, self).__init__(uniqueids, edges)
        
        #make sure we use the original history and update it as needed
        self.history_nodes = history_nodes

        self._make_merged_clusters()
    def __init__(self, clusters, ruler, history_nodes):
        '''
        @param clusters: a dictionary : {id1:ecal1, id2:ecal2, ...}.
        @param ruler: measures distance between two clusters,
            see Distance class for example.
            It should take the two objects as arguments and return a tuple
            of the form:
                link_type = 'ecal_ecal'
                is_link = true/false
                distance = float
        @param history_nodes: a dictionary of Nodes : { id:Node1, id: Node2 etc}.
            It could for example contain the simulation history nodes.
            A Node contains the id of a cluster.
            and says what it is linked to (its parents and children).
            New mergedcluster history detailing which clusters the mergedcluster was made from
            will be added to the existing history
        '''
        self.clusters = clusters

        # the merged clusters will be stored here
        self.merged_clusters = dict()

        # collate ids of clusters
        uniqueids = list(clusters.keys())

        #make the edges match cpp by using the same approach as cpp
        edges = dict()
        for obj1 in clusters.values():
            for obj2 in clusters.values():
                if obj1.uniqueid < obj2.uniqueid:
                    link_type, is_linked, distance = ruler(obj1, obj2)
                    edge = Edge(obj1.uniqueid, obj2.uniqueid, is_linked,
                                distance)
                    #the edge object is added into the edges dictionary
                    edges[edge.key] = edge

        #make the subgraphs of clusters
        super(MergedClusterBuilder, self).__init__(uniqueids, edges)

        #make sure we use the original history and update it as needed
        self.history_nodes = history_nodes
        self._make_and_store_merged_clusters()
Beispiel #9
0
    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]
Beispiel #10
0
    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]
Beispiel #11
0
 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)]
Beispiel #12
0
 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)]