Example #1
0
 def acceptance(self, track):
     # return False
     pt = track.pt
     eta = abs(track.p3.Eta())
     if eta < 1.35 and pt>0.5:
         return random.uniform(0,1)<0.95
     elif eta < 2.5 and pt>0.5:
         return random.uniform(0,1)<0.9 
     else:
         return False
Example #2
0
 def process(self, event):
     '''Process the event.
     
     This method creates:
      - event.var_random: the random variable, between 0 and 1.
     '''
     event.var_random = random.uniform(0,1)
Example #3
0
def particles(nptcs, pdgid, thetamin, thetamax, emin, emax, vertex=None):
    ngenerated = 0
    mass, charge = particle_data[pdgid]
    while ngenerated < nptcs:
        theta = random.uniform(thetamin, thetamax)
        phi = random.uniform(-math.pi, math.pi)
        energy = random.uniform(emin, emax)
        if vertex is None:
            vertex = Point(0, 0, 0)
        momentum = math.sqrt(energy ** 2 - mass ** 2)
        costheta = math.cos(theta)
        sintheta = math.sin(theta)
        cosphi = math.cos(phi)
        sinphi = math.sin(phi)
        p4 = LorentzVector(momentum * sintheta * cosphi, momentum * sintheta * sinphi, momentum * costheta, energy)
        ngenerated += 1
        yield Particle(p4, vertex, charge, pdgid)
Example #4
0
    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
Example #5
0
File: roc.py Project: HEP-FCC/heppy
 def is_tagged(self, is_signal):
     '''Return tagging value.
     
     @return: result of the tagging (boolean)
     @param is_b: specifies whether the object of interest is signal
       or background
     '''
     eff = self.eff if is_signal else self.fake_rate
     return random.uniform(0, 1) < eff
Example #6
0
 def electron_acceptance(self, track):
     '''returns True if electron is seen.
     
     No information, cooking something up.
     '''
     if track.p3().Mag() > 5 and \
        abs(track.theta()) < Tracker.theta_max:
         return random.uniform(0, 1) < 0.95
     else:
         return False
Example #7
0
 def acceptance(self, cluster):
     energy = cluster.energy
     eta = abs(cluster.position.Eta())
     if eta < self.eta_crack :
         if energy>1.:
             return random.uniform(0,1)<(1/(1+math.exp((energy-1.93816)/(-1.75330))))
         else:
             return False
     elif eta < 3. : 
         if energy>1.1:
             if energy<10.:
                 return random.uniform(0,1)<(1.05634-1.66943e-01*energy+1.05997e-02*(energy**2))
             else:
                 return random.uniform(0,1)<(8.09522e-01/(1+math.exp((energy-9.90855)/-5.30366)))
         else:
             return False
     elif eta < 5.:
         return energy>7.
     else:
         return False
Example #8
0
def particle(pdgid, thetamin, thetamax, ptmin, ptmax,
             flat_pt=False, papas = False,
             phimin=-math.pi, phimax=math.pi):
    '''Create and return a particle in a given phase space
    
    @param pdgid: the pdg ID code
    @param thetamin: min theta
    @param thetamax: max theta
    @param ptmin: min pt
    @param ptmax: max pt
    @param flat_pt: False by default, indicating that the pt of the
       particle should be chosen from a uniform distribution between
       ptmin and ptmax. if set to true,
       the energy of the particle is drawn from a uniform distribution
       between ptmin and ptmax (then considered as Emin and Emax).
    '''
    mass, charge = particle_data[pdgid]
    theta = random.uniform(thetamin, thetamax)
    phi = random.uniform(phimin, phimax)
    energy = random.uniform(ptmin, ptmax)
    costheta = math.cos(math.pi/2. - theta)
    sintheta = math.sin(math.pi/2. - theta)
    tantheta = sintheta / costheta
    cosphi = math.cos(phi)
    sinphi = math.sin(phi) 
    vertex = TVector3(0,0,0)
    if flat_pt:
        pt = energy
        momentum = pt / sintheta
        energy = math.sqrt(momentum**2 + mass**2)
    else:
        energy = max([energy, mass])
        momentum = math.sqrt(energy**2 - mass**2)
    tlv = TLorentzVector(momentum*sintheta*cosphi,
                         momentum*sintheta*sinphi,
                         momentum*costheta,
                         energy)
    if papas:
        return PapasParticle(tlv, vertex, charge, pdgid, subtype ='g') #pfobjects has a uniqueid
    else:
        return TlvParticle(pdgid, charge, tlv) #pfobjects has a uniqueid    
