def main(): """ Make sure that the numpy histograms I'm using match the ROOT histogram class output. Examples: - Matching wl.GetHisto to a TH1D - Matching wl.npTH1D to a TH1D - Filling the bins of a TH1D manually """ # start with 100 random values, from 0 to 10 r = 10 * np.random.rand(100) # bin from 0 to 10 in intervals of 1 (11 bins. nB = 10 b/c it is 0-indexed) xLo, xHi, xpb = 0, 10, 1 nB = int((xHi - xLo) / xpb) # make the TH1D purely w/ ROOT stuff c = TCanvas() th1 = TH1D("th", "", nB, xLo, xHi) for v in r: th1.Fill(v) # 1. getHisto and npTH1D x1, y1 = wl.GetHisto(r, xLo, xHi, xpb, shift=False) plt.plot(x1, y1, ls='steps', c='b', lw=6) plt.axvline(1, c='g', lw=1) x2, y2, xpb2 = wl.npTH1D(th1) plt.plot(x2, y2, ls='steps', c='r', lw=4) # 2. manually fill each histogram bin to match some known curve (used for pdfs) th2 = TH1D("t2", "t2", nB, xLo, xHi) # the +1 is very important, it covers the last bin for iB in range(nB + 1): ctr = (iB + 0.5) * xpb + xLo bLo, bHi = ctr - xpb / 2, ctr + xpb / 2 idx = np.where((x2 >= bLo) & (x2 < bHi)) hCts = np.sum(y2[idx]) th2.SetBinContent(iB, hCts) th1.SetLineColor(ROOT.kBlue) th2.SetLineColor(ROOT.kRed) th1.SetLineWidth(2) th1.Draw("hist") th2.Draw("hist same") c.Print("../plots/htmp.pdf") x3, y3, xpb3 = wl.npTH1D(th2) plt.plot(x3, y3, ls='steps', c='g', lw=2) plt.xlim(xLo, xHi) plt.tight_layout() plt.savefig("../plots/hnp.pdf")
def MakeCutPlot(c,cal,var,eb,elo,ehi,vb,vlo,vhi,d2Cut,d1Cut,outPlot,fastMode): """ Creates a channel-specific energy calibration plot. """ # Calculate cut vals (assumes plot range is correct) h1 = wl.H1D(cal,vb,vlo,vhi,var,d1Cut) h1Sum = h1.Integral() if h1Sum == 0: print "Error: Failed %s, histogram sum is 0 so cannot normalize, setting to [0,0,0,0,0]"%(var) return 0,0,0,0,0 h1.Scale(1/h1Sum) try: cut99,cut95,cut01,cut05,cut90 = wl.GetIntegralPoints(h1) except: print "Error: Failed %s using cut %s, setting to [0,0,0,0,0]"%(var,d1Cut) return 0,0,0,0,0 if fastMode: print "Returning fastMode output: ", cut99,cut95,cut01,cut05,cut90 return cut99,cut95,cut01,cut05,cut90 # Generate the plot for inspection. c.cd(2) gPad.SetLogy(0) h1.GetXaxis().SetRangeUser(cut01-abs(0.25*cut01), cut99 + abs(0.25*cut99) ) h1.SetTitle("") h1.GetXaxis().SetTitle(var) h1.Draw("hist") c.cd(1) gPad.SetLogy(0) cal.Draw("%s:trapENFCal>>b(%d,%d,%d,%d,%.3E,%.3E)"%(var,eb+10,elo-5,ehi+5,vb,cut01-abs(0.25*cut01),cut99+abs(0.25*cut99)) ,d2Cut) l1, l2, l3 = TLine(), TLine(), TLine() l1.SetLineColor(ROOT.kGreen) l2.SetLineColor(ROOT.kRed) l3.SetLineColor(ROOT.kMagenta) l1.DrawLine(elo-5, cut99, ehi+5, cut99) l2.DrawLine(elo-5, cut95, ehi+5, cut95) l2.DrawLine(elo-5, cut05, ehi+5, cut05) l1.DrawLine(elo-5, cut01, ehi+5, cut01) c.cd(3) x_h1, y_h1 = wl.npTH1D(h1) int_h1 = wl.integFunc(y_h1) g2 = TGraph(len(x_h1), x_h1, int_h1) g2.GetXaxis().SetRangeUser(cut01-abs(0.3*cut01), cut99 + abs(0.3*cut99) ) g2.SetTitle("") g2.GetXaxis().SetTitle(var) g2.GetYaxis().SetTitle("Percentile") g2.Draw("ACP") l1.DrawLine(cut99, 0, cut99, 1) l2.DrawLine(cut95, 0, cut95, 1) l1.DrawLine(cut01, 0, cut01, 1) l2.DrawLine(cut05, 0, cut05, 1) c.Print(outPlot) return cut99,cut95,cut01,cut05,cut90
def sp_correction(): from ROOT import TFile, TH1D tf = TFile("../data/lat-expo-efficiency-corr.root") surfPerc = tf.Get("surfPerc") xSp, ySp, xpb = wl.npTH1D(surfPerc) plt.plot(xSp, ySp, ls='steps') # plt.show() # brian's cal_det_pairs data directory "/global/projecta/projectdirs/majorana/users/bxyzhu/LATv2"
def MakeCutPlot(c, cal, var, eb, elo, ehi, vb, vlo, vhi, d2Draw, d2Cut, d1Cut, outPlot, fastMode): """ Repeated code is the DEVIL. Even if you have to pass in 1,000,000 arguments. """ # Calculate cut vals (assumes plot range is correct) h1 = wl.H1D(cal, vb, vlo, vhi, var, d1Cut) h1Sum = h1.Integral() if h1Sum == 0: return 0, 0, 0, 0, 0 h1.Scale(1 / h1Sum) cut99, cut95, cut01, cut05, cut90 = wl.GetIntegralPoints(h1) if fastMode: return cut99, cut95, cut01, cut05, cut90 # Generate the plot for inspection. c.cd(2) gPad.SetLogy(0) h1.Draw("hist") c.cd(1) gPad.SetLogy(0) cal.Draw(d2Draw, d2Cut) l1, l2 = TLine(), TLine() l1.SetLineColor(ROOT.kGreen) l2.SetLineColor(ROOT.kRed) l1.DrawLine(elo, cut99, ehi, cut99) l2.DrawLine(elo, cut95, ehi, cut95) l2.DrawLine(elo, cut05, ehi, cut05) l1.DrawLine(elo, cut01, ehi, cut01) c.cd(3) x_h1, y_h1 = wl.npTH1D(h1) int_h1 = wl.integFunc(y_h1) g2 = TGraph(len(x_h1), x_h1, int_h1) g2.Draw("ACP") l1.DrawLine(cut99, 0, cut99, 1) l2.DrawLine(cut95, 0, cut95, 1) l1.DrawLine(cut01, 0, cut01, 1) l2.DrawLine(cut05, 0, cut05, 1) c.Print(outPlot) return cut99, cut95, cut01, cut05, cut90
def getProfile(idx=None, update=False): from ROOT import TFile, TCanvas from ROOT import RooStats as RS f = TFile("%s/data/fitWorkspace.root" % dsi.latSWDir) fitWorkspace = f.Get("fitWorkspace") fData = fitWorkspace.allData().front() hitE = fitWorkspace.var("trapENFCal") model = fitWorkspace.pdf("model") fitResult = fitWorkspace.allGenericObjects().front() fPars = fitResult.floatParsFinal() nPars = fPars.getSize() # === get fit results: {name : [nCts, err]} === fitVals = {} for i in range(nPars): fp = fitResult.floatParsFinal() name = fp.at(i).GetName() fitVal, fitErr = fp.at(i).getValV(), fp.at(i).getError() if "amp" in name: # fitVals[name.split('-')[1]] = [fitVal, fitErr] fitVals[name] = [fitVal, fitErr, name.split('-')[1]] # for f in fitVals: # print(f, fitVals[f]) # === get "true" counts (reverse efficiency correction based on fit value) === hAx = getHistList("axion") x, y, xpb = wl.npTH1D(hAx) x, y = normPDF(x, y, eLo, eHi) nCts, nErr, _ = fitVals["amp-axion"] # fit result yc = nCts * getEffCorr(x, y, inv=True) nCorr = np.sum(yc) effCorr = nCorr / nCts print("nCts %d nCorr %.2f effCorr %.2f" % (nCts, nCorr, effCorr)) # thesis plot, don't delete # plt.step(x, y * nCts * (epb/xpb), c='r', lw=2, label="Eff-weighted: %.1f" % (nCts)) # plt.step(x, yc * (epb/xpb), c='b', lw=2, label="True counts: %.1f" % (nCorr)) # plt.xlabel("Energy (keV)", ha='right', x=1) # plt.ylabel("Counts / keV", ha='right', y=1) # plt.legend(loc=1) # plt.tight_layout() # plt.show() tMode = "UPDATE" if update else "RECREATE" tOut = TFile("%s/data/rs-plc.root" % dsi.latSWDir, "UPDATE") start = time.clock() name = "amp-axion" fitVal = fitVals[name][0] thisVar = fitWorkspace.var(name) pCL = 0.9 plc = RS.ProfileLikelihoodCalculator(fData, model, ROOT.RooArgSet(thisVar)) plc.SetConfidenceLevel(0.90) interval = plc.GetInterval() lower = interval.LowerLimit(thisVar) upper = interval.UpperLimit(thisVar) plot = RS.LikelihoodIntervalPlot(interval) plot.SetNPoints(50) plot.Draw("tf1") pName = "hP_%d" if idx is not None else "hP" hProfile = plot.GetPlottedObject() hProfile.SetName(pName) hProfile.SetTitle("PL %.2f %s lo %.3f mid %.3f hi %.3f eC %.3f" % (pCL, name, lower, fitVal, upper, effCorr)) hProfile.Write() print(hProfile.GetTitle()) tOut.Close() print("elapsed:", time.clock() - start)
def plotFit(plotRate=False): from ROOT import TFile, TCanvas, TH1D, TLegend, gStyle f = TFile("%s/data/fitWorkspace.root" % dsi.latSWDir) fitWorkspace = f.Get("fitWorkspace") fData = fitWorkspace.allData().front() fitResult = fitWorkspace.allGenericObjects().front() nPars = fitResult.floatParsFinal().getSize() hitE = fitWorkspace.var("trapENFCal") model = fitWorkspace.pdf("model") nData = fData.numEntries() fCov = fitResult.covQual() # fitWorkspace.Print() # === get fit results: {name : [nCts, err]} === fitVals = {} for i in range(nPars): fp = fitResult.floatParsFinal() name = fp.at(i).GetName() fitVal, fitErr = fp.at(i).getValV(), fp.at(i).getError() if "amp" in name: fitVals[name.split('-')[1]] = [fitVal, fitErr] # for f in fitVals: # print(f, fitVals[f]) # === make a rooplot of the fit === leg = TLegend(0.83, 0.5, 0.97, 0.9) gStyle.SetPalette(ROOT.kRainBow) nCol = float(gStyle.GetNumberOfColors()) fSpec = hitE.frame(RF.Range(eLo, eHi), RF.Bins(nB)) fData.plotOn(fSpec) for i, name in enumerate(bkgModel): pdfName = "ext-" + name col = gStyle.GetColorPalette(int(nCol / len(bkgModel) * i)) model.plotOn(fSpec, RF.Components(pdfName), RF.LineColor(col), RF.LineStyle(ROOT.kDashed), RF.Name(name)) leg.AddEntry(fSpec.findObject(name), name, "l") chiSquare = fSpec.chiSquare(nPars) model.plotOn(fSpec, RF.LineColor(ROOT.kRed), RF.Name("fmodel")) leg.AddEntry(fSpec.findObject("fmodel"), "Full Model, #chi^{2}/NDF = %.3f" % chiSquare, "l") c = TCanvas("c", "c", 1400, 1000) fSpec.SetTitle("") fSpec.Draw() leg.Draw("same") c.Print("%s/plots/sf-after.pdf" % dsi.latSWDir) c.Clear() # === duplicate the rooplot in matplotlib === plt.close() tf = TFile("%s/data/latDS%s.root" % (dsi.latSWDir, ''.join([str(d) for d in dsList]))) tt = tf.Get("skimTree") tCut = "isEnr==1" if enr is True else "isEnr==0" tCut = "isEnr" if enr else "!isEnr" tCut += " && trapENFCal >= %.1f && trapENFCal <= %.1f" % (eLo, eHi) n = tt.Draw("trapENFCal", tCut, "goff") trapE = tt.GetV1() trapE = [trapE[i] for i in range(n)] x, hData = wl.GetHisto(trapE, eLo, eHi, epb) if plotRate: hErr = np.asarray([np.sqrt(h) / detExp for h in hData]) # statistical error plt.errorbar(x, hData / detExp, yerr=hErr, c='k', ms=5, linewidth=0.5, fmt='.', capsize=1, zorder=1) else: hErr = np.asarray([np.sqrt(h) for h in hData]) # statistical error plt.errorbar(x, hData, yerr=hErr, c='k', ms=5, linewidth=0.5, fmt='.', capsize=1, zorder=1) # get the list of histograms and plot the components hList = getHistList() cmap = plt.cm.get_cmap('jet', len(hList) + 2) pdfs, pdfsCorr, nTot, nTotC = [], [], 0, 0 for i, h in enumerate(hList): name = h[1] x, y, xpb = wl.npTH1D(h[0]) x, y = normPDF(x, y, eLo, eHi) nCts, nErr = fitVals[name] # final result yc = nCts * getEffCorr(x, y, inv=True) if abs(nCts - np.sum(y * nCts)) > 2: print("norm error, %s nCts %d y*nCts %d" % (name, nCts, np.sum(y * nCts))) # plt.step(x, y * nCts * (epb/xpb), c=cmap(i), lw=2, label="%s cts: %.2f±%.2f" % (name, nCts, nErr)) # plot the histo xS = np.arange(eLo, eHi, 0.001) # plot a smoothed version yS = spline(x - xpb / 2, y, xS) if plotRate: plt.plot(xS, yS * nCts * (epb / xpb) / detExp, "--", c=cmap(i), lw=2, label="%s %.2f ± %.2f" % (name, nCts / detExp, nErr / detExp)) else: plt.plot(xS, yS * nCts * (epb / xpb), c=cmap(i), lw=2, label="%s cts: %d" % (name, nCts)) pdfs.append([x, y, xpb, nCts]) pdfsCorr.append([x, yc, xpb, nCts]) nTot += nCts nTotC += np.sum( yc ) # reverse the efficiency correction to get the "true" number of counts # get the fit model, and the efficiency-corrected final model xT, yT = getTotalModel(pdfs, eLo, eHi, epb, smooth=True) xTc, yTc = getTotalModel(pdfsCorr, eLo, eHi, epb, smooth=True, amp=False) if plotRate: plt.plot(xT, yT / detExp, 'r', lw=2, alpha=0.7, label="Rate: %.2f" % (nTot / detExp)) plt.plot(xTc, yTc / detExp, c='m', lw=3, alpha=0.7, label="Eff.corr: %.2f " % (nTotC / detExp)) plt.ylabel("Counts / keV / kg-d", ha='right', y=1) else: plt.plot(xT, yT, 'r', lw=2, alpha=0.7, label="Raw (no eff. corr): %d cts" % nTot) plt.plot(xTc, yTc, c='m', lw=3, alpha=0.7, label="Efficiency corrected: %d cts" % nTotC) plt.ylabel("Counts / %.1f keV" % epb, ha='right', y=1) plt.xlabel("Energy (keV)", ha='right', x=1) plt.legend(loc=1, fontsize=12) plt.xticks(np.arange(int(eLo) - 1, eHi + 1, 5)) plt.xlim(eLo, eHi) plt.ylim(ymin=0) plt.tight_layout() # plt.show() plt.savefig("%s/plots/sf-after-mpl.pdf" % dsi.latSWDir)
def fitModel(makePlots=False): from ROOT import TFile, TH1D, TCanvas, TLegend, gStyle # === load data into workspace === tf = TFile("%s/data/latDS%s.root" % (dsi.latSWDir, ''.join([str(d) for d in dsList]))) tt = tf.Get("skimTree") tCut = "isEnr==1" if enr is True else "isEnr==0" hitE = ROOT.RooRealVar("trapENFCal", "Energy", eLo, eHi, "keV") hEnr = ROOT.RooRealVar("isEnr", "isEnr", 0, 1, "") # hitW = ROOT.RooRealVar("weight", "weight", 1, 1000, "") fData = ROOT.RooDataSet("data", "data", tt, ROOT.RooArgSet(hitE, hEnr), tCut) # fData = ROOT.RooDataSet("data", "data", tt, ROOT.RooArgSet(hitE, hEnr, hitW), "", "weight") fitWorkspace = ROOT.RooWorkspace("fitWorkspace", "Fit Workspace") getattr(fitWorkspace, 'import')(hitE) getattr(fitWorkspace, 'import')(fData) # getattr(fitWorkspace,'import')(fWeight) tf2 = TFile("%s/data/specPDFs.root" % dsi.latSWDir) pdfList = ROOT.RooArgList("shapes") # === background model === hList = getHistList() bkgList = [] for h in hList: hB, name = h[0], h[1] pars = bkgVals[name] bkN = ROOT.RooRealVar("amp-" + name, "amp-" + name, pars[1], pars[2], pars[3]) bkDH = ROOT.RooDataHist("dh-" + name, "dh-" + name, ROOT.RooArgList(hitE), RF.Import(hB)) bkPDF = ROOT.RooHistPdf("pdf-" + name, "pdf-" + name, ROOT.RooArgSet(hitE), bkDH, 2) bkExt = ROOT.RooExtendPdf("ext-" + name, "ext-" + name, bkPDF, bkN) hitE.setRange(eLo, eHi) bkgList.append([bkExt, name, bkN, bkDH, bkPDF]) # this is separate b/c all the RooVars have to remain in memory for bkg in bkgList: pdfList.add(bkg[0]) model = ROOT.RooAddPdf("model", "total PDF", pdfList) if makePlots: # === make a rooplot of the initial guess parameters, don't let roofit normalize automatically leg = TLegend(0.83, 0.5, 0.97, 0.9) gStyle.SetPalette(ROOT.kRainBow) nCol = float(gStyle.GetNumberOfColors()) fSpec = hitE.frame(RF.Range(eLo, eHi), RF.Bins(nB)) fData.plotOn(fSpec) # wouter's note: DON'T DELETE # "the default behavior is when you plot a p.d.f. on an empty frame it is # plotted with unit normalization. When you plot it on a frame with data in # it, it will normalize to the number of events in that dataset." # (then after you do a fit, the pdf normalization changes again ...) nData = fData.numEntries() nTot = 0 for i, ext in enumerate(bkgList): extPDF, name = ext[0], ext[1] col = gStyle.GetColorPalette(int(nCol / len(bkgList) * i)) extPDF.plotOn( fSpec, RF.LineColor(col), RF.Normalization(bkgVals[name][1], ROOT.RooAbsReal.Raw), RF.Name(name)) leg.AddEntry(fSpec.findObject(name), name, "l") nTot += bkgVals[name][1] model.plotOn(fSpec, RF.LineColor(ROOT.kRed), RF.Name("fmodel"), RF.Normalization(nTot, ROOT.RooAbsReal.Raw)) leg.AddEntry(fSpec.findObject("fmodel"), "Full Model", "l") c = TCanvas("c", "c", 1400, 1000) fSpec.SetTitle("") fSpec.Draw() leg.Draw("same") c.Print("%s/plots/sf-before.pdf" % dsi.latSWDir) c.Clear() # === make a pyplot of the same thing tCut = "isEnr" if enr else "!isEnr" tCut += " && trapENFCal >= %.1f && trapENFCal <= %.1f" % (eLo, eHi) n = tt.Draw("trapENFCal", tCut, "goff") trapE = tt.GetV1() trapE = [trapE[i] for i in range(n)] x, hData = wl.GetHisto(trapE, eLo, eHi, epb) hErr = np.asarray([np.sqrt(h) for h in hData]) plt.errorbar(x, hData, yerr=hErr, c='k', ms=5, linewidth=0.5, fmt='.', capsize=1, zorder=1) # pretty convincing rooplot fake cmap = plt.cm.get_cmap('jet', len(hList) + 2) pdfs = [] for i, h in enumerate(hList): name = h[1] x, y, xpb = wl.npTH1D(h[0]) x, y = normPDF(x, y, eLo, eHi) nCts = bkgVals[h[1]][1] # the initial guess if abs(nCts - np.sum(y * nCts)) > 2: print("norm error, %s nCts %d y*nCts %d" % (name, nCts, np.sum(y * nCts))) # plt.step(x, y * nCts / xpb, c=cmap(i), lw=2, label="%s init cts: %d" % (name, nCts)) # plot the histo xS = np.arange(eLo, eHi, 0.001) # plot a smoothed version yS = spline(x - xpb / 2, y, xS) plt.plot(xS, yS * nCts / xpb, c=cmap(i), lw=2, label="%s init cts: %d" % (name, nCts)) pdfs.append([x, y, xpb, nCts]) xT, yT = getTotalModel(pdfs, eLo, eHi, epb, smooth=True) plt.step(xT, yT / epb, c='r', lw=2, label="Raw (no eff. corr): %d cts" % nTot) plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Counts / %.1f keV" % epb, ha='right', y=1) plt.legend(loc=1, fontsize=12) plt.xlim(eLo, eHi) plt.ylim(ymin=0) plt.tight_layout() # plt.show() plt.savefig("%s/plots/sf-before-mpl.pdf" % dsi.latSWDir) # === alright, now run the fit and output to the workspace minimizer = ROOT.RooMinimizer( model.createNLL(fData, RF.NumCPU(2, 0), RF.Extended(True))) minimizer.setPrintLevel(-1) minimizer.setStrategy(2) minimizer.migrad() fitResult = minimizer.save() # according to the internet, covQual==3 is a good indicator that it converged print("Fitter is done. Fit Cov Qual:", fitResult.covQual()) # save workspace to a TFile getattr(fitWorkspace, 'import')(fitResult) getattr(fitWorkspace, 'import')(model) tf3 = TFile("%s/data/fitWorkspace.root" % dsi.latSWDir, "RECREATE") fitWorkspace.Write() tf3.Close()
def getUnscaledPDFs(ma=0, makePlots=False): """ Generate a set of TH1D's to be turned into RooDataHist objects. Be careful they have the same axis limits and binning as the RooDataSet. Takes axion mass (in keV) as a parameter. """ from ROOT import TFile, TH1D # output files rOut = "%s/data/specPDFs.root" % dsi.latSWDir tf = TFile(rOut, "RECREATE") td = gROOT.CurrentDirectory() # print("Generating unscaled PDFs, eLo %.1f eHi %.1f epb %.2f: %s" % (eLo, eHi, epb, rOut)) # === 1. axion flux # axion flux scale. # NOTE: to do the fit and set a new limit, we set g_ae=1. # To plot an expected flux, we would use a real value. # Redondo's note: I calculated the flux using gae = 0.511*10^-10 # for other values of gae use: FLUX = Table*[gae/(0.511*10^-10)]^2 gae = 1 gRat = (gae / 5.11e-11) redondoScale = 1e19 * gRat**2 # convert table to [flux / (keV cm^2 d)] axData = [] with open("%s/data/redondoFlux.txt" % dsi.latSWDir) as f1: # 23577 entries lines = f1.readlines()[11:] for line in lines: data = line.split() axData.append([float(data[0]), float(data[1])]) axData = np.array(axData) def sig_ae(E, m): """ E, m are in units of keV. must multiply result by sig_pe """ beta = (1 - m**2. / E**2.)**(1. / 2) return (1 - (1. / 3.) * beta**(2. / 3.)) * (3. * E**2.) / (16. * np.pi * (1. / 137.) * 511.**2. * beta) # === 2. ge photoelectric xs phoData = [] with open("%s/data/ge76peXS.txt" % dsi.latSWDir) as f2: # 2499 entries, 0.01 kev intervals lines = f2.readlines() for line in lines: data = line.split() phoData.append([float(data[0]), float(data[1])]) phoData = np.array(phoData) # === 3. tritium tritData = [] with open("%s/data/TritiumSpectrum.txt" % dsi.latSWDir) as f3: # 20000 entries lines = f3.readlines()[1:] for line in lines: data = line.split() conv = float(data[2]) # raw spectrum convolved w/ ge cross section if conv < 0: conv = 0. tritData.append([float(data[1]), conv]) tritData = np.array(tritData) # NOTE: check sandbox/th1.py for examples of manually filling TH1D's and verifying wl.GetHisto and wl.npTH1D. # ROOT output h1 = TH1D("h1", "photoelectric", nBP, pLo, pHi) # [cm^2 / kg] h2 = TH1D("h2", "axioelectric", nBP, pLo, pHi) # [cm^2 / kg] h3 = TH1D("h3", "axion flux, gae=1", nBP, pLo, pHi) # [cts / (keV cm^2 d)] h4 = TH1D("h4", "convolved flux", nBP, pLo, pHi) # [cts / (keV d kg)] h5 = TH1D("h5", "tritium", nBP, pLo, pHi) # [cts] (normalized to 1) # manually fill ROOT histos (don't normalize yet) for iB in range(nBP + 1): ctr = (iB + 0.5) * ppb + pLo bLo, bHi = ctr - ppb / 2, ctr + ppb / 2 with warnings.catch_warnings(): warnings.simplefilter("ignore", category=RuntimeWarning) # if ma>0, we ignore entries with E <= m. # photoelectric x-section [cm^2 / kg] idx = np.where((phoData[:, 0] >= bLo) & (phoData[:, 0] < bHi)) pho = np.mean(phoData[idx][:, 1]) * 1000 if np.isnan(pho) or len(phoData[idx][:, 1]) == 0: pho = 0. if phoData[idx][:, 1].any() <= ma: pho = 0. h1.SetBinContent(iB + 1, pho) # axioelectric x-section [cm^2 / kg] if ctr > ma: axio = pho * sig_ae(ctr, ma) else: axio = 0. h2.SetBinContent(iB + 1, axio) # axion flux [flux / (cm^2 d keV)] idx = np.where((axData[:, 0] >= bLo) & (axData[:, 0] < bHi)) flux = np.mean(axData[idx][:, 1]) * redondoScale if np.isnan(flux): flux = 0. h3.SetBinContent(iB + 1, flux) # YES, adding 1 here. keeps the 6.6 keV line in the proper place for all binnings. # it must have to do w/ the way i'm reading in the data from the text files ... # axion flux PDF [flux / (keV d kg)] axConv = axio * flux h4.SetBinContent(iB + 1, axConv) # tritium idx = np.where((tritData[:, 0] >= bLo) & (tritData[:, 0] <= bHi)) trit = np.mean(tritData[idx][:, 1]) if np.isnan(trit): trit = 0. h5.SetBinContent(iB + 1, trit) # Pb210 (from separate file) tf2 = TFile("%s/data/Pb210PDFs.root" % dsi.latSWDir) h6 = tf2.Get("hPb210TDL") # with TDL h7 = tf2.Get("hPb210") # without TDL h6.SetName("h6") h7.SetName("h7") if makePlots: # === 1. verify the numpy histogram and ROOT histogram give the same output. OK x, h210, xpb = wl.npTH1D(h7) iE = np.where((x > 45) & (x < 48)) plt.plot(x[iE], h210[iE], ls='steps', lw=3, c='b') plt.xlabel("Energy (keV)", ha='right', x=1) plt.tight_layout() plt.savefig("%s/plots/sf-pk210.pdf" % dsi.latSWDir) from ROOT import TCanvas c = TCanvas() h7.GetXaxis().SetTitle("Energy (keV)") h7.GetXaxis().SetRangeUser(45, 48) h7.Draw('hist') c.Print('%s/plots/sf-pb210th1d.pdf' % dsi.latSWDir) # === 2. print ROOT histos to match w/ numpy histos c.Clear() h1.Draw("hist") c.Print("%s/plots/root-sigGe.pdf" % dsi.latSWDir) c.Clear() h2.Draw("hist") c.Print("%s/plots/root-sigAe.pdf" % dsi.latSWDir) c.Clear() h3.Draw("hist") c.Print("%s/plots/root-axFlux.pdf" % dsi.latSWDir) c.Clear() h4.Draw("hist") c.Print("%s/plots/root-axPDF.pdf" % dsi.latSWDir) c.Clear() h5.Draw("hist") c.Print("%s/plots/root-trit.pdf" % dsi.latSWDir) c.Clear() h6.Draw("hist") c.Print("%s/plots/root-pb210TDL.pdf" % dsi.latSWDir) c.Clear() h7.Draw("hist") c.Print("%s/plots/root-pb210.pdf" % dsi.latSWDir) gROOT.cd(td.GetPath()) h1.Write() h2.Write() h3.Write() h4.Write() h5.Write() h6.Write() h7.Write() tf.Close()
def burstCut(dsNum): """ ./tuneCuts.py [dsNum] -burst """ # rates = {0:(30,5), 1:(20,5), 3:(50,5), 4:(20,3), 5:(150.,5.)} # v1 - before fitSLo rates = { 0: (20, 5), 1: (20, 5), 3: (20, 5), 4: (20, 5), 5: (40., 5) } # v2 - after fitSlo chList = ds.GetGoodChanList(dsNum) nDets = len(chList) maxRate = rates[dsNum][0] maxChanRate = rates[dsNum][0] * rates[dsNum][1] / float(nDets) print "maxRate %d nDets %d factor %d maxChanRate %.2f" % ( rates[dsNum][0], nDets, rates[dsNum][1], maxChanRate) energyCut = "trapENFCal >= 1" ignoreList = {0: [656], 3: [592, 692], 4: [1332], 5: [692, 1232, 1124]} bkg = ROOT.TChain("skimTree") for ch in chList: if ch not in ignoreList[dsNum]: f = "~/project/latskim/latSkimDS%d_ch%d.root" % (dsNum, ch) print "Added", f bkg.Add(f) # append to the text file (input to ds_livetime.cc) ds_livetimeList = open("burstCut_v1.txt", 'a') for key in ignoreList: killChs = "" for val in ignoreList[key]: killChs += " %d " % val ds_livetimeList.write("%s %s \n" % (key, killChs)) c0 = ROOT.TCanvas("c0", "c0", 1000, 600) rlo, rhi = ds.dsRanges[dsNum][0], ds.dsRanges[dsNum][1] clo, chi = 570, 700 if dsNum == 4: clo, chi = 1100, 1400 if dsNum == 5: clo, chi = 570, 1400 h0 = wl.H2D(bkg, rhi - rlo, rlo, rhi, chi - clo, clo, chi, "channel:run", energyCut, "Run Number", "Channel") h0.Draw("colz") c0.SetLogz(1) c0.Print("./plots/burst/channelRateDS%d.pdf" % dsNum) c1 = ROOT.TCanvas("c", "c", 1600, 600) c1.Divide(2, 1, 0) c1.cd(1) ROOT.gPad.SetLogy(1) h1 = wl.H1D(bkg, rhi - rlo, rlo, rhi, "run", energyCut, "Run Number", "Counts") h1.SetLineColor(ROOT.kRed) h1.Draw() # Run & channel-based burst cut. runs, rates = wl.npTH1D(h1, "i") idx = np.where(rates > maxRate) print "Noisy runs:", runs[idx] burstCut, invBurstCut = energyCut + " && ", energyCut + " && (" print "maxChanRate:", maxChanRate for i, run in enumerate(runs[idx]): runCut = " && run==%d" % run # h2.append(ROOT.TH1D()) h2 = wl.H1D(bkg, chi - clo, clo, chi, "channel", energyCut + runCut, "channel", "Counts") if h2.GetEntries() == 0: continue chans, chRates = wl.npTH1D(h2, "i") idx2 = np.where(chRates > maxChanRate) print "run", int(run), "noisy chans", chans[idx2], "rates", chRates[ idx2], "total entries", h2.GetEntries( ), "runCut:", energyCut + runCut # Write run + channel groups to the file (input to ds_livetime.cc) noisyChans = "" for ch in chans[idx2]: noisyChans += "%d " % ch ds_livetimeList.write("%d %s \n" % (run, noisyChans)) # Make the TCut runBurst = "&& !(run==%d && (" % run invBurst = "|| (run==%d && (" % run if i == 0: runBurst = runBurst[3:] invBurst = invBurst[3:] for ch in chans[idx2]: runBurst += "channel==%d|| " % ch invBurst += "channel==%d|| " % ch runBurst = runBurst[:-3] + ")) " invBurst = invBurst[:-3] + ")) " burstCut += runBurst invBurstCut += invBurst invBurstCut += ")" ds_livetimeList.close() if len(runs[idx]) == 0: burstCut, invBurstCut = energyCut, energyCut # add the dead channels back in for ch in ignoreList[dsNum]: burstCut += " && channel!=%d" % ch print "\nBURST CUT:" print burstCut print "\nINVERSE BURST CUT:" print invBurstCut print "" h1a = wl.H1D(bkg, rhi - rlo, rlo, rhi, "run", burstCut) h1a.SetLineColor(ROOT.kBlue) h1a.Draw("same") c1.cd(2) ROOT.gPad.SetLogy(1) h1.Draw("hist") h1b = wl.H1D(bkg, rhi - rlo, rlo, rhi, "run", invBurstCut) h1b.SetLineColor(ROOT.kBlue) h1b.Draw("hist same") c1.Print("./plots/burst/burstCutDS%d.pdf" % dsNum) c2 = TCanvas("c2", "c2", 1000, 600) c2.SetLogy(1) eb, elo, ehi = 150, 0, 30 # 5 bins/kev h2 = wl.H1D(bkg, eb, elo, ehi, "trapENFCal", "", "Energy", "Counts") h2.SetLineColor(ROOT.kRed) h3 = wl.H1D(bkg, eb, elo, ehi, "trapENFCal", burstCut) h3.SetLineColor(ROOT.kBlue) h2.Draw("hist") h3.Draw("hist same") c2.Print("./plots/burst/energySpecDS%d.pdf" % dsNum)
def axionPeaks(): """ placeholder: get the axion peak energies here. """ from ROOT import TH1D gae = 1 gRat = (gae / 5.11e-11) redondoScale = 1e19 * gRat**2 # convert table to [flux / (keV cm^2 d)] xLo, xHi, xpb = 0, 10, 0.1 nB = int((xHi-xLo)/xpb) axData = [] with open("./data/redondoFlux.txt") as f1: # 23577 entries lines = f1.readlines()[11:] for line in lines: data = line.split() axData.append([float(data[0]),float(data[1])]) axData = np.array(axData) hAx = TH1D("hAx","axion flux, gae=1",nB,xLo,xHi) # [cts / (keV cm^2 d)] for iB in range(nB+1): ctr = (iB + 0.5)*xpb + xLo bLo, bHi = ctr - xpb/2, ctr + xpb/2 # print(iB, bLo, bHi) with warnings.catch_warnings(): warnings.simplefilter("ignore",category=RuntimeWarning) # axion flux [flux / (cm^2 d keV)] idx = np.where((axData[:,0] >= bLo) & (axData[:,0] < bHi)) flux = np.mean(axData[idx][:,1]) * redondoScale if np.isnan(flux): flux = 0. hAx.SetBinContent(iB+1, flux) xA, hA, xpb2 = wl.npTH1D(hAx) if xpb!=xpb2: print("WTF, error") exit(1) # make sure the saved PDF matches f = np.load("./data/specPDFs.npz") pdfs = f['arr_0'].item() xP, aP, xpb3 = pdfs["axFlux"] plt.plot(axData[:,0], axData[:,1] * redondoScale, '.k', ms=1, alpha=0.3, label='Raw Flux Data') plt.plot(xA, hA, ls='steps', c='r', lw=1, label='Flux, %.1f keV bins' % xpb) plt.plot(xP, aP, ls='steps', c='m', lw=1) plt.axvline(1, c='m', lw=1, label="1.0 keV") # try to locate the shifted peaks msList = [] msThresh = 10 maxtab,_ = wl.peakdet(hA, msThresh) for iMax in range(len(maxtab)): idx = int(maxtab[iMax][0]) if not 1 <= xA[idx] <= 7 : continue val = maxtab[iMax][1] xPk = xA[idx]-xpb/2 msList.append(xPk) print("%d idx %d ene %.2f val %.2e thresh %.2f" % (iMax, idx, xPk, val, msThresh)) plt.axvline(xPk, lw=1, c='g', label="%.2f" % xPk) plt.legend() plt.xlabel("Energy (keV)", ha='right', x=1) plt.tight_layout() # plt.show() plt.savefig('./plots/sf-axFlux-binned.pdf')
def plotPDFs(): """ Final consistency check on PDFs before we use them in the fitter. """ from ROOT import TFile tfU = TFile("./data/specPDFs.root") tfS = TFile("./data/scaledPDFs.root") f = np.load("./data/scaledPDFs.npz") pdfRaw, pdfNorm, pdfEff, pdfEffN = f['arr_0'].item(), f['arr_1'].item(), f['arr_2'].item(), f['arr_3'].item() # === 1. Ge photoelectric XS plt.close() xR, hR, _ = wl.npTH1D(tfU.Get("h1")) plt.semilogy(xR, hR, ls='steps', c='b', lw=3, label=r"$\sigma_{ge}$") plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel(r"$\mathregular{cm^2/kg}$", ha='right', y=1) plt.legend() plt.tight_layout() # plt.show() plt.savefig("./plots/sf-gexs.pdf") # === 2. axioelectric XS plt.close() xR, hR, _ = wl.npTH1D(tfU.Get("h2")) plt.plot(xR, hR, ls='steps', c='b', lw=3, label=r"$\sigma_{ae}$") plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel(r"$\mathregular{cm^2/kg}$", ha='right', y=1) plt.legend() plt.tight_layout() # plt.gca().yaxis.set_label_coords(-0.06, 1) # plt.show() plt.savefig("./plots/sf-axs.pdf") # === 3. axion flux, gae=1 plt.close() xR, hR, _ = wl.npTH1D(tfU.Get("h3")) plt.plot(xR, hR, ls='steps', c='b', lw=3, label=r"$\Phi_a$") plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel(r"Flux / (keV cm${}^2$ d)]", ha='right', y=1) plt.xlim(0,12) plt.legend() plt.tight_layout() # plt.show() plt.savefig("./plots/sf-axFlux.pdf") # === 4. solar axion PDF, gae=1 -- this is what we integrate to get N_exp plt.close() xR1, hR1, _ = wl.npTH1D(tfU.Get("h4")) xr, hr, xbr = pdfRaw["axion"] plt.plot(xR1, hR1, ls='steps', c='b', lw=3, label=r"$\Phi_a$") plt.plot(xr, hr, ls='steps', c='r', lw=1) plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Flux / (keV d kg)", ha='right', y=1) plt.xlim(0,10) plt.legend() plt.tight_layout() # plt.show() plt.savefig("./plots/sf-axPDF.pdf") # === 5. normalized, efficiency corrected solar axion PDF, gae=1 plt.close() xR2, hR2, _ = wl.npTH1D(tfS.Get("h4-e")) # this is normalized w/ efficiency - not what we want for N_exp xn, hn, xbn = pdfNorm["axion"] xe, he, xbe = pdfEff["axion"] xen, hen, xben = pdfEffN["axion"] # plt.plot(xR2, hR2, ls='steps', c='r', lw=3, label="root, eff. corrected, norm'd") plt.plot(xn, hn, ls='steps', c='m', lw=2, label="Normalized PDF") # plt.plot(xe, he, ls='steps', c='g', lw=2, label="numpy, eff. corrected") plt.plot(xen, hen, ls='steps', c='b', lw=2, label="Normalized Eff.Corr. PDF") henc = getEffCorr(xen, hen, inv=True) plt.plot(xen, henc, ls='steps', c='g', lw=2, label="Final") plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Counts (norm)", ha='right', y=1) plt.xlim(0,10) plt.legend() plt.tight_layout() # plt.show() plt.savefig("./plots/sf-axPDF-effnorm.pdf") # return # # === 5. tritium plt.close() xn, hn, xbn = pdfNorm["trit"] xen, hen, xben = pdfEffN["trit"] henc = getEffCorr(xen, hen, inv=True) plt.plot(xn, hn, ls='steps', c='r', lw=3, label="Tritium, norm. PDF") plt.plot(xen, hen, ls='steps', c='b', lw=3, label="w/ normalized efficiency correction") plt.plot(xen, henc, ls='steps', c='g', lw=2, label="Final") plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Counts (norm)", ha='right', y=1) plt.legend() plt.xlim(0,20) plt.tight_layout() # plt.show() plt.savefig('./plots/sf-trit.pdf') # === 6. Pb210-TDL PDF plt.close() xn, hn, xbn = pdfNorm["Pb210-TDL"] xen, hen, xben = pdfEffN["Pb210-TDL"] henc = getEffCorr(xen, hen, inv=True) plt.plot(xn, hn, ls='steps', c='r', lw=2, label="Pb210TDL, norm. PDF") plt.plot(xen, hen, ls='steps', c='b', lw=3, label="w/ normalized efficiency correction") plt.plot(xen, henc, ls='steps', c='g', lw=2, label="Final") plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Counts (norm)", ha='right', y=1) plt.legend(loc=2) plt.tight_layout() # plt.show() plt.savefig("./plots/sf-pb210.pdf")
def scalePDFs(eff=False, makePlots=False): """ Create scaled (normalized to 1) PDFs (both ROOT and numpy output). RooFit does that automatically, but I also need the numpy histos to be correct. Optionally, apply the DS-specific efficiency correction, using the global variable 'dsList'. Be very careful when you apply efficiency -- RooFit will automatically normalize those too. """ from ROOT import TFile, TH1D, gROOT rOut = "./data/scaledPDFs.root" tfOut = TFile(rOut,"RECREATE") td = gROOT.CurrentDirectory() npOut = "./data/scaledPDFs.npz" print("Generating scaled PDFs: %s" % (rOut)) # load unscaled PDFs tf = TFile("./data/specPDFs.root") h4 = tf.Get('h4') # axion pdf h5 = tf.Get('h5') # tritium h6 = tf.Get('h6') # Pb210TDL h7 = tf.Get('h7') # Pb210 x4, np4, xpb4 = wl.npTH1D(h4) x5, np5, xpb5 = wl.npTH1D(h5) x6, np6, xpb6 = wl.npTH1D(h6) x7, np7, xpb7 = wl.npTH1D(h7) # create a flat BG PDF over the current energy range nB = int((eHi-eLo)/0.05) h8 = TH1D("h8","flat BG",nB,eLo,eHi) for iB in range(nB+1): h8.SetBinContent(iB, 1) # the initial amplitude doesn't matter b/c we normalize to 1 x8, np8, xpb8 = wl.npTH1D(h8) # normalize PDFs, in the energy range we're using for the fit (eLo, eHi) # root h4.Scale(1/h4.Integral(h4.FindBin(eLo), h4.FindBin(eHi), 'width')) # axion h5.Scale(1/h5.Integral(h5.FindBin(eLo), h5.FindBin(eHi), 'width')) # tritium h6.Scale(1/h6.Integral(h6.FindBin(eLo), h6.FindBin(eHi), 'width')) # pb210-tdl h7.Scale(1/h7.Integral(h7.FindBin(eLo), h7.FindBin(eHi), 'width')) # pb210 h8.Scale(1/h8.Integral(h8.FindBin(eLo), h8.FindBin(eHi), 'width')) # flat bg # numpy np4n = np.divide(np4, np.sum(np4[np.where((x4 >= eLo) & (x4 <= eHi))] * xpb4)) np5n = np.divide(np5, np.sum(np5[np.where((x5 >= eLo) & (x5 <= eHi))] * xpb5)) np6n = np.divide(np6, np.sum(np6[np.where((x6 >= eLo) & (x6 <= eHi))] * xpb6)) np7n = np.divide(np7, np.sum(np7[np.where((x7 >= eLo) & (x7 <= eHi))] * xpb7)) np8n = np.divide(np8, np.sum(np8[np.where((x8 >= eLo) & (x8 <= eHi))] * xpb8)) if makePlots: # === 1. make sure I normalized correctly xR, yR, xpbR = wl.npTH1D(h4) plt.plot(x4, np4n, ls='steps', lw=3, label="numpy normalized") plt.plot(xR, yR, ls='steps', lw=2, label="root normalized") plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Counts (norm)", ha='right', y=1) plt.legend() plt.tight_layout() plt.savefig("./plots/sf-axionPDF-norm.pdf") # return # apply efficiency correction (to the scaled TH1D) if eff: h4e = getEffCorrTH1D(h4, h4.GetXaxis().GetXmin(), h4.GetXaxis().GetXmax()) # axion h5e = getEffCorrTH1D(h5, h5.GetXaxis().GetXmin(), h5.GetXaxis().GetXmax()) # tritium h6e = getEffCorrTH1D(h6, h6.GetXaxis().GetXmin(), h6.GetXaxis().GetXmax()) # pb210-tdl h7e = getEffCorrTH1D(h7, h7.GetXaxis().GetXmin(), h7.GetXaxis().GetXmax()) # pb210 h8e = getEffCorrTH1D(h8, h8.GetXaxis().GetXmin(), h8.GetXaxis().GetXmax()) # flat np4ne = getEffCorr(x4, np4n) np5ne = getEffCorr(x5, np5n) np6ne = getEffCorr(x6, np6n) np7ne = getEffCorr(x7, np7n) np8ne = getEffCorr(x8, np8n) if makePlots: # === 2. make sure the efficiency correction is right plt.close() xR, yR, xpbR = wl.npTH1D(h4e) plt.plot(xR, yR, ls='steps', label="root eff-corr") plt.plot(x4, np4ne, ls='steps', label="np eff-corr") plt.legend() # plt.show() plt.savefig("./plots/sf-effCorr-axion.pdf") # finally, normalize and scale the efficiency-corrected histos # this is what RooFit will essentially use (automatically) h4e.Scale(1/h4e.Integral(h4e.FindBin(eLo), h4e.FindBin(eHi), 'width')) # axion h5e.Scale(1/h5e.Integral(h5e.FindBin(eLo), h5e.FindBin(eHi), 'width')) # tritium h6e.Scale(1/h6e.Integral(h6e.FindBin(eLo), h6e.FindBin(eHi), 'width')) # pb210-tdl h7e.Scale(1/h7e.Integral(h7e.FindBin(eLo), h7e.FindBin(eHi), 'width')) # pb210 h8e.Scale(1/h8e.Integral(h8e.FindBin(eLo), h8e.FindBin(eHi), 'width')) # flat np4nen = np.divide(np4ne, np.sum(np4ne[np.where((x4 >= eLo) & (x4 <= eHi))] * xpb4)) np5nen = np.divide(np5ne, np.sum(np5ne[np.where((x5 >= eLo) & (x5 <= eHi))] * xpb5)) np6nen = np.divide(np6ne, np.sum(np6ne[np.where((x6 >= eLo) & (x6 <= eHi))] * xpb6)) np7nen = np.divide(np7ne, np.sum(np7ne[np.where((x7 >= eLo) & (x7 <= eHi))] * xpb7)) np8nen = np.divide(np8ne, np.sum(np8ne[np.where((x8 >= eLo) & (x8 <= eHi))] * xpb8)) if makePlots: # === 3. make sure I normalized the efficiency-corrected histos correctly plt.close() xR, yR, xpbR = wl.npTH1D(h4e) plt.plot(xR, yR, ls='steps', lw=3, label="root normalized") plt.plot(x4, np4nen, ls='steps', lw=2, label="numpy normalized") plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Counts (norm)", ha='right', y=1) plt.legend() plt.tight_layout() # plt.show() plt.savefig("./plots/sf-effCorr-axion-norm.pdf") # === 4. plot the different corrections together plt.close() plt.plot(x4, np4n, ls='steps', lw=3, label="normalized") plt.plot(x4, np4ne, ls='steps', lw=3, label="norm, eff.corr") plt.plot(x4, np4nen, ls='steps', lw=3, label="norm, eff.corr, norm'd again") plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Counts (norm)", ha='right', y=1) plt.xlim(0, 12) plt.legend() plt.tight_layout() # plt.show() plt.savefig("./plots/sf-effCorr-axion-norm-2.pdf") # === 5. plot the efficiency-corrected flat bg plt.close() plt.plot(x8, np8n, ls='steps', lw=3, label="Flat BG, normalized") plt.plot(x8, np8nen, ls='steps', lw=3, label="Flat BG, efficiency corrected, normalized") # reverse the normalization np8nenc = getEffCorr(x8, np8nen, inv=True) plt.plot(x8, np8nenc, ls='steps', lw=3, label="Flat BG, reverted efficiency correction") plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Counts (norm)", ha='right', y=1) plt.ylim(0, 0.05) plt.legend() plt.tight_layout() # plt.show() plt.savefig("./plots/sf-effCorr-flat.pdf") # save ROOT output (used by the fitter) gROOT.cd(td.GetPath()) if eff: h4e.Write() h5e.Write() h6e.Write() h7e.Write() h8e.Write() else: h4.Write() h5.Write() h6.Write() h7.Write() h8.Write() tfOut.Close() # save numpy output pdfRaw = { # this is the unscaled pdf "axion" : [x4, np4, xpb4], "trit" : [x5, np5, xpb5], "Pb210" : [x6, np6, xpb6], "Pb210-TDL" : [x7, np7, xpb7], "flat" : [x8, np8, xpb8] } pdfNorm = { # this is the normalized pdf "axion" : [x4, np4n, xpb4], "trit" : [x5, np5n, xpb5], "Pb210" : [x6, np6n, xpb6], "Pb210-TDL" : [x7, np7n, xpb7], "flat" : [x8, np8n, xpb8] } pdfEff = { # this is the efficiency corrected normalized pdf "axion" : [x4, np4ne, xpb4], "trit" : [x5, np5ne, xpb5], "Pb210" : [x6, np6ne, xpb6], "Pb210-TDL" : [x7, np7ne, xpb7], "flat" : [x8, np8ne, xpb8] } pdfEffN = { # this is the efficiency corrected normalized pdf, normalized again # b/c that's what roofit does automatically in a fit "axion" : [x4, np4nen, xpb4], "trit" : [x5, np5nen, xpb5], "Pb210" : [x6, np6nen, xpb6], "Pb210-TDL" : [x7, np7nen, xpb7], "flat" : [x8, np8nen, xpb8] } np.savez(npOut, pdfRaw, pdfNorm, pdfEff, pdfEffN)
def getEff(): """ ./job-panda.py -getEff METHOD: open up the latskim file for each channel. loop over the good run ranges. for each good range, make an energy histogram. then calculate the efficiency curve based on the sigma value and convolve it with the histogram points. """ import numpy as np import waveLibs as wl import scipy.special as spec import matplotlib.pyplot as plt from ROOT import TFile, TTree, TH1D, TF1, TCanvas, gROOT import ROOT, random gROOT.ProcessLine(".x ~/env/MJDClintPlotStyle.C") # gROOT.ProcessLine("gErrorIgnoreLevel = 3001;") # suppress ROOT messages bins, xlo, xhi = 50, 0, 15 # set it just high enough that the first bin center isn't negative hSumCorr = TH1D("hSumCorr", "hSumCorr", bins, xlo, xhi) hSumUncr = TH1D("hSumUncr", "hSumUncr", bins, xlo, xhi) dsNum = 1 # ch = 578 for ch in ds.GetGoodChanList(dsNum): inFile = TFile(homePath + "/project/latskim/latSkimDS%d_ch%d.root" % (dsNum, ch)) tree = inFile.Get("skimTree") fileCut = inFile.Get("theCut").GetTitle() _, _, goodRunErfs = ds.GetThreshDicts(dsNum) hUnc = wl.H1D(tree, bins, xlo, xhi, "trapENFCal", fileCut) hSumUncr.Add(hUnc) for erfs in goodRunErfs[ch]: runCut = " && run >= %d && run <= %d" % (erfs[0], erfs[1]) theCut = fileCut + runCut h1 = wl.H1D(tree, bins, xlo, xhi, "trapENFCal", theCut) h1x, h1y = wl.npTH1D(h1) # calculate efficiency curve thisErf = TF1("thisErf", "0.5*(1+TMath::Erf((x-[0])/(TMath::Sqrt(2)*[1]) ))") thisErf.SetParameter(0, erfs[2]) # mu thisErf.SetParameter(1, erfs[3]) # sigma h1.Divide(thisErf) # thisErf = 0.5 * (1 + spec.erf( (h1x - mu) / (np.sqrt(2) * sig) )) # h1yScaled = h1y / thisErf # nameStr = str(random.uniform(1.,2.)) # h2 = TH1D(nameStr,nameStr,bins,xlo,xhi) # for i in range(bins): # h2.SetBinContent(i,h1yScaled[i]) hSumCorr.Add(h1) # eff-corrected spectrum. c = TCanvas("c", "c", 800, 600) c.SetLogy(1) hSumCorr.SetLineColor(ROOT.kBlue) hSumCorr.Draw("hist") hSumUncr.SetLineColor(ROOT.kRed) hSumUncr.Draw("hist same") # l1 = TLegend c.Print("./plots/effWeight/eff_DS%d.pdf" % dsNum)
def plotFit(): from ROOT import TFile, TCanvas, TH1D f = TFile("%s/data/fitWorkspace.root" % dsi.latSWDir) fitWorkspace = f.Get("fitWorkspace") fData = fitWorkspace.allData().front() fitResult = fitWorkspace.allGenericObjects().front() nPars = fitResult.floatParsFinal().getSize() hitE = fitWorkspace.var("trapENFCal") model = fitWorkspace.pdf("model") # fitWorkspace.Print() # plot data fSpec = hitE.frame(RF.Range(eLo,eHi), RF.Bins(nB)) fData.plotOn(fSpec) # plot model and components model.plotOn(fSpec, RF.LineColor(ROOT.kRed), RF.Name("FullModel")) c = TCanvas("c","c", 1400, 1000) fSpec.SetTitle("") fSpec.Draw() c.Print("%s/plots/spectrum-after.pdf" % dsi.latSWDir) c.Clear() # get fit results fitVals = {} for i in range(nPars): fp = fitResult.floatParsFinal() name = fp.at(i).GetName() fitVal = fp.at(i).getValV() fitErr = fp.at(i).getError() print("%s fitVal %.2f error %.2f" % (name, fitVal, fitErr)) if name == "amp-68GeK": nPk = fitVal if name == "amp-bkg": nBk = fitVal if name == "amp-trit": nTr = fitVal # === duplicate the rooplot in matplotlib === plt.close() tf = TFile("%s/data/latDS%s.root" % (dsi.latSWDir,''.join([str(d) for d in dsList]))) tt = tf.Get("skimTree") tCut = "isEnr==1" if enr is True else "isEnr==0" tCut = "isEnr" if enr else "!isEnr" tCut += " && trapENFCal >= %.1f && trapENFCal <= %.1f" % (eLo, eHi) n = tt.Draw("trapENFCal", tCut, "goff") trapE = tt.GetV1() trapE = [trapE[i] for i in range(n)] x, hData = wl.GetHisto(trapE, eLo, eHi, epb) # plt.plot(x, hData, ls='steps', c='b') # normal histo hErr = np.asarray([np.sqrt(h) for h in hData]) # statistical error plt.errorbar(x, hData, yerr=hErr, c='k', ms=5, linewidth=0.5, fmt='.', capsize=1, zorder=1) # pretty convincing rooplot fake # plot the model components and total tf2 = TFile("%s/data/specPDFs.root" % dsi.latSWDir) # get (eff-corrected) histos and normalize to 1 in the global energy range hTr = tf2.Get("h5") if eff: hTr = getEffCorrTH1D(hTr, pLo, pHi, nBP) hBkg = getBkgPDF(eff) hPk = peakPDF(10.37, getSigma(10.37), "68GeK", eff) x1, y1, xpb1 = wl.npTH1D(hTr) x2, y2, xpb2 = wl.npTH1D(hBkg) x3, y3, xpb3 = wl.npTH1D(hPk) x1, y1 = normPDF(x1, y1, eLo, eHi) x2, y2 = normPDF(x2, y2, eLo, eHi) x3, y3 = normPDF(x3, y3, eLo, eHi) nTot = nTr + nBk + nPk if abs(nTr - np.sum(y1 * nTr)) > 3: print("Error in trit: nTr %d cts in curve %d" % (nTr, np.sum(y1*nTr))) if abs(nTr - np.sum(y2 * nTr)) > 3: print("Error in bkg: nTr %d cts in curve %d" % (nTr, np.sum(y2*nTr))) if abs(nTr - np.sum(y3 * nTr)) > 3: print("Error in peak: nTr %d cts in curve %d" % (nTr, np.sum(y3*nTr))) # === reverse the efficiency correction to get the "true" number of counts y1c = nTr * getEffCorr(x1, y1, inv=True) y2c = nBk * getEffCorr(x2, y2, inv=True) y3c = nPk * getEffCorr(x3, y3, inv=True) nTotC = np.sum(y1c) + np.sum(y2c) + np.sum(y3c) # === plot total model pdfs = [[x1,y1,xpb1,nTr],[x2,y2,xpb2,nBk],[x3,y3,xpb3,nPk]] xT, yT = getTotalModel(pdfs, eLo, eHi, epb, smooth=True) plt.step(xT, yT, c='b', lw=2, label="Raw (no eff. corr): %d cts" % nTot) # === plot components of the (uncorrected) model # *** NOTE: to plot after the fit, multiply by (global bin width / bin width when generated). to integrate, don't. *** plt.step(x1, y1 * nTr * (epb/ppb), c='m', lw=2, alpha=0.7, label="Tritium: %d cts" % nTr) plt.step(x2, y2 * nBk * (epb/epb), c='g', lw=2, alpha=0.7, label="Bkg: %d cts" % nBk) plt.step(x3, y3 * nPk * (epb/ppb), c='c', lw=2, alpha=0.7, label="68GeK %d cts" % nPk) # === plot efficiency corrected final model pdfs = [[x1,y1c,xpb1,nTr],[x2,y2c,xpb2,nBk],[x3,y3c,xpb3,nPk]] xTc, yTc = getTotalModel(pdfs, eLo, eHi, epb, smooth=True, amp=False) plt.step(xTc, yTc, c='r', lw=3, label="Efficiency corrected: %d cts" % nTotC) # === plot components of the corrected model # plt.step(x1, y1c * (epb/ppb), c='orange', lw=2, alpha=0.7, label="trit fit: %d corr: %d" % (nTr, np.sum(y1c))) # plt.step(x2, y2c * (epb/epb), c='orange', lw=2, alpha=0.7, label="bkg fit: %d corr: %d" % (nBk, np.sum(y2c))) # plt.step(x3, y3c * (epb/ppb), c='orange', lw=2, alpha=0.7, label="peak fit: %d corr: %d" % (nPk, np.sum(y3c))) plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Counts / %.1f keV" % epb, ha='right', y=1) plt.legend(loc=1, fontsize=12) plt.xlim(eLo, eHi) plt.ylim(ymin=0) plt.tight_layout() # plt.show() plt.savefig("%s/plots/sf4-mplafter.pdf" % dsi.latSWDir)
def plotModel(): from ROOT import TFile, TH1D tf = TFile("%s/data/latDS%s.root" % (dsi.latSWDir,''.join([str(d) for d in dsList]))) tt = tf.Get("skimTree") tCut = "isEnr==1" if enr is True else "isEnr==0" hitE = ROOT.RooRealVar("trapENFCal", "Energy", eLo, eHi, "keV") hEnr = ROOT.RooRealVar("isEnr", "isEnr", 0, 1, "") # hitW = ROOT.RooRealVar("weight", "weight", 1, 1000, "") fData = ROOT.RooDataSet("data", "data", tt, ROOT.RooArgSet(hitE, hEnr), tCut) # fData = ROOT.RooDataSet("data", "data", tt, ROOT.RooArgSet(hitE, hEnr, hitW), "", "weight") nData = fData.numEntries() fitWorkspace = ROOT.RooWorkspace("fitWorkspace","Fit Workspace") getattr(fitWorkspace,'import')(hitE) getattr(fitWorkspace,'import')(fData) # getattr(fitWorkspace,'import')(fWeight) tf2 = TFile("%s/data/specPDFs.root" % dsi.latSWDir) pdfList = ROOT.RooArgList("shapes") # tritium nTr = 1000 hTr = tf2.Get("h5") if eff: hTr = getEffCorrTH1D(hTr, pLo, pHi, nBP) trNum = ROOT.RooRealVar("amp-trit", "amp-trit", nTr, 0., 50000.) trDH = ROOT.RooDataHist("tr", "tr", ROOT.RooArgList(hitE), RF.Import(hTr)) hitE.setRange(eLo, eHi) trPdf = ROOT.RooHistPdf("trPdf", "trPdf", ROOT.RooArgSet(hitE), trDH, 2) trExt = ROOT.RooExtendPdf("ext-trit", "ext-trit", trPdf, trNum) pdfList.add(trExt) # flat bg nBk = 1000 hBkg = getBkgPDF(eff) bkgNum = ROOT.RooRealVar("amp-bkg", "amp-bkg", nBk, 0., 10000.) bkgDH = ROOT.RooDataHist("bkg", "bkg", ROOT.RooArgList(hitE), RF.Import(hBkg)) hitE.setRange(eLo, eHi) bkgPdf = ROOT.RooHistPdf("bkgPdf", "bkgPdf", ROOT.RooArgSet(hitE), bkgDH, 2) bkgExt = ROOT.RooExtendPdf("ext-bkg", "ext-bkg", bkgPdf, bkgNum) pdfList.add(bkgExt) # 68ge peak nPk = 100 hPk = peakPDF(10.37, getSigma(10.37), "68GeK", eff) pkDH = ROOT.RooDataHist("pk", "pk", ROOT.RooArgList(hitE), RF.Import(hPk)) hitE.setRange(eLo, eHi) pkPdf = ROOT.RooHistPdf("pkPdf", "pkPdf", ROOT.RooArgSet(hitE), pkDH, 2) pkNum = ROOT.RooRealVar("amp-68GeK", "amp-68GeK", nPk, 0.0, 1000.) pkExt = ROOT.RooExtendPdf("ext-68GeK", "ext-68GeK", pkPdf, pkNum) pdfList.add(pkExt) model = ROOT.RooAddPdf("model","total pdf",pdfList) # rooplot before fitting fSpec = hitE.frame(RF.Range(eLo,eHi), RF.Bins(int((eHi-eLo)/epb))) # wouter's note: DON'T DELETE # "the default behavior is when you plot a p.d.f. on an empty frame it is # plotted with unit normalization. When you plot it on a frame with data in # it, it will normalize to the number of events in that dataset." # (then after you do a fit, the pdf normalization changes again ...) fData.plotOn(fSpec) # bkgExt.plotOn(fSpec) # pkExt.plotOn(fSpec) # 1 -- individual components at their initial fit values # use this one for one component (you have to divide by (bin width of orig pdf) in numpy when you plot, but not when you integrate) trExt.plotOn(fSpec, RF.LineColor(ROOT.kMagenta), RF.Normalization(nTr, ROOT.RooAbsReal.Raw)) bkgExt.plotOn(fSpec, RF.LineColor(ROOT.kGreen), RF.Normalization(nBk, ROOT.RooAbsReal.Raw)) pkExt.plotOn(fSpec, RF.LineColor(ROOT.kBlue), RF.Normalization(nPk, ROOT.RooAbsReal.Raw)) # 2 -- the model, normalized according to the total number of counts in a really fking stupid way # model.plotOn(fSpec, RF.LineColor(ROOT.kRed)) # model.plotOn(fSpec, RF.Components("ext-trit"), RF.LineColor(ROOT.kMagenta), RF.Name("ext-trit")) # model.plotOn(fSpec, RF.Components("ext-bkg"), RF.LineColor(ROOT.kGreen), RF.Name("ext-bkg")) # model.plotOn(fSpec, RF.Components("ext-68GeK"), RF.LineColor(ROOT.kBlue), RF.Name("ext-68GeK")) from ROOT import TCanvas c = TCanvas("c","c", 1400, 1000) fSpec.SetTitle("") fSpec.Draw() c.Print("%s/plots/spectrum-before.pdf" % dsi.latSWDir) c.Clear() # === replicate the rooplot with numpy (no weights) === tCut = "isEnr" if enr else "!isEnr" tCut += " && trapENFCal >= %.1f && trapENFCal <= %.1f" % (eLo, eHi) n = tt.Draw("trapENFCal", tCut, "goff") trapE = tt.GetV1() trapE = [trapE[i] for i in range(n)] x, hData = wl.GetHisto(trapE, eLo, eHi, epb) # plt.plot(x, hData, ls='steps', c='b') # normal histo hErr = np.asarray([np.sqrt(h) for h in hData]) # statistical error plt.errorbar(x, hData, yerr=hErr, c='k', ms=5, linewidth=0.5, fmt='.', capsize=1, zorder=1) # pretty convincing rooplot fake # get (eff-corrected) histos and normalize them to the global energy range x1, y1, _ = wl.npTH1D(hTr) x2, y2, _ = wl.npTH1D(hBkg) x3, y3, _ = wl.npTH1D(hPk) x1, y1 = normPDF(x1, y1, eLo, eHi) x2, y2 = normPDF(x2, y2, eLo, eHi) x3, y3 = normPDF(x3, y3, eLo, eHi) # === 1. plot individual components of the model # *** NOTE: to plot, divide by (bin width when generated). to integrate, don't. *** plt.plot(x1, y1 * nTr / ppb, ls='steps', c='m', lw=2, label="trit init: %d int: %d" % (nTr, np.sum(y1 * nTr))) plt.plot(x2, y2 * nBk / epb, ls='steps', c='g', lw=2, label="bkg init: %d int: %d" % (nBk, np.sum(y2 * nBk))) plt.plot(x3, y3 * nPk / ppb, ls='steps', c='b', lw=2, label="68GeK init: %d int: %d" % (nPk, np.sum(y3 * nPk))) # === 2. replicate the stupid way a rooplot normalizes multiple pdf's based on the number of data counts (before a fit) # nModel = 3 # yTot = np.add(y1, y2, y3) # yTot *= nData/nModel # plt.plot(x1, yTot, ls='steps', c='r', lw=2, label="total, nData %d sum %d max %.1f" % (nData, int(np.sum(yTot)), np.amax(yTot))) # plt.plot(x1, y1 * nData/2, ls='steps', c='b', lw=2, label="tritium") # plt.plot(x2, y2 * nData/2, ls='steps', c='g', lw=2, label="bkg") # === 3. check a peak which was generated with a different binning than the global binning # print(np.sum(y3)) # this is 1 # print(np.sum(y3 * (epb/xpb3))) # this is bigger than 1, but matches the way rooplot normalizes it when plotted by itself. fk rooplot # print(np.sum(y3 * nPk)) # plt.plot(x3, y3 * nPk / xpb3, ls='steps', label="pk init value: %d int: %d" % (nPk, np.sum(y3 * nPk))) plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Counts / %.1f keV" % epb, ha='right', y=1) plt.legend(loc=1) plt.xlim(eLo, eHi) plt.ylim(ymin=0) plt.tight_layout() # plt.show() plt.savefig("%s/plots/sf4-mplplot.pdf" % dsi.latSWDir) # === alright, now run the fit and check the plot again minimizer = ROOT.RooMinimizer( model.createNLL(fData, RF.NumCPU(2,0), RF.Extended(True)) ) minimizer.setPrintLevel(-1) minimizer.setStrategy(2) minimizer.migrad() fitResult = minimizer.save() # according to the internet, covQual==3 is a good indicator that it converged print("Fitter is done. Fit Cov Qual:", fitResult.covQual()) # save workspace to a TFile getattr(fitWorkspace,'import')(fitResult) getattr(fitWorkspace,'import')(model) tf3 = TFile("%s/data/fitWorkspace.root" % dsi.latSWDir,"RECREATE") fitWorkspace.Write() tf3.Close()
def runFit(): from ROOT import TFile, TH1D tf = TFile("../data/latDS%s.root" % ''.join([str(d) for d in dsList])) tt = tf.Get("skimTree") tCut = "isEnr==1" if enr is True else "isEnr==0" hitE = ROOT.RooRealVar("trapENFCal", "Energy", eLo, eHi, "keV") hEnr = ROOT.RooRealVar("isEnr", "isEnr", 0, 1, "") # hitW = ROOT.RooRealVar("weight", "weight", 1, 1000, "") fData = ROOT.RooDataSet("data", "data", tt, ROOT.RooArgSet(hitE, hEnr), tCut) # # fData = ROOT.RooDataSet("data", "data", tt, ROOT.RooArgSet(hitE, hEnr, hitW), "", "weight") nData = fData.numEntries() tf2 = TFile("../data/specPDFs.root") trVal = 1000 trTH1D = tf2.Get("h5") trNum = ROOT.RooRealVar("amp-trit", "amp-trit", trVal) trDataHist = ROOT.RooDataHist("tr", "tr", ROOT.RooArgList(hitE), RF.Import(trTH1D)) hitE.setRange(eLo, eHi) trPdf = ROOT.RooHistPdf("trPdf", "trPdf", ROOT.RooArgSet(hitE), trDataHist, 0) trExt = ROOT.RooExtendPdf("ext-trit", "ext-trit", trPdf, trNum) # rooplot before fitting fSpec = hitE.frame(RF.Range(eLo, eHi), RF.Bins(int((eHi - eLo) / epb))) # wouter's note: DON'T DELETE # "the default behavior is when you plot a p.d.f. on an empty frame it is # plotted with unit normalization. When you plot it on a frame with data in # it, it will normalize to the number of events in that dataset." fData.plotOn(fSpec) # trExt.plotOn(fSpec) # default normalization: 1 if no data, nData if data # trExt.plotOn(fSpec, RF.Normalization(1, ROOT.RooAbsReal.Relative)) # this is relative to total counts, don't use it # trExt.plotOn(fSpec, RF.LineColor(ROOT.kBlue), RF.Normalization(trVal/epb, ROOT.RooAbsReal.NumEvent)) # equivalent to the Raw way # use this one (you have to divide by epb in numpy when you plot, but not when you integrate) trExt.plotOn(fSpec, RF.LineColor(ROOT.kMagenta), RF.Normalization(trVal, ROOT.RooAbsReal.Raw)) from ROOT import TCanvas c = TCanvas("c", "c", 1400, 1000) fSpec.SetTitle("") fSpec.Draw() c.Print("../plots/spectrum-before.pdf") # replicate the rooplot with numpy (no weights) tCut = "isEnr" if enr else "!isEnr" tCut += " && trapENFCal >= %.1f && trapENFCal <= %.1f" % (eLo, eHi) n = tt.Draw("trapENFCal", tCut, "goff") trapE = tt.GetV1() trapE = [trapE[i] for i in range(n)] x, hData = wl.GetHisto(trapE, eLo, eHi, epb) # plt.plot(x, hData, ls='steps', c='b') # normal histo hErr = np.asarray([np.sqrt(h) for h in hData]) # statistical error plt.errorbar(x, hData, yerr=hErr, c='k', ms=10, linewidth=0.8, fmt='.', capsize=2, zorder=1) # pretty convincing rooplot fake x, y, xpb = wl.npTH1D(trTH1D) # yn = np.divide(y, np.sum(y)) # plt.step(x, np.cumsum(yn)) # yn = np.divide(y, np.sum(y[np.where((x >= eLo) & (x <= eHi))] * xpb)) < -- this makes the norm != 1 # yn = np.divide(y, np.sum(y[np.where((x >= eLo) & (x <= eHi))])) # < -- this one works w/ no data # yn = np.multiply(yn, nData) # <-- this one works w/ data # plt.plot(x, yn, ls='steps', c='b', lw=2, label="tritium, nData %d sum %d max %.1f" % (nData, int(np.sum(yn)), np.amax(yn))) # NOTE: to plot to a set number of counts, divide by epb. to integrate, don't. plt.plot(x1, y1 * trVal / epb, ls='steps', c='m', lw=2, label="trit init value: %d int: %d" % (trVal, np.sum(y1 * trVal))) plt.xlabel("Energy (keV)", ha='right', x=1) plt.ylabel("Counts / %.1f keV" % epb, ha='right', y=1) plt.legend(loc=1) plt.tight_layout() # plt.show() plt.savefig("../plots/sf3-mplplot.pdf")