def __init__( self, dataPath, ewkPath, dsetMgr, luminosity, moduleInfoString, normFactors, #dataDrivenFakeTaus=False, #shapeOnly=False, #displayPurityBreakdown=False, #optionUseInclusiveNorm=False, optionCalculateQCDNormalizationSyst=True, normDataSrc=None, normEWKSrc=None, optionUseInclusiveNorm=False): self._shapePlots = [] self._shapePlotLabels = [] self._QCDNormalizationSystPlots = [] self._QCDNormalizationSystPlotLabels = [] self._moduleInfoString = moduleInfoString self._useInclusiveNorm = optionUseInclusiveNorm if len(normFactors.keys()) == 1 and normFactors.keys( )[0] == "Inclusive": self._useInclusiveNorm = True print ShellStyles.HighlightStyle( ) + "...Obtaining final shape" + ShellStyles.NormalStyle() # Determine list of plots to consider myObjects = dsetMgr.getDataset("Data").getDirectoryContent(dataPath) # Loop over plots to consider i = 0 for plotName in myObjects: i += 1 print ShellStyles.HighlightStyle( ) + "...Obtaining ctrl plot %d/%d: %s%s" % ( i, len(myObjects), plotName, ShellStyles.NormalStyle()) # Check that histograms exist mySkipStatus = self._sanityChecks(dsetMgr, dataPath, plotName) and self._sanityChecks( dsetMgr, ewkPath, plotName) if not mySkipStatus: continue # Obtain shape plots (the returned object is not owned) # print "DEBUG: ewkPath: ", ewkPath myShapeHisto = self._obtainShapeHistograms(i, dataPath, ewkPath, dsetMgr, plotName, luminosity, normFactors) # Obtain plots for systematics coming from met shape difference for control plots if optionCalculateQCDNormalizationSyst: if isinstance(myShapeHisto, ROOT.TH2): print ShellStyles.WarningLabel( ) + "Skipping met shape uncertainty because histogram has more than 1 dimensions!" else: self._obtainQCDNormalizationSystHistograms( myShapeHisto, dsetMgr, plotName, luminosity, normDataSrc, normEWKSrc)
def _sanityChecks(self, dsetMgr, dirName, plotName): ''' Check existence of histograms ''' # Definitions myStatus = True myFoundStatus = True # For-loop: All EWK datasets for d in dsetMgr.getDataset("EWK").datasets: if not d.hasRootHisto("%s/%s" % (dirName,plotName) ): myFoundStatus = False # If something is wrong if not myFoundStatus: myStatus = False msg = "Skipping '%s', because it does not exist for all EWK datasets (you probably forgot to set histo level to Vital when producing the multicrab)!" % (plotName) Print(ShellStyles.WarningLabel() + msg + ShellStyles.NormalStyle(), True) else: (myRootObject, myRootObjectName) = dsetMgr.getDataset("EWK").getFirstRootHisto("%s/%s" % (dirName,plotName) ) if isinstance(myRootObject, ROOT.TH2): msg ="Skipping '%s', because it is not a TH1 object" % (plotName) Print(ShellStyles.WarningLabel() + msg + ShellStyles.NormalStyle(), True) myStatus = False myRootObject.Delete() return myStatus
def check(a, b): if abs(a - b) < 0.00001: return TestPassedStyle() + "PASSED" + ShellStyles.NormalStyle() else: print ErrorStyle() + "FAILED (%f != %f)" % ( a, b) + ShellStyles.NormalStyle() raise Exception("Error: validation test failed!")
def selectLatest(self, dirs): if len(dirs) == 0: return "" if len(dirs) > 1: self.Print( "More than 1 path found! Will take the most recent one:") latest = dirs[0] for dir in dirs: if os.path.getmtime(dir) > os.path.getmtime(latest): latest = dir # Print all paths found and highlight the latest one for d in dirs: if d == latest: #self.Print(ShellStyles.NoteStyle() + latest + ShellStyles.NormalStyle(), False) self.Print( ShellStyles.SuccessStyle() + latest + ShellStyles.NormalStyle(), False) else: self.Print(d, False) return latest else: self.Verbose( ShellStyles.SuccessStyle() + "Selecting dir %s" % (dirs[0]) + ShellStyles.NormalStyle(), False) return dirs[0]
def __init__(self, binLabels, resultDirName, moduleInfoString, verbose=False): self._verbose = verbose self._templates = {} self._binLabels = binLabels self._sources = {} self._commentLines = [] self._NEvtsCR1 = {} self._NEvtsCR1_Error = {} self._NEvtsCR2 = {} self._NEvtsCR2_Error = {} self._NEvtsCR3 = {} self._NEvtsCR3_Error = {} self._NEvtsCR4 = {} self._NEvtsCR4_Error = {} self._TF = {} # Transfer Factor (TF) self._TF_Error = {} self._TF_Up = {} self._TF_Down = {} self._dqmKeys = OrderedDict() self._myPath = os.path.join(resultDirName, "normalisationPlots") self._BinLabelMap = {} self._FakeBNormalization = {} # for the time being same as TF self._FakeBNormalizationError = { } # for the time being same as TF_Error self._FakeBNormalizationUp = {} # for the time being same as TF_Up self._FakeBNormalizationDown = {} # for the time being same as TF_Down if not isinstance(binLabels, list): raise Exception("Error: binLabels needs to be a list of strings") self.Verbose("__init__") # No optimisation mode if moduleInfoString == "": moduleInfoString = "Default" if not os.path.exists(self._myPath): self.Print("Creating new directory %s" % (self._myPath), True) os.mkdir(self._myPath) self._plotDirName = os.path.join(resultDirName, "normalisationPlots", moduleInfoString) # If already exists, Delete an entire directory tree if os.path.exists(self._plotDirName): msg = "Removing directory tree %s" % (self._plotDirName) self.Verbose( ShellStyles.NoteStyle() + msg + ShellStyles.NormalStyle(), True) shutil.rmtree(self._plotDirName) msg = "Creating directory %s" % (self._plotDirName) self.Verbose( ShellStyles.SuccessStyle() + msg + ShellStyles.NormalStyle(), False) os.mkdir(self._plotDirName) return
def __init__(self, dataPath, ewkPath, dsetMgr, luminosity, moduleInfoString, normFactors, optionDoFakeBNormalisationSyst=True, normDataSrc=None, normEWKSrc=None, optionUseInclusiveNorm=False, keyList=[], verbose=False): self._verbose = verbose self._shapePlots = [] self._shapePlotLabels = [] self._QCDNormalizationSystPlots = [] self._QCDNormalizationSystPlotLabels = [] self._moduleInfoString = moduleInfoString self._useInclusiveNorm = optionUseInclusiveNorm if len(normFactors.keys()) == 1 and normFactors.keys()[0] == "Inclusive": self._useInclusiveNorm = True self._histoPathsData= self._GetHistoPaths(dsetMgr, "Data", dataPath, keyList) if ewkPath == dataPath: self._histoPathsEWK = self._histoPathsData else: self._histoPathsEWK = self._GetHistoPaths(dsetMgr, "EWK" , ewkPath , keyList) # Sanity check if len(self._histoPathsEWK) != len(self._histoPathsData): msg = "List of histograms for EWK does not match in size that of Data" raise Exception(ShellStyles.ErrorLabel() + msg + ShellStyles.NormalStyle()) # For-Loop: All plots to consider for i, plotName in enumerate(self._histoPathsData, 1): # Inform user of progress msg = "{:<9} {:>3} {:<1} {:<3} {:<80}".format("Histogram", "%i" % i, "/", "%s:" % (len(self._histoPathsData)), os.path.join(dataPath, plotName) ) self.PrintFlushed(ShellStyles.SuccessStyle() + msg + ShellStyles.NormalStyle(), False) if "JetEtaPhi_AfterAllSelections" in plotName: continue # Ensure that histograms exist && pass other sanity checks dataOk = self._sanityChecks(dsetMgr, dataPath, plotName) ewkOk = self._sanityChecks(dsetMgr, ewkPath , plotName) if dataOk*ewkOk == False: self.Print(ShellStyles.ErrorStyle() + msg + ShellStyles.NormalStyle(), i==1) continue self.Verbose("Obtaining shape plots (the returned object is not owned)", True) myShapeHisto = self._obtainShapeHistograms(i, dataPath, ewkPath, dsetMgr, plotName, luminosity, normFactors) # Obtain plots for systematics coming from invariant mass shape difference if optionDoFakeBNormalisationSyst: if isinstance(myShapeHisto, ROOT.TH2): msg = "Skipping invariant mass shape uncertainty because histogram has more than 1 dimensions!" self.Print(ShellStyles.WarningLabel() + msg, True) else: self._obtainQCDNormalizationSystHistograms(myShapeHisto, dsetMgr, plotName, luminosity, normDataSrc, normEWKSrc) #iro: fixme (missing plots) msg = "Obtaining final shape from data path %s" % (ShellStyles.NoteStyle() + dataPath + ShellStyles.NormalStyle()) self.Verbose(msg, True) return
def getTransferFactorsSrcFilename(dirName, fileName): src = os.path.join(dirName, fileName) if not os.path.exists(src): msg = "Normalisation factors ('%s') not found!\nRun script \"./getABCD_TF.py\" to auto-generate the transfer factors (TFs) file." % src raise Exception(ShellStyles.ErrorStyle() + msg + ShellStyles.NormalStyle()) else: Print( "Importing transfer factors (TFs) from file %s" % (ShellStyles.NoteStyle() + os.path.basename(src) + ShellStyles.NormalStyle()), True) return src
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 __init__(self, opts, basedir): self._opts = opts self._basedir = basedir self._allRetrieved = False self._limitCalculated = False self._output = "" self._findJobDir(basedir) if self._jobDir == None: if self._opts.printonly: msg = "Need to create and submit jobs first! Skipping ..." Print(ShellStyles.ErrorLabel() + msg, True) else: msg = "Creating and submitting " + basedir Verbose(msg, True) self._createAndSubmit() else: msg = "Check if limits have already been calculated ..." Verbose(msg, True) lumiPath = "%s/%s/limits.json" % (self._basedir, self._jobDir) if os.path.exists(lumiPath): msg = "File \"%s\" already exists!\n\tThe limit has already been calculated.\n\tSkipping ..." % ( lumiPath) Print( ShellStyles.NoteStyle() + msg + ShellStyles.NormalStyle(), True) self._limitCalculated = True else: msg = "Creating and submitting " + basedir Verbose(msg, True) self._createAndSubmit() #if not self._opts.printonly and not self._opts.lhcTypeAsymptotic: # self._getOutput() return
def main(opts): # Apply TDR style style = tdrstyle.TDRStyle() ROOT.gErrorIgnoreLevel = ROOT.kFatal # [Options: Print, kInfo, kWarning, kError, kBreak, kSysError, kFatal] ROOT.gROOT.SetBatch() ROOT.gStyle.SetOptStat(0) ROOT.gStyle.SetOptTitle(0) ROOT.gStyle.SetNdivisions(5, "X") # Find GoF directories (generated by GoF.sh script) myDirs = [] for d in os.listdir('.'): if not os.path.isdir(d): continue if "GoF_" in d: myDirs.append(d) if len(myDirs) < 1: raise Exception( "No goodness-of-fit directories found. Did your run the GoF.sh script to create them?" ) else: Verbose( "Found %d GoF directories: %s" % (len(myDirs), ", ".join(myDirs)), True) # For-loop: All GoF directories myAlgos = [] allowedAlgos = ["saturated", "KS", "AD"] # KS = Kolmogorov-Smirnov, AD = Anderson-Darling for d in myDirs: algo = d.split("_")[-1] if algo not in allowedAlgos: raise Exception( "The algorithm \"%s\" is invalid. Expected one of the following: %s" % (opts.algorithm, ", ".join(allowedAlgos))) else: myAlgos.append(algo) # For-loop: All GoF algorithms ran Print( "Found %d GoF algorithm results: %s" % (len(myDirs), ", ".join(myAlgos)), True) for i, algo in enumerate(myAlgos, 1): # Definitions opts.algorithm = algo opts.inputDir = "%s/GoF_%s" % (os.getcwd(), algo) opts.inputfile = "GoF_%s/higgsCombinetoys*.GoodnessOfFit.mH%s.*.root" % ( algo, opts.mass) opts.outputfile = "GoF_%s/GoF_%s_mH%s.root" % (algo, algo, opts.mass) doPlots(i, opts) Verbose( "All plots saved under directory %s" % (ShellStyles.NoteStyle() + aux.convertToURL(opts.saveDir, opts.url) + ShellStyles.NormalStyle()), True) return
def GetBinText(bin): #if bin == "Inclusive": # return "combined" #else: # return "bin-" + str(bin) if bin == "0": return "p_{T} < 80 GeV/c, |#eta| < 0.8" elif bin == "1": return "p_{T} = 80-200 GeV/c, |#eta| < 0.8" elif bin == "2": return "p_{T} > 200 GeV/c, |#eta| < 0.8" elif bin == "3": return "p_{T} < 80 GeV/c, |#eta| = 0.8-1.6" elif bin == "4": return "p_{T} = 80-200 GeV/c, |#eta| = 0.8-1.6" elif bin == "5": return "p_{T} > 200 GeV/c, |#eta| = 0.8-1.6" elif bin == "6": return "p_{T} < 80 GeV/c, |#eta| > 1.6" elif bin == "7": return "p_{T} = 80-200 GeV/c, |#eta| > 1.6" elif bin == "8": return "p_{T} > 200 GeV/c, |#eta| > 1.6" elif bin == "Inclusive": return "combined" else: raise Exception(ShellStyles.ErrorStyle() + "Unexpected bin %s" % (bin) + ShellStyles.NormalStyle())
def save(self,dirname): myFilename = dirname+"/signalAreaEvaluation.txt" myFile = open(myFilename, "w") myFile.write(self._output) myFile.close() print ShellStyles.HighlightStyle()+"Signal area evaluation written to: "+ShellStyles.NormalStyle()+myFilename self._output = ""
def getNormFactorFileList(dirName, fileBaseName): scriptList = [] # For-loop: All items (files/dir) in directory for item in os.listdir(dirName): fullPath = os.path.join(dirName, item) # Skip directories if os.path.isdir(fullPath): continue # Find files matching the script "Base" name (without moduleInfoStrings) if item.startswith((fileBaseName).replace("%s.py", "")): if item.endswith(".py"): scriptList.append(item) if len(scriptList) < 1: msg = "ERROR! Found no normalization info files under dir %s. Did you generate them?" % dirName raise Exception(ShellStyles.ErrorStyle() + msg + ShellStyles.NormalStyle()) else: msg = "Found %s norm-factor file(s):\n\t%s" % ( len(scriptList), "\n\t".join( os.path.join([os.path.join(dirName, s) for s in scriptList]))) Verbose(ShellStyles.NoteLabel() + msg, True) return scriptList
def __init__(self, dsetMgr, dsetLabelData, dsetLabelEwk, histoName, dataPath, ewkPath, luminosity, optionUseInclusiveNorm, verbose=False): self._verbose = verbose self._uniqueN = 0 self._splittedHistoReader = splittedHistoReader.SplittedHistoReader( dsetMgr, dsetLabelData) self._histoName = histoName self._optionUseInclusiveNorm = optionUseInclusiveNorm dataFullName = os.path.join(dataPath, histoName) ewkFullName = os.path.join(ewkPath, histoName) if (self._optionUseInclusiveNorm): msg = "Will create \"Inclusive\"-histogram results" self.Verbose( ShellStyles.NoteStyle() + msg + ShellStyles.NormalStyle(), False) self._dataList = list( self._getInclusiveHistogramsFromSingleSource( dsetMgr, dsetLabelData, dataFullName, luminosity)) # was called by default self._ewkList = list( self._getInclusiveHistogramsFromSingleSource( dsetMgr, dsetLabelEwk, ewkFullName, luminosity)) # was called by default else: msg = "Will create \"Splitted\"-histogram results" self.Verbose( ShellStyles.NoteStyle() + msg + ShellStyles.NormalStyle(), False) self._dataList = list( self._splittedHistoReader.getSplittedBinHistograms( dsetMgr, dsetLabelData, dataFullName, luminosity)) #FIXME: Does this work for Inclusive? self._ewkList = list( self._splittedHistoReader.getSplittedBinHistograms( dsetMgr, dsetLabelEwk, ewkFullName, luminosity)) #FIXME: Does this work for Inclusive? return
def _getAnalysisType(self, analysis): myAnalyses = ["HToTauNu", "HToTB"] if analysis not in myAnalyses: msg = "Unsupported analysis \"%s\". Please select one of the following: %s" % (analysis, ", ".join(myAnalyses)) raise Exception(ShellStyles.ErrorStyle() + msg + ShellStyles.NormalStyle() ) else: self.Print("Analysis type set to %s" % (sh_Note + analysis + sh_Normal), True) return analysis
def IsTH1(h, raiseExcept=False): if not isinstance(h, ROOT.TH1): msg = "Expected object of type ROOT.TH1, got \"%s\" instead" % (type(h)) if raiseExcept: raise Exception(ShellStyles.ErrorStyle() + msg + ShellStyles.NormalStyle()) return False else: return True
def writeModuleToRootFile(self, rootfile): # Create module directory rootfile.cd("/") myModuleDir = rootfile.mkdir(self._moduleName) # Save shape information for h in self._shapes: h.SetDirectory(myModuleDir) # Save data-driven control plots myDDPlotsDirName = "ForDataDrivenCtrlPlots" myDDPlotsDir = myModuleDir.mkdir(myDDPlotsDirName) for h in self._dataDrivenControlPlots: h.SetDirectory(myDDPlotsDir) # Save counter histogram myCounterDir = myModuleDir.mkdir("counters") myWeightedCounterDir = myCounterDir.mkdir("weighted") self._hCounters = ROOT.TH1F("counter", "counter", len(self._counters), 0, len(self._counters)) i = 1 for key in self._counters.keys(): self._hCounters.GetXaxis().SetBinLabel(i, key) i += 1 self._hCounters.SetBinContent(i, self._counters[key]) self._hCounters.SetBinError(i, self._counterUncertainties[key]) self._hCounters.SetDirectory(myWeightedCounterDir) # Save splittedBinInfo hType = str(type(self._hSplittedBinInfo)).lower() if "none" not in hType: self._hSplittedBinInfo.SetDirectory(myModuleDir) else: msg = "WARNING! Unexpected problem with splitted bin info histogram. Type is %s" % ( hType) self.Print( ShellStyles.ErrorStyle() + msg + ShellStyles.NormalStyle(), True) # Save parameter set, code version and data version #myModuleDir.Add(self._psetInfo) # Create config info for the module myConfigInfoDir = myModuleDir.mkdir("configInfo") self._hConfigInfo = ROOT.TH1F( "configinfo", "configinfo", 2, 0, 2 ) # Have to store the histogram to keep it alive for writing self._hConfigInfo.GetXaxis().SetBinLabel(1,"control") self._hConfigInfo.GetXaxis().SetBinLabel(1, "control") self._hConfigInfo.SetBinContent(1, 1) #self._hConfigInfo.GetXaxis().SetBinLabel(2,"energy") #self._hConfigInfo.SetBinContent(2, self._energy) self._hConfigInfo.GetXaxis().SetBinLabel(2, "luminosity") self._hConfigInfo.SetBinContent(2, self._luminosity) self._hConfigInfo.SetDirectory(myConfigInfoDir) myConfigInfoDir.Add(self._dataVersion) #myConfigInfoDir.Add(self._codeVersion) #.SetDirectory(rootfile) #self._codeVersion.SetDirectory(rootfile) return
def _GetHistoPaths(self, dsetMgr, dataset, folderPath, keyList): ''' Determine list of histograms to consider (full paths) The keyList contains strings that if ALL 2are contained in a histogram name the histogram will be added to the list of objects to be returned. ''' # Get all objects inside the ROOT file under specific directory msg = "Obtaining all ROOT file contents for dataset %s from folder %s (these must be filled in the Verification Region (VR))" % (dataset, ShellStyles.NoteStyle() + folderPath + ShellStyles.NormalStyle()) self.Verbose(msg, True) allObjects = dsetMgr.getDataset(dataset).getDirectoryContent(folderPath) keepObjects = [] skipObjects = [] # Remove anything which does not contain any string from the keyList for o in allObjects: if all(k in o for k in keyList): keepObjects.append(o) #print o elif any(k in o for k in keyList): pass else: skipObjects.append(o) # Count histograms in lists nAll = len(allObjects) nKeep = len(keepObjects) nSkip = len(skipObjects) if nKeep == 0: msg = "Did not find any compatible object under dir %s. Check the \"keyList\" provided" % (folderPath) raise Exception(ShellStyles.ErrorLabel() + msg + ShellStyles.NormalStyle()) # Now remove anything which does not contain any string from the keyList msg = "Skipping %i histograms for dataset %s. Did not match all keys %s" % (nSkip, dataset, ", ".join(keyList) ) self.Verbose(ShellStyles.NoteStyle() + msg + ShellStyles.NormalStyle(), True) for hName in skipObjects: self.Verbose(os.path.join(folderPath, hName), False) # Now remove anything which does not contain any string from the keyList msg = "Found %i histograms for dataset %s. Matched all keys %s" % (nKeep, dataset, ", ".join(keyList) ) self.Verbose(ShellStyles.NoteStyle() + msg + ShellStyles.NormalStyle(), True) for hName in keepObjects: self.Verbose(os.path.join(folderPath, hName), False) return keepObjects
def _getAnalysisType(self, analysis): myAnalyses = ["HToTauNu", "HToTB", "HToHW", "HToHW_background"] if analysis not in myAnalyses: msg = "Unsupported analysis \"%s\". Please select one of the following: %s" % ( analysis, ", ".join(myAnalyses)) raise Exception(ShellStyles.ErrorStyle() + msg + ShellStyles.NormalStyle()) else: return analysis
def _validateDatacard(self, config): if config.ControlPlots == None: return if config.OptionSqrtS == None: raise Exception( ShellStyles.ErrorLabel() + "Please set the parameter OptionSqrtS = <integer_value_in_TeV> in the config file!" + ShellStyles.NormalStyle()) return
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 _printSelection(self): # Define style here myNotSelectedStr = " " mySelectedStr = " %s--> " % (ShellStyles.HighlightStyle()) mySelectedSuffix = " <--%s" % (ShellStyles.NormalStyle()) print "\nSelected data eras:" for i in range(0, len(self._availableEras)): myStr = myNotSelectedStr mySuffix = "" if self._availableEras[i] in self._selectedEras: myStr = mySelectedStr mySuffix = mySelectedSuffix print "%s%2d: %s%s" % (myStr, i, self._availableEras[i].replace( "Run", ""), mySuffix) print "\nSelected search modes:" for i in range(0, len(self._availableSearchModes)): myStr = myNotSelectedStr mySuffix = "" if self._availableSearchModes[i] in self._selectedSearchModes: myStr = mySelectedStr mySuffix = mySelectedSuffix print "%s%2d: %s%s" % (myStr, i, self._availableSearchModes[i], mySuffix) print "\nSelected optimization modes:" for i in range(0, len(self._availableOptimizationModes)): myStr = myNotSelectedStr mySuffix = "" if self._availableOptimizationModes[ i] in self._selectedOptimizationModes: myStr = mySelectedStr mySuffix = mySelectedSuffix if self._availableOptimizationModes[i] == "": print "%s%2d: (nominal)%s" % (myStr, i, mySuffix) else: print "%s%2d: %s%s" % ( myStr, i, self._availableOptimizationModes[i].replace( "Opt", ""), mySuffix) if not self._disableSystematicsList: print "\nSelected systematic variations:" for i, systVar in enumerate(self._availableSystematicVariations): myStr = myNotSelectedStr mySuffix = "" if systVar in self._selectedSystematicVariations: myStr = mySelectedStr mySuffix = mySelectedSuffix if systVar == "": print "%s%2d: (nominal)%s" % (myStr, i, mySuffix) else: print "%s%2d: %s%s" % ( myStr, i, systVar.replace("SystVar", ""), mySuffix) print ""
def _sanityChecks(self, dsetMgr, dirName, plotName): myStatus = True myFoundStatus = True for d in dsetMgr.getDataset("EWK").datasets: if not d.hasRootHisto("%s/%s" % (dirName, plotName)): myFoundStatus = False if not myFoundStatus: myStatus = False print ShellStyles.WarningLabel( ) + "Skipping '%s', because it does not exist for all EWK datasets (you probably forgot to set histo level to Vital when producing the multicrab)!" % ( plotName) + ShellStyles.NormalStyle() else: (myRootObject, myRootObjectName) = dsetMgr.getDataset("EWK").getFirstRootHisto( "%s/%s" % (dirName, plotName)) if isinstance(myRootObject, ROOT.TH2): print ShellStyles.WarningLabel( ) + "Skipping '%s', because it is not a TH1 object!" % ( plotName) + ShellStyles.NormalStyle() myStatus = False myRootObject.Delete() return myStatus
def GetEnergy(self, dsetMgr): ''' Obtain luminosity information from the dataset manager ''' if isinstance(dsetMgr.getDataset("Data"), dataset.Dataset): myEnergy = dsetMgr.getDataset("Data").getEnergy() else: myEnergy = dsetMgr.getDataset("Data").datasets[0].getEnergy() msg = "Centre-of-Mass energy is %s TeV" % ( ShellStyles.NoteStyle() + myEnergy + ShellStyles.NormalStyle()) self.Verbose(msg, True) return float(myEnergy)
def getListOfSystematics(self): if self._analysisType == "HToTauNu": return self.getSystematicsForHToTauNu() elif self._analysisType == "HToTB": return self.getSystematicsForHToTB() elif self._analysisType == "HToHW": return self.getSystematicsForHToHW() elif self._analysisType == "HToHW_background": return self.getSystematicsForHToHW_background() else: raise Exception(ShellStyles.ErrorStyle() + "This should never be reached" + ShellStyles.NormalStyle())
def __init__(self, resultDirName, moduleInfoString, verbose=False): self._verbose = verbose self._templates = {} self._sources = {} self._commentLines = [] self._BinLabelMap = {} self._TF = {} # Transfer Factor (TF) self._TF_Error = {} self._TF_Up = {} self._TF_Down = {} self._dqmKeys = OrderedDict() self._myPath = os.path.join(resultDirName, "normalisationPlots") self.Verbose("__init__") # No optimisation mode if moduleInfoString == "": moduleInfoString = "Default" if not os.path.exists(self._myPath): self.Print("Creating new directory %s" % (self._myPath), True) os.mkdir(self._myPath) self._plotDirName = os.path.join(resultDirName, "normalisationPlots", moduleInfoString) # If already exists, Delete an entire directory tree if os.path.exists(self._plotDirName): msg = "Removing directory tree %s" % (self._plotDirName) self.Verbose( ShellStyles.NoteStyle() + msg + ShellStyles.NormalStyle(), True) shutil.rmtree(self._plotDirName) msg = "Creating directory %s" % (self._plotDirName) self.Verbose( ShellStyles.SuccessStyle() + msg + ShellStyles.NormalStyle(), False) os.mkdir(self._plotDirName) return
def ApplyBlinding(myObject, blindedRange = []): ''' myObject must be an instance of: h=histograms.Histo(rootHisto, "Label") and the rooHistos is an instance of: rootHisto = p.histoMgr.getHisto("HistoName").getRootHisto() ''' if len(blindedRange) != 2: msg = "Blinded range list requires exactly 2 values (got %s)" % len(blindedRange) raise Exception(ShellStyles.ErrorStyle() + msg + ShellStyles.NormalStyle()) # Definitions myMin = None myMax = None myHisto = myObject.getRootHisto() # For-loop: All histogram bins for i in range (1, myHisto.GetNbinsX()+1): myUpEdge = myHisto.GetXaxis().GetBinUpEdge(i) myLowEdge = myHisto.GetXaxis().GetBinLowEdge(i) # Define conditions c1 = (myLowEdge >= blindedRange[0] and myLowEdge <= blindedRange[1]) c2 = (myUpEdge >= blindedRange[0] and myUpEdge <= blindedRange[1]) c3 = (myLowEdge <= blindedRange[0] and myUpEdge >= blindedRange[1]) # Blind if any edge of the current bin is inside the blinded range or if bin spans over the blinded range if ( c1 or c2 or c3): if myMin == None or myLowEdge < myMin: myMin = myLowEdge if myMax == None or myUpEdge > myMax: myMax = myUpEdge # Blind data by setting bin content to -1.0 myHisto.SetBinContent(i, -1.0) myHisto.SetBinError(i, 0.0) if myMin == None: return None # Prepare blinding string for printing on canvas myMinFormat = "%" + "d" myMaxFormat = "%" + "d" if abs(myMin) < 1.0 and abs(myMin) > 0.00000001: myMinFormat = "%%.%df" % (abs(int(log10(myMin)))+1) if abs(myMax) < 1.0 and abs(myMax) > 0.00000001: myMaxFormat = "%%.%df" % (abs(int(log10(myMax)))+1) bString = myMinFormat%myMin+"-"+myMaxFormat%myMax return bString
def GetLuminosity(self, dsetMgr): ''' Obtain luminosity information from the dataset manager by looping over all data datasets ''' myLuminosity = 0.0 myDataDatasets = dsetMgr.getDataDatasets() for d in myDataDatasets: myLuminosity += d.getLuminosity() msg = "Integrated luminosity is %s%.3f%s" % ( ShellStyles.NoteStyle(), myLuminosity, ShellStyles.NormalStyle()) self.Verbose(msg, True) return myLuminosity
def GetTotalUncertainyTable(self, hRate, hSystUp, hSystDown, hLine, align): table = [] # Calculate total uncertainty rateNominalSum = hRate.Integral() rateSystUpSum = hSystUp.Integral() rateSystDownSum = hSystDown.Integral() signalUncert = 0.0 ctrlUncert = 0.0 ratio = 1.0 ratioSigma = 0.0 nBinsX = hRate.GetNbinsX() # For-loop: All bins in histo (up) for i in range(1, nBinsX + 1): signalUncert += hSystUp.GetBinError(i)**2 ctrlUncert += hSystDown.GetBinError(i)**2 # Sanity check if rateSystUpSum > 0.0 and rateSystDownSum > 0.0: # Calculate ratio and its error with error propagation ratio = rateSystUpSum / rateSystDownSum # Calculate ratio error with error propagation ratioSigma = errorPropagationForDivision(rateSystUpSum, sqrt(signalUncert), rateSystDownSum, sqrt(ctrlUncert)) # Calculate % errors up/down table.append(hLine) sigmaUp = (ratio + ratioSigma - 1.0) * 100 sigmaDown = (ratio - ratioSigma - 1.0) * 100 rangeX = "%s to %s" % (hRate.GetBinCenter(1), hRate.GetBinCenter(nBinsX)) rangeBins = "1 to %d" % (nBinsX) table.append( align.format(rangeBins, rangeX, "%.1f" % rateNominalSum, "%.1f" % rateSystUpSum, "%.1f" % rateSystDownSum, "%.1f" % (sigmaUp), "%.1f" % (sigmaDown))) evtYield = "{:^85}".format( "Events +/- stat. +/- syst. = %.1f +/- %.1f +/- %.1f" % (rateNominalSum, abs(rateNominalSum - rateSystUpSum), abs(rateNominalSum - rateSystDownSum))) table.append(ShellStyles.HighlightAltStyle() + evtYield + ShellStyles.NormalStyle()) table.append(hLine) return table
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