Example #9
0
def monojet(pdgids, theta, phi, pstar, jetenergy, vertex=None):
    particles = []
    if vertex is None:
        vertex = TVector3(0.0, 0.0, 0.0)
    jetp4star = TLorentzVector()
    for pdgid in pdgids[:-1]:
        mass, charge = particle_data[pdgid]
        phistar = random.uniform(-math.pi, math.pi)
        thetastar = random.uniform(-math.pi, math.pi)
        sint = math.sin(thetastar)
        cost = math.cos(thetastar)
        sinp = math.sin(phistar)
        cosp = math.cos(phistar)
        pz = pstar * cost
        px = pstar * sint * cosp
        py = pstar * sint * sinp
        p4 = TLorentzVector()
        p4.SetXYZM(px, py, pz, mass)
        jetp4star += p4
        particles.append(Particle(p4, vertex, charge, pdgid))
    pdgid = pdgids[-1]
    mass, charge = particle_data[pdgid]
    p4 = TLorentzVector()
    p4.SetVectM(-jetp4star.Vect(), mass)
    particles.append(Particle(p4, vertex, charge, pdgid))
    jetp4star += p4

    # boosting to lab
    gamma = jetenergy / jetp4star.M()
    beta = math.sqrt(1 - 1 / gamma ** 2)
    boostvec = TVector3(math.sin(theta) * math.cos(phi), math.sin(theta) * math.sin(phi), math.cos(theta))
    boostvec *= beta
    boosted_particles = []
    jetp4 = LorentzVector()
    for ptc in particles:
        bp4 = LorentzVector(ptc.p4())
        bp4.Boost(boostvec)
        jetp4 += bp4
        boosted_particles.append(Particle(bp4, ptc.vertex, ptc.q(), ptc.pdgid()))
    # print jetp4.M(), jetp4.E()
    return boosted_particles
Example #10
0
def particle(pdgid, thetamin, thetamax, ptmin, ptmax, flat_pt=False):
    mass, charge = particle_data[pdgid]
    theta = random.uniform(thetamin, thetamax)
    phi = random.uniform(-math.pi, math.pi)
    energy = random.uniform(ptmin, ptmax)
    costheta = math.cos(math.pi/2. - theta)
    sintheta = math.sin(math.pi/2. - theta)
    tantheta = sintheta / costheta
    cosphi = math.cos(phi)
    sinphi = math.sin(phi)        
    if flat_pt:
        pt = energy
        momentum = pt / sintheta
        energy = math.sqrt(momentum**2 + mass**2)
    else:
        energy = max([energy, mass])
        momentum = math.sqrt(energy**2 - mass**2)
    tlv = TLorentzVector(momentum*sintheta*cosphi,
                         momentum*sintheta*sinphi,
                         momentum*costheta,
                         energy)
    return Particle(pdgid, charge, tlv) 
Example #11
0
File: CMS.py Project: HEP-FCC/heppy
 def muon_acceptance(self, track):
     """Delphes parametrization
     https://github.com/delphes/delphes/blob/master/cards/delphes_card_CMS.tcl
     96d6bcf 
     """        
     rnd = random.uniform(0, 1)
     eta = abs(track.p3().Eta())
     pt = track.p3().Perp()
     if pt < 10.:
         return False
     elif eta < 2.4:
         return rnd < 0.95
     else:
         return False
Example #12
0
 def acceptance(self, cluster):
     energy = cluster.energy
     eta = abs(cluster.position.Eta())
     if eta < self.eta_crack:
         if energy > 1.:
             return random.uniform(0, 1) < (1 / (1 + math.exp(
                 (energy - 1.93816) / (-1.75330))))
         else:
             return False
     elif eta < 3.:
         if energy > 1.1:
             if energy < 10.:
                 return random.uniform(
                     0, 1) < (1.05634 - 1.66943e-01 * energy + 1.05997e-02 *
                              (energy**2))
             else:
                 return random.uniform(0, 1) < (8.09522e-01 / (1 + math.exp(
                     (energy - 9.90855) / -5.30366)))
         else:
             return False
     elif eta < 5.:
         return energy > 7.
     else:
         return False
Example #13
0
 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
