def __init__( self, *args ): self.filenames = args # Hold the data self.histogram_titles = {} self.histogram_data = {} # Let's keep all the header information self.headers = [] # The first file defines the data structure. We want an error if we combine differently structured files. first_file = True # Read all files for filename in self.filenames: if os.path.exists( filename ): self.filename = filename else: raise IOError( "File does not exist: %s" % filename ) header = "" with open( filename ) as f: reading_header = True # read content of file for line in f.readlines(): if line.startswith( "# Histogram"): reading_header = False key, value = line.rstrip().lstrip("# Histogram").split(":") self.histogram_titles[int(key)] = value.lstrip().rstrip() elif line[0]!='#': s_n, s_x0, s_y, s_y_err, s_hits = line.rstrip().rstrip('|').split('|') n = int(s_n) x0 = float(s_x0) y = float(s_y) y_err = float(s_y_err) hits = int(s_hits) # protection: Take structure from first file. Any extra bin subsequent files will raise error if first_file: if not self.histogram_data.has_key(n): self.histogram_data[n] = {} if not self.histogram_data[n].has_key(x0): self.histogram_data[n][x0] = u_float(0) self.histogram_data[n][x0]+=u_float(y,y_err) else: if reading_header: header+=line # Keep headers self.headers.append( header ) first_file = False logger.info( "Read %i histograms from file %s", len(self.histogram_data.keys()), filename ) # Make histograms. Don't make them again. self.__histos = { n: self.__make_histo__( n ) for n in self.histogram_data.keys() }
def xsec(self, modified_couplings = None, overwrite=False, skip=False): key = self.getKey( modified_couplings ) # Do we have the x-sec? if self.xsecDB.contains(key) and not overwrite: logger.debug( "Found x-sec %s for key %r. Do nothing.", self.xsecDB.get(key), key ) return self.xsecDB.get(key) elif skip: return u_float(0) else: print "Trying to get xsec" self.__initialize( modified_couplings ) logger.info( "Calculating x-sec" ) # rerun MG to obtain the correct x-sec (with more events) with open( os.path.join( self.processTmpDir, 'Cards/run_card.dat'), 'a') as f: f.write(".false. = gridpack\n") logger.info( "Calculate x-sec: Calling bin/generate_events" ) output = subprocess.check_output([ os.path.join( self.processTmpDir, 'bin/generate_events') , '-f']) for i in range(10): try: output = subprocess.check_output([ os.path.join( self.processTmpDir, 'bin/generate_events') , '-f']) m = re.search("Cross-section :\s*(.*) \pb", output) logger.info( "x-sec: {} pb".format(m.group(1)) ) break except ValueError: logger.info("Encountered problem during the MG run. Restarting.") xsec_ = u_float.fromString(m.group(1)) self.xsecDB.add(key, xsec_, overwrite=True) logger.info( "Done!" ) return xsec_
def getEstimateFromCard(cardFile, estimateName, binName): res = u_float(0) binNumber = getBinNumber(cardFile, binName) uncName = 'Stat_' + binName + '_' + estimateName with open(cardFile) as f: binList = False estimateList = False for line in f: if len(line.split())==0: continue if line.split()[0] == "bin": if not binList: binList = True else: binList = line.split()[1:] if line.split()[0] == "process": if not estimateList: estimateList = line.split()[1:] if line.split()[0] == "rate": for i in range(len(binList)): if binList[i] == binNumber and estimateList[i]==estimateName: try: res.val = float(line.split()[1:][i]) except: res.val = 0 #return float(line.split()[1:][i]) if line.split()[0] != uncName: continue for i in range(len(binList)): if binList[i] == binNumber and estimateList[i]==estimateName: try: res.sigma = (float(line.split()[2:][i])-1)*res.val except: res.sigma = 0. return res
def _estimate(self, region, channel, setup): ''' Concrete implementation of abstract method 'estimate' as defined in Systematic ''' logger.debug("MC prediction for %s channel %s" % (self.name, channel)) if channel == 'all': # 'all' is the total of all contributions return sum( [self.cachedEstimate(region, c, setup) for c in channels]) elif channel == 'SF': # 'all' is the total of all contributions return sum([ self.cachedEstimate(region, c, setup) for c in ['MuMu', 'EE'] ]) else: preSelection = setup.preselection('MC', channel=channel, isFastSim=self.isFastSim) cut = "&&".join([ region.cutString(setup.sys['selectionModifier']), preSelection['cut'] ]) weight = preSelection['weightStr'] logger.debug("Using cut %s and weight %s" % (cut, weight)) return setup.lumi[channel] / 1000. * u_float( **self.sample[channel].getYieldFromDraw(selectionString=cut, weightString=weight))
def _estimate(self, region, channel, setup): ''' Concrete implementation of abstract method 'estimate' as defined in Systematic ''' logger.debug( "MC prediction for %s channel %s" %(self.name, channel.name) ) if channel.name=='all': # 'all' is the total of all contributions if setup.nLeptons == 1: channels = singlelepChannels elif setup.nLeptons == 3: channels = trilepChannels elif setup.nLeptons == 4: channels = quadlepChannels else: raise NotImplementedError return sum([self.cachedEstimate(region, c, setup) for c in channels]) #elif channel=='SF': # # 'all' is the total of all contributions # return sum([self.cachedEstimate(region, c, setup) for c in ['MuMu', 'EE']]) else: preSelection = setup.preselection('MC', nElectrons=channel.nE, nMuons=channel.nM, isFastSim = self.isFastSim) cut = "&&".join([region.cutString(setup.sys['selectionModifier']), preSelection['cut']]) weight = preSelection['weightStr'] logger.debug( "Using cut %s and weight %s"%(cut, weight) ) return setup.lumi/1000.*u_float(**self.sample.getYieldFromDraw(selectionString = cut, weightString = weight) )
def yieldFromCache(self, setup, sample, c, selectionString, weightString): s = (sample, c, selectionString, weightString) if self.helperCache and self.helperCache.contains(s): return self.helperCache.get(s) else: yieldFromDraw = u_float( **setup.samples[sample][c].getYieldFromDraw( selectionString, weightString)) if self.helperCache: self.helperCache.add(s, yieldFromDraw) return yieldFromDraw
def getTotalPostFitUncertainty(cardFile, binName): binNumber = getBinNumber(cardFile, binName) with open(cardFile) as f: binList = False estimateList = False ind = [] uncertainties = False uncDict = {} totalUnc = {} for line in f: if len(line.split())==0: continue if line.split()[0] == "bin": if not binList: binList = True else: binList = line.split()[1:] for i,b in enumerate(binList): if b == binName: ind.append(i) print ind if line.split()[0] == "process": if not estimateList: estimateList = line.split()[1:] estimateList = estimateList[ind[1]:ind[-1]+1] if line.split()[0] == "rate": estimates = line.split()[1:] estimates = [float(a) for a in estimates[ind[1]:ind[-1]+1]] if line.split()[0] == 'PU': uncertainties = True if uncertainties: uncDict[line.split()[0]] = [ 0 if a =='-' else float(a)-1 for a in line.split()[2:][ind[1]:ind[-1]+1] ] print estimateList print estimates nuisanceFile = cardFile.replace('.txt','_nuisances_full.txt') for unc in uncDict.keys(): totalUnc[unc] = 0 for i in range(len(estimates)): #totalUnc[unc] += uncDict[unc][i] * estimates[i] * ( 1 + getPull(nuisanceFile,unc)*uncDict[unc][i] ) #* getConstrain(nuisanceFile, unc) totalUnc[unc] += uncDict[unc][i] * estimates[i] * math.exp( getPull(nuisanceFile,unc)*uncDict[unc][i] ) #totalUnc[unc] += (uncDict[unc][i] * estimates[i] * math.exp( getPull(nuisanceFile,unc)*uncDict[unc][i] ))**2 if totalUnc[unc] > 0: print unc, totalUnc[unc] #totalUnc[unc] = math.sqrt(totalUnc[unc]) total = 0 for unc in totalUnc.keys(): total += totalUnc[unc]**2 estimatesPostFit = [] for e in estimateList: res = getEstimateFromCard(cardFile, e, binName) res = applyAllNuisances(cardFile, e, res, binName) estimatesPostFit.append(res.val) estimatePostFit = sum(estimatesPostFit) return u_float(estimatePostFit,math.sqrt(total))
def getObservationFromCard(cardFile, binName): res = u_float(0) binNumber = getBinNumber(cardFile, binName) with open(cardFile) as f: binList = False estimateList = False for line in f: if len(line.split())==0: continue if line.split()[0] == "bin": binList = line.split()[1:] if line.split()[0] == "observation": for i in range(len(binList)): if binList[i] == binNumber:# and estimateList[i]==estimateName: try: res.val = float(line.split()[1:][i]) except: res.val = 0 return res
def observation(self, region, channel, setup): if channel=='all': return sum([self.cachedEstimate(region, c, setup) for c in channels]) if channel=='SF': return sum([self.cachedObservation(region, c, setup) for c in ['MuMu', 'EE']]) else: preSelection = setup.preselection('Data', channel=channel) cut = "&&".join([region.cutString(setup.sys['selectionModifier']), preSelection['cut']]) logger.debug( "Using cut %s"% cut ) if hasattr(setup, 'blinding') and setup.blinding: weight = 'weight*' + setup.blinding else: weight = 'weight' return u_float(**self.sample[channel].getYieldFromDraw(selectionString = cut, weightString = weight) )
def getValFrom1BinnedHistOrGraph(hist): """ if input is AsymTGraph, the average of errors is given """ if type(hist) in [ROOT.TH1F, ROOT.TH1D]: v = hist.GetBinContent(1) e = hist.GetBinError(1) if type(hist) in [ROOT.TH2F, ROOT.TH2D]: v = hist.GetBinContent(1, 1) e = hist.GetBinError(1, 1) if type(hist) in [ROOT.TGraphAsymmErrors]: v = hist.GetY()[0] el = hist.GetEYlow()[0] eh = hist.GetEYhigh()[0] if el and eh: e = sum([abs(el), abs(eh)]) / 2. else: e = max(abs(el), abs(eh)) #print hist , (v,el,eh) #return (v, el, eh ) return u_float(v, e)
def observation(self, region, channel, setup): if channel.name == 'all': if setup.nLeptons == 3: channels = trilepChannels elif setup.nLeptons == 4: channels = quadlepChannels else: raise NotImplementedError preSelection = setup.preselection('Data') cut = "&&".join([ region.cutString(setup.sys['selectionModifier']), preSelection['cut'] ]) logger.info( "Getting Data observation for channel %s and region %s" % (channel.name, region.cutString())) logger.info("Using cut %s" % cut) weight = 'weight' #return u_float(**self.sample.getYieldFromDraw(selectionString = cut, weightString = weight) ) return sum( [self.cachedEstimate(region, c, setup) for c in channels]) #if channel=='SF': # return sum([self.cachedObservation(region, c, setup) for c in ['MuMu', 'EE']]) else: preSelection = setup.preselection('Data', nElectrons=channel.nE, nMuons=channel.nM) cut = "&&".join([ region.cutString(setup.sys['selectionModifier']), preSelection['cut'] ]) logger.debug("Using cut %s" % cut) weight = 'weight' return u_float(**self.sample.getYieldFromDraw(selectionString=cut, weightString=weight))
def getEstimate(sample, region, channel, overwrite=False): ''' to be extended ''' res = resultsDB(results_directory + "resultsCache_v2.db", "TopEFT", columns) key = { "process": sample.name, "channel": channel, "region": region.cutString(), "lumi": lumi, "presel": presel, "weightString": weightString } if res.contains(key) and not overwrite: print "Found estimate for %s in region %s" % (sample.name, region) return res.get(key) else: print "Adding estimate for %s in region %s" % (sample.name, region) y = u_float( sample.getYieldFromDraw("&&".join([presel, region.cutString()]), weightString)) res.add(key, y, overwrite=True) return y
def reweight_func(pt, cosThetaStar): return u_float(t.GetBinContent(t.FindBin(cosThetaStar, pt)), t.GetBinError(t.FindBin(cosThetaStar, pt)))
def _estimate(self, region, channel, setup): if not setup.nonprompt: raise (NotImplementedError, "Need a nonprompt setup") ''' Concrete implementation of abstract method 'estimate' as defined in Systematic ''' logger.info("Prediction for %s channel %s" % (self.name, channel)) if channel.name == 'all': # estimate fake contribution from events with at least three loose leptons, and less than 3 tight leptons # take loose leptons with same pT requirements like analysis leptons tmpSample = self.sample variables = map(TreeVariable.fromString, [ "run/I", "lumi/I", "evt/I", "Z_pt/F", "cosThetaStar/F", "weight/F", "met_pt/F", "Z_mass/F", "nJetSelected/I", "nBTag/I", 'Z_l1_index/I', 'Z_l2_index/I', 'nonZ_l1_index/I', 'nonZ_l2_index/I', "nLeptons_FO_3l/I", "nLeptons_tight_3l/I", "nLeptons_tight_4l/I" ]) if not self.sample.isData: logger.info("Adding weights to be read.") variables += map( TreeVariable.fromString, ['reweightPU36fb/F', 'reweightBTagDeepCSV_SF/F']) variables += [ VectorTreeVariable.fromString( 'lep[pt/F,ptCorr/F,eta/F,phi/F,FO_3l/I,tight_3l/I,FO_SS/I,tight_SS/I,jetPtRatiov2/F,pdgId/I]' ) ] tmpSample.setSelectionString([ setup.preselection(self.dataMC, nElectrons=channel.nE, nMuons=channel.nM)['cut'], region.cutString() ]) reader = tmpSample.treeReader(allBranchesActive=True, variables=variables) reader.start() fakeYield = u_float(0) nEvents = u_float(tmpSample.getYieldFromDraw()) logger.info("Runing over %s events.", nEvents.val) while reader.run(): nLep = len([l for l in reader.event.lep_pt if l > 0]) lep = [ getObjDict(reader.event, "lep" + '_', [ "pt", "ptCorr", "eta", "phi", "FO_3l", "FO_SS", "tight_3l", "tight_SS", "pdgId", "jetPtRatiov2" ], i) for i in range(nLep) ] # get the relevant leptons lep = [l for l in lep if l[setup.leptonId]] # get tight and loose separately looseNotTight = [l for l in lep if not l[setup.tight_ID]] tight = [l for l in lep if l[setup.tight_ID]] nLooseNotTight = len(looseNotTight) nTight = len(tight) # Really get ALL possible combinations. allCombinations = itertools.combinations( tight + looseNotTight, setup.nLeptons) for comb in allCombinations: FR = 1. nLooseNotTight = 0 for l in comb: if l[setup.tight_ID]: continue else: if abs(l['pdgId']) == 11: FRmap = self.elMap elif abs(l['pdgId']) == 13: FRmap = self.muMap else: raise NotImplementedError # we run out of stats in data at higher pt, hence we cut at a lower value ptCut = 45. if self.sample.isData else 99. ptCorrected = l[ 'ptCorr'] if l['ptCorr'] < ptCut else (ptCut - 1) FR_from_map = FRmap.GetBinContent( FRmap.FindBin(ptCorrected, abs(l['eta']))) if self.sample.isData: FR *= FR_from_map / (1 - FR_from_map) else: FR *= FR_from_map nLooseNotTight += 1 FR *= (-1)**(nLooseNotTight + 1) allweights = [setup.sys['weight']] + setup.sys['reweight'] if self.sample.isData: weight = 1 else: weights = [ getattr(reader.event, w) for w in allweights ] weight = reduce(mul, weights, 1) fakeYield += (weight * FR) # apply the statistical uncertainty to the result result = u_float(0.) if nEvents.val == 0 else u_float( fakeYield, (nEvents.sigma / nEvents.val) * fakeYield) return result if self.sample.isData else (result * setup.lumi / 1000.)
p = Process(process=proc, nEvents=50000, config=config) if p.hasXSec(modified_couplings=modified_couplings): logger.debug( "Couplings: %s", ", ".join([ "%s=%5.4f" % c for c in modified_couplings.items() ])) xsec_val = p.xsec( modified_couplings=modified_couplings) ratio = xsec_val / SM_xsec[proc] x_list.append(x) y_list.append(y) z_list.append(ratio.val) else: ratio = u_float(-1.) config.cleanup() if interpolate: a = toGraph2D(nameStr, nameStr, len(x_list), x_list, y_list, z_list) xmin = min(x_list) xmax = max(x_list) ymin = min(y_list) ymax = max(y_list) bin_size_x = (abs(xmax) + abs(xmin)) / (3 * len(points[comb[0]])) bin_size_y = (abs(ymax) + abs(ymin)) / (3 * len(points[comb[1]])) nxbins = max( 1,
years = [2016,2017] if options.combine else [options.year] for i, r in enumerate(regions): #i = i+15 totalYield = 0. backgroundYield = 0. totalUncertainty = 0. backgroundUncertainty = 0. if options.postFit: suffix = '_bestfit' if options.bestFit else '_r1' postFitResults = getPrePostFitFromMLF(cardFile.replace('.txt','_FD%s.root'%suffix)) #r1 for p,tex in processes: pYield = u_float(0,0) preYield = u_float(0,0) pError = 0 for year in years: postfix = '_%s'%year prefix = 'dc_%s_'%year if options.combine else '' binName = prefix+'Bin%s'%i logger.info("Working on bin %s, process %s, year %s.", binName, p, year) proc = "%s_%s"%(p,year) if p in ["WZ","ZZ","TTX","rare","XG"] else p res = getEstimateFromCard(cardFile, proc, binName, postfix=postfix) if options.postFit: tmpYield = u_float(0,0) # postfit: all uncertainties already taken care of
def mult(self, l): if len(l) > 0: res = l[0] for i in l[1:]: res = res*i else: res = u_float(1) return res
def getPartialSF(self, effMap, pt, eta): sf = effMap.GetBinContent(effMap.GetXaxis().FindBin(pt), effMap.GetYaxis().FindBin(eta)) err = effMap.GetBinError( effMap.GetXaxis().FindBin(pt), effMap.GetYaxis().FindBin(eta)) return u_float(sf, err)
def wrapper(s): logger.info("Now working on %s", s.name) xSecScale = 1 c = cardFileWriter.cardFileWriter() c.releaseLocation = combineReleaseLocation for coup in nonZeroCouplings: try: modification_dict[coup] = getCouplingFromName(s.name, coup) logger.info("The following coupling is set to non-zero value: %s: %s", coup, modification_dict[coup]) except ValueError: logger.info("The following coupling is kept at zero: %s: %s", coup, modification_dict[coup]) continue try: p = Process(process = "ttZ_ll", nEvents = 5000, config = config, xsec_cache=xsecDB) xsec = p.xsecDB.get(modification_dict) except IndexError: logger.info("Looking into backup DB for x-sec") p = Process(process = "ttZ_ll", nEvents = 5000, config = config, xsec_cache=xsecDB_Backup) xsec = p.xsecDB.get(modification_dict) if not xsec: try: p = Process(process = "ttZ_ll", nEvents = 5000, config = config, xsec_cache=xsecDB_Backup) xsec = p.xsecDB.get(modification_dict) except IndexError: logger.info("No x-sec found.") logger.info("Found modified x-sec of %s", xsec) cardFileName = os.path.join(limitDir, s.name+'.txt') if not os.path.exists(cardFileName) or overWrite: counter=0 c.reset() c.setPrecision(3) postfix = '_%s'%args.year c.addUncertainty('PU', 'lnN') # correlated c.addUncertainty('JEC'+postfix, 'lnN') # uncorrelated, for now! c.addUncertainty('btag_heavy'+postfix, 'lnN') # uncorrelated, wait for offical recommendation c.addUncertainty('btag_light'+postfix, 'lnN') # uncorrelated, wait for offical recommendation c.addUncertainty('trigger'+postfix, 'lnN') # uncorrelated, statistics dominated c.addUncertainty('leptonSF', 'lnN') # correlated c.addUncertainty('scale', 'lnN') # correlated. c.addUncertainty('scale_sig', 'lnN') # correlated. c.addUncertainty('PDF', 'lnN') # correlated. c.addUncertainty('PartonShower', 'lnN') # correlated. c.addUncertainty('nonprompt', 'lnN') # correlated?! c.addUncertainty('WZ_xsec', 'lnN') # correlated. c.addUncertainty('WZ_bb', 'lnN') # correlated c.addUncertainty('WZ_powheg', 'lnN') # correlated c.addUncertainty('ZZ_xsec', 'lnN') # correlated. c.addUncertainty('ZG_xsec', 'lnN') # correlated. c.addUncertainty('rare', 'lnN') # correlated. c.addUncertainty('ttX', 'lnN') # correlated. c.addUncertainty('Lumi'+postfix, 'lnN') uncList = ['PU', 'JEC', 'btag_heavy', 'btag_light', 'leptonSF', 'trigger'] for unc in uncList: uncertainties[unc] = [] ## use rate parameters?? #c.addRateParameter('WZ', 1, '[0,2]') #c.addRateParameter('ZZ', 1, '[0,2]') for setupPair in setups: # extract the nominal and nonprompt setup from the pair setup, setupNP = setupPair signal = MCBasedEstimate(name="TTZ", sample=setup.samples["TTZ"], cacheDir=setup.defaultCacheDir()) #nonprompt = FakeEstimate(name="nonPromptDD", sample=setup.samples["Data"], setup=setupNP, cacheDir=setup.defaultCacheDir()) if args.unblind or (setup == setup3l_CR) or (setup == setup4l_CR): observation = DataObservation(name="Data", sample=setup.samples["Data"], cacheDir=setup.defaultCacheDir()) logger.info("Using data!") else: observation = MCBasedEstimate(name="observation", sample=setup.samples["pseudoData"], cacheDir=setup.defaultCacheDir()) logger.info("Using pseudo-data!") for e in setup.estimators: e.initCache(setup.defaultCacheDir()) for r in setup.regions: totalBackground = u_float(0) for channel in setup.channels: niceName = ' '.join([channel.name, r.__str__()]) binname = 'Bin'+str(counter) logger.info("Working on %s", binname) counter += 1 c.addBin(binname, [e.name.split('-')[0] for e in setup.estimators]+["nonPromptDD"], niceName) #c.addBin(binname, 'nonPromptDD', niceName) for e in setup.estimators: name = e.name.split('-')[0] if name.count('WZ'): logger.info("Using reweighting to powheg for WZ sample") wzReweighting = WZReweighting( cacheDir = reweightCacheWZ ) f = wzReweighting.cachedReweightingFunc( setup.WZselection ) powhegExpected = e.reweight1D(r, channel, setup, f) expected = e.cachedEstimate(r, channel, setup) print expected WZ_powheg_unc = (powhegExpected-expected)/expected else: expected = e.cachedEstimate(r, channel, setup) logger.info("Adding expectation %s for process %s", expected.val, name) c.specifyExpectation(binname, name, expected.val if expected.val > 0.01 else 0.01) totalBackground += expected if not args.statOnly: # uncertainties pu = 1 + e.PUSystematic( r, channel, setup).val if expected.val>0.01 else 1.1 jec = 1 + e.JECSystematic( r, channel, setup).val if expected.val>0.01 else 1.1 btag_heavy = 1 + e.btaggingSFbSystematic(r, channel, setup).val if expected.val>0.01 else 1.1 btag_light = 1 + e.btaggingSFlSystematic(r, channel, setup).val if expected.val>0.01 else 1.1 trigger = 1 + e.triggerSystematic(r, channel, setup).val if expected.val>0.01 else 1.1 leptonSF = 1 + e.leptonSFSystematic(r, channel, setup).val if expected.val>0.01 else 1.1 if name.count('WZ'): WZ_powheg = 1 + WZ_powheg_unc.val if expected.val>0.01 else 1.1 c.specifyUncertainty('PU', binname, name, 1 + e.PUSystematic( r, channel, setup).val) if not name.count('nonprompt'): c.specifyUncertainty('JEC'+postfix, binname, name, jec) c.specifyUncertainty('btag_heavy'+postfix, binname, name, btag_heavy) c.specifyUncertainty('btag_light'+postfix, binname, name, btag_light) c.specifyUncertainty('trigger'+postfix, binname, name, trigger) c.specifyUncertainty('leptonSF', binname, name, leptonSF) c.specifyUncertainty('scale', binname, name, 1.01) c.specifyUncertainty('PDF', binname, name, 1.01) c.specifyUncertainty('Lumi'+postfix, binname, name, 1.025 ) if name.count('ZZ'): c.specifyUncertainty('ZZ_xsec', binname, name, 1.10) if name.count('ZG'): c.specifyUncertainty('ZG_xsec', binname, name, 1.20) if name.count('WZ'): c.specifyUncertainty('WZ_xsec', binname, name, 1.10) if setup == setup3l: c.specifyUncertainty('WZ_bb', binname, name, 1.08) c.specifyUncertainty('WZ_powheg', binname, name, WZ_powheg) if name.count('nonprompt'): c.specifyUncertainty('nonprompt', binname, name, 1.30) if name.count('rare'): c.specifyUncertainty('rare', binname, name, 1.50) if name.count('TTX'): c.specifyUncertainty('ttX', binname, name, 1.11) #MC bkg stat (some condition to neglect the smaller ones?) uname = 'Stat_'+binname+'_'+name+postfix c.addUncertainty(uname, 'lnN') if expected.val > 0: c.specifyUncertainty(uname, binname, name, 1 + expected.sigma/expected.val ) else: c.specifyUncertainty(uname, binname, name, 1.01 ) uname = 'Stat_'+binname+'_nonprompt'+postfix c.addUncertainty(uname, 'lnN') if setup.nLeptons == 3 and setupNP: nonprompt = FakeEstimate(name="nonPromptDD", sample=setup.samples["Data"], setup=setupNP, cacheDir=setup.defaultCacheDir()) np = nonprompt.cachedEstimate(r, channel, setupNP) if np.val < 0.01: np = u_float(0.01,0.) c.specifyExpectation(binname, 'nonPromptDD', np.val ) c.specifyUncertainty(uname, binname, "nonPromptDD", 1 + np.sigma/np.val ) c.specifyUncertainty('nonprompt', binname, "nonPromptDD", 1.30) else: np = u_float(0) c.specifyExpectation(binname, 'nonPromptDD', np.val) if args.expected: sig = signal.cachedEstimate(r, channel, setup) obs = totalBackground + sig + np elif args.unblind or (setup == setup3l_CR) or (setup == setup4l_CR): obs = observation.cachedObservation(r, channel, setup) else: obs = observation.cachedEstimate(r, channel, setup) c.specifyObservation(binname, int(round(obs.val,0)) ) if args.useShape: logger.info("Using 2D reweighting method for shapes") if args.model == "dim6top_LO": source_gen = dim6top_central elif args.model == "ewkDM": source_gen = ewkDM_central signalReweighting = SignalReweighting( source_sample = source_gen, target_sample = s, cacheDir = reweightCache) f = signalReweighting.cachedReweightingFunc( setup.genSelection ) sig = signal.reweight2D(r, channel, setup, f) else: sig = signal.cachedEstimate(r, channel, setup) xSecMod = 1 if args.useXSec: xSecMod = xsec.val/xsec_central.val logger.info("x-sec is multiplied by %s",xSecMod) c.specifyExpectation(binname, 'signal', sig.val * xSecScale * xSecMod ) logger.info('Adding signal %s'%(sig.val * xSecScale * xSecMod)) if sig.val>0: c.specifyUncertainty('Lumi'+postfix, binname, 'signal', 1.025 ) if not args.statOnly: # uncertainties pu = 1 + e.PUSystematic( r, channel, setup).val jec = 1 + e.JECSystematic( r, channel, setup).val btag_heavy = 1 + e.btaggingSFbSystematic(r, channel, setup).val btag_light = 1 + e.btaggingSFlSystematic(r, channel, setup).val trigger = 1 + e.triggerSystematic(r, channel, setup).val leptonSF = 1 + e.leptonSFSystematic(r, channel, setup).val if sig.sigma/sig.val < 0.05: uncertainties['PU'] += [pu] uncertainties['JEC'] += [jec] uncertainties['btag_heavy'] += [btag_heavy] uncertainties['btag_light'] += [btag_light] uncertainties['trigger'] += [trigger] uncertainties['leptonSF'] += [leptonSF] c.specifyUncertainty('PU', binname, "signal", pu) c.specifyUncertainty('JEC'+postfix, binname, "signal", jec) c.specifyUncertainty('btag_heavy'+postfix, binname, "signal", btag_heavy) c.specifyUncertainty('btag_light'+postfix, binname, "signal", btag_light) c.specifyUncertainty('trigger'+postfix, binname, "signal", trigger) c.specifyUncertainty('leptonSF', binname, "signal", leptonSF) # This doesn't get the right uncertainty in CRs. However, signal doesn't matter there anyway. if setup in [setup3l, setup4l]: c.specifyUncertainty('scale_sig', binname, "signal", 1 + scale_cache.get({"region":r, "channel":channel.name, "PDFset":"scale"}).val) c.specifyUncertainty('PDF', binname, "signal", 1 + PDF_cache.get({"region":r, "channel":channel.name, "PDFset":PDFset}).val) c.specifyUncertainty('PartonShower',binname, "signal", PS_cache.get({"region":r, "channel":channel.name, "PDFset":"PSscale"}).val) #something wrong here? #c.specifyUncertainty('scale_sig', binname, "signal", 1.05) #1.30 #c.specifyUncertainty('PDF', binname, "signal", 1.04) #1.15 uname = 'Stat_'+binname+'_signal'+postfix c.addUncertainty(uname, 'lnN') c.specifyUncertainty(uname, binname, 'signal', 1 + sig.sigma/sig.val ) else: uname = 'Stat_'+binname+'_signal'+postfix c.addUncertainty(uname, 'lnN') c.specifyUncertainty(uname, binname, 'signal', 1 ) #c.addUncertainty('Lumi'+postfix, 'lnN') #c.specifyFlatUncertainty('Lumi'+postfix, 1.026) cardFileName = c.writeToFile(cardFileName) else: logger.info("File %s found. Reusing.",cardFileName) res = {} if not os.path.isdir(limitDir): os.makedirs(limitDir) resDB = resultsDB(limitDir+'/results.sq', "results", setup.resultsColumns) res = {"signal":s.name} if not overWrite and res.DB.contains(key): res = resDB.getDicts(key)[0] logger.info("Found result for %s, reusing", s.name) else: # We don't calculate limits here, but just in case we find a way how to do it, put placeholders here res.update({"exp":0, "obs":0, "exp1up":0, "exp2up":0, "exp1down":0, "exp2down":0}) # Don't extract all the nuisances by default signalRegions = range(15,30) ## shouldn't be hardcoded masks = ['mask_ch1_Bin'+str(i)+'=1' for i in signalRegions] masks = ','.join(masks) if args.calcNuisances: c.calcNuisances(cardFileName, masks=masks) # extract the NLL #nll = c.calcNLL(cardFileName, options="") nll = c.physicsModel(cardFileName, options="", normList=["WZ_norm","ZZ_norm"], masks=masks) # fastScan turns of profiling if nll["nll0"] > 0: res.update({"dNLL_postfit_r1":nll["nll"], "dNLL_bestfit":nll["bestfit"], "NLL_prefit":nll["nll0"]}) else: res.update({"dNLL_postfit_r1":-999, "dNLL_bestfit":-999, "NLL_prefit":-999}) logger.info("Fits failed, adding values -999 as results") logger.info("Adding results to database") resDB.add(res, nll['nll_abs'], overwrite=True) print print "NLL results:" print "{:>15}{:>15}{:>15}".format("Pre-fit", "Post-fit r=1", "Best fit") print "{:15.2f}{:15.2f}{:15.2f}".format(float(res["NLL_prefit"]), float(res["NLL_prefit"])+float(res["dNLL_postfit_r1"]), float(res["NLL_prefit"])+float(res["dNLL_bestfit"])) print 'PU', min(uncertainties['PU']), max(uncertainties['PU']) print 'JEC', min(uncertainties['JEC']), max(uncertainties['JEC']) print 'btag_heavy', min(uncertainties['btag_heavy']), max(uncertainties['btag_heavy']) print 'btag_light', min(uncertainties['btag_light']), max(uncertainties['btag_light']) print 'trigger', min(uncertainties['trigger']), max(uncertainties['trigger']) print 'leptonSF', min(uncertainties['leptonSF']), max(uncertainties['leptonSF'])
} processes = ["ttZ", "ttH", "ttW"] SM_xsec = {} modified_couplings = {args.coupling: 0.0} for proc in processes: logger.info("Checking SM x-sec:") config = Configuration(model_name=model_name, modified_couplings=modified_couplings) p = Process(process=proc, nEvents=50000, config=config) SM_xsec[proc] = p.xsec() logger.info("SM x-sec for %s is %s", proc, SM_xsec[proc]) if SM_xsec[proc].val == 0.: SM_xsec[proc] = u_float(1) del config hists = [] fits = [] m = 0 if args.scale: scale = lambdaSqInv[args.coupling] else: scale = 1 for proc in processes: #hists.append(ROOT.TGraph(len(couplingValues))) #hists.append(ROOT.TH1F(p.process,"",len(couplingValues),min(couplingValues),max([abs(min(couplingValues)),max(couplingValues)])))
#triggers = {"singleLep_addDiLep_addTriLep": "(%s)"%"||".join(singleMuTTZ+singleEleTTZ+diMuTriggers+diEleTriggers+EMuTriggers+trilepTriggers)} #triggers = {"stopDilepMix": "((HLT_mumuIso||HLT_mumuNoiso)||(HLT_ee_DZ||HLT_ee_33||HLT_ee_33_MW)||(HLT_mue||HLT_mu30e30)||HLT_SingleMu_noniso||HLT_SingleEle_noniso)"} #triggers = {"ttHMix": "(%s)"%"||".join(singleMuTriggers+singleEleTriggers+diMuTriggers+diEleTriggers+EMuTriggers+trilepTriggers)} #triggers = {"ttHMix_no3l": "(%s)"%"||".join(singleMuTriggers+singleEleTriggers+diMuTriggers+diEleTriggers+EMuTriggers)} for trigger in triggers: for c in channels: print c h_total = ROOT.TH1F("total", "", nReg, 0, nReg) h_trigg = ROOT.TH1F("trigger", "", nReg, 0, nReg) h_ratio = ROOT.TH1F("eff", "", nReg, 0, nReg) h_ratio.Sumw2() for j, r in enumerate(regions): num = u_float(0) denom = u_float(0) for i, sample in enumerate(signal + bkg): print sample.name val = sample.getYieldFromDraw( '&&'.join([presel, channels[c], r]), "weight*35.9") trig = sample.getYieldFromDraw( '&&'.join([presel, channels[c], r, triggers[trigger]]), "weight*35.9") print j, val, trig num += u_float(val) denom += u_float(trig) h_total.SetBinContent(j + 1, num.val) h_total.SetBinError(j + 1, num.sigma) h_trigg.SetBinContent(j + 1, denom.val)