def test_merge_different_layers(self): clusters = [ Cluster(20, TVector3(1, 0, 0), 0.04, 'ecal_in'), Cluster(20, TVector3(1, 0, 0), 0.04, 'hcal_in') ] merge_clusters(clusters, 'hcal_in') self.assertEqual(len(clusters), 2)
def applyCuts(particles): test = True pdic = {} for p in particles: if p[3] in pdic: pdic[p[3] + 1000] = TVector3(p[6], p[7], p[8]) else: pdic[p[3]] = TVector3(p[6], p[7], p[8]) ## check electron angle #electron = pdic[ 11 ] #if electron.Theta() < ThetaMin: #return False #if electron.Theta() > ThetaMax: #return False pi = pdic[2212] if pi.Theta() < ThetaMin: return False if pi.Theta() > ThetaMax: return False pi = pdic[-211] if pi.Theta() < ThetaMin: return False if pi.Theta() > ThetaMax: return False return test
def CostHE(p1, charge1, p2): #Cosine of the theta decay angle (top (Q=+2/3)) in the Helicity frame pTop1CM = TLorentzVector(0,0,-1,1) # In the CM frame pTop2CM = TLorentzVector(0,0,-1,1) # In the CM frame pDitopCM = TLorentzVector(0,0,-1,1) # In the CM frame pTop1Ditop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame pTop2Ditop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame beta = TVector3(0,0,0) zaxisCS = TVector3(0,0,0) # Get the muons parameters in the CM frame pTop1CM.SetPxPyPzE(p1.Px(),p1.Py(),p1.Pz(),p1.E()) pTop2CM.SetPxPyPzE(p2.Px(),p2.Py(),p2.Pz(),p2.E()) # Obtain the Ditop parameters in the CM frame pDitopCM=pTop1CM+pTop2CM # Translate the muon parameters in the Ditop rest frame beta=(-1./pDitopCM.E())*pDitopCM.Vect() if(beta.Mag()>=1): return 666. pTop1Ditop=pTop1CM pTop2Ditop=pTop2CM pTop1Ditop.Boost(beta) pTop2Ditop.Boost(beta) # Determine the z axis for the calculation of the polarization angle (i.e. the direction of the Ditop in the CM system) zaxis=(pDitopCM.Vect()).Unit() # Calculation of the polarization angle (angle between mu+ and the z axis defined above) cost = -999. if(charge1>0): cost = zaxis.Dot((pTop1Ditop.Vect()).Unit()) else: cost = zaxis.Dot((pTop2Ditop.Vect()).Unit()) return cost
def print_crystal_placement(self, idxclover, coord=None): theta_rotation = TRotation() phi_rotation = TRotation() theta_rotation.RotateY(self.placement.Theta()) phi_rotation.RotateZ(self.placement.Phi()) for k, (xsign, ysign) in enumerate([(-1, +1), (+1, +1), (-1, -1), (+1, -1)]): crystal_offset = TVector3(xsign * self.xdispl, ysign * self.ydispl, self.covergap) crystal_offset = phi_rotation * theta_rotation * crystal_offset crystal = TVector3(self.placement.X() + crystal_offset.X(), self.placement.Y() + crystal_offset.Y(), self.placement.Z() + crystal_offset.Z()) if coord == "Spherical": print("clover.{0:02d}.{1}.{2}.vec_sph: ".format( idxclover, chr(0x40 + k + 1), 0) + str(np.around(crystal.Mag(), 10)) + " " + str(np.around(crystal.Theta() * 180 / np.pi, 10)) + " " + str(np.around(crystal.Phi() * 180 / np.pi, 10))) else: print("clover.{0:02d}.{1}.{2}.vec: ".format( idxclover, chr(0x40 + k + 1), 0) + str(np.around(crystal.X(), 10)) + " " + str(np.around(crystal.Y(), 10)) + " " + str(np.around(crystal.Z(), 10))) print("")
def test_ip_many(self): npoints = 100 radii = np.linspace(0.1, 0.2, npoints) angles = np.linspace(0, math.pi, npoints) momenta = np.linspace(200, 500, npoints) mass = 0.5 field = 1e-5 origin = TVector3(0, 0, 0) for radius, angle, momentum in zip(radii, angles, momenta): ip_pos = TVector3(math.cos(angle), math.sin(angle), 0) ip_pos *= radius smom = TVector3(math.cos(angle - math.pi / 2.), math.sin(angle - math.pi / 2.), 0) smom *= momentum p4 = TLorentzVector() p4.SetVectM(smom, mass) helix_vertex = copy.deepcopy(ip_pos) delta = copy.deepcopy(smom.Unit()) delta *= radius helix_vertex += delta helix = Helix(field, 1., p4, helix_vertex) ip_mine = helix.compute_IP_2(origin, smom) ip_nic = compute_IP(helix, origin, smom) ip_luc = helix.compute_IP(origin, smom) nplaces = 8 self.assertAlmostEqual(abs(ip_luc), radius, places=nplaces) #COLIN in the following, I modify Nic's minimization args # so that they work, and to reach Lucas' precision # it works with nplaces = 5 though. self.assertAlmostEqual(abs(ip_mine), radius, places=nplaces)
def test_layerfan(self): c1 = Cluster(10, TVector3(1, 0, 0), 1., 'ecal_in') c2 = Cluster(20, TVector3(1, 0, 0), 1., 'hcal_in') p3 = c1.position.Unit()*100. p4 = TLorentzVector() p4.SetVectM(p3, 1.) path = StraightLine(p4, TVector3(0,0,0)) charge = 1. tr = Track(p3, charge, path) tr.path.points['ecal_in'] = c1.position tr.path.points['hcal_in'] = c2.position elems = [c1, c2, tr] for ele in elems: link_type, link_ok, distance = ruler(ele, ele) if ele!=tr: self.assertTrue(link_ok) elif ele==tr: self.assertFalse(link_ok) #ecal hcal no longer linked to match c++ so have adjusted test accordingly link_type, link_ok, distance = ruler(c2, c1) self.assertFalse(link_ok) self.assertEqual(link_type, None) link_type, link_ok, distance = ruler(tr, c1) self.assertTrue(link_ok) link_type, link_ok, distance = ruler(tr, c2) self.assertTrue(link_ok)
def propagate_one(self, particle, cylinder, dummy=None): line = StraightLine(particle.p4(), particle.vertex) particle.set_path(line) # TODO theta = line.udir.Theta() if line.udir.Z(): destz = cylinder.z if line.udir.Z() > 0. else -cylinder.z length = (destz - line.origin.Z()) / math.cos(theta) # import pdb; pdb.set_trace() assert (length >= 0) destination = line.origin + line.udir * length rdest = destination.Perp() if rdest > cylinder.rad: udirxy = TVector3(line.udir.X(), line.udir.Y(), 0.) originxy = TVector3(line.origin.X(), line.origin.Y(), 0.) # solve 2nd degree equation for intersection # between the straight line and the cylinder # in the xy plane to get k, # the propagation length a = udirxy.Mag2() b = 2 * udirxy.Dot(originxy) c = originxy.Mag2() - cylinder.rad**2 delta = b**2 - 4 * a * c km = (-b - math.sqrt(delta)) / (2 * a) # positive propagation -> correct solution. kp = (-b + math.sqrt(delta)) / (2 * a) # print delta, km, kp destination = line.origin + line.udir * kp #TODO deal with Z == 0 #TODO deal with overlapping cylinders particle.points[cylinder.name] = destination
def smearing_significance_IP(self, ptc): """Given a particle, smear the IP and compute the track significance and the probability that the track comes from the primary vertex. The smearing is made with a gaussian variable with mean = 0 and sigma = resolution; in addition the smearing is applied to the x' and y' component of the IP, that are the component in a frame in which the vector IP lies on the x'y' plane. """ resolution = self.cfg_ana.resolution(ptc) ptc.path.ip_resolution = resolution ptc.path.x_prime = ptc.path.vector_impact_parameter.Mag() * math.cos( ptc.path.vector_impact_parameter.Phi()) ptc.path.y_prime = ptc.path.vector_impact_parameter.Mag() * math.sin( ptc.path.vector_impact_parameter.Phi()) ptc.path.z_prime = 0 ptc.path.vector_ip_rotated = TVector3(ptc.path.x_prime, ptc.path.y_prime, ptc.path.z_prime) ptc.path.ip_smear_factor_x = random.gauss(0, ptc.path.ip_resolution) ptc.path.ip_smear_factor_y = random.gauss(0, ptc.path.ip_resolution) ptc.path.x_prime_smeared = ptc.path.x_prime + ptc.path.ip_smear_factor_x ptc.path.y_prime_smeared = ptc.path.y_prime + ptc.path.ip_smear_factor_y ptc.path.z_prime_smeared = 0 ptc.path.vector_ip_rotated_smeared = TVector3(ptc.path.x_prime_smeared, ptc.path.y_prime_smeared, ptc.path.z_prime_smeared) ptc.path.smeared_impact_parameter = ptc.path.vector_ip_rotated_smeared.Mag( ) * ptc.path.sign_impact_parameter ptc.path.significance_impact_parameter = ptc.path.smeared_impact_parameter / ptc.path.ip_resolution ptc.path.track_probability = self.track_probability(ptc) if self.cfg_ana.method == 'complex': ptc.path.min_dist_to_jet_significance = ptc.path.sign_impact_parameter\ * ptc.path.min_dist_to_jet.Mag()\ / ptc.path.ip_resolution
def lowEnergyCleaning(bgorec): ''' Section 3.2, cut coming from Xin's code Needs to be clearly studied Andrii by e-mail: I remember this issue, there were some low-energy protons, with very low energy deposit, falling into the electron xtrl region. The cut was implemented "by eye" (as far as I know) by Xin. If you look at Figure 5 (two plots on the top left), there is shower RMS w.r.t cos(theta), where you can see those events (below magenta line). They occur only below 250 GeV. First of all, you could produce a plot similar to Figure 5 (using proton and electron MC), and apply your own cut in a similar way to Xin. Or just use his formula (check with him) to put a cut on RMS-cos(theta) plane. ''' bgoTotalE = bgorec.GetTotalEnergy() / 1000. # in GeV if bgoTotalE >= 250: return True # Save some computations below bgoRec_intercept = [bgorec.GetInterceptYZ(), bgorec.GetInterceptXZ()] bgoRec_slope = [bgorec.GetSlopeYZ(), bgorec.GetSlopeXZ()] vec_s0_a = TVector3(bgoRec_intercept[1], bgoRec_intercept[0], 0.) vec_s1_a = TVector3(bgoRec_intercept[1] + bgoRec_slope[1], bgoRec_intercept[0] + bgoRec_slope[0], 1.) bgoRecDirection = ( vec_s1_a - vec_s0_a).Unit() # Unit vector pointing from front to back cosBgoRecTheta = np.cos(bgoRecDirection.Theta()) sumRms = sum(getRMS(bgorec)) if bgoTotalE < 100: if sumRms < (270 - 100 * (cosBgoRecTheta**6)): return False elif bgoTotalE < 250: if sumRms < (800 - 600 * (cosBgoRecTheta**1.2)): return False return True
def calcPZeta(self): tau1PT = TVector3(self.leg1().p4().x(), self.leg1().p4().y(), 0.) tau2PT = TVector3(self.leg2().p4().x(), self.leg2().p4().y(), 0.) metPT = TVector3(self.met().p4().x(), self.met().p4().y(), 0.) zetaAxis = (tau1PT.Unit() + tau2PT.Unit()).Unit() self.pZetaVis_ = tau1PT * zetaAxis + tau2PT * zetaAxis self.pZetaMET_ = metPT * zetaAxis
def PAssymVarMC(collections): pv_x=collections[0] pv_y=collections[1] pv_z=collections[2] Bcands=collections[3] Bidx=collections[4] assym=-99. if Bidx<0: return [assym] pv_vtx=TVector3() pv_vtx.SetXYZ(pv_x,pv_y,pv_z) Bcand=Bcands[Bidx] b_vtx=TVector3() b_vtx.SetXYZ(getattr(Bcand,"vtx_x"), getattr(Bcand,"vtx_y"), getattr(Bcand,"vtx_z")) k_p=TVector3() e1_p=TVector3() e2_p=TVector3() k_p.SetPtEtaPhi(getattr(Bcand,"fit_k_pt"), getattr(Bcand,"fit_k_eta"), getattr(Bcand,"fit_k_phi")) e1_p.SetPtEtaPhi(getattr(Bcand,"fit_l1_pt"), getattr(Bcand,"fit_l1_eta"), getattr(Bcand,"fit_l1_phi")) e2_p.SetPtEtaPhi(getattr(Bcand,"fit_l2_pt"), getattr(Bcand,"fit_l2_eta"), getattr(Bcand,"fit_l2_phi")) assym= (((e1_p+e2_p).Cross(pv_vtx-b_vtx)).Mag()-(k_p.Cross(pv_vtx-b_vtx)).Mag())/(((e1_p+e2_p).Cross(pv_vtx-b_vtx)).Mag()+(k_p.Cross(pv_vtx-b_vtx)).Mag()) return [assym]
def smearing_significance_IP(self, ptc): resolution = self.cfg_ana.resolution(ptc) ptc.path.ip_resolution = resolution ptc.path.x_prime = ptc.path.vector_impact_parameter.Mag() * math.cos( ptc.path.vector_impact_parameter.Phi()) ptc.path.y_prime = ptc.path.vector_impact_parameter.Mag() * math.sin( ptc.path.vector_impact_parameter.Phi()) ptc.path.z_prime = 0 ptc.path.vector_ip_rotated = TVector3(ptc.path.x_prime, ptc.path.y_prime, ptc.path.z_prime) ptc.path.ip_smear_factor_x = random.gauss(0, ptc.path.ip_resolution) ptc.path.ip_smear_factor_y = random.gauss(0, ptc.path.ip_resolution) ptc.path.x_prime_smeared = ptc.path.x_prime + ptc.path.ip_smear_factor_x ptc.path.y_prime_smeared = ptc.path.y_prime + ptc.path.ip_smear_factor_y ptc.path.z_prime_smeared = 0 ptc.path.vector_ip_rotated_smeared = TVector3(ptc.path.x_prime_smeared, ptc.path.y_prime_smeared, ptc.path.z_prime_smeared) ptc.path.smeared_impact_parameter = ptc.path.vector_ip_rotated_smeared.Mag( ) * ptc.path.sign_impact_parameter ptc.path.significance_impact_parameter = ptc.path.smeared_impact_parameter / ptc.path.ip_resolution ptc.path.track_probability = self.track_probability(ptc)
def smear_IP(path, gx, gy): """Given a particle, smear the IP and compute the track significance and the probability that the track comes from the primary vertex. The smearing is made with a gaussian variable with mean = 0 and sigma = resolution; in addition the smearing is applied to the x' and y' component of the IP, that are the component in a frame in which the vector IP lies on the x'y' plane. """ # resolution = self.cfg_ana.resolution(ptc) # ptc.path.ip_resolution = resolution #COLIN->NIC: is this just taking the X and Y component? ipvector = path.impact_parameter.vector path.x_prime = ipvector.Mag()*math.cos(ipvector.Phi()) path.y_prime = ipvector.Mag()*math.sin(ipvector.Phi()) path.z_prime = 0 #COLIN->NIC: is the goal to just do path.vector_impact_parameter.Perp()? why is that called "rotated?" path.vector_ip_rotated = TVector3(path.x_prime, path.y_prime, path.z_prime) #COLIN->NIC: shouldn't smearing be done on the magnitude of the impact parameter vector? #in other words, I think that smearing should be correlated on the x and y components. #COLIN: the resolution should be in the same units as the impact parameter vector (meters?) path.x_prime_smeared = path.x_prime + gx path.y_prime_smeared = path.y_prime + gy path.z_prime_smeared = 0 path.vector_ip_rotated_smeared = TVector3(path.x_prime_smeared, path.y_prime_smeared, path.z_prime_smeared) #COLIN->NIC It looks like we are keeping the sign of the impact parameter before smearing. Why? # I think that smearing should be able to change the sign. path.smeared_impact_parameter = path.vector_ip_rotated_smeared.Mag() * path.impact_parameter.sign path.significance_impact_parameter = path.smeared_impact_parameter / path.IP_resolution
def test_merge_pair_away(self): clusters = [ Cluster(20, TVector3(1,0,0), 0.04, 'hcal_in'), Cluster(20, TVector3(1,1.1,0.0), 0.04, 'hcal_in')] merge_clusters(clusters, 'hcal_in') self.assertEqual( len(clusters), 2 ) self.assertEqual( len(clusters[0].subclusters), 1) self.assertEqual( len(clusters[1].subclusters), 1)
def calcPZeta(self): l0PT = TVector3(self.l0() .p4().x(), self.l0() .p4().y(), 0.) l1PT = TVector3(self.l1().p4().x(), self.l1().p4().y(), 0.) l2PT = TVector3(self.l2().p4().x(), self.l2().p4().y(), 0.) metPT = TVector3(self.met().p4().x(), self.met().p4().y(), 0.) zetaAxis = (l0PT.Unit() + l1PT.Unit() + l2PT.Unit()).Unit() self.pZetaVis_ = l0PT*zetaAxis + l1PT*zetaAxis + l2PT*zetaAxis self.pZetaMET_ = metPT*zetaAxis
def calcPZeta(self): mu1PT = TVector3(self.mu1().p4().x(), self.mu1().p4().y(), 0.) mu2PT = TVector3(self.mu2().p4().x(), self.mu2().p4().y(), 0.) mu3PT = TVector3(self.mu3().p4().x(), self.mu3().p4().y(), 0.) metPT = TVector3(self.met().p4().x(), self.met().p4().y(), 0.) zetaAxis = (mu1PT.Unit() + mu2PT.Unit() + mu3PT.Unit()).Unit() self.pZetaVis_ = mu1PT * zetaAxis + mu2PT * zetaAxis + mu3PT * zetaAxis self.pZetaMET_ = metPT * zetaAxis
def setUp(self): # goes along x self.p4 = TLorentzVector(1, 0, 0, 1.1) # starts at y = 0.1 self.true_IP = 0.1 self.vertex = TVector3(0, self.true_IP, 0) self.helix = Helix(1, 1, self.p4, self.vertex) # global origin self.origin = TVector3(0, 0, 0)
def test_ecal_hcal(self): c1 = Cluster(10, TVector3(1, 0, 0), 4., 'ecal_in') c2 = Cluster(20, TVector3(1, 0, 0), 4., 'hcal_in') link_type, link_ok, distance = ruler(c1, c2) self.assertTrue(link_ok) self.assertEqual(distance, 0.) pos3 = TVector3(c1.position) pos3.RotateZ(0.059) c3 = Cluster(30, pos3, 5, 'hcal_in') link_type, link_ok, distance = ruler(c1, c3) self.assertEqual(distance, 0.059)
def __init__(self, idx): self.pTID = t_pTID[idx] self.pPDG = t_pPDG[idx] self.pKE = t_pKE[idx] self.pKinkAngle = t_pKinkAngle[idx] * 180. / 3.1416 self.pPos = None self.pDir = None if t_pExitdX[idx] > -9999.: self.pPos = TVector3(t_pExitX[idx], t_pExitY[idx], t_pExitZ[idx]) self.pDir = TVector3(t_pExitdX[idx], t_pExitdY[idx], t_pExitdZ[idx])
def fillMETAndDiLeptonBranches(self, event, tau1, tau2, met, met_vars): """Help function to compute variable related to the MET and visible tau candidates, and fill the corresponding branches.""" # PROPAGATE TES/LTF/JTF shift to MET (assume shift is already applied to object) if self.ismc and 't' in self.channel: if hasattr(tau1,'es') and tau1.es!=1: dp = tau1.tlv*(1.-1./tau1.es) # assume shift is already applied correctmet(met,dp) if hasattr(tau2,'es') and tau2.es!=1: dp = tau2.tlv*(1.-1./tau2.es) #print ">>> fillMETAndDiLeptonBranches: Correcting MET for es=%.3f, pt=%.3f, dpt=%.3f, gm=%d"%(tau2.es,tau2.pt,dp.Pt(),tau2.genPartFlav) correctmet(met,tau2.tlv*(1.-1./tau2.es)) tau1 = tau1.tlv # continue with TLorentzVector tau2 = tau2.tlv # continue with TLorentzVector # MET self.out.met[0] = met.Pt() self.out.metphi[0] = met.Phi() self.out.mt_1[0] = sqrt( 2*self.out.pt_1[0]*met.Pt()*(1-cos(deltaPhi(self.out.phi_1[0],met.Phi()))) ) self.out.mt_2[0] = sqrt( 2*self.out.pt_2[0]*met.Pt()*(1-cos(deltaPhi(self.out.phi_2[0],met.Phi()))) ) ###self.out.puppimetpt[0] = event.PuppiMET_pt ###self.out.puppimetphi[0] = event.PuppiMET_phi ###self.out.metsignificance[0] = event.MET_significance ###self.out.metcov00[0] = event.MET_covXX ###self.out.metcov01[0] = event.MET_covXY ###self.out.metcov11[0] = event.MET_covYY ###self.out.fixedGridRhoFastjetAll[0] = event.fixedGridRhoFastjetAll # PZETA leg1 = TVector3(tau1.Px(),tau1.Py(),0.) leg2 = TVector3(tau2.Px(),tau2.Py(),0.) zetaAxis = TVector3(leg1.Unit()+leg2.Unit()).Unit() # bisector of visible tau candidates pzetavis = leg1*zetaAxis + leg2*zetaAxis # bisector of visible ditau momentum onto zeta axis pzetamiss = met.Vect()*zetaAxis # projection of MET onto zeta axis self.out.pzetamiss[0] = pzetamiss self.out.pzetavis[0] = pzetavis self.out.dzeta[0] = pzetamiss - 0.85*pzetavis # MET SYSTEMATICS for unc, met_var in met_vars.iteritems(): getattr(self.out,"met_"+unc)[0] = met_var.Pt() getattr(self.out,"metphi_"+unc)[0] = met_var.Phi() getattr(self.out,"mt_1_"+unc)[0] = sqrt( 2 * self.out.pt_1[0] * met_var.Pt() * ( 1 - cos(deltaPhi(self.out.phi_1[0],met_var.Phi())) )) getattr(self.out,"dzeta_"+unc)[0] = met_var.Vect()*zetaAxis - 0.85*pzeta_vis # DILEPTON self.out.m_vis[0] = (tau1 + tau2).M() self.out.pt_ll[0] = (tau1 + tau2).Pt() self.out.dR_ll[0] = tau1.DeltaR(tau2) self.out.dphi_ll[0] = deltaPhi(self.out.phi_1[0], self.out.phi_2[0]) self.out.deta_ll[0] = abs(self.out.eta_1[0] - self.out.eta_2[0]) self.out.chi[0] = exp(abs(tau1.Rapidity() - tau2.Rapidity()))
def test_merge_pair(self): clusters = [ Cluster(20, TVector3(1, 0, 0), 0.1, 'hcal_in'), Cluster(20, TVector3(1.,0.05,0.), 0.1, 'hcal_in')] merged_clusters = merge_clusters(clusters, 'hcal_in') self.assertEqual( len(merged_clusters), 1 ) self.assertEqual( merged_clusters[0].energy, clusters[0].energy + clusters[1].energy) self.assertEqual( merged_clusters[0].position.X(), (clusters[0].position.X() + clusters[1].position.X())/2.) self.assertEqual( len(merged_clusters[0].subclusters), 2) self.assertEqual( merged_clusters[0].subclusters[0], clusters[0]) self.assertEqual( merged_clusters[0].subclusters[1], clusters[1])
def PhiHE(p1, charge1, p2): # Phi decay angle (top (Q=+2/3)) in the Helicity frame pTop1Lab = TLorentzVector(0,0,-1,1) # In the lab. frame pTop2Lab = TLorentzVector(0,0,-1,1) # In the lab. frame pProjLab = TLorentzVector(0,0,-1,1) # In the lab. frame pTargLab = TLorentzVector(0,0,-1,1) # In the lab. frame pDitopLab = TLorentzVector(0,0,-1,1) # In the lab. frame pTop1Ditop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame pTop2Ditop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame pProjDitop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame pTargDitop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame beta = TVector3(0,0,0) xaxis = TVector3(0,0,0) yaxis = TVector3(0,0,0) zaxis = TVector3(0,0,0) mp = 0.93827231 ep = 6500. # Get the muons parameters in the LAB frame pTop1Lab.SetPxPyPzE(p1.Px(),p1.Py(),p1.Pz(),p1.E()) pTop2Lab.SetPxPyPzE(p2.Px(),p2.Py(),p2.Pz(),p2.E()) # Obtain the Ditop parameters in the LAB frame pDitopLab=pTop1Lab+pTop2Lab zaxis=(pDitopLab.Vect()).Unit() # Translate the muon parameters in the Ditop rest frame beta=(-1./pDitopLab.E())*pDitopLab.Vect() if(beta.Mag()>=1.): return 666. pProjLab.SetPxPyPzE(0.,0.,-ep,TMath.Sqrt(ep*ep+mp*mp)) pTargLab.SetPxPyPzE(0.,0.,+ep,TMath.Sqrt(ep*ep+mp*mp)) pProjDitop=pProjLab pTargDitop=pTargLab pProjDitop.Boost(beta) pTargDitop.Boost(beta) yaxis=((pProjDitop.Vect()).Cross(pTargDitop.Vect())).Unit() xaxis=(yaxis.Cross(zaxis)).Unit() pTop1Ditop=pTop1Lab pTop2Ditop=pTop2Lab pTop1Ditop.Boost(beta) pTop2Ditop.Boost(beta) phi = -999. if(charge1>0.): phi = TMath.ATan2((pTop1Ditop.Vect()).Dot(yaxis),(pTop1Ditop.Vect()).Dot(xaxis)) else: phi = TMath.ATan2((pTop2Ditop.Vect()).Dot(yaxis),(pTop2Ditop.Vect()).Dot(xaxis)) return phi
def PhiCS(p1, charge1, p2): # Phi decay angle (top (Q=+2/3)) in the Collins-Soper frame pTop1CM = TLorentzVector(0,0,-1,1) # In the CM frame pTop2CM = TLorentzVector(0,0,-1,1) # In the CM frame pProjCM = TLorentzVector(0,0,-1,1) # In the CM frame pTargCM = TLorentzVector(0,0,-1,1) # In the CM frame pDitopCM = TLorentzVector(0,0,-1,1) # In the CM frame pTop1Ditop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame pTop2Ditop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame pProjDitop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame pTargDitop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame beta = TVector3(0,0,0) yaxisCS = TVector3(0,0,0) xaxisCS = TVector3(0,0,0) zaxisCS = TVector3(0,0,0) mp = 0.93827231 ep = 6500. # Fill the Lorentz vector for projectile and target in the CM frame pProjCM.SetPxPyPzE(0.,0.,-ep,TMath.Sqrt(ep*ep+mp*mp)) pTargCM.SetPxPyPzE(0.,0.,+ep,TMath.Sqrt(ep*ep+mp*mp)) # Get the muons parameters in the CM frame pTop1CM.SetPxPyPzE(p1.Px(),p1.Py(),p1.Pz(),p1.E()) pTop2CM.SetPxPyPzE(p2.Px(),p2.Py(),p2.Pz(),p2.E()) # Obtain the Ditop parameters in the CM frame pDitopCM=pTop1CM+pTop2CM # Translate the Ditop parameters in the Ditop rest frame beta=(-1./pDitopCM.E())*pDitopCM.Vect() if(beta.Mag()>=1): return 666. pTop1Ditop=pTop1CM pTop2Ditop=pTop2CM pProjDitop=pProjCM pTargDitop=pTargCM pTop1Ditop.Boost(beta) pTop2Ditop.Boost(beta) pProjDitop.Boost(beta) pTargDitop.Boost(beta) # Determine the z axis for the CS angle zaxisCS=(((pProjDitop.Vect()).Unit())-((pTargDitop.Vect()).Unit())).Unit() yaxisCS=(((pProjDitop.Vect()).Unit()).Cross((pTargDitop.Vect()).Unit())).Unit() xaxisCS=(yaxisCS.Cross(zaxisCS)).Unit() phi = -999. if(charge1>0.): phi = TMath.ATan2((pTop1Ditop.Vect()).Dot(yaxisCS),((pTop1Ditop.Vect()).Dot(xaxisCS))) else: phi = TMath.ATan2((pTop2Ditop.Vect()).Dot(yaxisCS),((pTop2Ditop.Vect()).Dot(xaxisCS))) if(phi>TMath.Pi()): phi = phi-TMath.Pi() return phi
def CostCS(p1, charge1, p2): #Cosine of the theta decay angle (top (Q=+2/3)) in the Collins-Soper frame pTop1CM = TLorentzVector(0,0,-1,1) # In the CM. frame pTop2CM = TLorentzVector(0,0,-1,1) # In the CM. frame pProjCM = TLorentzVector(0,0,-1,1) # In the CM. frame pTargCM = TLorentzVector(0,0,-1,1) # In the CM. frame pDitopCM = TLorentzVector(0,0,-1,1) # In the CM. frame pTop1Ditop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame pTop2Ditop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame pProjDitop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame pTargDitop = TLorentzVector(0,0,-1,1) # In the Ditop rest frame beta = TVector3(0,0,0) zaxisCS = TVector3(0,0,0) mp = 0.93827231 ep = 6500. # Fill the Lorentz vector for projectile and target in the CM frame pProjCM.SetPxPyPzE(0.,0.,-ep,TMath.Sqrt(ep*ep+mp*mp)) pTargCM.SetPxPyPzE(0.,0.,+ep,TMath.Sqrt(ep*ep+mp*mp)) # Get the Topons parameters in the CM frame pTop1CM.SetPxPyPzE(p1.Px(),p1.Py(),p1.Pz(),p1.E()) pTop2CM.SetPxPyPzE(p2.Px(),p2.Py(),p2.Pz(),p2.E()) # Obtain the Ditop parameters in the CM frame pDitopCM=pTop1CM+pTop2CM # Translate the Ditop parameters in the Ditop rest frame beta=(-1./pDitopCM.E())*pDitopCM.Vect() if(beta.Mag()>=1): return 666. pTop1Ditop=pTop1CM pTop2Ditop=pTop2CM pProjDitop=pProjCM pTargDitop=pTargCM pTop1Ditop.Boost(beta) pTop2Ditop.Boost(beta) pProjDitop.Boost(beta) pTargDitop.Boost(beta) # Determine the z axis for the CS angle zaxisCS=(((pProjDitop.Vect()).Unit())-((pTargDitop.Vect()).Unit())).Unit(); # Determine the CS angle (angle between Top+ and the z axis defined above) cost = -999 if(charge1>0): cost = zaxisCS.Dot((pTop1Ditop.Vect()).Unit()) else: cost = zaxisCS.Dot((pTop2Ditop.Vect()).Unit()) return cost
def fillMETAndDiLeptonBranches(self, event, tau1, tau2, met, met_vars): """Help function to compute variable related to the MET and visible tau candidates, and fill the corresponding branches.""" # MET self.out.met[0] = met.Pt() self.out.metphi[0] = met.Phi() self.out.pfmt_1[0] = sqrt( 2 * self.out.pt_1[0] * met.Pt() * (1 - cos(deltaPhi(self.out.phi_1[0], met.Phi())))) self.out.pfmt_2[0] = sqrt( 2 * self.out.pt_2[0] * met.Pt() * (1 - cos(deltaPhi(self.out.phi_2[0], met.Phi())))) ###self.out.puppimetpt[0] = event.PuppiMET_pt ###self.out.puppimetphi[0] = event.PuppiMET_phi ###self.out.metsignificance[0] = event.MET_significance ###self.out.metcovXX[0] = event.MET_covXX ###self.out.metcovXY[0] = event.MET_covXY ###self.out.metcovYY[0] = event.MET_covYY ###self.out.fixedGridRhoFastjetAll[0] = event.fixedGridRhoFastjetAll # PZETA leg1 = TVector3(tau1.Px(), tau1.Py(), 0.) leg2 = TVector3(tau2.Px(), tau2.Py(), 0.) zetaAxis = TVector3(leg1.Unit() + leg2.Unit()).Unit() pzeta_vis = leg1 * zetaAxis + leg2 * zetaAxis pzeta_miss = met.Vect() * zetaAxis self.out.pzetamiss[0] = pzeta_miss self.out.pzetavis[0] = pzeta_vis self.out.dzeta[0] = pzeta_miss - 0.85 * pzeta_vis # MET SYSTEMATICS for label in self.jecMETlabels: met_var = met_vars[label] getattr(self.out, "met_" + label)[0] = met_var.Pt() getattr(self.out, "pfmt_1_" + label)[0] = sqrt( 2 * self.out.pt_1[0] * met_var.Pt() * (1 - cos(deltaPhi(self.out.phi_1[0], met_var.Phi())))) getattr(self.out, "dzeta_" + label)[0] = met_var.Vect() * zetaAxis - 0.85 * pzeta_vis # DILEPTON self.out.m_vis[0] = (tau1 + tau2).M() self.out.pt_ll[0] = (tau1 + tau2).Pt() self.out.dR_ll[0] = tau1.DeltaR(tau2) self.out.dphi_ll[0] = deltaPhi(self.out.phi_1[0], self.out.phi_2[0]) self.out.deta_ll[0] = abs(self.out.eta_1[0] - self.out.eta_2[0]) self.out.chi[0] = exp(abs(tau1.Rapidity() - tau2.Rapidity()))
def smearing_significance_IP(self, ptc): """Given a particle, smear the IP and compute the track significance and the probability that the track comes from the primary vertex. The smearing is made with a gaussian variable with mean = 0 and sigma = resolution; in addition the smearing is applied to the x' and y' component of the IP, that are the component in a frame in which the vector IP lies on the x'y' plane. """ resolution = self.cfg_ana.resolution(ptc) ptc.path.ip_resolution = resolution #COLIN->NIC: is this just taking the X and Y component? ptc.path.x_prime = ptc.path.vector_impact_parameter.Mag() * math.cos( ptc.path.vector_impact_parameter.Phi()) ptc.path.y_prime = ptc.path.vector_impact_parameter.Mag() * math.sin( ptc.path.vector_impact_parameter.Phi()) ptc.path.z_prime = 0 #COLIN->NIC: is the goal to just do ptc.path.vector_impact_parameter.Perp()? why is that called "rotated?" ptc.path.vector_ip_rotated = TVector3(ptc.path.x_prime, ptc.path.y_prime, ptc.path.z_prime) #COLIN->NIC: shouldn't smearing be done on the magnitude of the impact parameter vector? #in other words, I think that smearing should be correlated on the x and y components. ptc.path.ip_smear_factor_x = random.gauss(0, ptc.path.ip_resolution) ptc.path.ip_smear_factor_y = random.gauss(0, ptc.path.ip_resolution) #COLIN: the resolution should be in the same units as the impact parameter vector (meters?) ptc.path.x_prime_smeared = ptc.path.x_prime + ptc.path.ip_smear_factor_x ptc.path.y_prime_smeared = ptc.path.y_prime + ptc.path.ip_smear_factor_y ptc.path.z_prime_smeared = 0 ptc.path.vector_ip_rotated_smeared = TVector3(ptc.path.x_prime_smeared, ptc.path.y_prime_smeared, ptc.path.z_prime_smeared) #COLIN->NIC It looks like we are keeping the sign of the impact parameter before smearing. Why? # I think that smearing should be able to change the sign. ptc.path.smeared_impact_parameter = ptc.path.vector_ip_rotated_smeared.Mag( ) * ptc.path.sign_impact_parameter ptc.path.significance_impact_parameter = ptc.path.smeared_impact_parameter / ptc.path.ip_resolution #COLIN track probability is about tagging, not impact parameter smearing. do that in a separate JetTag analyzer ptc.path.track_probability = self.track_probability(ptc) if self.cfg_ana.method == 'complex': #COLIN don't we want to do that in all cases? #COLIN remove dependence to cfg_ana by introducing addtl arg to function ptc.path.min_dist_to_jet_significance = ptc.path.sign_impact_parameter\ * ptc.path.min_dist_to_jet.Mag()\ / ptc.path.ip_resolution
def pi0_mass(root_chain): if root_chain.n_showers < 2: return -1 shower_energies = sorted( [e[2] for e in root_chain.shower_energy], reverse=True) shower_ids = [] for i_sh in range(root_chain.n_showers): if root_chain.shower_energy[i_sh][2] in shower_energies: shower_ids.append(i_sh) v_1 = TVector3( root_chain.shower_dir_x[shower_ids[0]], root_chain.shower_dir_y[shower_ids[0]], root_chain.shower_dir_z[shower_ids[0]]) v_2 = TVector3( root_chain.shower_dir_x[shower_ids[1]], root_chain.shower_dir_y[shower_ids[1]], root_chain.shower_dir_z[shower_ids[1]]) cos = v_1.Dot(v_2) / (v_1.Mag() * v_2.Mag()) angle = math.acos(cos) e1 = root_chain.shower_energy[shower_ids[0]][2] e2 = root_chain.shower_energy[shower_ids[1]][2] for i_sh in range(root_chain.n_showers): if i_sh in shower_ids: continue v_x = TVector3( root_chain.shower_dir_x[i_sh], root_chain.shower_dir_y[i_sh], root_chain.shower_dir_z[i_sh]) cos_1 = v_x.Dot(v_1) / (v_x.Mag() * v_1.Mag()) cos_2 = v_x.Dot(v_2) / (v_x.Mag() * v_2.Mag()) if math.acos(cos_1) < math.acos(cos_2): e1 += root_chain.shower_energy[i_sh][2] else: e2 += root_chain.shower_energy[i_sh][2] pi0_mass = math.sqrt(4 * e1 * e2 * (math.sin(angle / 2)**2)) return pi0_mass
def compute_IP_2(self, vertex, jet_direction): self.IP_origin = vertex def distquad(time): x, y, z = self.coord_at_time(time) dist2 = (x - vertex.x())**2 + (y - vertex.y())**2 + (z - vertex.z())**2 return dist2 minim_answer = scipy.optimize.minimize_scalar( distquad, bracket=[-0.5e-14, 0.5e-14], # bounds = [-1e-11, 1e-11], args=(), # method='bounded', tol=1e-12, # options={'disp': 0, 'maxiter': 1e5, 'xatol': 1e-20} ) self.IP_t = minim_answer.x self.IP_vector = self.point_at_time(self.IP_t) - vertex jet_direction = jet_direction.Unit() self.IP_sign = self.IP_vector.Dot(jet_direction) if self.IP_sign == 0: self.IP_sign = 1 self.IP = self.IP_vector.Mag() * sign(self.IP_sign) x, y, z = self.coord_at_time(self.IP_t) self.IP_coord = TVector3(x, y, z) return self.IP
def compute_IP(self, vertex, jet): '''find the impact parameter of the trajectory with respect to a given point (vertex). The impact parameter has the same sign as the scalar product of the vector pointing from the given vertex to the point of closest approach with the given jet direction. new attributes : * closest_t = time of closest approach to the primary vertex. * IP = signed impact parameter * IPcoord = TVector3 of the point of closest approach to the primary vertex ''' self.vertex_IP = vertex def distquad(time): x, y, z = self.coord_at_time(time) dist2 = (x-vertex.x())**2 + (y-vertex.y())**2\ + (z-vertex.z())**2 return dist2 minim_answer = opti.bracket(distquad, xa=-0.5e-14, xb=0.5e-14) self.closest_t = minim_answer[1] vector_IP = self.point_at_time(minim_answer[1]) - vertex Pj = jet.p4().Vect().Unit() signIP = vector_IP.Dot(Pj) self.IP = minim_answer[4]**(1.0 / 2) * sign(signIP) x, y, z = self.coord_at_time(minim_answer[1]) self.IPcoord = TVector3(x, y, z)
def test2TVector3(self): """Verify that using one operator* overload does not mask the others""" # ROOT-10278 if exp_pyroot: v = TVector3(1., 2., 3.) v * 2 self.assertEqual(v * v, 14.0)