def make_and_store_cluster(self, ptc, detname, fraction=1., size=None): '''adds a cluster in a given detector, with a given fraction of the particle energy. Stores the cluster in the appropriate collection and records cluster in the history''' detector = self.detector.elements[detname] propagator(ptc.q()).propagate_one(ptc, detector.volume.inner, self.detector.elements['field'].magnitude) if size is None: size = detector.cluster_size(ptc) cylname = detector.volume.inner.name if not cylname in ptc.points: # TODO Colin particle was not extrapolated here... # issue must be solved! errormsg = ''' SimulationError : cannot make cluster for particle: particle: {ptc} with vertex rho={rho:5.2f}, z={zed:5.2f} cannot be extrapolated to : {det}\n'''.format(ptc=ptc, rho=ptc.vertex.Perp(), zed=ptc.vertex.Z(), det=detector.volume.inner) self.logger.warning(errormsg) raise SimulationError('Particle not extrapolated to the detector, so cannot make a cluster there. No worries for now, problem will be solved :-)') clusters = self.cluster_collection(cylname) cluster = Cluster(ptc.p4().E()*fraction, ptc.points[cylname], size, cylname, len(clusters), ptc) #update collections and history ptc.clusters[cylname] = cluster clusters[cluster.uniqueid] = cluster self.update_history(ptc.uniqueid, cluster.uniqueid,) pdebugger.info(" ".join(("Made", cluster.__str__()))) return cluster
def make_cluster(self, ptc, detname, fraction=1.0, size=None): """adds a cluster in a given detector, with a given fraction of the particle energy.""" detector = self.detector.elements[detname] propagator(ptc.q()).propagate_one(ptc, detector.volume.inner, self.detector.elements["field"].magnitude) if size is None: size = detector.cluster_size(ptc) cylname = detector.volume.inner.name if not cylname in ptc.points: # TODO Colin particle was not extrapolated here... # issue must be solved! errormsg = """ SimulationError : cannot make cluster for particle: particle: {ptc} with vertex rho={rho:5.2f}, z={zed:5.2f} cannot be extrapolated to : {det}\n""".format( ptc=ptc, rho=ptc.vertex.Perp(), zed=ptc.vertex.Z(), det=detector.volume.inner ) self.logger.warning(errormsg) raise SimulationError( "Particle not extrapolated to the detector, so cannot make a cluster there. No worries for now, problem will be solved :-)" ) cluster = Cluster(ptc.p4().E() * fraction, ptc.points[cylname], size, cylname, ptc) ptc.clusters[cylname] = cluster pdebugger.info(" ".join(("Made", cluster.__str__()))) return cluster
def simulate_electron(self, ptc): '''Simulate an electron corresponding to gen particle ptc. Uses the methods detector.electron_energy_resolution and detector.electron_acceptance to smear the electron track. Later on, the particle flow algorithm will use the tracks coming from an electron to reconstruct electrons. This method does not simulate an electron energy deposit in the ECAL. ''' pdebugger.info("Simulating Electron") ecal = self.detector.elements['ecal'] track = self.make_and_store_track(ptc) propagator(ptc.q()).propagate_one( ptc, ecal.volume.inner, self.detector.elements['field'].magnitude ) eres = self.detector.electron_energy_resolution(ptc) smeared_track = self.make_smeared_track(track, eres) if self.detector.electron_acceptance(smeared_track): self.smeared_tracks[smeared_track.uniqueid] = smeared_track self.update_history(track.uniqueid, smeared_track.uniqueid) ptc.track_smeared = smeared_track else: pdebugger.info(str('Rejected {}'.format(smeared_track)))
def propagate_electron(self, ptc): pdebugger.info("Propogate Electron") ecal = self.detector.elements['ecal'] propagator(ptc.q()).propagate_one(ptc, ecal.volume.inner, self.detector.elements['field'].magnitude) return
def make_cluster(self, ptc, detname, fraction=1., size=None): '''adds a cluster in a given detector, with a given fraction of the particle energy.''' detector = self.detector.elements[detname] propagator(ptc.q()).propagate_one( ptc, detector.volume.inner, self.detector.elements['field'].magnitude) if size is None: size = detector.cluster_size(ptc) cylname = detector.volume.inner.name if not cylname in ptc.points: # TODO Colin particle was not extrapolated here... # issue must be solved! errormsg = ''' SimulationError : cannot make cluster for particle: particle: {ptc} with vertex rho={rho:5.2f}, z={zed:5.2f} cannot be extrapolated to : {det}\n'''.format(ptc=ptc, rho=ptc.vertex.Perp(), zed=ptc.vertex.Z(), det=detector.volume.inner) self.logger.warning(errormsg) raise SimulationError( 'Particle not extrapolated to the detector, so cannot make a cluster there. No worries for now, problem will be solved :-)' ) cluster = Cluster(ptc.p4().E() * fraction, ptc.points[cylname], size, cylname, ptc) ptc.clusters[cylname] = cluster pdebugger.info(" ".join(("Made", cluster.__str__()))) return cluster
def smear_electron(self, ptc): pdebugger.info("Smearing Electron") ecal = self.detector.elements["ecal"] propagator(ptc.q()).propagate_one(ptc, ecal.volume.inner, self.detector.elements["field"].magnitude) if ptc.q() != 0: pdebugger.info(" ".join(("Made", ptc.track.__str__()))) smeared = copy.deepcopy(ptc) return smeared
def reconstruct_cluster(self, cluster, layer, parent_ids, energy=None, vertex=None): '''construct a photon if it is an ecal construct a neutral hadron if it is an hcal ''' if self.locked[cluster.uniqueid]: return if vertex is None: vertex = TVector3() pdg_id = None propagate_to = None if layer == 'ecal_in': pdg_id = 22 #photon propagate_to = [self.detector.elements['ecal'].volume.inner] elif layer == 'hcal_in': pdg_id = 130 #K0 propagate_to = [ self.detector.elements['ecal'].volume.inner, self.detector.elements['hcal'].volume.inner ] else: raise ValueError('layer must be equal to ecal_in or hcal_in') assert (pdg_id) mass, charge = particle_data[pdg_id] if energy is None: energy = cluster.energy if energy < mass: return None if mass == 0: momentum = energy #avoid sqrt for zero mass else: momentum = math.sqrt(energy**2 - mass**2) p3 = cluster.position.Unit() * momentum p4 = TLorentzVector(p3.Px(), p3.Py(), p3.Pz(), energy) #mass is not accurate here particle = Particle(p4, vertex, charge, pdg_id, len(self.particles), subtype='r') # alice: this may be a bit strange because we can make a photon # with a path where the point is actually that of the hcal? # nb this only is problem if the cluster and the assigned layer # are different propagator(charge).propagate([particle], propagate_to) #merge Nov 10th 2016 not sure about following line (was commented out in papasevent branch) particle.clusters[ layer] = cluster # not sure about this either when hcal is used to make an ecal cluster? self.locked[ cluster. uniqueid] = True #just OK but not nice if hcal used to make ecal. pdebugger.info(str('Made {} from {}'.format(particle, cluster))) self.insert_particle(parent_ids, particle)
def simulate_hadron(self, ptc): """Simulate a hadron, neutral or charged. ptc should behave as pfobjects.Particle. """ pdebugger.info("Simulating Hadron") # implement beam pipe scattering ecal = self.detector.elements["ecal"] hcal = self.detector.elements["hcal"] beampipe = self.detector.elements["beampipe"] frac_ecal = 0.0 propagator(ptc.q()).propagate_one(ptc, beampipe.volume.inner, self.detector.elements["field"].magnitude) propagator(ptc.q()).propagate_one(ptc, beampipe.volume.outer, self.detector.elements["field"].magnitude) mscat.multiple_scattering(ptc, beampipe, self.detector.elements["field"].magnitude) # re-propagate after multiple scattering in the beam pipe # indeed, multiple scattering is applied within the beam pipe, # so the extrapolation points to the beam pipe entrance and exit # change after multiple scattering. propagator(ptc.q()).propagate_one(ptc, beampipe.volume.inner, self.detector.elements["field"].magnitude) propagator(ptc.q()).propagate_one(ptc, beampipe.volume.outer, self.detector.elements["field"].magnitude) propagator(ptc.q()).propagate_one(ptc, ecal.volume.inner, self.detector.elements["field"].magnitude) # these lines moved earlier in order to match cpp logic if ptc.q() != 0: pdebugger.info(" ".join(("Made", ptc.track.__str__()))) smeared_track = self.smear_track(ptc.track, self.detector.elements["tracker"]) if smeared_track: ptc.track_smeared = smeared_track if "ecal_in" in ptc.path.points: # doesn't have to be the case (long-lived particles) path_length = ecal.material.path_length(ptc) if path_length < sys.float_info.max: # ecal path length can be infinite in case the ecal # has lambda_I = 0 (fully transparent to hadrons) time_ecal_inner = ptc.path.time_at_z(ptc.points["ecal_in"].Z()) deltat = ptc.path.deltat(path_length) time_decay = time_ecal_inner + deltat point_decay = ptc.path.point_at_time(time_decay) ptc.points["ecal_decay"] = point_decay if ecal.volume.contains(point_decay): frac_ecal = random.uniform(0.0, 0.7) cluster = self.make_cluster(ptc, "ecal", frac_ecal) # For now, using the hcal resolution and acceptance # for hadronic cluster # in the ECAL. That's not a bug! smeared = self.smear_cluster(cluster, hcal, acceptance=ecal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared cluster = self.make_cluster(ptc, "hcal", 1 - frac_ecal) smeared = self.smear_cluster(cluster, hcal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared
def smear_electron(self, ptc): pdebugger.info("Smearing Electron") ecal = self.detector.elements['ecal'] propagator(ptc.q()).propagate_one( ptc, ecal.volume.inner, self.detector.elements['field'].magnitude) if ptc.q() != 0: pdebugger.info(" ".join(("Made", ptc.track.__str__()))) smeared = copy.deepcopy(ptc) return smeared
def simulate_photon(self, ptc): pdebugger.info("Simulating Photon") detname = 'ecal' ecal = self.detector.elements[detname] propagator(ptc.q()).propagate_one(ptc, ecal.volume.inner) cluster = self.make_and_store_cluster(ptc, detname) smeared = self.make_and_store_smeared_cluster(cluster, ecal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared
def simulate_photon(self, ptc): pdebugger.info("Simulating Photon") detname = "ecal" ecal = self.detector.elements[detname] propagator(ptc.q()).propagate_one(ptc, ecal.volume.inner) cluster = self.make_cluster(ptc, detname) smeared = self.smear_cluster(cluster, ecal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared
def simulate_electron(self, ptc): pdebugger.info("Simulating Electron") ecal = self.detector.elements["ecal"] propagator(ptc.q()).propagate_one(ptc, ecal.volume.inner, self.detector.elements["field"].magnitude) cluster = self.make_cluster(ptc, "ecal") smeared_cluster = self.smear_cluster(cluster, ecal) if smeared_cluster: ptc.clusters_smeared[smeared_cluster.layer] = smeared_cluster smeared_track = self.smear_track(ptc.track, self.detector.elements["tracker"]) if smeared_track: ptc.track_smeared = smeared_track
def simulate_electron(self, ptc): pdebugger.info("Simulating Electron") ecal = self.detector.elements['ecal'] propagator(ptc.q()).propagate_one( ptc, ecal.volume.inner, self.detector.elements['field'].magnitude) cluster = self.make_cluster(ptc, 'ecal') smeared_cluster = self.smear_cluster(cluster, ecal) if smeared_cluster: ptc.clusters_smeared[smeared_cluster.layer] = smeared_cluster smeared_track = self.smear_track(ptc.track, self.detector.elements['tracker']) if smeared_track: ptc.track_smeared = smeared_track
def simulate_hadron(self, ptc): '''Simulate a hadron, neutral or charged. ptc should behave as pfobjects.Particle. ''' pdebugger.info("Simulating Hadron") #implement beam pipe scattering ecal = self.detector.elements['ecal'] hcal = self.detector.elements['hcal'] frac_ecal = 0. if ptc.q() != 0 : #track is now made outside of the particle and then the particle is told where the track is track = self.make_and_store_track(ptc) tracker = self.detector.elements['tracker'] smeared_track = self.make_and_store_smeared_track( ptc, track, tracker.resolution, tracker.acceptance ) propagator(ptc.q()).propagate_one(ptc, ecal.volume.inner, self.detector.elements['field'].magnitude) if 'ecal_in' in ptc.path.points: # doesn't have to be the case (long-lived particles) path_length = ecal.material.path_length(ptc) if path_length < sys.float_info.max: # ecal path length can be infinite in case the ecal # has lambda_I = 0 (fully transparent to hadrons) time_ecal_inner = ptc.path.time_at_z(ptc.points['ecal_in'].Z()) deltat = ptc.path.deltat(path_length) time_decay = time_ecal_inner + deltat point_decay = ptc.path.point_at_time(time_decay) ptc.points['ecal_decay'] = point_decay if ecal.volume.contains(point_decay): frac_ecal = random.uniform(0., 0.7) cluster = self.make_and_store_cluster(ptc, 'ecal', frac_ecal) # For now, using the hcal resolution and acceptance # for hadronic cluster # in the ECAL. That's not a bug! smeared = self.make_and_store_smeared_cluster(cluster, hcal, acceptance=ecal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared cluster = self.make_and_store_cluster(ptc, 'hcal', 1-frac_ecal) smeared = self.make_and_store_smeared_cluster(cluster, hcal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared
def reconstruct_cluster(self, cluster, layer, parent_ids, energy=None, vertex=None): '''construct a photon if it is an ecal construct a neutral hadron if it is an hcal ''' if self.locked[cluster.uniqueid]: return if vertex is None: vertex = TVector3() pdg_id = None propagate_to = None if layer=='ecal_in': pdg_id = 22 #photon propagate_to = [ self.detector.elements['ecal'].volume.inner ] elif layer=='hcal_in': pdg_id = 130 #K0 propagate_to = [ self.detector.elements['ecal'].volume.inner, self.detector.elements['hcal'].volume.inner ] else: raise ValueError('layer must be equal to ecal_in or hcal_in') assert(pdg_id) mass, charge = particle_data[pdg_id] if energy is None: energy = cluster.energy if energy < mass: return None if mass == 0: momentum = energy #avoid sqrt for zero mass else: momentum = math.sqrt(energy**2 - mass**2) p3 = cluster.position.Unit() * momentum p4 = TLorentzVector(p3.Px(), p3.Py(), p3.Pz(), energy) #mass is not accurate here particle = Particle(p4, vertex, charge, pdg_id) particle.set_dagid(IdCoder.make_id(IdCoder.PFOBJECTTYPE.PARTICLE, len(self.particles), 'r', particle.idvalue)) # alice: this may be a bit strange because we can make a photon # with a path where the point is actually that of the hcal? # nb this only is problem if the cluster and the assigned layer # are different propagator(charge).propagate([particle], propagate_to) #merge Nov 10th 2016 not sure about following line (was commented out in papasevent branch) particle.clusters[layer] = cluster # not sure about this either when hcal is used to make an ecal cluster? self.locked[cluster.uniqueid] = True #just OK but not nice if hcal used to make ecal. pdebugger.info(str('Made {} from {}'.format(particle, cluster))) self.insert_particle(parent_ids, particle)
def simulate_electron(self, ptc): '''Simulate an electron corresponding to gen particle ptc. Uses the methods detector.electron_energy_resolution and detector.electron_acceptance to smear the electron track. Later on, the particle flow algorithm will use the tracks coming from an electron to reconstruct electrons. This method does not simulate an electron energy deposit in the ECAL. ''' pdebugger.info("Simulating Electron") ecal = self.detector.elements['ecal'] track = self.make_and_store_track(ptc) propagator(ptc.q()).propagate_one( ptc, ecal.volume.inner, self.detector.elements['field'].magnitude) smeared_track = self.make_and_store_smeared_track( ptc, track, self.detector.electron_resolution, self.detector.electron_acceptance)
def reconstruct_cluster(self, cluster, layer, energy=None, vertex=None): """construct a photon if it is an ecal construct a neutral hadron if it is an hcal """ if vertex is None: vertex = TVector3() pdg_id = None propagate_to = None if layer == "ecal_in": pdg_id = 22 # photon propagate_to = [self.detector.elements["ecal"].volume.inner] elif layer == "hcal_in": pdg_id = 130 # K0 propagate_to = [self.detector.elements["ecal"].volume.inner, self.detector.elements["hcal"].volume.inner] else: raise ValueError("layer must be equal to ecal_in or hcal_in") assert pdg_id mass, charge = particle_data[pdg_id] if energy is None: energy = cluster.energy if energy < mass: return None if mass == 0: momentum = energy # avoid sqrt for zero mass else: momentum = math.sqrt(energy ** 2 - mass ** 2) p3 = cluster.position.Unit() * momentum p4 = TLorentzVector(p3.Px(), p3.Py(), p3.Pz(), energy) # mass is not accurate here particle = Particle(p4, vertex, charge, pdg_id, Identifier.PFOBJECTTYPE.RECPARTICLE) # path = StraightLine(p4, vertex) # path.points[layer] = cluster.position # alice: this may be a bit strange because we can make a photon # with a path where the point is actually that of the hcal? # nb this only is problem if the cluster and the assigned layer # are different # particle.set_path(path) propagator(charge).propagate([particle], propagate_to) particle.clusters[layer] = cluster # not sure about this either when hcal is used to make an ecal cluster? self.locked[cluster.uniqueid] = True # just OK but not nice if hcal used to make ecal. pdebugger.info(str("Made {} from {}".format(particle, cluster))) return particle
def simulate_electron(self, ptc): '''Simulate an electron corresponding to gen particle ptc. Uses the methods detector.electron_energy_resolution and detector.electron_acceptance to smear the electron track. Later on, the particle flow algorithm will use the tracks coming from an electron to reconstruct electrons. This method does not simulate an electron energy deposit in the ECAL. ''' pdebugger.info("Simulating Electron") ecal = self.detector.elements['ecal'] track = self.make_and_store_track(ptc) propagator(ptc.q()).propagate_one( ptc, ecal.volume.inner, self.detector.elements['field'].magnitude ) smeared_track = self.make_and_store_smeared_track( ptc, track, self.detector.electron_resolution, self.detector.electron_acceptance )
def simulate_electron(self, ptc): '''Simulate an electron corresponding to gen particle ptc. Uses the methods detector.electron_energy_resolution and detector.electron_acceptance to smear the electron track. Later on, the particle flow algorithm will use the tracks coming from an electron to reconstruct electrons. This method does not simulate an electron energy deposit in the ECAL. ''' pdebugger.info("Simulating Electron") ecal = self.detector.elements['ecal'] track = self.make_and_store_track(ptc) propagator(ptc.q()).propagate_one( ptc, ecal.volume.inner, self.detector.elements['field'].magnitude) eres = self.detector.electron_energy_resolution(ptc) smeared_track = self.make_smeared_track(track, eres) if self.detector.electron_acceptance(smeared_track): self.smeared_tracks[smeared_track.uniqueid] = smeared_track self.update_history(track.uniqueid, smeared_track.uniqueid) ptc.track_smeared = smeared_track else: pdebugger.info(str('Rejected {}'.format(smeared_track)))
def simulate_electron(self, ptc): '''Simulate an electron corresponding to gen particle ptc. Uses the methods detector.electron_energy_resolution and detector.electron_acceptance to smear the electron track. Later on, the particle flow algorithm will use the tracks coming from an electron to reconstruct electrons. This method does not simulate an electron energy deposit in the ECAL. ''' pdebugger.info("Simulating Electron") ecal = self.detector.elements['ecal'] propagator(ptc.q()).propagate_one( ptc, ecal.volume.inner, self.detector.elements['field'].magnitude) eres = self.detector.electron_energy_resolution(ptc) scale_factor = random.gauss(1, eres) track = ptc.track smeared_track = SmearedTrack(track, track.p3 * scale_factor, track.charge, track.path) pdebugger.info(" ".join(("Made", smeared_track.__str__()))) if self.detector.electron_acceptance(smeared_track): ptc.track_smeared = smeared_track else: pdebugger.info(str('Rejected {}'.format(smeared_track)))
def propagate(self, ptc): """propagate the particle to all detector cylinders""" propagator(ptc.q()).propagate([ptc], self.detector.cylinders(), self.detector.elements["field"].magnitude)
def propagate(self, ptc): '''propagate the particle to all detector cylinders''' propagator( ptc.q()).propagate([ptc], self.detector.cylinders(), self.detector.elements['field'].magnitude)
def propagate_electron(self, ptc): pdebugger.info("Propogate Electron") ecal = self.detector.elements['ecal'] propagator(ptc.q()).propagate_one( ptc, ecal.volume.inner, self.detector.elements['field'].magnitude) return
def simulate_hadron(self, ptc): '''Simulate a hadron, neutral or charged. ptc should behave as pfobjects.Particle. ''' pdebugger.info("Simulating Hadron") #implement beam pipe scattering ecal = self.detector.elements['ecal'] hcal = self.detector.elements['hcal'] beampipe = self.detector.elements['beampipe'] frac_ecal = 0. if ptc.q() != 0 : #track is now made outside of the particle and then the particle is told where the track is track = self.make_and_store_track(ptc) resolution = self.detector.elements['tracker'].pt_resolution(track) smeared_track = self.make_smeared_track(track, resolution) if self.detector.elements['tracker'].acceptance(smeared_track): self.smeared_tracks[smeared_track.uniqueid] = smeared_track self.update_history(track.uniqueid, smeared_track.uniqueid ) ptc.track_smeared = smeared_track else: pdebugger.info(str('Rejected {}'.format(smeared_track))) propagator(ptc.q()).propagate_one(ptc, beampipe.volume.inner, self.detector.elements['field'].magnitude) propagator(ptc.q()).propagate_one(ptc, beampipe.volume.outer, self.detector.elements['field'].magnitude) #pdebug next line must be editted out to match cpp #mscat.multiple_scattering(ptc, beampipe, self.detector.elements['field'].magnitude) #re-propagate after multiple scattering in the beam pipe #indeed, multiple scattering is applied within the beam pipe, #so the extrapolation points to the beam pipe entrance and exit #change after multiple scattering. propagator(ptc.q()).propagate_one(ptc, beampipe.volume.inner, self.detector.elements['field'].magnitude) propagator(ptc.q()).propagate_one(ptc, beampipe.volume.outer, self.detector.elements['field'].magnitude) propagator(ptc.q()).propagate_one(ptc, ecal.volume.inner, self.detector.elements['field'].magnitude) if 'ecal_in' in ptc.path.points: # doesn't have to be the case (long-lived particles) path_length = ecal.material.path_length(ptc) if path_length < sys.float_info.max: # ecal path length can be infinite in case the ecal # has lambda_I = 0 (fully transparent to hadrons) time_ecal_inner = ptc.path.time_at_z(ptc.points['ecal_in'].Z()) deltat = ptc.path.deltat(path_length) time_decay = time_ecal_inner + deltat point_decay = ptc.path.point_at_time(time_decay) ptc.points['ecal_decay'] = point_decay if ecal.volume.contains(point_decay): frac_ecal = random.uniform(0., 0.7) cluster = self.make_and_store_cluster(ptc, 'ecal', frac_ecal) # For now, using the hcal resolution and acceptance # for hadronic cluster # in the ECAL. That's not a bug! smeared = self.make_and_store_smeared_cluster(cluster, hcal, acceptance=ecal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared cluster = self.make_and_store_cluster(ptc, 'hcal', 1-frac_ecal) smeared = self.make_and_store_smeared_cluster(cluster, hcal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared
def simulate_hadron(self, ptc): '''Simulate a hadron, neutral or charged. ptc should behave as pfobjects.Particle. ''' pdebugger.info("Simulating Hadron") #implement beam pipe scattering ecal = self.detector.elements['ecal'] hcal = self.detector.elements['hcal'] beampipe = self.detector.elements['beampipe'] frac_ecal = 0. propagator(ptc.q()).propagate_one( ptc, beampipe.volume.inner, self.detector.elements['field'].magnitude) propagator(ptc.q()).propagate_one( ptc, beampipe.volume.outer, self.detector.elements['field'].magnitude) mscat.multiple_scattering(ptc, beampipe, self.detector.elements['field'].magnitude) #re-propagate after multiple scattering in the beam pipe #indeed, multiple scattering is applied within the beam pipe, #so the extrapolation points to the beam pipe entrance and exit #change after multiple scattering. propagator(ptc.q()).propagate_one( ptc, beampipe.volume.inner, self.detector.elements['field'].magnitude) propagator(ptc.q()).propagate_one( ptc, beampipe.volume.outer, self.detector.elements['field'].magnitude) propagator(ptc.q()).propagate_one( ptc, ecal.volume.inner, self.detector.elements['field'].magnitude) # these lines moved earlier in order to match cpp logic if ptc.q() != 0: pdebugger.info(" ".join(("Made", ptc.track.__str__()))) smeared_track = self.smear_track(ptc.track, self.detector.elements['tracker']) if smeared_track: ptc.track_smeared = smeared_track if 'ecal_in' in ptc.path.points: # doesn't have to be the case (long-lived particles) path_length = ecal.material.path_length(ptc) if path_length < sys.float_info.max: # ecal path length can be infinite in case the ecal # has lambda_I = 0 (fully transparent to hadrons) time_ecal_inner = ptc.path.time_at_z(ptc.points['ecal_in'].Z()) deltat = ptc.path.deltat(path_length) time_decay = time_ecal_inner + deltat point_decay = ptc.path.point_at_time(time_decay) ptc.points['ecal_decay'] = point_decay if ecal.volume.contains(point_decay): frac_ecal = random.uniform(0., 0.7) cluster = self.make_cluster(ptc, 'ecal', frac_ecal) # For now, using the hcal resolution and acceptance # for hadronic cluster # in the ECAL. That's not a bug! smeared = self.smear_cluster(cluster, hcal, acceptance=ecal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared cluster = self.make_cluster(ptc, 'hcal', 1 - frac_ecal) smeared = self.smear_cluster(cluster, hcal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared
def simulate_hadron(self, ptc): '''Simulate a hadron, neutral or charged. ptc should behave as pfobjects.Particle. ''' pdebugger.info("Simulating Hadron") #implement beam pipe scattering ecal = self.detector.elements['ecal'] hcal = self.detector.elements['hcal'] beampipe = self.detector.elements['beampipe'] frac_ecal = 0. if ptc.q() != 0: #track is now made outside of the particle and then the particle is told where the track is track = self.make_and_store_track(ptc) resolution = self.detector.elements['tracker'].pt_resolution(track) smeared_track = self.make_smeared_track(track, resolution) if self.detector.elements['tracker'].acceptance(smeared_track): self.smeared_tracks[smeared_track.uniqueid] = smeared_track self.update_history(track.uniqueid, smeared_track.uniqueid) ptc.track_smeared = smeared_track else: pdebugger.info(str('Rejected {}'.format(smeared_track))) propagator(ptc.q()).propagate_one( ptc, beampipe.volume.inner, self.detector.elements['field'].magnitude) propagator(ptc.q()).propagate_one( ptc, beampipe.volume.outer, self.detector.elements['field'].magnitude) #pdebug next line must be editted out to match cpp #mscat.multiple_scattering(ptc, beampipe, self.detector.elements['field'].magnitude) #re-propagate after multiple scattering in the beam pipe #indeed, multiple scattering is applied within the beam pipe, #so the extrapolation points to the beam pipe entrance and exit #change after multiple scattering. propagator(ptc.q()).propagate_one( ptc, beampipe.volume.inner, self.detector.elements['field'].magnitude) propagator(ptc.q()).propagate_one( ptc, beampipe.volume.outer, self.detector.elements['field'].magnitude) propagator(ptc.q()).propagate_one( ptc, ecal.volume.inner, self.detector.elements['field'].magnitude) if 'ecal_in' in ptc.path.points: # doesn't have to be the case (long-lived particles) path_length = ecal.material.path_length(ptc) if path_length < sys.float_info.max: # ecal path length can be infinite in case the ecal # has lambda_I = 0 (fully transparent to hadrons) time_ecal_inner = ptc.path.time_at_z(ptc.points['ecal_in'].Z()) deltat = ptc.path.deltat(path_length) time_decay = time_ecal_inner + deltat point_decay = ptc.path.point_at_time(time_decay) ptc.points['ecal_decay'] = point_decay if ecal.volume.contains(point_decay): frac_ecal = random.uniform(0., 0.7) cluster = self.make_and_store_cluster( ptc, 'ecal', frac_ecal) # For now, using the hcal resolution and acceptance # for hadronic cluster # in the ECAL. That's not a bug! smeared = self.make_and_store_smeared_cluster( cluster, hcal, acceptance=ecal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared cluster = self.make_and_store_cluster(ptc, 'hcal', 1 - frac_ecal) smeared = self.make_and_store_smeared_cluster(cluster, hcal) if smeared: ptc.clusters_smeared[smeared.layer] = smeared