def update_history(self, parentid, childid): '''Updates the history adding new nodes if needed and recording parent child relationship''' child = self.history.setdefault( childid, Node(childid)) #creates a new node if it is not there already parent = self.history.setdefault(parentid, Node(parentid)) parent.add_child(child)
def process(self, event): event.papasevent = PapasEvent(event.iEv) papasevent = event.papasevent #make a dict from the gen_particles list so that it can be stored into the papasevent collections gen_particles = getattr(event, self.cfg_ana.gen_particles) gen_particles_collection = {} for g in gen_particles: #set the papas identifiers for use in DAG g.set_dagid( IdCoder.make_id(IdCoder.PFOBJECTTYPE.PARTICLE, g.objid()[0], 'g', g.p4().E())) gen_particles_collection[g.dagid()] = g #make a dict from the rec_particles list so that it can be stored into the papasevent collections rec_particles = getattr(event, self.cfg_ana.rec_particles) #if there are no rec_particles we assume this was an evernt discarded during reconstruction and skip it if len(rec_particles) == 0: self.mainLogger.error( 'no reconsrtucted particles found -> Event discarded') return False rec_particles_collection = {} for r in rec_particles: #set the papas identifiers for use in DAG r.set_dagid( IdCoder.make_id(IdCoder.PFOBJECTTYPE.PARTICLE, r.objid()[0], 'r', r.p4().E())) rec_particles_collection[r.dagid()] = r #create the history links for relationship between gen and rec particles particle_links = getattr(event, self.cfg_ana.gen_rec_links) for plink in particle_links: genid = None recid = None for g in gen_particles: if g.objid() == plink.id1(): genid = g.dagid() break for g in rec_particles: if g.objid() == plink.id2(): recid = g.dagid() break if recid == None or genid == None: self.mainLogger.error( 'Error: One of the particles in the Particle Link was not found-> discarding event' ) return False child = papasevent.history.setdefault( recid, Node(recid)) #creates a new node if it is not there already parent = papasevent.history.setdefault(genid, Node(genid)) parent.add_child(child) papasevent.add_collection(gen_particles_collection) papasevent.add_collection(rec_particles_collection)
def build_collections_and_history(self, papasevent, sim_particles): #todo this should be integrated into the simulator in the future simulated_particles = dict() tracks = dict() smeared_tracks=dict() smeared_hcals = dict() true_hcals = dict() smeared_ecals = dict() true_ecals = dict() smeared_tracks = dict() true_tracks = dict() history = papasevent.history for ptc in sim_particles: uid = ptc.uniqueid simulated_particles[uid] = ptc history[uid] = Node(uid) if ptc.track: track_id = ptc.track.uniqueid true_tracks[track_id] = ptc.track history[track_id] = Node(track_id) history[uid].add_child(history[track_id]) if ptc.track_smeared: smtrack_id = ptc.track_smeared.uniqueid smeared_tracks[smtrack_id] = ptc.track_smeared history[smtrack_id] = Node(smtrack_id) history[track_id].add_child(history[smtrack_id]) if len(ptc.clusters) > 0 : for key, clust in ptc.clusters.iteritems(): if Identifier.get_type(clust.uniqueid) == Identifier.PFOBJECTTYPE.ECALCLUSTER: true_ecals[clust.uniqueid] = clust elif Identifier.get_type(clust.uniqueid) == Identifier.PFOBJECTTYPE.HCALCLUSTER: true_hcals[clust.uniqueid] = clust else: assert(False) history[clust.uniqueid] = Node(clust.uniqueid) history[uid].add_child(history[clust.uniqueid]) if len(ptc.clusters_smeared) > 0 : #need to put in link between true and smeared cluster for key1, smclust in ptc.clusters_smeared.iteritems(): if (key == key1): if Identifier.get_type(smclust.uniqueid) == Identifier.PFOBJECTTYPE.ECALCLUSTER: smeared_ecals[smclust.uniqueid]=smclust elif Identifier.get_type(smclust.uniqueid) == Identifier.PFOBJECTTYPE.HCALCLUSTER: smeared_hcals[smclust.uniqueid]=smclust history[smclust.uniqueid] = Node(smclust.uniqueid) history[clust.uniqueid].add_child(history[smclust.uniqueid]) papasevent.add_collection(simulated_particles) papasevent.add_collection(true_tracks) papasevent.add_collection(smeared_tracks) papasevent.add_collection(smeared_hcals) papasevent.add_collection(true_hcals) papasevent.add_collection(smeared_ecals) papasevent.add_collection(true_ecals)
def insert_particle(self, block, newparticle): ''' The new particle will be inserted into the history_nodes (if present). A new node for the particle will be created if needed. It will have as its parents the block and all the elements of the block. ''' #Note that although it may be possible to specify more closely that the particle comes from #some parts of the block, there are frequently ambiguities and so for now the particle is #linked to everything in the block if (newparticle) : newid = newparticle.uniqueid self.particles[newid] = newparticle #check if history nodes exists if (self.history_nodes == None): return #find the node for the block blocknode = self.history_nodes[block.uniqueid] #find or make a node for the particle if newid in self.history_nodes : pnode = self.history_nodes[newid] else : pnode = Node(newid) self.history_nodes[newid] = pnode #link particle to the block blocknode.add_child(pnode) #link particle to block elements for element_id in block.element_uniqueids: self.history_nodes[element_id].add_child(pnode)
def simulate(self, ptcs, history): self.reset() self.history = history # import pdb; pdb.set_trace() for gen_ptc in ptcs: if gen_ptc.q() and gen_ptc.pt() < 0.2 and abs( gen_ptc.pdgid()) >= 100: # to avoid numerical problems in propagation (and avoid making a particle that is not used) continue ptc = pfsimparticle(gen_ptc, len(self.simulated_particles)) self.history[ptc.uniqueid] = Node(ptc.uniqueid) if ptc.pdgid() == 22: self.simulate_photon(ptc) elif abs(ptc.pdgid()) == 11: #check with colin # self.propagate_electron(ptc) self.simulate_electron(ptc) elif abs(ptc.pdgid()) == 13: #check with colin # self.propagate_muon(ptc) self.simulate_muon(ptc) elif abs(ptc.pdgid()) in [12, 14, 16]: self.simulate_neutrino(ptc) elif abs(ptc.pdgid()) > 100: #TODO make sure this is ok self.simulate_hadron(ptc) self.ptcs.append(ptc) self.simulated_particles[ptc.uniqueid] = ptc
def __init__(self, papasevent, uniqueids, ruler, subtype='r'): ''' papasevent a PapasEvent (see above) uniqueids list of which ids from papasevent to build blocks out of 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 subtype says which identifier subtype to use when creating new blocks eg 'r' reconstructed, 's' split ''' uniqueids = sorted(uniqueids) self.papasevent = papasevent if self.papasevent.history is None: self.papasevent.history = dict( (idt, Node(idt)) for idt in uniqueids) # compute edges between each pair of nodes edges = dict() for id1 in uniqueids: for id2 in uniqueids: if id1 < id2: edge = self._make_edge(id1, id2, ruler) #the edge object is added into the edges dictionary edges[edge.key] = edge #use the underlying BlockBuilder to construct the blocks super(PFBlockBuilder, self).__init__(uniqueids, edges, subtype, self.papasevent.history)
def add_ecal_cluster(self, uid): clust = Cluster(uid, 'ecal_in') # make a cluster uniqueid = clust.uniqueid self.event.ecal_clusters[ uniqueid] = clust # add into the collection of clusters self.event.history[uniqueid] = Node( uniqueid) #add into the collection of History Nodes
def process(self, event): event.simulator = self if self.is_display: self.display.clear() pfsim_particles = [] gen_particles = getattr(event, self.cfg_ana.gen_particles) try: self.simulator.simulate(gen_particles) except (PropagationError, SimulationError) as err: self.mainLogger.error(str(err) + ' -> Event discarded') return False pfsim_particles = self.simulator.ptcs if self.is_display: self.display.register(GTrajectories(pfsim_particles), layer=1) #these are the particles before simulation simparticles = sorted(pfsim_particles, key=lambda ptc: ptc.e(), reverse=True) setattr(event, self.simname, simparticles) #extract the tracks and clusters (extraction is prior to Colins merging step) event.tracks = dict() event.ecal_clusters = dict() event.hcal_clusters = dict() if "tracker" in self.simulator.pfinput.elements: for element in self.simulator.pfinput.elements["tracker"]: event.tracks[element.uniqueid] = element if "ecal_in" in self.simulator.pfinput.elements: for element in self.simulator.pfinput.elements["ecal_in"]: event.ecal_clusters[element.uniqueid] = element if "hcal_in" in self.simulator.pfinput.elements: for element in self.simulator.pfinput.elements["hcal_in"]: event.hcal_clusters[element.uniqueid] = element ruler = Distance() #create history node #note eventually history will be created by the simulator and passed in # as an argument and this will no longer be needed uniqueids = list(event.tracks.keys()) + list( event.ecal_clusters.keys()) + list(event.hcal_clusters.keys()) history = dict((idt, Node(idt)) for idt in uniqueids) #Now merge the simulated clusters and tracks as a separate pre-stage (prior to new reconstruction) # and set the event to point to the merged cluster pfevent = PFEvent(event, 'tracks', 'ecal_clusters', 'hcal_clusters') merged_ecals = MergedClusterBuilder(pfevent.ecal_clusters, ruler, history) setattr(event, self.mergedecalsname, merged_ecals.merged) merged_hcals = MergedClusterBuilder(pfevent.hcal_clusters, ruler, merged_ecals.history_nodes) setattr(event, self.mergedhcalsname, merged_hcals.merged) setattr(event, self.historyname, merged_hcals.history_nodes)
def simparticle(ptc, index): '''Create a sim particle to be used in papas from an input particle. ''' tp4 = ptc.p4() vertex = ptc.start_vertex().position() charge = ptc.q() pid = ptc.pdgid() simptc = Particle(tp4, vertex, charge, pid) simptc.set_dagid( IdCoder.make_id(IdCoder.PFOBJECTTYPE.PARTICLE, index, 's', simptc.idvalue)) pdebugger.info(" ".join(("Made", simptc.__str__()))) #simptc.gen_ptc = ptc #record that sim particle derives from gen particle child = papasevent.history.setdefault( simptc.dagid(), Node(simptc.dagid( ))) #creates a new node if it is not there already parent = papasevent.history.setdefault(ptc.dagid(), Node(ptc.dagid())) parent.add_child(child) return simptc
def __init__(self, pfevent, ruler, history_nodes=None): ''' pfevent is event structure inside which we find tracks is a dictionary : {id1:track1, id2:track2, ...} ecal is a dictionary : {id1:ecal1, id2:ecal2, ...} hcal is a dictionary : {id1:hcal1, id2:hcal2, ...} get_object() which allows a cluster or track to be found from its id 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 history_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. ''' #given a unique id this can return the underying object self.pfevent = pfevent # collate all the ids of tracks and clusters and, if needed, make history nodes uniqueids = [] uniqueids = list(pfevent.tracks.keys()) + list( pfevent.ecal_clusters.keys()) + list(pfevent.hcal_clusters.keys()) uniqueids = sorted(uniqueids) self.history_nodes = history_nodes if history_nodes is None: self.history_nodes = dict((idt, Node(idt)) for idt in uniqueids) # compute edges between each pair of nodes edges = dict() for id1 in uniqueids: for id2 in uniqueids: if id1 < id2: edge = self._make_edge(id1, id2, ruler) #the edge object is added into the edges dictionary edges[edge.key] = edge #use the underlying BlockBuilder to construct the blocks super(PFBlockBuilder, self).__init__(uniqueids, edges, self.history_nodes, pfevent)
def add_particle(self, uid, pdgid, parents): ''' creates a new particle and then updates the event to include the new node and its parental links pdgid = is the particle type id eg 22 for photon parents = list of the unique ids (from Identifier class) for the elements from which the particle has been reconstructed ''' particle = ReconstructedParticle(uid, pdgid) self.event.reconstructed_particles[particle.uniqueid] = particle #Now create the history node and links particle_node = Node(particle.uniqueid) self.event.history[particle.uniqueid] = particle_node for parent in parents: self.event.history[parent].add_child(particle_node)
def _make_blocks (self) : ''' uses the DAGfloodfill algorithm in connection with the BlockBuilder nodes to work out which elements are connected Each set of connected elements will be used to make a new PFBlock ''' for subgraph in self.subgraphs: #make the block block = PFBlock(subgraph, self.edges, self.startindex + len(self.blocks), subtype=self.subtype) pdebugger.info("Made {}".format(block)) #put the block in the dict of blocks self.blocks[block.uniqueid] = block #make a node for the block and add into the history Nodes if (self.history != None): blocknode = Node(block.uniqueid) self.history[block.uniqueid] = blocknode #now add in the links between the block elements and the block into the history for elemid in block.element_uniqueids: self.history[elemid].add_child(blocknode)
def insert_particle(self, parent_ids, newparticle): ''' The new particle will be inserted into the history_nodes (if present). A new node for the particle will be created if needed. It will have as its parents the block and all the elements of the block. ''' #Note that although it may be possible to specify more closely that the particle comes from #some parts of the block, there are frequently ambiguities and so for now the particle is #linked to everything in the block if newparticle: newid = newparticle.uniqueid self.particles[newid] = newparticle #check if history nodes exists if self.papasevent.history is None: return assert (newid not in self.papasevent.history) particlenode = Node(newid) self.papasevent.history[newid] = particlenode #add in parental history for pid in parent_ids: self.papasevent.history[pid].add_child(particlenode)
def _make_and_store_merged_clusters(self): ''' This takes the subgraphs of connected clusters that are to be merged, and makes a new MergedCluster. It stores the new MergedCluser into the self.merged_clusters collection. It then updates the history to record the links between the clusters and the merged cluster. ''' for subgraph in self.subgraphs: # TODO may want to order subgraphs from largest to smallest at some point subgraph.sort(reverse=True) #start with highest E or pT clusters overlapping_clusters = [ self.clusters[node_id] for node_id in subgraph ] supercluster = MergedCluster(overlapping_clusters, len(self.merged_clusters)) self.merged_clusters[supercluster.uniqueid] = supercluster if self.history_nodes: snode = Node(supercluster.uniqueid) self.history_nodes[supercluster.uniqueid] = snode for node_id in subgraph: self.history_nodes[node_id].add_child(snode) pdebugger.info(str('Made {}'.format(supercluster)))
def _make_merged_clusters(self): #carry out the merging of linked clusters for subgraphids in self.subgraphs: subgraphids.sort() first = None supercluster =None snode = None for elemid in subgraphids : if not first: first = elemid supercluster = MergedCluster(self.clusters[elemid]) self.merged[supercluster.uniqueid] = supercluster; if (self.history_nodes) : snode = Node(supercluster.uniqueid) self.history_nodes[supercluster.uniqueid] = snode else: thing = self.clusters[elemid] supercluster += thing if (self.history_nodes) : self.history_nodes[elemid].add_child(snode) pdebugger.info('Merged Cluster from {}\n'.format(self.clusters[elemid])) pdebugger.info(str('Made {}\n'.format(supercluster)))
def simulate(self, ptcs, history): self.reset() self.history = history # import pdb; pdb.set_trace() for ptc in ptcs: if ptc.q() and ptc.pt() < 0.2 and abs(ptc.pdgid()) >= 100: # to avoid numerical problems in propagation (and avoid making a particle that is not used) continue pdebugger.info(str('Simulating {}'.format(ptc))) parent = self.history.setdefault(ptc.dagid(), Node(ptc.dagid())) if ptc.pdgid() == 22: self.simulate_photon(ptc) elif abs(ptc.pdgid()) == 11: #check with colin # self.propagate_electron(ptc) self.simulate_electron(ptc) elif abs(ptc.pdgid()) == 13: #check with colin # self.propagate_muon(ptc) self.simulate_muon(ptc) elif abs(ptc.pdgid()) in [12, 14, 16]: self.simulate_neutrino(ptc) elif abs(ptc.pdgid()) > 100: #TODO make sure this is ok self.simulate_hadron(ptc) self.ptcs.append(ptc) self.simulated_particles[ptc.dagid()] = ptc
def add_particle(self, uid, pdgid): particle = Particle(uid, pdgid) uniqueid = particle.uniqueid self.event.sim_particles[uniqueid] = particle self.event.history[uniqueid] = Node(uniqueid)
def test_papasevent(self): #create a dummy papasevent papasevent = PapasEvent(0) ecals = dict() tracks = dict() mixed = dict() for i in range(0, 2): uid = Identifier.make_id(Identifier.PFOBJECTTYPE.ECALCLUSTER, 't', 4.5) ecals[uid] = uid papasevent.history[uid] = Node(uid) uidt = Identifier.make_id(Identifier.PFOBJECTTYPE.TRACK, 's', 4.5) tracks[uidt] = uidt papasevent.history[uidt] = Node(uidt) papasevent.history[uidt].add_child(papasevent.history[uid]) lastid = Identifier.make_id(Identifier.PFOBJECTTYPE.ECALCLUSTER, 't', 3) ecals[lastid] = lastid papasevent.history[lastid] = Node(lastid) papasevent.add_collection(ecals) papasevent.add_collection(tracks) #create HistoryHelper hhelper = HistoryHelper(papasevent) #get all ids in event ids = hhelper.event_ids() self.assertTrue(len(ids) == 5) #check id_from_pretty self.assertTrue(hhelper.id_from_pretty('et5') == lastid) #check get_linked_ids linked = hhelper.get_linked_ids( lastid) #everything linked to lastid (which is just lastid) self.assertTrue(linked[0] == lastid and len(linked) == 1) self.assertTrue( hhelper.get_linked_ids(ids[0], direction="undirected")[1] == hhelper.id_from_pretty('ts2')) self.assertTrue( hhelper.get_linked_ids(ids[0], direction="parents") == hhelper.get_linked_ids(ids[0], direction="undirected")) self.assertTrue( hhelper.get_linked_ids(ids[0], direction="children") == [hhelper.id_from_pretty('et1')]) #filter_ids self.assertTrue(len(hhelper.filter_ids(ids, 'ts')) == 2) self.assertTrue(hhelper.filter_ids(ids, 'no') == []) #get_collection self.assertTrue(len(hhelper.get_collection(ids[1:2], 'no')) == 0) self.assertTrue(len(hhelper.get_collection([99], 'no')) == 0) self.assertTrue(len(hhelper.get_collection(ids[0:2], 'ts')) == 1) pass #get_history_subgroups subgroups = hhelper.get_history_subgroups() self.assertTrue(len(subgroups) == 3) #get_linked_collection self.assertTrue( hhelper.get_linked_collection(hhelper.id_from_pretty( 'et1'), 'ts').keys() == [hhelper.id_from_pretty('ts2')]) self.assertRaises(KeyError, hhelper.get_linked_collection, 0, 'ts') self.assertTrue( len( hhelper.get_linked_collection(hhelper.id_from_pretty('et1'), 'no')) == 0)
def add_nodes(self, nodedict, values): for e1 in values: nodedict[e1.uniqueid] = Node(e1.uniqueid)
def add_track(self, uid): track = Track(uid) uniqueid = track.uniqueid self.event.tracks[uniqueid] = track self.event.history[uniqueid] = Node(uniqueid)
def add_hcal_cluster(self, uid): clust = Cluster(uid, 'hcal_in') uniqueid = clust.uniqueid self.event.hcal_clusters[uniqueid] = clust self.event.history[uniqueid] = Node(uniqueid)