#!/usr/bin/env python import sys from ROOT import gROOT, gStyle, TFile, TTree, TCanvas, gDirectory, TH1, TGraph, gPad, TF1 c = TCanvas("c","c",1200,900); c.Print("low_x.pdf[") gROOT.SetBatch(True) gStyle.SetOptFit(1) gStyle.SetStatW(0.2) gStyle.SetStatH(0.1) # The "magic cut" that cleans up the mass distribution is using truth information to require p(A')>0.8*Ebeam (in addition to the same cut on the reconstructed pair). This gives you a much more symmetric mass distribution. # The reason this cut works is that there is a significant population of A' generated at low x, where the detector and recon pick up the daughter positron and the recoil e-. # This contamination is O(10%) in these plots (with minimal cuts), probably less after standard analysis cuts. # This magic cut is obviously cheating, since there's no simple/clean equivalent cut in data. # In my thesis analysis I used this cut when calculating acceptance and mass resolution. # The main reason was that without the cut, the acceptance vs. Z fits are harder (the decay Z distribution is no longer a clean exponential because the A' don't all have the same boost) # The right thing to do is to replace this with a mass cut. # It might be possible to find a cut in data specific to these events (maybe in vertexing? the recoil e- will point back to the target, the e+ will not - similar to a L1 WAB conversion) but not easy. # this file is available at http://www.slac.stanford.edu/~meeg/hps3/users/meeg/vertexing/acceptance/apsignal_displaced_60_dq_tri.root # 60 MeV A', truth tuple after reconstruction inFile = TFile("apsignal_displaced_60_dq_tri.root") ntuple = inFile.Get("ntuple") ntuple.SetAlias("corrM","uncM-0.15e-3*(elePX/eleP-posPX/posP)*uncVZ/uncM") #"-0.15e-3*(elePX/eleP-posPX/posP)*uncVZ/uncM" is an empirical correction to the misreconstructed mass from the vertexer #triEndZ is the true decay Z, a cut at 5 selects near-prompt A' #triP is the truth momentum of the 622 particle (i.e. the A' momentum thrown by MadGraph) ntuple.Draw("corrM-0.06:triEndZ>>h(100,-10,100,100,-0.04,0.04)","uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("uncP/Ebeam>0.8;decay Z [mm];mass residual [GeV]") gPad.SetLogy(0) c.Print("low_x.pdf") ntuple.Draw("corrM-0.06:triEndZ>>h(100,-10,100,100,-0.04,0.04)","triP>0.8*1.056&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("p(A')/Ebeam>0.8, uncP/Ebeam>0.8;decay Z [mm];mass residual [GeV]") gPad.SetLogy(0) c.Print("low_x.pdf") # anticut ntuple.Draw("corrM-0.06:triEndZ>>h(100,-10,100,100,-0.04,0.04)","triP<0.8*1.056&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("p(A')/Ebeam<0.8, uncP/Ebeam>0.8;decay Z [mm];mass residual [GeV]") gPad.SetLogy(0) c.Print("low_x.pdf") ntuple.Draw("corrM-0.06>>h(100,-0.04,0.04)","triEndZ<5&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("prompt A', uncP/Ebeam>0.8;mass residual [GeV]") gDirectory.Get("h").Fit("gaus","","",-0.005,0.005) gPad.SetLogy(1) c.Print("low_x.pdf") # after the magic cut ntuple.Draw("corrM-0.06>>h(100,-0.04,0.04)","triEndZ<5&&triP>0.8*1.056&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("prompt A', p(A')/Ebeam>0.8, uncP/Ebeam>0.8;mass residual [GeV]") gDirectory.Get("h").Fit("gaus","","",-0.005,0.005) gPad.SetLogy(1) c.Print("low_x.pdf") # anticut ntuple.Draw("corrM-0.06>>h(100,-0.04,0.04)","triEndZ<5&&triP<0.8*1.056&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("prompt A', p(A')/Ebeam<0.8, uncP/Ebeam>0.8;mass residual [GeV]") gDirectory.Get("h").Fit("gaus","","",-0.005,0.005) gPad.SetLogy(1) c.Print("low_x.pdf") gStyle.SetOptStat(0) ntuple.Draw("corrM-0.06:triP/1.056>>h(100,0,1.1,100,-0.04,0.04)","triEndZ<5&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("prompt A', uncP/Ebeam>0.8;p(A')/Ebeam;mass residual [GeV]") gPad.SetLogy(0) c.Print("low_x.pdf") # high p(A') events have good correlation between truth and recon p(e+e-); low p(A') events are uncorrelated ntuple.Draw("uncP/1.056:triP/1.056>>h(100,0,1.1,100,0.5,1.1)","triEndZ<5&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("prompt A', uncP/Ebeam>0.8;p(A')/Ebeam;uncP/Ebeam") gPad.SetLogy(0) c.Print("low_x.pdf") ntuple.Draw("uncP/1.056:triP/1.056>>h(100,0,1.1,100,0,1.1)","triEndZ<5","colz") gDirectory.Get("h").SetTitle("prompt A', uncP/Ebeam>0.8;p(A')/Ebeam;uncP/Ebeam") gPad.SetLogy(0) c.Print("low_x.pdf") ntuple.Draw("triPosP/1.056:triP/1.056>>h(100,0,1.1,100,0,1.1)","triEndZ<5&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("prompt A', uncP/Ebeam>0.8;p(A')/Ebeam;p(e+ from A' decay)/Ebeam") gPad.SetLogy(0) c.Print("low_x.pdf") ntuple.Draw("triEle1P/1.056:triP/1.056>>h(100,0,1.1,100,0,1.1)","triEndZ<5&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("prompt A', uncP/Ebeam>0.8;p(A')/Ebeam;p(e- from A' decay)/Ebeam") gPad.SetLogy(0) c.Print("low_x.pdf") # in low p(A') events, p(recon e-)+p(a')=Ebeam, this proves we're picking up the recoil e- ntuple.Draw("eleP/1.056:triP/1.056>>h(100,0,1.1,100,0,1.1)","triEndZ<5&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("prompt A', uncP/Ebeam>0.8;p(A')/Ebeam;p(reconstructed e-)/Ebeam") gPad.SetLogy(0) c.Print("low_x.pdf") # two populations of events: truth and recon p(e-) match, or truth p(e-) is much lower (we are picking the wrong e-) ntuple.Draw("triEle1P/1.056:eleP/1.056>>h(100,0,1.1,100,0,1.1)","triEndZ<5&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("prompt A', uncP/Ebeam>0.8;p(reconstructed e-)/Ebeam;p(e- from A' decay)/Ebeam") gPad.SetLogy(0) c.Print("low_x.pdf") # use the difference between truth and recon p(e-) as a proxy for "are we picking the correct e-": events with the wrong e- have broad, negative mass residual distribution ntuple.Draw("corrM-0.06:(eleP-triEle1P)/1.056>>h(100,-0.5,1.1,100,-0.04,0.04)","triEndZ<5&&uncP>0.8*1.056","colz") gDirectory.Get("h").SetTitle("prompt A', uncP/Ebeam>0.8;p(reconstructed e-)-p(e- from A' decay)/Ebeam;mass residual [GeV]") gPad.SetLogy(0) c.Print("low_x.pdf") c.Print("low_x.pdf]")