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'])
def wrapper(s): logger.info("Now working on %s", s.name) xSecScale = 1 c = cardFileWriter.cardFileWriter() c.releaseLocation = combineReleaseLocation for coup in nonZeroCouplings: modification_dict[coup] = getCouplingFromName(s.name, coup) logger.info("The following coupling is set to non-zero value: %s: %s", coup, modification_dict[coup]) xsec = p.xsecDB.get(modification_dict) 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.addUncertainty('PU', 'lnN') c.addUncertainty('JEC', 'lnN') c.addUncertainty('btag', 'lnN') c.addUncertainty('trigger', 'lnN') c.addUncertainty('leptonSF', 'lnN') c.addUncertainty('scale', 'lnN') c.addUncertainty('scale_sig', 'lnN') c.addUncertainty('PDF', 'lnN') c.addUncertainty('nonprompt', 'lnN') c.addUncertainty('WZ_xsec', 'lnN') c.addUncertainty('ZZ_xsec', 'lnN') c.addUncertainty('rare', 'lnN') c.addUncertainty('ttX', 'lnN') c.addUncertainty('tZq', 'lnN') for setup in setups: signal = MCBasedEstimate(name="TTZ", sample=setup.samples["TTZ"], cacheDir=setup.defaultCacheDir()) observation = MCBasedEstimate(name="observation", sample=setup.samples["pseudoData"], cacheDir=setup.defaultCacheDir()) #observation = DataObservation(name='Data', sample=setup.sample['pseudoData'], cacheDir=setup.defaultCacheDir()) for e in setup.estimators: e.initCache(setup.defaultCacheDir()) for r in setup.regions: for channel in setup.channels: niceName = ' '.join([channel, r.__str__()]) binname = 'Bin'+str(counter) counter += 1 c.addBin(binname, [e.name.split('-')[0] for e in setup.estimators], niceName) for e in setup.estimators: name = e.name.split('-')[0] expected = e.cachedEstimate(r, channel, setup) c.specifyExpectation(binname, name, round(expected.val,3) if expected.val > 0 else 0.01) if expected.val>0: if not args.statOnly: c.specifyUncertainty('PU', binname, name, 1.01) c.specifyUncertainty('JEC', binname, name, 1.03) #1.05 c.specifyUncertainty('btag', binname, name, 1.03) #1.05 c.specifyUncertainty('trigger', binname, name, 1.03) #1.04 c.specifyUncertainty('leptonSF', binname, name, 1.05) #1.07 c.specifyUncertainty('scale', binname, name, 1.01) c.specifyUncertainty('PDF', binname, name, 1.01) if name.count('ZZ'): c.specifyUncertainty('ZZ_xsec', binname, name, 1.20) #1.20 if name.count('WZ'): c.specifyUncertainty('WZ_xsec', binname, name, 1.10) #1.20 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.10) #1.15 if name.count('TZQ'): c.specifyUncertainty('tZq', binname, name, 1.10) #1.15 #MC bkg stat (some condition to neglect the smaller ones?) uname = 'Stat_'+binname+'_'+name c.addUncertainty(uname, 'lnN') c.specifyUncertainty(uname, binname, name, round(1+expected.sigma/expected.val,3) ) 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_LO_ttZ_ll_ctZ_0p00_ctZI_0p00 elif args.model == "ewkDM": source_gen = ewkDM_central target_gen = s 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', round(sig.val*xSecScale * xSecMod, 3) ) if sig.val>0: if not args.statOnly: c.specifyUncertainty('PU', binname, "signal", 1.01) c.specifyUncertainty('JEC', binname, "signal", 1.03) #1.05 c.specifyUncertainty('btag', binname, "signal", 1.03) #1.05 c.specifyUncertainty('trigger', binname, "signal", 1.03) #1.04 c.specifyUncertainty('leptonSF', binname, "signal", 1.05) #1.07 c.specifyUncertainty('scale_sig', binname, "signal", 1.10) #1.30 c.specifyUncertainty('PDF', binname, "signal", 1.05) #1.15 uname = 'Stat_'+binname+'_signal' c.addUncertainty(uname, 'lnN') c.specifyUncertainty(uname, binname, 'signal', round(1 + sig.sigma/sig.val,3) ) else: uname = 'Stat_'+binname+'_signal' c.addUncertainty(uname, 'lnN') c.specifyUncertainty(uname, binname, 'signal', 1 ) c.addUncertainty('Lumi', 'lnN') c.specifyFlatUncertainty('Lumi', 1.026) cardFileName = c.writeToFile(cardFileName) else: logger.info("File %s found. Reusing.",cardFileName) res = {} if getResult(s) and not overWrite: res = getResult(s) logger.info("Found result for %s, reusing", s.name) else: # calculate the limit #limit = c.calcLimit(cardFileName)#, options="--run blind") #res.update({"exp":limit['0.500'], "obs":limit['-1.000'], "exp1up":limit['0.840'], "exp2up":limit['0.975'], "exp1down":limit['0.160'], "exp2down":limit['0.025']}) res.update({"exp":0, "obs":0, "exp1up":0, "exp2up":0, "exp1down":0, "exp2down":0}) # run the checks c.calcNuisances(cardFileName) # extract the NLL nll = c.calcNLL(cardFileName, options="--fastScan") 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") addResult(s, 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"])) if xSecScale != 1: for k in res: res[k] *= xSecScale
def wrapper(s): logger.info("Now working on %s", s.name) c = cardFileWriter.cardFileWriter() c.releaseLocation = combineReleaseLocation cards = {} # get the seperated cards for year in [2016,2017]: subDir = '' cardDir = "regionsE_%s"%(year) if args.useXSec: cardDir += "_xsec" if args.useShape: cardDir += "_shape" exp = "_expected" if args.expected else '' cardDir += "_lowUnc%s"%exp if args.includeCR: cardDir += "_SRandCR" baseDir = os.path.join(analysis_results) limitDir = os.path.join(baseDir, 'cardFiles', cardDir, subDir, '_'.join([args.model, args.signal])) #resDB = resultsDB(limitDir+'/results.sq', "results", setup.resultsColumns) cardFileName = os.path.join(limitDir, s.name+'.txt') if not os.path.isfile(cardFileName): raise IOError("File %s doesn't exist!"%cardFileName) cards[year] = cardFileName limitDir = limitDir.replace('2017','COMBINED') # run combine and store results in sqlite database if not os.path.isdir(limitDir): os.makedirs(limitDir) resDB = resultsDB(limitDir+'/results.sq', "results", setup.resultsColumns) res = {"signal":s.name} overWrite = True if not overWrite and res.DB.contains(key): res = resDB.getDicts(key)[0] logger.info("Found result for %s, reusing", s.name) else: signalRegions = range(15,30) masks_2016 = ['mask_ch1_dc_2016_Bin'+str(i)+'=1' for i in signalRegions] masks_2017 = ['mask_ch1_dc_2017_Bin'+str(i)+'=1' for i in signalRegions] masks = ','.join(masks_2016+masks_2017) combinedCard = c.combineCards( cards ) # 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 if args.calcNuisances: c.calcNuisances(combinedCard, masks=masks) #nll = c.physicsModel(combinedCard, options="", normList=["WZ_norm","ZZ_norm"], masks=masks) # fastScan turns of profiling nll = c.calcNLL(combinedCard) 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) logger.info("Results stored in %s", limitDir)
def wrapper(s): xSecScale = 1 c = cardFileWriter.cardFileWriter() c.releaseLocation = combineReleaseLocation cardFileName = os.path.join(limitDir, s.name + '.txt') if not os.path.exists(cardFileName) or overWrite: counter = 0 c.reset() c.addUncertainty('PU', 'lnN') c.addUncertainty('JEC', 'lnN') c.addUncertainty('btag', 'lnN') c.addUncertainty('trigger', 'lnN') c.addUncertainty('leptonSF', 'lnN') c.addUncertainty('scale', 'lnN') c.addUncertainty('scale_sig', 'lnN') c.addUncertainty('PDF', 'lnN') c.addUncertainty('nonprompt', 'lnN') c.addUncertainty('WZ_xsec', 'lnN') c.addUncertainty('ZZ_xsec', 'lnN') c.addUncertainty('rare', 'lnN') c.addUncertainty('ttX', 'lnN') c.addUncertainty('tZq', 'lnN') for setup in setups: for r in setup.regions: for channel in setup.channels: niceName = ' '.join([channel, r.__str__()]) binname = 'Bin' + str(counter) counter += 1 c.addBin(binname, [p.name for p in processes], niceName) for p in processes: name = p.name expected = getEstimate( p, r, channel ) #{"process":nam, "region":r, "lumi":35.9, "presel":"nLep==3&&isTTZ&&nJetGodd>2&&nBTag>0", "weightString":"weight", "channel":channel}) c.specifyExpectation(binname, name, expected.val) if expected.val > 0: c.specifyUncertainty('PU', binname, name, 1.01) c.specifyUncertainty('JEC', binname, name, 1.05) c.specifyUncertainty('btag', binname, name, 1.05) c.specifyUncertainty('trigger', binname, name, 1.04) c.specifyUncertainty('leptonSF', binname, name, 1.07) c.specifyUncertainty('scale', binname, name, 1.01) c.specifyUncertainty('PDF', binname, name, 1.01) if name.count('ZZ'): c.specifyUncertainty('ZZ_xsec', binname, name, 1.20) if name.count('WZ'): c.specifyUncertainty('WZ_xsec', binname, name, 1.20) 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.15) if name.count('TZQ'): c.specifyUncertainty('tZq', binname, name, 1.15) #MC bkg stat (some condition to neglect the smaller ones?) uname = 'Stat_' + binname + '_' + name c.addUncertainty(uname, 'lnN') c.specifyUncertainty( uname, binname, name, 1 + expected.sigma / expected.val) c.specifyObservation( binname, int(round((getEstimate( pseudoData, r, channel).val)))) #can also be pseudoDataPriv #signalSetup = setup.systematicClone() signal = getEstimate( s, r, channel ) #resultsCache.get({"process":s.name, "region":r, "lumi":35.9, "presel":"nLep==3&&isTTZ&&nJetGodd>2&&nBTag>0", "weightString":"weight", "channel":channel}) c.specifyExpectation(binname, 'signal', signal.val * xSecScale) if signal.val > 0: c.specifyUncertainty('PU', binname, "signal", 1.01) c.specifyUncertainty('JEC', binname, "signal", 1.05) c.specifyUncertainty('btag', binname, "signal", 1.05) c.specifyUncertainty('trigger', binname, "signal", 1.04) c.specifyUncertainty('leptonSF', binname, "signal", 1.07) c.specifyUncertainty('scale_sig', binname, "signal", 1.30) c.specifyUncertainty('PDF', binname, "signal", 1.15) uname = 'Stat_' + binname + '_signal' c.addUncertainty(uname, 'lnN') c.specifyUncertainty(uname, binname, 'signal', 1 + signal.sigma / signal.val) else: uname = 'Stat_' + binname + '_signal' c.addUncertainty(uname, 'lnN') c.specifyUncertainty(uname, binname, 'signal', 1) ## alternative signal model #signal_ALT = getEstimate(s, r, channel) #c.specifyExpectation(binname, 'signal_ALT', signal_ALT.val*xSecScale ) # #if signal_ALT.val>0: # c.specifyUncertainty('PU', binname, "signal_ALT", 1.01) # c.specifyUncertainty('JEC', binname, "signal_ALT", 1.05) # c.specifyUncertainty('btag', binname, "signal_ALT", 1.05) # c.specifyUncertainty('trigger', binname, "signal_ALT", 1.04) # c.specifyUncertainty('leptonSF', binname, "signal_ALT", 1.07) # c.specifyUncertainty('scale_sig', binname, "signal_ALT", 1.30) # c.specifyUncertainty('PDF', binname, "signal_ALT", 1.15) # uname = 'Stat_'+binname+'_signal_ALT' # c.addUncertainty(uname, 'lnN') # c.specifyUncertainty(uname, binname, 'signal_ALT', 1 + signal_ALT.sigma/signal_ALT.val ) #else: # uname = 'Stat_'+binname+'_signal_ALT' # c.addUncertainty(uname, 'lnN') # c.specifyUncertainty(uname, binname, 'signal_ALT', 1 ) c.addUncertainty('Lumi', 'lnN') c.specifyFlatUncertainty('Lumi', 1.026) cardFileName = c.writeToFile(cardFileName) else: print "File %s found. Reusing." % cardFileName res = {} if getResult(s) and not overWrite: res = getResult(s) print "Found result for %s, reusing" % s.name else: # calculate the limit limit = c.calcLimit(cardFileName) #, options="--run blind") res.update({ "exp": limit['0.500'], "obs": limit['-1.000'], "exp1up": limit['0.840'], "exp2up": limit['0.975'], "exp1down": limit['0.160'], "exp2down": limit['0.025'] }) # run the checks c.calcNuisances(cardFileName) # extract the NLL nll = c.calcNLL(cardFileName) res.update({ "dNLL_postfit_r1": nll["nll"], "dNLL_bestfit": nll["bestfit"], "NLL_prefit": nll["nll0"] }) addResult(s, res, nll['nll_abs'], overwrite=True) 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"])) if xSecScale != 1: for k in res: res[k] *= xSecScale
histo.Add(histos[i_histo + 1]) histos[i_histo + 1].Scale(-1) # compute differences h_signal, h_backgrounds = histos[0], histos[1:] logger.info("Total signal %s %f", h_signal.GetName(), h_signal.Integral()) for i_h, h in enumerate(h_backgrounds): logger.info("Total bkg %i %s: %f", i_h, h.GetName(), h.Integral()) result = {} lumi_factor = 136. / 300. signal_strengths = [0, 0.25, 0.5, 0.75, 1., 1.5, 2, 2.2] for signal_strength in signal_strengths: c = cardFileWriter.cardFileWriter() bkg_sys = 1.1 bkg_shape_sys = 1.1 for i in range(len(h_backgrounds)): c.addUncertainty('bkg_sys_%i' % i, 'lnN') c.addUncertainty('bkg_shape_sys_%i' % i, 'lnN') c.addUncertainty('sig_sys', 'lnN') sig_sys = 1.25 for i_bin in range(1, 1 + h_signal.GetNbinsX()): c.addBin('Bin' + str(i_bin), [h.GetName() for h in h_backgrounds], 'Bin' + str(i_bin)) y_signal = h_signal.GetBinContent(i_bin)