Example #14
0
 def electron_acceptance(self, ptc):
     """Delphes parametrization
     https://github.com/delphes/delphes/blob/master/cards/delphes_card_CMS.tcl
     96d6bcf 
     """
     rnd = random.uniform(0, 1)
     if ptc.pt() < 10.:
         return False
     else:
         eta = abs(ptc.eta())
         if eta < 1.5:
             return rnd < 0.95
         elif eta < 2.5:
             return rnd < 0.85
         else:
             return False
Example #15
0
 def electron_acceptance(self, track):
     """Delphes parametrization
     https://github.com/delphes/delphes/blob/master/cards/delphes_card_CMS.tcl
     96d6bcf 
     """
     rnd = random.uniform(0, 1)
     pt = track.p3().Perp()
     if pt < 10.:
         return False
     else:
         eta = abs(track.p3().Eta())
         if eta < 1.5:
             return rnd < 0.95
         elif eta < 2.5:
             return rnd < 0.85
         else:
             return False
Example #16
0
 def muon_resolution(self, ptc):
     """Delphes parametrization
     
       # resolution formula for muons
       set ResolutionFormula {
                      (abs(eta) <= 0.5) * (pt > 0.1) * sqrt(0.01^2 + pt^2*1.0e-4^2) +
                      (abs(eta) > 0.5 && abs(eta) <= 1.5) * (pt > 0.1) * sqrt(0.015^2 + pt^2*1.5e-4^2) +
                      (abs(eta) > 1.5 && abs(eta) <= 2.5) * (pt > 0.1) * sqrt(0.025^2 + pt^2*3.5e-4^2)}
     """
     rnd = random.uniform(0, 1)
     eta = abs(ptc.eta())
     cstt = None
     vart = None
     if eta < 0.5:
         cstt, vart = 0.01, 1e-4
     elif eta < 1.5:
         cstt, vart = 0.015, 1.5e-4
     else:
         cstt, vart = 0.025, 3.5e-4
     res = math.sqrt(cstt**2 + vart**2)
     return res
Example #17
0
File: CMS.py Project: HEP-FCC/heppy
 def muon_resolution(self, track):
     """Delphes parametrization
     
       # resolution formula for muons
       set ResolutionFormula {
                      (abs(eta) <= 0.5) * (pt > 0.1) * sqrt(0.01^2 + pt^2*1.0e-4^2) +
                      (abs(eta) > 0.5 && abs(eta) <= 1.5) * (pt > 0.1) * sqrt(0.015^2 + pt^2*1.5e-4^2) +
                      (abs(eta) > 1.5 && abs(eta) <= 2.5) * (pt > 0.1) * sqrt(0.025^2 + pt^2*3.5e-4^2)}
     """
     rnd = random.uniform(0, 1)
     eta = abs(track.p3().Eta())
     pt = track.p3().Perp()
     cstt = None
     vart = None
     if eta < 0.5:
         cstt, vart = 0.01, 1e-4
     elif eta < 1.5:
         cstt, vart = 0.015, 1.5e-4
     else:
         cstt, vart = 0.025, 3.5e-4
     res = math.sqrt(cstt**2 + (pt * vart)**2)
     return res
Example #18
0
    def acceptance(self, track):
        '''Returns True if the track is seen.
        
        Currently taken from
        https://indico.cern.ch/event/650053/contributions/2672772/attachments/1501093/2338117/FCCee_MDI_Jul30.pdf

        Original values for CLIC:
        Acceptance from the CLIC CDF p107, Fig. 5.12 without background.
        The tracker is taken to be efficient up to theta = 80 degrees. 
        '''
        rnd = random.uniform(0, 1)
        pt = track.p3().Pt()
        theta = abs(track.theta())
        if theta < self.theta_max:
            if pt < 0.1:
                return False
            elif pt < 0.3:
                return rnd < 0.9
            elif pt < 1:
                return rnd < 0.95
            else:
                return rnd < 0.99
        return False
Example #19
0
    def acceptance(self, track):
        '''Returns True if the track is seen.
        
        Currently taken from
        https://indico.cern.ch/event/650053/contributions/2672772/attachments/1501093/2338117/FCCee_MDI_Jul30.pdf

        Original values for CLIC:
        Acceptance from the CLIC CDF p107, Fig. 5.12 without background.
        The tracker is taken to be efficient up to theta = 80 degrees. 
        '''
        rnd = random.uniform(0,1)
        pt = track.p3().Pt()
        theta = abs(track.theta())
        if theta < self.__class__.theta_max:
            if pt < 0.1:
                return False
            elif pt < 0.3:
                return rnd < 0.9
            elif pt < 1:
                return rnd < 0.95
            else:
                return rnd < 0.99
        return False
