def createBinnedFitUncertaintyHistograms(hRate, hUp, hDown, applyFrom, opts): hupList = [] hDownList = [] # find bin myFirstBin = hRate.GetXaxis().FindBin(applyFrom + 0.0001) for i in range(myFirstBin, hRate.GetNbinsX() + 1): hup = aux.Clone( hRate, "%s_%s_fitBinByBin%dUp" % (hRate.GetTitle(), hRate.GetTitle(), i)) hup.SetTitle(hup.GetName()) hdown = aux.Clone( hRate, "%s_%s_fitBinByBin%dDown" % (hRate.GetTitle(), hRate.GetTitle(), i)) hup.SetTitle(hdown.GetName()) for j in range(1, hRate.GetNbinsX() + 1): hup.SetBinError(j, 0.0) hdown.SetBinError(j, 0.0) if opts.doubleFitUncert: hup.SetBinContent( i, (hUp.GetBinContent(i) - hRate.GetBinContent(i)) * 2.0 + hRate.GetBinContent(i)) hdown.SetBinContent( i, (hDown.GetBinContent(i) - hRate.GetBinContent(i)) * 2.0 + hRate.GetBinContent(i)) else: hup.SetBinContent(i, hUp.GetBinContent(i)) hdown.SetBinContent(i, hDown.GetBinContent(i)) if hDown.GetBinContent(i) < 0.0: hdown.SetBinContent(i, 0.0) hupList.append(hup) hDownList.append(hdown) # Return histogram lists return (hupList, hDownList)
def getDataDrivenQCDHistoForSplittedBin(self, binIndex): ''' Return the sum of data-ewk in a given phase space split bin at bin-index 0 you have the inclusive histogram! ''' if binIndex >= len(self._dataList): # FIXME: New addition to fix "optionUseInclusiveNorm" functionality (24-Mar-2018). Should not affect binned result! if self._optionUseInclusiveNorm: #new h = aux.Clone(self._dataList[0]) #new newName = h.GetName() + "_DataDriven" #new h.SetName(newName) #new return h #new msg = "Requested bin index %d out of range (0-%d)!" % ( binIndex, len(self._dataList)) raise Exception(ShellStyles.ErrorStyle() + msg, ShellStyles.NormalStyle()) # Clone the Data histos h = aux.Clone(self._dataList[binIndex]) newName = h.GetName() + "_DataDriven" h.SetName(newName) self.Verbose( "Cloned histo %s from histo %s" % (h.GetName(), self._dataList[0].GetName()), True) # Subtract the EWK histos self.Verbose( "Subtracting histo %s from histo %s (bin=%i)" % (self._ewkList[binIndex].GetName(), h.GetName(), binIndex), False) h.Add(self._ewkList[binIndex], -1.0) return h
def calculateTotalVariationHistograms(self, hRate, hup, hdown): # Create empty histogram templates hFitUncertaintyUpTotal = aux.Clone(hup[0], self._label + "_TailFitUp") hFitUncertaintyDownTotal = aux.Clone(hup[0], self._label + "_TailFitDown") hFitUncertaintyUpTotal.Reset() # clean bin contents and errors hFitUncertaintyDownTotal.Reset() # clean bin contents and errors for i in range(1, hup[0].GetNbinsX() + 1): myPedestal = hRate.GetBinContent(i) myVarianceUp = 0.0 myVarianceDown = 0.0 for j in range(0, len(hup)): a = 0.0 b = 0.0 if hup[j].GetBinContent(i) > 0.0: a = hup[j].GetBinContent(i) - myPedestal else: a = -myPedestal if hdown[j].GetBinContent(i) > 0.0: b = hdown[j].GetBinContent(i) - myPedestal else: b = -myPedestal if abs(a) != float('Inf') and not math.isnan( a) and abs(b) != float('Inf') and not math.isnan(b): (varA, varB) = aux.getProperAdditivesForVariationUncertainties( a, b) # essentially squaring a and b myVarianceUp += varA myVarianceDown += varB hFitUncertaintyUpTotal.SetBinContent( i, myPedestal + math.sqrt(myVarianceUp)) hFitUncertaintyDownTotal.SetBinContent( i, myPedestal - math.sqrt(myVarianceDown)) return (hFitUncertaintyUpTotal, hFitUncertaintyDownTotal)
def _obtainShapeHistograms(self, i, dataPath, ewkPath, dsetMgr, plotName, luminosity, normFactors): self.Verbose("_obtainShapeHistograms()", True) if self._verbose: self.PrintShapeInputSummary(dataPath, ewkPath, dsetMgr, plotName, luminosity, normFactors) self.Verbose("Obtain the (pre-normFactor) shape %s as \"DataDrivenQCDShape\" type object" % (plotName), True) myShape = dataDrivenQCDCount.DataDrivenQCDShape(dsetMgr, "Data", "EWK", plotName, dataPath, ewkPath, luminosity, self._useInclusiveNorm, self._verbose) if self._verbose: msg = "Printing TH1s (before NormFactors) of \"Data\", \"Data-Driven QCD\", \"EWK\", and \"Bin-by\Bin Purity\" and \"Integrated Purity\"" self.Print(msg, True) PrintTH1Info(myShape.getIntegratedDataHisto()) PrintTH1Info(myShape.getIntegratedDataDrivenQCDHisto()) #Data-EWK. NormFactor not applied PrintTH1Info(myShape.getIntegratedEwkHisto()) PrintTH1Info(myShape.getPurityHisto()) # Splitted-bin (disabled for Inclusive mode) PrintTH1Info(myShape.getIntegratedPurityForShapeHisto()) self.PrintShapePuritySummary(myShape) self.Verbose("Obtain the (post-normFactor) shape %s as \"QCDInvertedShape\" type object (Takes \"DataDrivenQCDShape\" type object as argument)" % (plotName), True) moduleInfo = self._moduleInfoString + "_" + plotName myPlot= QCDInvertedShape(myShape, moduleInfo, normFactors, optionUseInclusiveNorm=self._useInclusiveNorm) myPlot.PrintSettings(printHistos=self._verbose, verbose=self._verbose) # Define histogram name as will be written in the ROOT file self.Verbose("%sDefining the name of histogram objects, as they will appear in the ROOT file%s" % (ShellStyles.WarningStyle(), ShellStyles.NormalStyle()), True) hName = plotName + "%d" %i hTitle = plotName.replace("CRSelections", "AllSelections").replace("Baseline_", "").replace("Inverted_", "")#FIXME: not elegant! # DataDriven myShape.delete() myPlotHisto = aux.Clone(myPlot.getResultShape(), "ctrlPlotShapeInManager") myPlot.delete() myPlotHisto.SetName(hName) myPlotHisto.SetTitle(hTitle) self._shapePlots.append(myPlotHisto) self._shapePlotLabels.append(myPlotHisto.GetTitle())# this is the name the object will have in the ROOT file # MC EWK hName = plotName + "%d_MCEWK" %i myPlotMCEWKHisto = aux.Clone(myPlot.getResultMCEWK(), "ctrlPlotMCEWKInManager") myPlotMCEWKHisto.SetName(hName) myPlotMCEWKHisto.SetTitle(hTitle + "_MCEWK") self._shapePlots.append(myPlotMCEWKHisto) self._shapePlotLabels.append(myPlotMCEWKHisto.GetTitle())# this is the name the object will have in the ROOT file # Purity hName = plotName + "%d_Purity" %i #self.Print("myPlot.getResultPurity().GetName() = %s" % myPlot.getResultPurity().GetName(), True) #self.Print("myPlot.getResultPurity().GetIntegral() = %s" % myPlot.getResultPurity().Integral(), True) myPlotPurityHisto = aux.Clone(myPlot.getResultPurity(), "ctrlPlotPurityInManager") myPlotPurityHisto.SetName(hName) myPlotPurityHisto.SetTitle(hTitle + "_Purity") self._shapePlots.append(myPlotPurityHisto) self._shapePlotLabels.append(myPlotPurityHisto.GetTitle())# this is the name the object will have in the ROOT file return myPlotHisto
def _createHistograms(self,data,expectedList): for e in expectedList: self._expectedList.append(aux.Clone(self._hFrame)) self._expectedList[len(self._expectedList)-1].Reset() self._expectedListSystUp.append(aux.Clone(self._hFrame)) self._expectedListSystUp[len(self._expectedListSystUp)-1].Reset() self._expectedListSystDown.append(aux.Clone(self._hFrame)) self._expectedListSystDown[len(self._expectedListSystDown)-1].Reset() self._expectedLabelList.append(e.name) self._data = aux.Clone(self._hFrame) self._data.Reset()
def _obtainQCDNormalizationSystHistograms(self, shapeHisto, dsetMgr, plotName, luminosity, normDataSrc, normEWKSrc): print ShellStyles.HighlightStyle( ) + "...Obtaining region transition systematics" + ShellStyles.NormalStyle( ) myPlotSignalRegionShape = dataDrivenQCDCount.DataDrivenQCDShape( dsetMgr=dsetMgr, dsetLabelData="Data", dsetLabelEwk="EWK", histoName=plotName, dataPath=normDataSrc + "QCDNormalizationSignal", ewkPath=normEWKSrc + "QCDNormalizationSignal", luminosity=luminosity) myPlotControlRegionShape = dataDrivenQCDCount.DataDrivenQCDShape( dsetMgr=dsetMgr, dsetLabelData="Data", dsetLabelEwk="EWK", histoName=plotName, dataPath=normDataSrc + "QCDNormalizationControl", ewkPath=normEWKSrc + "QCDNormalizationControl", luminosity=luminosity) myPlotRegionTransitionSyst = metSyst.SystematicsForMetShapeDifference( myPlotSignalRegionShape, myPlotControlRegionShape, shapeHisto, moduleInfoString=self._moduleInfoString, quietMode=True) myPlotSignalRegionShape.delete() myPlotControlRegionShape.delete() # Store up and down variations #hUp = aux.Clone(myPlotRegionTransitionSyst.getUpHistogram(), "QCDfactMgrSystQCDSystUp%d"%i) #hUp.SetTitle(plotName+"systQCDUp") #self._QCDNormalizationSystPlots.append(hUp) #self._QCDNormalizationSystPlotLabels.append(hUp.GetTitle()) #hDown = aux.Clone(myPlotRegionTransitionSyst.getDownHistogram(), "QCDfactMgrSystQCDSystDown%d"%i) #hDown.SetTitle(plotName+"systQCDDown") #self._QCDNormalizationSystPlots.append(hDown) #self._QCDNormalizationSystPlotLabels.append(hDown.GetTitle()) # Store source histograms hNum = aux.Clone( myPlotRegionTransitionSyst.getCombinedSignalRegionHistogram(), "QCDfactMgrSystQCDSystNumerator") hNum.SetTitle(plotName + "systQCDNumerator") self._QCDNormalizationSystPlots.append(hNum) self._QCDNormalizationSystPlotLabels.append(hNum.GetTitle()) hDenom = aux.Clone( myPlotRegionTransitionSyst.getCombinedCtrlRegionHistogram(), "QCDfactMgrSystQCDSystDenominator") hDenom.SetTitle(plotName + "systQCDDenominator") self._QCDNormalizationSystPlots.append(hDenom) self._QCDNormalizationSystPlotLabels.append(hDenom.GetTitle()) # Free memory myPlotRegionTransitionSyst.delete()
def getIntegratedDataDrivenQCDHisto(self): ''' Return the sum of data-ewk integrated over the phase space splitted bins ''' # 1) Do the "Inclusive" histogram (here I assume that the first in the list is the inclusive) h = aux.Clone(self._dataList[0]) histoName = "_".join(h.GetName().split( "_", 2)[:2]) + "_DataMinusEWK_Integrated" # histoName = h.GetName()+"Integrated" #original code h.SetName(histoName) # Subtract the EWK histo from Data histo (QCD=Data-EWK) h.Add(self._ewkList[0], -1.0) # 2) Do the bin-by-bin histograms # For-loop: All data histos for i in range(1, len(self._dataList)): # starts from bin #1 (not zero) # Bin-by-bin mode has not been validated by me yet print "FIXME " * 20 h.Add(self._dataList[i]) # Subtract the EWK histo from Data histo (QCD=Data-EWK) h.Add(self._ewkList[i], -1.0) return h
def getDataDrivenQCDHistoForSplittedBin(self, binIndex): if binIndex >= len(self._dataList): raise Exception(ShellStyles.ErrorLabel()+"DataDrivenQCDShape::getDataDrivenQCDForSplittedBin: requested bin index %d out of range (0-%d)!"%(binIndex,len(self._dataList))) h = aux.Clone(self._dataList[binIndex]) h.SetName(h.GetName()+"dataDriven") h.Add(self._ewkList[binIndex], -1.0) return h
def _obtainShapeHistograms(self, i, dataPath, ewkPath, dsetMgr, plotName, luminosity, normFactors): myShape = dataDrivenQCDCount.DataDrivenQCDShape(dsetMgr=dsetMgr, dsetLabelData="Data", dsetLabelEwk="EWK", histoName=plotName, dataPath=dataPath, ewkPath=ewkPath, luminosity=luminosity) myPlot = QCDInvertedShape(myShape, self._moduleInfoString+"_"+plotName, normFactors, optionUseInclusiveNorm=self._useInclusiveNorm) myShape.delete() myPlotHisto = aux.Clone(myPlot.getResultShape(), "ctrlPlotShapeInManager") myPlot.delete() myPlotHisto.SetName(plotName+"%d"%i) myPlotHisto.SetTitle(plotName) self._shapePlots.append(myPlotHisto) self._shapePlotLabels.append(plotName) # MC EWK and purity #myPlotMCEWKHisto = aux.Clone(myPlot.getResultMCEWK(), "ctrlPlotMCEWKInManager") #myPlotMCEWKHisto.SetName(plotName+"%d_MCEWK"%i) #myPlotMCEWKHisto.SetTitle(plotName+"_MCEWK") #self._shapePlots.append(myPlotMCEWKHisto) #self._shapePlotLabels.append(myPlotMCEWKHisto.GetTitle()) #myPlotPurityHisto = aux.Clone(myPlot.getResultPurity(), "ctrlPlotPurityInManager") #myPlotPurityHisto.SetName(plotName+"%d_Purity"%i) #myPlotPurityHisto.SetTitle(plotName+"_Purity") #self._shapePlots.append(myPlotPurityHisto) #self._shapePlotLabels.append(myPlotPurityHisto.GetTitle()) return myPlotHisto
def getIntegratedDataDrivenQCDHisto(self): ''' Return the sum of data-ewk integrated over the phase space splitted bins ''' # Do the "Inclusive" histogram (here I assume that the first in the list is the inclusive) h = aux.Clone(self._dataList[0]) histoName = "_".join(h.GetName().split( "_", 2)[:2]) + "_DataDriven_Integrated" h.SetName(histoName) self.Verbose( "Cloned histo %s from histo %s" % (h.GetName(), self._dataList[0].GetName()), True) # Subtract the EWK histo from Data histo (QCD=Data-EWK) self.Verbose( "Subtracting histo %s from histo %s" % (self._ewkList[0].GetName(), h.GetName()), False) h.Add(self._ewkList[0], -1.0) # For-loop: All data histos [N.B. Starts from bin 1 (not 0=inclusive) ] for i in range(1, len(self._dataList)): msg = "Splitted-bin mode has not been validated yet" #raise Exception(ShellStyles.ErrorStyle() + msg + ShellStyles.NormalStyle()) # Accumulate given bin-histo from Data h.Add(self._dataList[i]) # Subtract given bin-histo from EWK h.Add(self._ewkList[i], -1.0) return h
def _obtainHistograms(self, i, dsetMgr, plotName, luminosity): self.Verbose( "Obtain histogram %s as \"NewShape\" type object" % (plotName), True) myShape = NewShape(dsetMgr, opts.newDsetName, opts.dsetsToMerge, self._moduleInfoString, plotName, luminosity, self._verbose) myPlot = myShape.getIntegratedNewDsetHisto( ) #myPlot = myShape.getIntegratedEwkHisto() if self._verbose: aux.PrintTH1Info(myPlot) self.Verbose( "Cloning histogram %s, settting name and title" % (plotName), True) saveName = "%s_%d" % (plotName, i) myPlotHisto = aux.Clone(myPlot) myPlotHisto.SetName(saveName) myPlotHisto.SetTitle(plotName) # Append the plot to the list. The plot title is the name the object will saved as in the ROOT file saveName = myPlotHisto.GetTitle() self.Verbose( "Saving histogram %s for dataset %s" % (saveName, opts.newDsetName), i == 1) if self._verbose: aux.PrintTH1Info(myPlotHisto) self._myPlots.append(myPlotHisto) self._myPlotLabels.append(saveName) # Delete objects from memory # myPlot.delete() myShape.delete() return myPlotHisto
def _obtainShapeHistograms(self, i, dataPath, ewkPath, dsetMgr, plotName, luminosity, normFactors): Verbose("_obtainShapeHistograms()", True) if self._verbose: self.PrintShapeInputSummary(dataPath, ewkPath, dsetMgr, plotName, luminosity, normFactors) Verbose("Obtain the (pre-normFactor) shape %s as \"DataDrivenQCDShape\" type object" % (plotName), True) myShape = dataDrivenQCDCount.DataDrivenQCDShape(dsetMgr, "Data", "EWK", plotName, dataPath, ewkPath, luminosity, self._useInclusiveNorm) #pre-normFactor if self._verbose: msg = "Printing TH1s (before NormFactors) of \"Data\", \"Data-Driven QCD\", \"EWK\", and \"Bin-by\Bin Purity\" and \"Integrated Purity\"" Print(msg, True) PrintTH1Info(myShape.getIntegratedDataHisto()) PrintTH1Info(myShape.getIntegratedDataDrivenQCDHisto()) #Data-EWK. NormFactor not applied PrintTH1Info(myShape.getIntegratedEwkHisto()) PrintTH1Info(myShape.getPurityHisto()) PrintTH1Info(myShape.getIntegratedPurityForShapeHisto()) if self._verbose: self.PrintShapePuritySummary(myShape) Verbose("Obtain the (post-normFactor) shape %s as \"QCDInvertedShape\" type object (Takes \"DataDrivenQCDShape\" type object as argument)" % (plotName), True) moduleInfo = self._moduleInfoString + "_" + plotName myPlot = QCDInvertedShape(myShape, moduleInfo, normFactors, optionUseInclusiveNorm=self._useInclusiveNorm) myPlot.PrintSettings(printHistos=self._verbose, verbose=self._verbose) myShape.delete() myPlotHisto = aux.Clone(myPlot.getResultShape(), "ctrlPlotShapeInManager") myPlot.delete() myPlotHisto.SetName(plotName+"%d"%i) myPlotHisto.SetTitle(plotName) self._shapePlots.append(myPlotHisto) self._shapePlotLabels.append(plotName) # MC EWK and purity myPlotMCEWKHisto = aux.Clone(myPlot.getResultMCEWK(), "ctrlPlotMCEWKInManager") myPlotMCEWKHisto.SetName(plotName+"%d_MCEWK"%i) myPlotMCEWKHisto.SetTitle(plotName+"_MCEWK") self._shapePlots.append(myPlotMCEWKHisto) self._shapePlotLabels.append(myPlotMCEWKHisto.GetTitle()) myPlotPurityHisto = aux.Clone(myPlot.getResultPurity(), "ctrlPlotPurityInManager") myPlotPurityHisto.SetName(plotName+"%d_Purity"%i) myPlotPurityHisto.SetTitle(plotName+"_Purity") self._shapePlots.append(myPlotPurityHisto) self._shapePlotLabels.append(myPlotPurityHisto.GetTitle()) return myPlotHisto
def getIntegratedDataDrivenQCDHisto(self): h = aux.Clone(self._dataList[0]) h.SetName(h.GetName()+"Integrated") h.Add(self._ewkList[0],-1.0) for i in range(1, len(self._dataList)): h.Add(self._dataList[i]) h.Add(self._ewkList[i],-1.0) return h
def getDataHistoForSplittedBin(self, binIndex): ''' Return the data in a given phase space split bin ''' if binIndex >= len(self._dataList): # FIXME: New addition to fix "optionUseInclusiveNorm" functionality (24-Mar-2018). Should not affect binned result! if self._optionUseInclusiveNorm: #new h = aux.Clone(self._dataList[0]) #new h.SetName(h.GetName() + "_") #new return h #new msg = "Requested bin index %d out of range (0-%d)!" % ( binIndex, len(self._dataList)) raise Exception(ShellStyles.ErrorLabel() + msg + ShellStyles.NormalStyle()) h = aux.Clone(self._dataList[binIndex]) h.SetName(h.GetName() + "_") return h
def getIntegratedEwkHisto(self): ''' Return the sum of ewk integrated over the phase space splitted bins ''' h = aux.Clone(self._histoList[0]) h.SetName("_".join(h.GetName().split("_", 2)[:2]) + "_EWK_Integrated") for i in range(1, len(self._histoList)): h.Add(self._histoList[i]) return h
def getIntegratedDataHisto(self): ''' Return the sum of data integrated over the phase space splitted bins ''' h = aux.Clone(self._dataList[0]) #h.SetName(h.GetName()+"Integrated") #original code h.SetName("_".join(h.GetName().split("_", 2)[:2]) + "_Data_Integrated") for i in range(1, len(self._dataList)): h.Add(self._dataList[i]) return h
def getEwkHistoForSplittedBin(self, binIndex): ''' Return the EWK MC in a given phase space split bin ''' if binIndex >= len(self._dataList): raise Exception( ShellStyles.ErrorLabel() + "DataDrivenQCDShape::getEwkHistoForSplittedBin: requested bin index %d out of range (0-%d)!" % (binIndex, len(self._ewkList))) h = aux.Clone(self._ewkList[binIndex]) h.SetName(h.GetName() + "_") return h
def calculateTotalVariationHistograms(self, hRate, hup, hdown): # Calculate total uncertainty (only for reference, note that can give also negative results) hFitUncertaintyUpTotal = aux.Clone(hup[0], self._label + "_TailFitUp") hFitUncertaintyUpTotal.Reset() hFitUncertaintyDownTotal = aux.Clone(hup[0], self._label + "_TailFitDown") hFitUncertaintyDownTotal.Reset() for i in range(1, hup[0].GetNbinsX() + 1): myPedestal = hRate.GetBinContent(i) myVarianceUp = 0.0 myVarianceDown = 0.0 for j in range(0, len(hup)): a = 0.0 b = 0.0 #if hup[j].GetBinContent(i) > 1e-10: #a = hup[j].GetBinContent(i) - myPedestal #if hdown[j].GetBinContent(i) > 1e-10: #b = hdown[j].GetBinContent(i) - myPedestal if hup[j].GetBinContent(i) > 0.0: a = hup[j].GetBinContent(i) - myPedestal else: a = -myPedestal if hdown[j].GetBinContent(i) > 0.0: b = hdown[j].GetBinContent(i) - myPedestal else: b = -myPedestal if abs(a) != float('Inf') and not math.isnan( a) and abs(b) != float('Inf') and not math.isnan(b): (varA, varB) = aux.getProperAdditivesForVariationUncertainties( a, b) myVarianceUp += varA myVarianceDown += varB #print j,hup[j].GetBinContent(i),hdown[j].GetBinContent(i),a,b,varA,varB #print self._hFitFineBinning.GetXaxis().GetBinLowEdge(i),":", myPedestal,math.sqrt(myVarianceUp), math.sqrt(myVarianceDown), myPedestal+math.sqrt(myVarianceUp), myPedestal-math.sqrt(myVarianceDown) hFitUncertaintyUpTotal.SetBinContent( i, myPedestal + math.sqrt(myVarianceUp)) hFitUncertaintyDownTotal.SetBinContent( i, myPedestal - math.sqrt(myVarianceDown)) return (hFitUncertaintyUpTotal, hFitUncertaintyDownTotal)
def __init__(self, h, label, fitFuncName, fitmin, fitmax, applyFitFrom, doPlots=False, luminosity=None): self._label = label self._fittedRate = None self._centralParams = None self._eigenVectors = None self._eigenValues = None self._fitmin = fitmin self._hRate = aux.Clone(h) self._luminosity = luminosity # Initialize style myStyle = tdrstyle.TDRStyle() myStyle.setOptStat(True) myStyle.tdrStyle.SetOptFit(True) # Find fit function class scaleFactor = h.Integral(h.FindBin(fitmin), h.GetNbinsX() + 1) * 1.01 self._myFitFuncObject = self._findFitFunction(fitFuncName, scaleFactor) # Obtain bin list for fine binning (compatibility with fine binning) myBinList = [] for i in range(1, h.GetNbinsX() + 1): myBinList.append(h.GetXaxis().GetBinLowEdge(i)) myBinList.append(h.GetXaxis().GetBinUpEdge(h.GetNbinsX())) # Do fit myFitResult = self._doFit(h, myBinList, fitFuncName, fitmin, fitmax) # Calculate eigenvectors and values self._calculateEigenVectorsAndValues(myFitResult, printStatus=True) # Create histograms and control plots if doPlots: (hFitUncertaintyUp, hFitUncertaintyDown) = self.calculateVariationHistograms( myBinList, applyFitFrom) self.makeVariationPlotDetailed("FineBinning", self._hRate, self._hFitFineBinning, hFitUncertaintyUp, hFitUncertaintyDown) (hupTotal, hdownTotal) = self.calculateTotalVariationHistograms( self._hFitFineBinning, hFitUncertaintyUp, hFitUncertaintyDown) self.makeVariationPlotSimple("FineBinning", self._hRate, self._hFitFineBinning, hupTotal, hdownTotal)
def getAndRebinQCDShapeNuisanceHistos(columnName, rootFile, hRate, nuisanceInfo, binlist): if not "QCD" in columnName: return [] myHistograms = [] # Loop over nuisance info for n in nuisanceInfo: if n["distribution"] == "shape" and n[ columnName] == "1" and "QCD_metshape" in n["name"]: # Obtain numerator and denominator myNumName = "%s_QCD_metshapeSource_Numerator" % (columnName) myDenomName = "%s_QCD_metshapeSource_Denominator" % (columnName) hNum = rootFile.Get(myNumName) if hNum == None: raise Exception(ErrorLabel() + "Cannot find histogram '%s'!" % myNumName) hDenom = rootFile.Get(myDenomName) if hDenom == None: raise Exception(ErrorLabel() + "Cannot find histogram '%s'!" % myDenomName) myArray = array.array("d", binlist) hDenomRebinned = hDenom.Rebin(len(myArray) - 1, "", myArray) hNumRebinned = hNum.Rebin(len(myArray) - 1, "", myArray) hDenom.Delete() hNum.Delete() # Create output histograms hUp = aux.Clone(hRate, "%s_QCD_metshapeUp" % columnName) hDown = aux.Clone(hRate, "%s_QCD_metshapeDown" % columnName) hUp.Reset() hDown.Reset() # Calculate systematicsForMetShapeDifference.createSystHistograms( hRate, hUp, hDown, hNumRebinned, hDenomRebinned) myHistograms.append(hUp) myHistograms.append(hDown) return myHistograms
def getIntegratedPurityForShapeHisto(self): ''' Return the QCD purity in bins of the final shape ''' hData = self.getIntegratedDataHisto() hEwk = self.getIntegratedEwkHisto() # newName = ("_".join(hData.GetName().split("_", 2)[:2]) + "_IntegratedPurity_" + str(self._uniqueN) ) newName = hData.GetName() + "_Purity" h = aux.Clone(hData, newName) nameList = self._dataList[0].GetName().split("_") newTitle = "PurityByFinalShapeBin_%s" % nameList[0][:len(nameList[0]) - 1] h.SetTitle(newTitle) self._uniqueN += 1 # For-loop: All bins for i in range(1, h.GetNbinsX() + 1): myPurity = 0.0 myUncert = 0.0 nData = hData.GetBinContent(i) nEWK = hEwk.GetBinContent(i) # Calculate the purity if (nData > 0.0): myPurity = (nData - nEWK) / nData # Sanity check if myPurity < 0.0: myPurity = 0.0 myUncert = 0.0 else: # Assume binomial error myUncertSq = myPurity * (1.0 - myPurity) / nData if myUncertSq >= 0.0: myUncert = sqrt(myUncertSq) else: msg = "Purity is greater than 1 (%.4f) in bin %i of histogram %s" % ( myPurity, i, h.GetName()) self.Verbose(ShellStyles.WarningLabel() + msg, True) myUncert = 0.0 # Set the purity value for the given bin h.SetBinContent(i, myPurity) h.SetBinError(i, myUncert) return h
def getIntegratedPurityForShapeHisto(self): hData = self.getIntegratedDataHisto() hEwk = self.getIntegratedEwkHisto() h = aux.Clone(hData, "%s_purity_%d"%(hData,self._uniqueN)) myNameList = self._dataList[0].GetName().split("_") h.SetTitle("PurityByFinalShapeBin_%s"%myNameList[0][:len(myNameList[0])-1]) self._uniqueN += 1 for i in range(1, h.GetNbinsX()+1): myPurity = 0.0 myUncert = 0.0 if (hData.GetBinContent(i) > 0.0): myPurity = (hData.GetBinContent(i) - hEwk.GetBinContent(i)) / hData.GetBinContent(i) if myPurity < 0.0: myPurity = 0.0 myUncert = 0.0 else: myUncert = sqrt(myPurity * (1.0-myPurity) / hData.GetBinContent(i)) # Assume binomial error h.SetBinContent(i, myPurity) h.SetBinError(i, myUncert) return h
def getIntegratedNewDsetHisto(self): ''' Return the sum of all datasets to be merged over the entire phase space ''' newName = "%s_%s" % (self._histoName, self._newDsetName) histo = aux.Clone(self._histoList[0], newName) histo.Reset() # For-loop: All histograms in list for i, h in enumerate(self._histoList, 0): self.Verbose( "self.histoList[%s] = %s " % (i, self._histoList[i].GetName()), True) histo.Add(self._histoList[i]) self.Verbose("histo.Integral() += %.2f" % (histo.Integral()), False) self.Verbose( "Integral of histogram %s is %.3f (Entries = %d)" % (histo.GetName(), histo.Integral(), histo.GetEntries()), True) return histo
def getIntegratedPurityForShapeHisto(self): ''' Return the QCD purity in bins of the final shape ''' hData = self.getIntegratedDataHisto() hEwk = self.getIntegratedEwkHisto() #cloneName = "%s_purity_%d" % (hData, self._uniqueN) # original code cloneName = ("_".join(hData.GetName().split("_", 2)[:2]) + "_IntegratedPurity_" + str(self._uniqueN)) h = aux.Clone(hData, cloneName) nameList = self._dataList[0].GetName().split("_") h.SetTitle("PurityByFinalShapeBin_%s" % nameList[0][:len(nameList[0]) - 1]) self._uniqueN += 1 # For-loop: All bins for i in range(1, h.GetNbinsX() + 1): myPurity = 0.0 myUncert = 0.0 if (hData.GetBinContent(i) > 0.0): myPurity = (hData.GetBinContent(i) - hEwk.GetBinContent(i)) / hData.GetBinContent(i) if myPurity < 0.0: myPurity = 0.0 myUncert = 0.0 else: # Assume binomial error myUncertSq = myPurity * (1.0 - myPurity) / hData.GetBinContent(i) if myUncertSq >= 0.0: myUncert = sqrt(myUncertSq) else: msg = "Purity is greater than 1 (%.4f) in bin %i of histogram %s" % ( myPurity, i, h.GetName()) self.Verbose(ShellStyles.WarningLabel() + msg, True) myUncert = 0.0 h.SetBinContent(i, myPurity) h.SetBinError(i, myUncert) return h
def _obtainScaleFactor(self, h, fitmin, fitmax): raise Exception( "There is something fishy in this function, validate before using") minbin = h.GetXaxis().FindBin(fitmin) maxbin = h.GetXaxis().FindBin(fitmax) hh = aux.Clone(h) preFactor = hh.Integral(minbin, hh.GetNbinsX() + 1) hh.Scale(1.0 / preFactor) myFitFunc = FitFuncPreFitForIntegral(self._fitmin) myFittedRate = ROOT.TF1(self._label + "myFitForIntegral", myFitFunc, fitmin, fitmax, myFitFunc.getNparam()) myFitResult = hh.Fit(myFittedRate, _fitOptions) # Set fitted params to function for i in range(0, myFitFunc.getNparam()): myFittedRate.SetParameter(i, myFitResult.Parameter(i)) # Calculate integral from fitmin to infinity and divide by bin width to normalize myBinWidth = (hh.GetXaxis().GetBinLowEdge(maxbin) - hh.GetXaxis().GetBinLowEdge(minbin)) / (maxbin - minbin) myScaleFactor = myFittedRate.Integral(minbin, 1e5) / myBinWidth * preFactor print "Scale factor calc cross-check: integral from histogram = %f, integral from fit = %f" % ( preFactor, myScaleFactor) print myFittedRate.Integral(minbin, 1e5), myBinWidth, preFactor return myScaleFactor
def _doCalculate(self, shape, moduleInfoString, normFactors, optionPrintPurityByBins, optionDoNQCDByBinHistograms): # Calculate final shape in signal region (shape * w_QCD) nSplitBins = shape.getNumberOfPhaseSpaceSplitBins() # Initialize result containers self._resultShape = aux.Clone( shape.getDataDrivenQCDHistoForSplittedBin(0)) self._resultShape.Reset() self._resultShape.SetTitle("NQCDFinal_Total_%s" % moduleInfoString) self._resultShape.SetName("NQCDFinal_Total_%s" % moduleInfoString) self._resultShapeEWK = aux.Clone( shape.getDataDrivenQCDHistoForSplittedBin(0)) self._resultShapeEWK.Reset() self._resultShapeEWK.SetTitle("NQCDFinal_EWK_%s" % moduleInfoString) self._resultShapeEWK.SetName("NQCDFinal_EWK_%s" % moduleInfoString) self._resultShapePurity = aux.Clone( shape.getDataDrivenQCDHistoForSplittedBin(0)) self._resultShapePurity.Reset() self._resultShapePurity.SetTitle("NQCDFinal_Purity_%s" % moduleInfoString) self._resultShapePurity.SetName("NQCDFinal_Purity_%s" % moduleInfoString) self._histogramsList = [] myUncertaintyLabels = ["statData", "statEWK"] self._resultCountObject = extendedCount.ExtendedCount( 0.0, [0.0, 0.0], myUncertaintyLabels) if optionDoNQCDByBinHistograms: for i in range(0, nSplitBins): hBin = aux.Clone(self._resultShape) hBin.SetTitle( "NQCDFinal_%s_%s" % (shape.getPhaseSpaceBinFileFriendlyTitle(i).replace( " ", ""), moduleInfoString)) hBin.SetName( "NQCDFinal_%s_%s" % (shape.getPhaseSpaceBinFileFriendlyTitle(i).replace( " ", ""), moduleInfoString)) self._histogramsList.append(hBin) if isinstance(self._resultShape, ROOT.TH2): self._doCalculate2D(nSplitBins, shape, normFactors, optionPrintPurityByBins, optionDoNQCDByBinHistograms, myUncertaintyLabels) return # Intialize counters for purity calculation in final shape binning myShapeDataSum = [] myShapeDataSumUncert = [] myShapeEwkSum = [] myShapeEwkSumUncert = [] for j in range(1, self._resultShape.GetNbinsX() + 1): myShapeDataSum.append(0.0) myShapeDataSumUncert.append(0.0) myShapeEwkSum.append(0.0) myShapeEwkSumUncert.append(0.0) # Calculate results separately for each phase space bin and then combine for i in range(0, nSplitBins): # Get data-driven QCD, data, and MC EWK shape histogram for the phase space bin h = shape.getDataDrivenQCDHistoForSplittedBin(i) hData = shape.getDataHistoForSplittedBin(i) hEwk = shape.getEwkHistoForSplittedBin(i) # Get normalization factor wQCDLabel = shape.getPhaseSpaceBinFileFriendlyTitle(i) if self._optionUseInclusiveNorm: wQCDLabel = "Inclusive" wQCD = 0.0 if not wQCDLabel in normFactors.keys(): print ShellStyles.WarningLabel( ) + "No normalization factors available for bin '%s' when accessing histogram %s! Ignoring this bin..." % ( wQCDLabel, shape.getHistoName()) else: wQCD = normFactors[wQCDLabel] # Loop over bins in the shape histogram for j in range(1, h.GetNbinsX() + 1): myResult = 0.0 myStatDataUncert = 0.0 myStatEwkUncert = 0.0 if abs(h.GetBinContent(j)) > 0.00001: # Ignore zero bins # Calculate result myResult = h.GetBinContent(j) * wQCD # Calculate abs. stat. uncert. for data and for MC EWK myStatDataUncert = hData.GetBinError(j) * wQCD myStatEwkUncert = hEwk.GetBinError(j) * wQCD #errorPropagation.errorPropagationForProduct(hLeg1.GetBinContent(j), hLeg1Data.GetBinError(j), myEffObject.value(), myEffObject.uncertainty("statData")) # Do not calculate here MC EWK syst. myCountObject = extendedCount.ExtendedCount( myResult, [myStatDataUncert, myStatEwkUncert], myUncertaintyLabels) self._resultCountObject.add(myCountObject) if optionDoNQCDByBinHistograms: self._histogramsList[i].SetBinContent( j, myCountObject.value()) self._histogramsList[i].SetBinError( j, myCountObject.statUncertainty()) self._resultShape.SetBinContent( j, self._resultShape.GetBinContent(j) + myCountObject.value()) self._resultShape.SetBinError( j, self._resultShape.GetBinError(j) + myCountObject.statUncertainty()**2) # Sum squared # Sum items for purity calculation myShapeDataSum[j - 1] += hData.GetBinContent(j) * wQCD myShapeDataSumUncert[j - 1] += (hData.GetBinError(j) * wQCD)**2 myShapeEwkSum[j - 1] += hEwk.GetBinContent(j) * wQCD myShapeEwkSumUncert[j - 1] += (hEwk.GetBinError(j) * wQCD)**2 h.Delete() hData.Delete() hEwk.Delete() # Take square root of uncertainties for j in range(1, self._resultShape.GetNbinsX() + 1): self._resultShape.SetBinError( j, math.sqrt(self._resultShape.GetBinError(j))) # Print result print "NQCD Integral(%s) = %s " % ( shape.getHistoName(), self._resultCountObject.getResultStringFull("%.1f")) # Print purity as function of final shape bins if optionPrintPurityByBins: print "Purity of shape %s" % shape.getHistoName() print "shapeBin purity purityUncert" for j in range(1, self._resultShape.GetNbinsX() + 1): myPurity = 0.0 myPurityUncert = 0.0 if abs(myShapeDataSum[j - 1]) > 0.000001: myPurity = 1.0 - myShapeEwkSum[j - 1] / myShapeDataSum[j - 1] myPurityUncert = errorPropagation.errorPropagationForDivision( myShapeEwkSum[j - 1], math.sqrt(myShapeEwkSumUncert[j - 1]), myShapeDataSum[j - 1], math.sqrt(myShapeDataSumUncert[j - 1])) # Store MC EWK content self._resultShapeEWK.SetBinContent(j, myShapeEwkSum[j - 1]) self._resultShapeEWK.SetBinError( j, math.sqrt(myShapeEwkSumUncert[j - 1])) self._resultShapePurity.SetBinContent(j, myPurity) self._resultShapePurity.SetBinError(j, myPurityUncert) # Print purity info of final shape if optionPrintPurityByBins: myString = "" if j < self._resultShape.GetNbinsX(): myString = "%d..%d" % ( self._resultShape.GetXaxis().GetBinLowEdge(j), self._resultShape.GetXaxis().GetBinUpEdge(j)) else: myString = ">%d" % ( self._resultShape.GetXaxis().GetBinLowEdge(j)) myString += " %.3f %.3f" % (myPurity, myPurityUncert) print myString
def getIntegratedEwkHisto(self): h = aux.Clone(self._ewkList[0]) h.SetName(h.GetName()+"Integrated") for i in range(1, len(self._dataList)): h.Add(self._ewkList[i]) return h
def printSummaryInfo(columnNames, myNuisanceInfo, cachedHistos, hObs, m, luminosity, opts): config = aux.load_module(opts.settings) def addOrReplace(dictionary, key, newItem): if not key in dictionary.keys(): dictionary[key] = newItem.Clone() else: dictionary[key].Add(newItem) def getHisto(cachedHistos, name): for h in cachedHistos: if h.GetName() == name: return h raise Exception("Cannot find histogram '%s'!" % name) # Create for each column a root histo with uncertainties myDict = OrderedDict() myTotal = None # Loop over columns (datasets) for c in columnNames: # Bugfix to prevent crashing with blacklisted datasets if c in config.Blacklist: continue hRate = aux.Clone(getHisto(cachedHistos, c)) myRHWU = RootHistoWithUncertainties(hRate) for n in myNuisanceInfo: # Add shape uncertainties if n["name"] != "observation" and n[ "distribution"] == "shape" and n[ c] == "1" and not "statBin" in n["name"]: hUp = aux.Clone( getHisto(cachedHistos, "%s_%sUp" % (c, n["name"]))) hDown = aux.Clone( getHisto(cachedHistos, "%s_%sDown" % (c, n["name"]))) myRHWU.addShapeUncertaintyFromVariation(n["name"], hUp, hDown) # Add constant uncertainties elif n["name"] != "observation" and n["name"] != "rate" and n[ "name"] != "process" and n[c] != "-" and n[ c] != "1" and not "statBin" in n[ "name"] and not "BinByBin" in n["name"]: diffUp = 0.0 diffDown = 0.0 if "/" in n[c]: mySplit = n[c].split("/") diffDown = float(mySplit[0]) - 1.0 diffUp = float(mySplit[1]) - 1.0 else: diffDown = float(n[c]) - 1.0 diffUp = float(n[c]) - 1.0 myRHWU.addNormalizationUncertaintyRelative( n["name"], diffUp, diffDown) # Store column info _myBr = 0.01 myAddToTotalStatus = False if c.startswith("HH") or c.startswith("CMS_Hptntj_HH"): myRHWU.Scale(_myBr**2) addOrReplace(myDict, "Hp", myRHWU) elif c.startswith("HW") or c.startswith("CMS_Hptntj_HW"): myRHWU.Scale(2.0 * _myBr * (1.0 - _myBr)) addOrReplace(myDict, "Hp", myRHWU) elif c.startswith("Hp") or c.startswith("CMS_Hptntj_Hp"): addOrReplace(myDict, "Hp", myRHWU) elif c == "EWK_Tau" or c.startswith("CMS_Hptntj_EWK_Tau"): addOrReplace(myDict, "EWKtau", myRHWU) myAddToTotalStatus = True elif c.endswith("genuinetau"): addOrReplace(myDict, c.replace("CMS_Hptntj_", ""), myRHWU) myAddToTotalStatus = True elif c.endswith("faketau"): addOrReplace(myDict, "EWKfakes", myRHWU) myAddToTotalStatus = True elif c.startswith("QCD") or c.startswith("CMS_Hptntj_QCD"): addOrReplace(myDict, "QCD", myRHWU) myAddToTotalStatus = True else: myDict[c] = myRHWU myAddToTotalStatus = True if myAddToTotalStatus: if myTotal == None: myTotal = myRHWU.Clone() else: myTotal.Add(myRHWU.Clone()) myDict["Totalbkg"] = myTotal # Make table print "\nEvent yields:" myTotal = None for item in myDict.keys(): if myDict[item] != None: myDict[item].makeFlowBinsVisible() rate = myDict[item].getRate() stat = myDict[item].getRateStatUncertainty() (systUp, systDown) = myDict[item].getRateSystUncertainty() #myDict[item].Debug() print "%11s: %.1f +- %.1f (stat.) + %.1f - %.1f (syst.)" % ( item, rate, stat, systUp, systDown) print "Observation: %d\n\n" % hObs.Integral(0, hObs.GetNbinsX() + 2) def setTailFitUncToStat(rhwu): tailfitNames = filter(lambda n: "_TailFit_" in n, rhwu.getShapeUncertaintyNames()) rhwu.setShapeUncertaintiesAsStatistical(tailfitNames) #rhwu.printUncertainties() #print rhwu.getShapeUncertaintiesAsStatistical() return rhwu myLogList = [False, True] for l in myLogList: # Create post fit shape myStackList = [] if "QCD" in myDict.keys(): myHisto = histograms.Histo( setTailFitUncToStat(myDict["QCD"].Clone()), "QCD", legendLabel=ControlPlotMaker._legendLabelQCD) myHisto.setIsDataMC(isData=False, isMC=True) myStackList.append(myHisto) if "EWKtau" in myDict.keys(): myHisto = histograms.Histo( setTailFitUncToStat(myDict["EWKtau"].Clone()), "Embedding", legendLabel=ControlPlotMaker._legendLabelEmbedding) myHisto.setIsDataMC(isData=False, isMC=True) myStackList.append(myHisto) for c in myDict.keys(): if c.endswith("genuinetau"): histoID = c.replace("CMS_Hptntj_", "").replace("_genuinetau", "") lookupTable = { # Map column name to style in plots.py "tt": "TT", "W": "WJets", "t": "SingleTop", "DY": "DYJetsToLL", "VV": "Diboson", "tt_and_singleTop": "TTandSingleTop", "EWK": "EWK" } histoString = lookupTable[histoID] myHisto = histograms.Histo( setTailFitUncToStat(myDict[c].Clone()), histoString, legendLabel=c.replace("CMS_Hptntj_", "")) myHisto.setIsDataMC(isData=False, isMC=True) myStackList.append(myHisto) if "EWKfakes" in myDict.keys() and myDict["EWKfakes"] != None: myHisto = histograms.Histo( myDict["EWKfakes"].Clone(), "EWKfakes", legendLabel=ControlPlotMaker._legendLabelEWKFakes) myHisto.setIsDataMC(isData=False, isMC=True) myStackList.append(myHisto) myBlindedStatus = not opts.unblinded myBlindingString = None hObsLocal = aux.Clone(hObs) if myBlindedStatus: myBlindingString = "%d-%d GeV" % (hObs.GetXaxis().GetBinLowEdge(1), hObs.GetXaxis().GetBinUpEdge( hObs.GetNbinsX())) for i in range(0, hObs.GetNbinsX()): hObsLocal.SetBinContent(i, -1.0) hObsLocal.SetBinError(i, 0.0) # Add data myDataHisto = histograms.Histo(hObsLocal, "Data") myDataHisto.setIsDataMC(isData=True, isMC=False) myStackList.insert(0, myDataHisto) # Add signal mySignalLabel = "TTToHplus_M%d" % float(m) if float(m) > 179: mySignalLabel = "HplusTB_M%d" % float(m) myHisto = histograms.Histo(myDict["Hp"].Clone(), mySignalLabel) myHisto.setIsDataMC(isData=False, isMC=True) myStackList.insert(1, myHisto) # Make plot myStackPlot = plots.DataMCPlot2(myStackList) myStackPlot.setLuminosity(luminosity) #myStackPlot.setEnergy("%d"%self._config.OptionSqrtS) myStackPlot.setDefaultStyles() myParams = {} if myBlindedStatus: myParams["blindingRangeString"] = myBlindingString myParams["cmsTextPosition"] = "right" myParams["ratio"] = True myParams["ratioType"] = "errorScale" myParams["ratioYlabel"] = "Data/Bkg. " myParams["stackMCHistograms"] = True myParams["addMCUncertainty"] = True myParams["addLuminosityText"] = True myParams["moveLegend"] = {"dx": -0.14, "dy": -0.10} myParams["ratioErrorOptions"] = {"numeratorStatSyst": False} myParams["ratioCreateLegend"] = True #myParams["ratioMoveLegend"] = {"dx": -0.51, "dy": 0.03} myParams["ratioMoveLegend"] = {"dx": -0.06, "dy": -0.1} myParams["opts2"] = {"ymin": 0.0, "ymax": 2.5} myParams["xlabel"] = "m_{T} (GeV)" #if l: # myParams["ylabel"] = "< Events / bin >" #else: myParams["ylabel"] = "Events / 20 GeV" a = hObsLocal.GetXaxis().GetBinWidth(1) b = hObsLocal.GetXaxis().GetBinWidth(hObsLocal.GetNbinsX()) #if abs(a-b) < 0.0001: #myParams["ylabel"] += "%d GeV"%a #else: #myParams["ylabel"] += "%d-%d GeV"%(a,b) #myParams["divideByBinWidth"] = l myParams["log"] = l myPlotName = "PostTailFitShape_M%d" % float(m) if l: # scale ymin by 20 in order to compare the rebinned mT with same y-scale # ymax(factor) takes care of max automatically myParams["opts"] = {"ymin": 20 * 1e-5} else: myParams["opts"] = {"ymin": 0.0} myPlotName += "_Linear" plots.drawPlot(myStackPlot, myPlotName, **myParams)
def updateNuisanceTail(opts, hOriginalShape, hFittedShape, rootFile, histoName, skipNotFoundTest=False): myList = [] myPostfixes = ["Up", "Down"] for postfix in myPostfixes: # Obtain original nuisance histogram hOriginalNuisance = rootFile.Get(histoName + postfix) hOriginalNuisance.Scale(opts.lumiProjection * opts.bkgxsecProjection) if hOriginalNuisance == None: if skipNotFoundTest: return [] else: raise Exception(ErrorLabel() + "Cannot open histogram '%s'!" % (histoName + postfix)) # Sanity check if hOriginalShape.GetNbinsX() != hOriginalNuisance.GetNbinsX(): raise Exception("This should not happen") # Prepare new histogram hNewNuisance = aux.Clone(hFittedShape, histoName + postfix) hNewNuisance.Reset() hNewNuisance.SetMarkerSize(0) # Loop over final histogram bins for i in range(1, hFittedShape.GetNbinsX() + 1): myOriginalBin = hOriginalShape.GetXaxis().FindBin( hFittedShape.GetXaxis().GetBinLowEdge(i) + 0.0001) myOriginalBinUpEdge = hOriginalShape.GetXaxis().FindBin( hFittedShape.GetXaxis().GetBinUpEdge(i) - 0.0001) if myOriginalBin != myOriginalBinUpEdge: raise Exception( ErrorLabel() + "final rebinning boundaries at %d-%d do not match to original histogram (needed for shape nuisance scaling)!" % (hFittedShape.GetXaxis().GetBinLowEdge(i), hFittedShape.GetXaxis().GetBinUpEdge(i))) # Original relative uncertainty (if ambiguous, leave as None, i.e. perform no scaling myOriginalDelta = None if abs(hOriginalNuisance.GetBinContent(myOriginalBin)) < 0.00001: myOriginalDelta = None elif abs(hOriginalShape.GetBinContent(myOriginalBin)) < 0.00001: myOriginalDelta = None else: myOriginalDelta = hOriginalNuisance.GetBinContent( myOriginalBin) / hOriginalShape.GetBinContent( myOriginalBin) #print i, myOriginalBin, myOriginalDelta, hOriginalNuisance.GetBinContent(myOriginalBin), hOriginalShape.GetBinContent(myOriginalBin) # Calculate new variation counts myNewVariation = None if myOriginalDelta == None: # scale by bin width difference myNewVariation = hOriginalNuisance.GetBinContent( myOriginalBin) * hFittedShape.GetXaxis().GetBinWidth( i) / hOriginalNuisance.GetXaxis().GetBinWidth( myOriginalBin) else: myNewVariation = myOriginalDelta * hFittedShape.GetBinContent( i) #print i, myNewVariation, hFittedShape.GetBinContent(i) # Store hNewNuisance.SetBinContent(i, myNewVariation) hNewNuisance.SetBinError(i, hOriginalShape.GetBinError(myOriginalBin)) # Finalize hOriginalNuisance.Delete() hNewNuisance.SetTitle(histoName + postfix) myList.append(hNewNuisance) return myList
def drawAllInOne(self, myAllShapeNuisances, luminosity): myMaxSize = len(myAllShapeNuisances) # Create pads canvasHeight = _cHeaderHeight + _cBodyHeight * myMaxSize + _cFooterHeight c = ROOT.TCanvas("","",600,canvasHeight) c.Divide(1,myMaxSize) myHeightBefore = canvasHeight myHeightAfter = canvasHeight for i in range(0,myMaxSize): myHeightBefore = myHeightAfter p = c.cd(i+1) myTopMargin = 0.0 myBottomMargin = 0.0 if i == 0: # Top histogram with header myHeightAfter -= _cHeaderHeight + _cBodyHeight myTopMargin = float(_cHeaderHeight) / float(_cHeaderHeight+_cBodyHeight) elif i == myMaxSize-1: # Bottom histogram with x axis label and title myHeightAfter -= _cFooterHeight + _cBodyHeight myBottomMargin = float(_cFooterHeight) / float(_cFooterHeight+_cBodyHeight) else: # Middle histogram, only body myHeightAfter -= _cBodyHeight (xlow, ylow, xup, yup) = [ROOT.Double(x) for x in [0.0]*4] p.GetPadPar(xlow, ylow, xup, yup) p.SetPad(xlow, float(myHeightAfter)/float(canvasHeight), xup, float(myHeightBefore)/float(canvasHeight)) p.SetBorderMode(0) p.SetFillStyle(4000) p.SetTopMargin(myTopMargin) p.SetBottomMargin(myBottomMargin) # Draw plots if len(self._ratioPlotList) == 0: print "No ratioplots in list! Cannot draw all-in-one plot!" return o = self._ratioPlotList[0].getFrame2() myEmptyPlot = aux.Clone(o) # Keep the clone if it is needed to draw the x axis for i in range(0,myMaxSize): p = c.cd(i+1) # Find plot myPlotIndex = None for j in range(0,len(self._systNameList)): if myAllShapeNuisances[i] == self._systNameList[j]: myPlotIndex = j plot = None if myPlotIndex != None: plot = self._ratioPlotList[myPlotIndex].getFrame2() else: if i == myMaxSize-1: plot = myEmptyPlot # Use this to draw the x axis else: plot = self._ratioPlotList[0].getFrame2() # Only the empty frame matters # Draw plot if i == myMaxSize-1: # Bottom histogram plot.GetXaxis().SetTitleOffset(0.6*myMaxSize+0.6) # 6.6/10, 3.6/5 else: plot.GetXaxis().SetTitleSize(0) plot.GetXaxis().SetLabelSize(0) plot.GetYaxis().SetLabelSize(26) plot.GetYaxis().SetTitleOffset(0.34*myMaxSize+0.1) # 3.5/10, 1.8/5 # plot.SetMinimum(0.001) # plot.SetMaximum(1.999) plot.SetMinimum(0.601) plot.SetMaximum(1.399) plot.Draw() # Plot frame for every nuisance if myPlotIndex != None: self._ratioPlotList[myPlotIndex].ratioHistoMgr.draw() # Plot content only if affected self._ratioPlotList[0].ratioLine.Draw("L") p.RedrawAxis() # Labels for shape nuisance and dataset myHeight = 0.82 if i == 0: myHeight = myHeight*float(_cBodyHeight) / float(_cHeaderHeight+_cBodyHeight) elif i == myMaxSize-1: myHeight = (myHeight*float(_cBodyHeight)+float(_cFooterHeight)) / float(_cFooterHeight +_cBodyHeight) histograms.addText(x=0.18, y=myHeight, text=myAllShapeNuisances[i], size=30) myHeight = 0.08 if i == 0: myHeight = myHeight*float(_cBodyHeight) / float(_cHeaderHeight+_cBodyHeight) elif i == myMaxSize-1: myHeight = (myHeight*float(_cBodyHeight)+float(_cFooterHeight)) / float(_cFooterHeight +_cBodyHeight) histograms.addText(x=0.93, y=myHeight, text=self._dsetName, size=30, align="right") # Header labels if i == 0: histograms.addStandardTexts(lumi=luminosity, cmsTextPosition="outframe") # Labels for non-existing nuisances if myPlotIndex == None: myHeight = 0.44 if i == 0: myHeight = myHeight*float(_cBodyHeight) / float(_cHeaderHeight+_cBodyHeight) elif i == myMaxSize-1: myHeight = (myHeight*float(_cBodyHeight)+float(_cFooterHeight)) / float(_cFooterHeight +_cBodyHeight) histograms.addText(x=0.555, y=myHeight, text="Not affected", size=30, align="center") # Save plot myPlotName = "shapeSystRatioOnlyAll_%s"%(self._dsetName) backup = ROOT.gErrorIgnoreLevel ROOT.gErrorIgnoreLevel = ROOT.kError for suffix in [".png",".C",".eps"]: c.Print("%s/%s%s"%(_dirname,myPlotName,suffix)) ROOT.gErrorIgnoreLevel = backup