def getSignalTreeFromJob(self, job, dilepton, cut="", useNLL=False): if len(self.runRanges) > 1: log.logError("Should only have one runRange when calling getTreeFromJob") runRange = self.runRanges[0] signalType = job.split("_")[0] append = {} append["2016"] = "_Summer16" append["2017"] = "_Fall17" append["2018"] = "_Autumn18" if useNLL: path = locations[runRange.era]["dataSetPathSignalNLL%s"%signalType] else: path = locations[runRange.era]["dataSetPathSignal%s"%signalType] tree = ROOT.TChain() tree.Add(readTrees(path, dilepton)[job+append[runRange.era]]) if (cut != ""): log.logDebug("Cutting tree down to: %s" % cut) if tree.GetEntries() > 0: tree = tree.CopyTree(cut) log.logError("Tree size: %d entries" % (tree.GetEntries())) if (tree != None): tree.SetDirectory(0) return tree
def clone(self): if (self.is2DHistogram): log.logError("Cloning of 2d histograms not supported!") return None cloneHistogram = ROOT.TH1F(self.histogram) clone = Result(cloneHistogram) clone.dataName = self.dataName clone.dataVersion = self.dataVersion clone.taskName = self.taskName clone.flagName = self.flagName clone.dataType = self.dataType clone.scaled = self.scaled clone.unscaledIntegral = self.unscaledIntegral clone.scalingFactor = self.scalingFactor clone.luminosity = self.luminosity clone.xSection = self.xSection clone.kFactor = self.kFactor clone.nEvents = self.nEvents clone.__scaledAndAdded = self.__scaledAndAdded clone.currentIntegralError = self.currentIntegralError clone.title = self.title # not supported self.is2DHistogram = False return clone
def getTreeFromJob(self, job, dilepton, cut="", useNLL=False): if len(self.runRanges) > 1: log.logError("Should only have one runRange when calling getTreeFromJob") runRange = self.runRanges[0] if useNLL: path = locations[runRange.era].dataSetPathNLL else: path = locations[runRange.era].dataSetPath tree = ROOT.TChain() tree.Add(readTrees(path, dilepton)[job]) cut = cut + runRange.runCut if useNLL: cut = cut + " && vetoHEM == 1" if (cut != ""): log.logDebug("Cutting tree down to: %s" % cut) if tree.GetEntries() > 0: tree = tree.CopyTree(cut) log.logError("Tree size: %d entries" % (tree.GetEntries())) if (tree != None): tree.SetDirectory(0) return tree
def provideNCanvas(n=2, title="Same Sign Dilepton SUSY analysis"): if (n < 1): log.logError("'%d' is not a valid number of pads!") return None if (n == 1): [c1, pad1, pad2] = provideDoubleCanvas() return [c1, [pad1]] if (n == 2): [c1, pad1, pad2] = provideDoubleCanvas() return [c1, [pad1, pad2]] if (n == 3): [c1, pad1, pad2, pad3, pad4] = provideQuadCanvas() return [c1, [pad1, pad2, pad3]] if (n == 4): [c1, pad1, pad2, pad3, pad4] = provideQuadCanvas() return [c1, [pad1, pad2, pad3, pad4]] # window settings theCanvasSizeX = 1520 theCanvasSizeY = 920 theScreenSizeX = 1680 theScreenSizeY = 1050 # canvas posX = int(theScreenSizeX * 0.04) posY = int(theScreenSizeY * 0.03) #posX = (theScreenSizeX - theCanvasSizeX) / 2 #posY = (theScreenSizeY - theCanvasSizeY) / 2 c1 = TCanvas('c1', title, posX, posY, theCanvasSizeX, theCanvasSizeY) i = int(math.ceil(-0.5 + 0.5 * math.sqrt(4.0 * n + 1.0))) nRows = i nColumns = i + 1 log.logDebug("no. of columns: %d" % nColumns) log.logDebug("no. of rows: %d" % nRows) c1.Divide(nColumns, nRows, 0.0001, 0.0001) pads = [] iPad = 1 for iRow in range(0, nRows): for iColumn in range(0, nColumns): if (iPad <= n): c1.cd(iPad) pad = TPad('pad%d' % iPad, 'Pad for %dth histogram' % iPad, 0.03, 0.03, 0.97, 0.97, 0) pad.Draw() pads.extend([pad]) iPad += 1 log.logDebug("Pads: %s" % pads) return [c1, pads]
def _calculateRatios(self): if (self.hasHistograms): tempRatioUp = None tempRatioDown = None nBin = 0 for iBin in range(1, 1 + self.denominator.GetNbinsX()): den = self.denominator.GetBinContent(iBin) denError = self.denominator.GetBinError(iBin) denUp = self.denominatorUp.GetBinContent(iBin) denUpError = self.denominatorUp.GetBinError(iBin) denDown = self.denominatorDown.GetBinContent(iBin) denDownError = self.denominatorDown.GetBinError(iBin) #~ log.logDebug("den: %f +- %f" % (den, denError)) #~ log.logDebug("denup: %f +- %f" % (denUp, denUpError)) #~ log.logDebug("dendown: %f +- %f" % (denDown, denDownError)) x = self.denominator.GetBinCenter(iBin) width = self.denominator.GetBinWidth(iBin) # assure that bin is in view range if (self.xMin < x and x < self.xMax): ratioUp = Ratio(denUp, den, math.pow(denUpError, 2.0), math.pow(denError, 2.0), x, width) ratioDown = Ratio(denDown, den, math.pow(denDownError, 2.0), math.pow(denError, 2.0), x, width) #~ log.logInfo("ratioUp: %f, ratioDown: %f" % (ratioUp.ratio, ratioDown.ratio)) if (tempRatioUp != None): tempRatioUp.addRatio(ratioUp) tempRatioDown.addRatio(ratioDown) else: tempRatioUp = ratioUp tempRatioDown = ratioDown #~ if (tempRatioUp.isFullEnough(self.rebinErrorBoundary) and tempRatioDown.isFullEnough(self.rebinErrorBoundary)): if (iBin == self.binMerging[nBin]): nBin = nBin + 1 self.__ratiosUp__.append(tempRatioUp) self.__ratiosDown__.append(tempRatioDown) tempRatioUp = None tempRatioDown = None if (tempRatioUp != None): self.__ratiosUp__.append(tempRatioUp) self.__ratiosDown__.append(tempRatioDown) else: log.logError( "Trying to calculate error ratios, but histograms not set!")
def getHistogramFromFile(self, fileName, histoPath): log.logDebug("Getting histogram '%s'\n from file %s" % (histoPath, fileName)) file = TFile(fileName, 'READ') histogram = file.Get(histoPath) if (histogram == None): log.logError("Could not get histogram '%s'\n from file %s" % (histoPath, fileName)) file.Close() return None else: histogram.SetDirectory(0) histogram.Sumw2() file.Close() return histogram
def integral(self): #log.logDebug("bin1: %f" % self.histogram.GetBinContent(1)) #a = self.histogram.GetBinContent(1) #if (a == ): # log.logError("NAN!") try: min = 0 binMin = self.histogram.FindBin(min) binMax = self.histogram.FindBin(Result.xMax) return self.histogram.Integral(binMin, binMax) except: log.logError("Cannot get histogram integral") return - 1
def getTrees(theConfig, datasets, central=True): import dataInterface #~ theDataInterface = dataInterface.dataInterface(dataVersion=dataVersion) theDataInterface = dataInterface.DataInterface(theConfig.dataSetPath,theConfig.dataVersion) treePathOFOS = "/EMuDileptonTree" treePathEE = "/EEDileptonTree" treePathMM = "/MuMuDileptonTree" treesMCOFOS = ROOT.TList() treesMCEE = ROOT.TList() treesMCMM = ROOT.TList() if central: cut = theConfig.selection.cut + " && abs(eta1) < 1.4 && abs(eta2) < 1.4" else: cut = theConfig.selection.cut + " && 1.6 <= TMath::Max(abs(eta1),abs(eta2)) && !(abs(eta1) > 1.4 && abs(eta1) < 1.6) && !(abs(eta2) > 1.4 && abs(eta2) < 1.6)" for dataset in datasets: scale = 0.0 # dynamic scaling jobs = dataInterface.InfoHolder.theDataSamples[theConfig.dataVersion][dataset] if (len(jobs) > 1): log.logDebug("Scaling and adding more than one job: %s" % (jobs)) for job in jobs: treeMCOFOSraw = theDataInterface.getTreeFromJob(theConfig.flag, theConfig.task, job, treePathOFOS, dataVersion=theConfig.dataVersion, cut=theConfig.selection.cut) treeMCEEraw = theDataInterface.getTreeFromJob(theConfig.flag, theConfig.task, job, treePathEE, dataVersion=theConfig.dataVersion, cut=theConfig.selection.cut) treeMCMMraw = theDataInterface.getTreeFromJob(theConfig.flag, theConfig.task, job, treePathMM, dataVersion=theConfig.dataVersion, cut=theConfig.selection.cut) dynNTotal = theDataInterface.getEventCount(job, theConfig.flag, theConfig.task) dynXsection = theDataInterface.getCrossSection(job) dynScale = dynXsection * theConfig.runRange.lumi / dynNTotal if (dynScale != scale): log.logInfo("dyn scale for %s (%s): n = %d, x = %f => %f" % (job, dataset, dynNTotal, dynXsection, dynScale)) scale = dynScale else: log.logError("No dynamic scale applied. This should never happen!") # convert trees treesMCOFOS.Add(dataInterface.DataInterface.convertDileptonTree(treeMCOFOSraw, weight=scale)) treesMCEE.Add(dataInterface.DataInterface.convertDileptonTree(treeMCEEraw, weight=scale)) treesMCMM.Add(dataInterface.DataInterface.convertDileptonTree(treeMCMMraw, weight=scale)) treeMCOFOStotal = ROOT.TTree.MergeTrees(treesMCOFOS) treeMCEEtotal = ROOT.TTree.MergeTrees(treesMCEE) treeMCMMtotal = ROOT.TTree.MergeTrees(treesMCMM) return (treeMCOFOStotal, treeMCEEtotal, treeMCMMtotal)
def _calculateRatios(self): if (self.hasHistograms): tempRatioUp = None tempRatioDown = None nBin = 0 for iBin in range(1, 1 + self.denominator.GetNbinsX()): den = self.denominator.GetBinContent(iBin) denError = self.denominator.GetBinError(iBin) denUp = self.denominatorUp.GetBinContent(iBin) denUpError = self.denominatorUp.GetBinError(iBin) denDown = self.denominatorDown.GetBinContent(iBin) denDownError = self.denominatorDown.GetBinError(iBin) #~ log.logDebug("den: %f +- %f" % (den, denError)) #~ log.logDebug("denup: %f +- %f" % (denUp, denUpError)) #~ log.logDebug("dendown: %f +- %f" % (denDown, denDownError)) x = self.denominator.GetBinCenter(iBin) width = self.denominator.GetBinWidth(iBin) # assure that bin is in view range if (self.xMin < x and x < self.xMax): ratioUp = Ratio(denUp, den, math.pow(denUpError, 2.0), math.pow(denError, 2.0), x, width) ratioDown = Ratio(denDown, den, math.pow(denDownError, 2.0), math.pow(denError, 2.0), x, width) #~ log.logInfo("ratioUp: %f, ratioDown: %f" % (ratioUp.ratio, ratioDown.ratio)) if (tempRatioUp != None): tempRatioUp.addRatio(ratioUp) tempRatioDown.addRatio(ratioDown) else: tempRatioUp = ratioUp tempRatioDown = ratioDown #~ if (tempRatioUp.isFullEnough(self.rebinErrorBoundary) and tempRatioDown.isFullEnough(self.rebinErrorBoundary)): if (iBin == self.binMerging[nBin]): nBin = nBin+1 self.__ratiosUp__.append(tempRatioUp) self.__ratiosDown__.append(tempRatioDown) tempRatioUp = None tempRatioDown = None if (tempRatioUp != None): self.__ratiosUp__.append(tempRatioUp) self.__ratiosDown__.append(tempRatioDown) else: log.logError("Trying to calculate error ratios, but histograms not set!")
def scale(self, factor): if (self.histogram == None): log.logError("Trying to scale empty result") return if (self.is2DHistogram): log.logError("Scaling not implemented for 2D histograms.") return self.histogram.Scale(factor) #log.logDebug("Result: Scaling factor = %f" % (self.scalingFactor)) if (self.scalingFactor < 0): self.scalingFactor = factor else: self.scalingFactor *= factor if (self.currentIntegralError > 0.0): self.currentIntegralError *= factor #log.logDebug("Result: Scaling factor afterwards = %f" % (self.scalingFactor)) self.scaled = True
def integralError(self): if (self.currentIntegralError >= 0.0): return self.currentIntegralError if (self.is2DHistogram): log.logError("Integral error not implemented for 2D histograms.") return - 1 if (self.scaled): # have differently scaled histograms been added? (cannot calculate error the usual way) if (self.__scaledAndAdded): log.logError("Result scaled and added, but integral error value not set.") return - 1 # usual way if (self.unscaledIntegral < 0 or self.scalingFactor < 0): log.logWarning("Could not determine integral error: unscaled integral or scaling factor not set!") return - 1 #log.logDebug("Scaled Error: sqrt(%f) * %f = %f" % (self.unscaledIntegral, self.scalingFactor, sqrt(self.unscaledIntegral) * self.scalingFactor)) return sqrt(self.unscaledIntegral) * self.scalingFactor else: return sqrt(self.integral())
def parseSLHA(slha, pdgIds=[24]): """ parse SUSY Les Houches Accord (SLHA) formated strings (e.g. SOFTSUSY output) """ from re import match result = {} massBlock = "" block = None for line in slha.splitlines(): blockRe = match("Block ([a-zA-Z]+).*", line) if not blockRe == None: block = blockRe.group(1) if block == "MASS": for pdgId in pdgIds: pdgIdRe = match("\s*%s\s*([0-9.e\+-]+)"%pdgId, line) if not pdgIdRe == None: result[pdgId] = float(pdgIdRe.group(1)) for pdgId in pdgIds: if not pdgId in result: log.logError("could not find %s"%pdgId) log.logDebug(slha) return result
def getTreeFromDataset(self, dataset, dilepton, cut="", useNLL=False): tree = ROOT.TChain() baseCut = cut for runRange in self.runRanges: if useNLL: path = locations[runRange.era].dataSetPathNLL else: path = locations[runRange.era].dataSetPath log.logDebug("Adding %s tree from %s"%(dataset, path)) ROOT.TH1.AddDirectory(False) tmpTree = readTrees(path, dilepton)[dataset] ROOT.TH1.AddDirectory(True) tree.Add(tmpTree) runCuts = [] runCut = "" for runRange in self.runRanges: runCuts.append(runRange.runCut[3:]) if useNLL: runCuts.append("vetoHEM == 1") runCut = "&& (%s)"%(" || ".join(runCuts)) cut = cut + runCut print tree.GetEntries() if (cut != ""): log.logDebug("Cutting tree down to: %s" % cut) #tree = tree.CopyTree(cut, "", 1000) tree = tree.CopyTree(cut) #log.logError("Tree size: %d entries" % (tree.GetEntries())) if (tree != None): tree.SetDirectory(0) else: log.logError("Tree invalid") return tree
def getSignalTrees(theConfig, signals, useNLL=False): import dataInterface treesMCEM = ROOT.TList() treesMCEE = ROOT.TList() treesMCMM = ROOT.TList() runRanges = theConfig.runRanges cut = theConfig.selection.cut for runRange in runRanges: scale = 0.0 theDataInterface = dataInterface.DataInterface([ runRange, ]) for signal in signals: treeMCEMraw = theDataInterface.getSignalTreeFromJob(signal, "EMu", cut=cut, useNLL=useNLL) treeMCEEraw = theDataInterface.getSignalTreeFromJob(signal, "EE", cut=cut, useNLL=useNLL) treeMCMMraw = theDataInterface.getSignalTreeFromJob(signal, "MuMu", cut=cut, useNLL=useNLL) from helpers import getSignalGenEvents, getSignalXsec dynXsection = getSignalXsec(signal, runRange) dynNTotal = getSignalGenEvents(signal, runRange) dynScale = dynXsection * runRange.lumi / (dynNTotal) if (dynScale != scale): log.logInfo("dyn scale for %s: n = %d, x = %f => %f" % (signal, dynNTotal, dynXsection, dynScale)) scale = dynScale else: log.logError( "No dynamic scale applied. This should never happen!") if not treeMCEMraw == None: treesMCEM.Add( dataInterface.DataInterface.convertDileptonTree( treeMCEMraw, weight=scale)) if not treeMCEEraw == None: treesMCEE.Add( dataInterface.DataInterface.convertDileptonTree( treeMCEEraw, weight=scale)) if not treeMCMMraw == None: treesMCMM.Add( dataInterface.DataInterface.convertDileptonTree( treeMCMMraw, weight=scale)) treeMCEMtotal = ROOT.TTree.MergeTrees(treesMCEM) treeMCEEtotal = ROOT.TTree.MergeTrees(treesMCEE) treeMCMMtotal = ROOT.TTree.MergeTrees(treesMCMM) return (treeMCEMtotal, treeMCEEtotal, treeMCMMtotal)
def getTrees(theConfig, datasets, useNLL=False): import dataInterface treesMCEM = ROOT.TList() treesMCEE = ROOT.TList() treesMCMM = ROOT.TList() runRanges = theConfig.runRanges cut = theConfig.selection.cut for runRange in runRanges: theDataInterface = dataInterface.DataInterface([ runRange, ]) for dataset in datasets: scale = 0.0 # dynamic scaling eventCounts = totalNumberOfGeneratedEvents( locations[runRange.era].dataSetPath) proc = Process(getattr(Backgrounds[runRange.era], dataset), eventCounts) if (len(proc.samples) > 1): log.logDebug("Scaling and adding more than one job: %s" % (proc.samples)) for job, dynNTotal, dynXsection, dynNegWeightFraction in zip( proc.samples, proc.nEvents, proc.xsecs, proc.negWeightFractions): treeMCEMraw = theDataInterface.getTreeFromJob(job, "EMu", cut=cut, useNLL=useNLL) treeMCEEraw = theDataInterface.getTreeFromJob(job, "EE", cut=cut, useNLL=useNLL) treeMCMMraw = theDataInterface.getTreeFromJob(job, "MuMu", cut=cut, useNLL=useNLL) #~ dynScale = dynXsection * theConfig.runRange.lumi / dynNTotal print runRange.lumi dynScale = dynXsection * runRange.lumi / ( dynNTotal * (1 - 2 * dynNegWeightFraction)) if (dynScale != scale): log.logInfo( "dyn scale for %s (%s): n = %d, x = %f => %f" % (job, dataset, dynNTotal, dynXsection, dynScale)) scale = dynScale else: log.logError( "No dynamic scale applied. This should never happen!") # convert trees if not treeMCEMraw == None: treesMCEM.Add( dataInterface.DataInterface.convertDileptonTree( treeMCEMraw, weight=scale)) if not treeMCEEraw == None: treesMCEE.Add( dataInterface.DataInterface.convertDileptonTree( treeMCEEraw, weight=scale)) if not treeMCMMraw == None: treesMCMM.Add( dataInterface.DataInterface.convertDileptonTree( treeMCMMraw, weight=scale)) treeMCEMtotal = ROOT.TTree.MergeTrees(treesMCEM) treeMCEEtotal = ROOT.TTree.MergeTrees(treesMCEE) treeMCMMtotal = ROOT.TTree.MergeTrees(treesMCMM) return (treeMCEMtotal, treeMCEEtotal, treeMCMMtotal)
def setXSection(self, xSection): if (xSection <= 0.0): log.logError("Cannot set result cross section to zero or less (%f)" % xSection) else: self.xSection = xSection
def addResult(self, result): if (self.histogram == None): log.logWarning("Adding to empty result!") if (result.histogram == None): log.logWarning("... also adding empty result!") return result if (result.histogram == None): log.logWarning("Adding empty result!") return self if (not self.scaled == result.scaled): log.logError("Cannot add scaled and unscaled results") return None if (self.dataType != result.dataType): log.logError("Cannot add results of different data types (%d, %d)" % (self.dataType, results.dataType)) return None # lumi info if (self.luminosity > 0 and result.luminosity > 0): if (self.dataType == InfoHolder.DataTypes.Data): self.luminosity += result.luminosity # for data else: pass # for MC and Unknown else: log.logWarning("Adding results without complete luminosity information (%f, %f)" % (self.luminosity, result.luminosity)) self.luminosity = -1 # xSection info if (self.xSection > 0 and result.xSection > 0): self.xSection += result.xSection else: if (self.dataType != InfoHolder.DataTypes.Data): log.logWarning("Adding results without complete xSection information (%f, %f)" % (self.xSection, result.xSection)) self.xSection = -1 # xSection info if (self.kFactor > 0 and result.kFactor > 0): if (self.kFactor != result.kFactor): log.logHighlighted("Adding results with different kFactors (%f, %f). Will not be able to track this any more." % (self.kFactor, result.kFactor)) self.kFactor = -1 else: log.logInfo("Adding results without complete kFactor information (%f, %f)" % (self.kFactor, result.kFactor)) self.kFactor = -1 if (not self.scaled): self.histogram.Add(result.histogram) return self if (self.scalingFactor == result.scalingFactor): self.unscaledIntegral += result.unscaledIntegral self.histogram.Add(result.histogram) return self log.logDebug("Combining results: %s, %s" % (str(self), str(result))) # first calculate new error self.currentIntegralError = sqrt(self.integralError() * self.integralError() + result.integralError() * result.integralError()) # then change histogram self.histogram.Add(result.histogram) self.unscaledIntegral += result.unscaledIntegral self.scalingFactor = -1 # finally mark result as scaled and added self.__scaledAndAdded = True log.logDebug("... to: %s" % (str(self))) return self