Example #20
0
    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
Example #21
0
    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
Example #22
0
 def process(self, event):
     event.var_random = random.uniform(0,1)
Example #23
0
def multiple_scattering( particle, detector_element, field ):
    '''This function computes the scattering of a particle while propagating through the detector.
    
    As described in the pdg booklet, Passage of particles through matter, multiple scattering through small angles.
    the direction of a charged particle is modified.
    
    This function takes a particle (that has been propagated until the detector element
    where it will be scattered) and the detector element responsible for the scattering.
    The magnetic field has to be specified in order to create the new trajectory.
    
    Then this function computes the new direction, randomly choosen according to
    Moliere's theory of multiple scattering (see pdg booklet) and replaces the
    initial path of the particle by this new scattered path.
    
    The particle can now be propagated in the next part of the detector.
    '''

    if not particle.q():
        return
    # reject particles that could not be extrapolated to detector element
    # (particle created too late, out of the detector element)
    surface_in = '{}_in'.format(detector_element.name)
    surface_out = '{}_out'.format(detector_element.name)
    if not surface_in in particle.path.points or \
        not surface_out in particle.path.points:
        return
    
    #TODOCOLIN : check usage of private attributes
    in_point = particle.path.points[surface_in]
    out_point = particle.path.points[surface_out]
    phi_in = particle.path.phi( in_point.X(), in_point.Y())
    phi_out = particle.path.phi( out_point.X(), out_point.Y())
    t_scat = particle.path.time_at_phi((phi_in+phi_out)*0.5)
    # compute p4_t = p4 at t_scat :
    p4_0 = particle.path.p4.Clone()
    p4tx = p4_0.X()*math.cos(particle.path.omega*t_scat)\
           + p4_0.Y()*math.sin(particle.path.omega*t_scat)
    p4ty =-p4_0.X()*math.sin(particle.path.omega*t_scat)\
           + p4_0.Y()*math.cos(particle.path.omega*t_scat)
    p4tz = p4_0.Z()
    p4tt = p4_0.T()
    p4_t = TLorentzVector(p4tx, p4ty, p4tz, p4tt)

    # now, p4t will be modified with respect to the multiple scattering
    # first one has to determine theta_0 the width of the gaussian :
    P = p4_t.Vect().Dot(p4_t.Vect().Unit())
    deltat = particle.path.time_at_phi(phi_out)-particle.path.time_at_phi(phi_in)
    x = abs(particle.path.path_length(deltat))
    X_0 = detector_element.material.x0

    theta_0 = 1.0*13.6e-3/(1.0*particle.path.speed/constants.c*P)*abs(particle.path.charge)
    theta_0 *= (1.0*x/X_0)**(1.0/2)*(1+0.038*math.log(1.0*x/X_0))

    # now, make p4_t change due to scattering :
    theta_space = random.gauss(0, theta_0*2.0**(1.0/2))
    psi = constants.pi*random.uniform(0,1) #double checked
    p3i = p4_t.Vect().Clone()
    e_z = TVector3(0,0,1)
    #first rotation : theta, in the xy plane
    a = p3i.Cross(e_z)
    #this may change the sign, but randomly, as the sign of theta already is
    p4_t.Rotate(theta_space,a)
    #second rotation : psi (isotropic around initial direction)
    p4_t.Rotate(psi,p3i.Unit())

    # creating new helix, ref at scattering point :
    helix_new_t = Helix(field, particle.path.charge, p4_t,
                        particle.path.point_at_time(t_scat))

    # now, back to t=0
    p4sx = p4_t.X()*math.cos(-particle.path.omega*t_scat)\
           + p4_t.Y()*math.sin(-particle.path.omega*t_scat)
    p4sy =-p4_t.X()*math.sin(-particle.path.omega*t_scat)\
           + p4_t.Y()*math.cos(-particle.path.omega*t_scat)
    p4sz = p4_t.Z()
    p4st = p4_t.T()
    p4_scat = TLorentzVector(p4sx, p4sy, p4sz, p4st)

    # creating new helix, ref at new t0 point :
    helix_new_0 = Helix(field, particle.path.charge, p4_scat,
                        helix_new_t.point_at_time(-t_scat))

    # replacing the particle's path with the scatterd one :
    particle.set_path(helix_new_0, option = 'w')
Example #24
0
 def is_b_tagged(self, is_b):
     eff = self.eff if is_b else self.fake_rate
     return random.uniform(0, 1) < eff
Example #25
0
def multiple_scattering(particle, detector_element, field):
    '''This function computes the scattering of a particle while propagating through the detector.
    
    As described in the pdg booklet, Passage of particles through matter, multiple scattering through small angles.
    the direction of a charged particle is modified.
    
    This function takes a particle (that has been propagated until the detector element
    where it will be scattered) and the detector element responsible for the scattering.
    The magnetic field has to be specified in order to create the new trajectory.
    
    Then this function computes the new direction, randomly choosen according to
    Moliere's theory of multiple scattering (see pdg booklet) and replaces the
    initial path of the particle by this new scattered path.
    
    The particle can now be propagated in the next part of the detector.
    '''

    if not particle.q():
        return
    # reject particles that could not be extrapolated to detector element
    # (particle created too late, out of the detector element)
    surface_in = '{}_in'.format(detector_element.name)
    surface_out = '{}_out'.format(detector_element.name)
    if not surface_in in particle.path.points or \
        not surface_out in particle.path.points:
        return

    #TODOCOLIN : check usage of private attributes
    in_point = particle.path.points[surface_in]
    out_point = particle.path.points[surface_out]
    phi_in = particle.path.phi(in_point.X(), in_point.Y())
    phi_out = particle.path.phi(out_point.X(), out_point.Y())
    t_scat = particle.path.time_at_phi((phi_in + phi_out) * 0.5)
    # compute p4_t = p4 at t_scat :
    p4_0 = particle.path.p4.Clone()
    p4tx = p4_0.X()*math.cos(particle.path.omega*t_scat)\
           + p4_0.Y()*math.sin(particle.path.omega*t_scat)
    p4ty =-p4_0.X()*math.sin(particle.path.omega*t_scat)\
           + p4_0.Y()*math.cos(particle.path.omega*t_scat)
    p4tz = p4_0.Z()
    p4tt = p4_0.T()
    p4_t = TLorentzVector(p4tx, p4ty, p4tz, p4tt)

    # now, p4t will be modified with respect to the multiple scattering
    # first one has to determine theta_0 the width of the gaussian :
    P = p4_t.Vect().Dot(p4_t.Vect().Unit())
    deltat = particle.path.time_at_phi(phi_out) - particle.path.time_at_phi(
        phi_in)
    x = abs(particle.path.path_length(deltat))
    X_0 = detector_element.material.x0

    theta_0 = 1.0 * 13.6e-3 / (1.0 * particle.path.speed / constants.c *
                               P) * abs(particle.path.charge)
    theta_0 *= (1.0 * x / X_0)**(1.0 / 2) * (1 +
                                             0.038 * math.log(1.0 * x / X_0))

    # now, make p4_t change due to scattering :
    theta_space = random.gauss(0, theta_0 * 2.0**(1.0 / 2))
    psi = constants.pi * random.uniform(0, 1)  #double checked
    p3i = p4_t.Vect().Clone()
    e_z = TVector3(0, 0, 1)
    #first rotation : theta, in the xy plane
    a = p3i.Cross(e_z)
    #this may change the sign, but randomly, as the sign of theta already is
    p4_t.Rotate(theta_space, a)
    #second rotation : psi (isotropic around initial direction)
    p4_t.Rotate(psi, p3i.Unit())

    # creating new helix, ref at scattering point :
    helix_new_t = Helix(field, particle.path.charge, p4_t,
                        particle.path.point_at_time(t_scat))

    # now, back to t=0
    p4sx = p4_t.X()*math.cos(-particle.path.omega*t_scat)\
           + p4_t.Y()*math.sin(-particle.path.omega*t_scat)
    p4sy =-p4_t.X()*math.sin(-particle.path.omega*t_scat)\
           + p4_t.Y()*math.cos(-particle.path.omega*t_scat)
    p4sz = p4_t.Z()
    p4st = p4_t.T()
    p4_scat = TLorentzVector(p4sx, p4sy, p4sz, p4st)

    # creating new helix, ref at new t0 point :
    helix_new_0 = Helix(field, particle.path.charge, p4_scat,
                        helix_new_t.point_at_time(-t_scat))

    # replacing the particle's path with the scatterd one :
    particle.set_path(helix_new_0, option='w')
Example #26
0
 def process(self, event):
     event.var_random = random.uniform(0, 1)
Example #27
0
 def is_b_tagged(self, is_b):
     eff = self.eff if is_b else self.fake_rate
     return random.uniform(0, 1) < eff
Example #28
0
    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