def _estimate(self, region, channel, setup): if setup.verbose: printHeader("MC prediction for %s channel %s" % (self.name, channel)) if channel == 'all': return sum([ self.cachedEstimate(region, c, setup) for c in ['MuMu', 'EE', 'EMu'] ], u_float(0., 0.)) else: preSelection = setup.preselection('MC', channel=channel) cut = "&&".join([ region.cutString(setup.sys['selectionModifier']), preSelection['cut'] ]) weight = preSelection['weightStr'] if setup.verbose: print "Using cut %s and weight %s" % (cut, weight) if not self.sample[channel].has_key('chain'): loadChain(self.sample[channel]) return setup.lumi[channel] / 1000. * u_float( getYieldFromChain(self.sample[channel]['chain'], cutString=cut, weight=weight, returnError=True))
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 ['MuMu', 'EE', 'EMu'] ]) else: # Important! We use 'allZ' (mll>20) in case of EMu zWindow = 'allZ' if channel == 'EMu' else 'offZ' preSelection = setup.preselection('MC', zWindow=zWindow, channel=channel) 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 yieldFromCache(self, setup, sample, channel, selectionString, weightString): s = (sample, channel, selectionString, weightString) if self.helperCache.contains(s): return self.helperCache.get(s) else: yieldFromDraw = u_float(**setup.sample[sample][channel].getYieldFromDraw(selectionString, weightString)) self.helperCache.add(s, yieldFromDraw, save=True) return yieldFromDraw
def yieldFromCache(self, setup, sample, channel, selectionString, weightString): s = (sample, channel, selectionString, weightString) if self.helperCache.contains(s): return self.helperCache.get(s) else: yieldFromDraw = u_float( **setup.sample[sample][channel].getYieldFromDraw( selectionString, weightString)) self.helperCache.add(s, yieldFromDraw, save=True) return yieldFromDraw
def _estimate(self, region, channel, setup): if setup.verbose: printHeader("MC prediction for %s channel %s" %(self.name, channel)) if channel=='all': return sum( [ self.cachedEstimate(region, c, setup) for c in ['MuMu', 'EE', 'EMu'] ], u_float(0., 0.) ) else: preSelection = setup.preselection('MC', channel=channel) cut = "&&".join([region.cutString(setup.sys['selectionModifier']), preSelection['cut']]) weight = preSelection['weightStr'] if setup.verbose: print "Using cut %s and weight %s"%(cut, weight) if not self.sample[channel].has_key('chain'): loadChain(self.sample[channel]) return setup.lumi[channel]/1000.*u_float(getYieldFromChain(self.sample[channel]['chain'], cutString = cut, weight=weight, returnError = True) )
def _estimate(self, region, channel, setup): printHeader("DD DY prediction for %s channel %s" %(self.name, channel)) #Sum of all channels for 'all' if channel=='all': return sum( [ self.cachedEstimate(region, c, setup) for c in ['MuMu', 'EE', 'EMu'] ], u_float(0.,0.) ) #MC based for 'EMu' elif channel=='EMu': preSelection = setup.preselection('MC', zWindow="allZ", channel=channel) cut = "&&".join([region.cutString(setup.sys['selectionModifier']), preSelection['cut'] ]) weight = preSelection['weightStr'] if setup.verbose: print "Using cut %s and weight %s"%(cut, weight) return setup.lumi[channel]/1000. * u_float( getYieldFromChain(setup.sample['DY'][channel]['chain'], cutString = cut, weight=weight, returnError = True) ) #Data driven for EE and MuMu else: preSelection = setup.preselection('MC', zWindow="offZ", channel=channel) weight = preSelection['weightStr'] assert abs(1.-setup.lumi[channel]/setup.sample['Data'][channel]['lumi'])<0.01, "Lumi specified in setup %f does not match lumi in data sample %f in channel %s"%(setup.lumi[channel], setup.sample['Data'][channel]['lumi'], channel) cut_offZ_1b = "&&".join([region.cutString(setup.sys['selectionModifier']), setup.selection('MC', channel=channel, zWindow = 'offZ', **setup.defaultParameters(update={'nBTags':(1,-1)}))['cut'] ]) cut_onZ_1b = "&&".join([region.cutString(setup.sys['selectionModifier']), setup.selection('MC', channel=channel, zWindow = 'onZ', **setup.defaultParameters(update={'nBTags':(1,-1)}))['cut'] ]) cut_onZ_0b = "&&".join([region.cutString(setup.sys['selectionModifier']), setup.selection('MC', channel=channel, zWindow = 'onZ', **setup.defaultParameters(update={'nBTags':(0,0)}))['cut'] ]) cut_data_onZ_0b = "&&".join([region.cutString(setup.sys['selectionModifier']), setup.selection('Data', channel=channel, zWindow = 'onZ', **setup.defaultParameters(update={'nBTags':(0,0)}) )['cut'] ]) # R1 = DY-MC (offZ, 1b) / DY-MC (onZ, 1b) # R2 = DY-MC (onZ, 1b) / DY-MC (onZ, 0b) # DY-est = R1*R2*(Data(2l, onZ, 0b) - EWK(onZ, 0b)) = DY-MC (offZ, 1b) / DY-MC (onZ, 0b) *( Data(2l, onZ, 0b) - EWK(onZ, 0b)) yield_offZ_1b = setup.lumi[channel]/1000.*u_float( getYieldFromChain(setup.sample['DY'][channel]['chain'], cutString = cut_offZ_1b, weight=weight, returnError = True)) if setup.verbose: print "yield_offZ_1b: %s"%yield_offZ_1b yield_onZ_0b = setup.lumi[channel]/1000.*u_float( getYieldFromChain(setup.sample['DY'][channel]['chain'], cutString = cut_onZ_0b, weight=weight, returnError = True)) if setup.verbose: print "yield_onZ_0b: %s"%yield_onZ_0b yield_data = u_float( getYieldFromChain(setup.sample['Data'][channel]['chain'], cutString = cut_data_onZ_0b, weight=weight, returnError = True)) if setup.verbose: print "yield_data: %s (for cut: %s \n with weight: %s)"%(yield_data, cut_data_onZ_0b, weight) #electroweak subtraction print "\n Substracting electroweak backgrounds from data: \n" yield_other = u_float(0., 0.) for s in ['TTJets' , 'TTZ' , 'other']: yield_other += setup.lumi[channel]/1000.*u_float(getYieldFromChain(setup.sample[s][channel]['chain'], cutString = cut_onZ_0b, weight=weight, returnError=True)) if setup.verbose: print "yield_other_onZ_0b %s added, now: %s"%(s, yield_other) normRegYield = yield_data - yield_other if normRegYield.val<0: print "\n !!!Warning!!! \n Negative normalization region yield data: (%s), MC: (%s) \n"%(yield_data, yield_other) mcRatio = yield_offZ_1b / yield_onZ_0b res = mcRatio * normRegYield print "mcRatio is: ", mcRatio 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 ['MuMu', 'EE', 'EMu'] ], u_float(0., 0.) ) else: # Important! We use 'allZ' (mll>20) in case of EMu zWindow= 'allZ' if channel=='EMu' else 'offZ' preSelection = setup.preselection('MC', zWindow=zWindow, channel=channel) 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): printHeader("DD DY prediction for %s channel %s" % (self.name, channel)) #Sum of all channels for 'all' if channel == 'all': return sum([ self.cachedEstimate(region, c, setup) for c in ['MuMu', 'EE', 'EMu'] ], u_float(0., 0.)) #MC based for 'EMu' elif channel == 'EMu': preSelection = setup.preselection('MC', zWindow="allZ", channel=channel) cut = "&&".join([ region.cutString(setup.sys['selectionModifier']), preSelection['cut'] ]) weight = preSelection['weightStr'] if setup.verbose: print "Using cut %s and weight %s" % (cut, weight) return setup.lumi[channel] / 1000. * u_float( getYieldFromChain(setup.sample['DY'][channel]['chain'], cutString=cut, weight=weight, returnError=True)) #Data driven for EE and MuMu else: preSelection = setup.preselection('MC', zWindow="offZ", channel=channel) weight = preSelection['weightStr'] assert abs( 1. - setup.lumi[channel] / setup.sample['Data'][channel]['lumi'] ) < 0.01, "Lumi specified in setup %f does not match lumi in data sample %f in channel %s" % ( setup.lumi[channel], setup.sample['Data'][channel]['lumi'], channel) cut_offZ_1b = "&&".join([ region.cutString(setup.sys['selectionModifier']), setup.selection( 'MC', channel=channel, zWindow='offZ', **setup.defaultParameters(update={'nBTags': (1, -1)}))['cut'] ]) cut_onZ_1b = "&&".join([ region.cutString(setup.sys['selectionModifier']), setup.selection( 'MC', channel=channel, zWindow='onZ', **setup.defaultParameters(update={'nBTags': (1, -1)}))['cut'] ]) cut_onZ_0b = "&&".join([ region.cutString(setup.sys['selectionModifier']), setup.selection( 'MC', channel=channel, zWindow='onZ', **setup.defaultParameters(update={'nBTags': (0, 0)}))['cut'] ]) cut_data_onZ_0b = "&&".join([ region.cutString(setup.sys['selectionModifier']), setup.selection( 'Data', channel=channel, zWindow='onZ', **setup.defaultParameters(update={'nBTags': (0, 0)}))['cut'] ]) # R1 = DY-MC (offZ, 1b) / DY-MC (onZ, 1b) # R2 = DY-MC (onZ, 1b) / DY-MC (onZ, 0b) # DY-est = R1*R2*(Data(2l, onZ, 0b) - EWK(onZ, 0b)) = DY-MC (offZ, 1b) / DY-MC (onZ, 0b) *( Data(2l, onZ, 0b) - EWK(onZ, 0b)) yield_offZ_1b = setup.lumi[channel] / 1000. * u_float( getYieldFromChain(setup.sample['DY'][channel]['chain'], cutString=cut_offZ_1b, weight=weight, returnError=True)) if setup.verbose: print "yield_offZ_1b: %s" % yield_offZ_1b yield_onZ_0b = setup.lumi[channel] / 1000. * u_float( getYieldFromChain(setup.sample['DY'][channel]['chain'], cutString=cut_onZ_0b, weight=weight, returnError=True)) if setup.verbose: print "yield_onZ_0b: %s" % yield_onZ_0b yield_data = u_float( getYieldFromChain(setup.sample['Data'][channel]['chain'], cutString=cut_data_onZ_0b, weight=weight, returnError=True)) if setup.verbose: print "yield_data: %s (for cut: %s \n with weight: %s)" % ( yield_data, cut_data_onZ_0b, weight) #electroweak subtraction print "\n Substracting electroweak backgrounds from data: \n" yield_other = u_float(0., 0.) for s in ['TTJets', 'TTZ', 'other']: yield_other += setup.lumi[channel] / 1000. * u_float( getYieldFromChain(setup.sample[s][channel]['chain'], cutString=cut_onZ_0b, weight=weight, returnError=True)) if setup.verbose: print "yield_other_onZ_0b %s added, now: %s" % ( s, yield_other) normRegYield = yield_data - yield_other if normRegYield.val < 0: print "\n !!!Warning!!! \n Negative normalization region yield data: (%s), MC: (%s) \n" % ( yield_data, yield_other) mcRatio = yield_offZ_1b / yield_onZ_0b res = mcRatio * normRegYield print "mcRatio is: ", mcRatio return res
def _estimate(self, region, channel, setup): # Sum of all channels for 'all' if channel == "all": estimate = sum([self.cachedEstimate(region, c, setup) for c in ["MuMu", "EE", "EMu"]]) # MC based for 'EMu' elif channel == "EMu": weight = setup.weightString() preSelection = setup.preselection("MC", zWindow="allZ", channel=channel) cut = "&&".join([region.cutString(setup.sys["selectionModifier"]), preSelection["cut"]]) estimate = ( setup.lumi[channel] / 1000.0 * u_float(**setup.sample["DY"][channel].getYieldFromDraw(selectionString=cut, weightString=weight)) ) # Data driven for EE and MuMu (calculate for data luminosity) else: weight = setup.weightString() cut_offZ_1b = "&&".join( [ region.cutString(setup.sys["selectionModifier"]), setup.selection( "MC", channel=channel, zWindow="offZ", **setup.defaultParameters(update={"nBTags": (1, -1)}) )["cut"], ] ) cut_onZ_0b = "&&".join( [ region.cutString(setup.sys["selectionModifier"]), setup.selection( "MC", channel=channel, zWindow="onZ", **setup.defaultParameters(update={"nBTags": (0, 0)}) )["cut"], ] ) cut_data_onZ_0b = "&&".join( [ region.cutString(), setup.selection( "Data", channel=channel, zWindow="onZ", **setup.defaultParameters(update={"nBTags": (0, 0)}) )["cut"], ] ) # Calculate ratio (offZ,1b)/(onZ,0b) yield_offZ_1b = ( u_float( **setup.sample["DY"][channel].getYieldFromDraw(selectionString=cut_offZ_1b, weightString=weight) ) * setup.dataLumi[channel] / 1000 ) yield_onZ_0b = ( u_float(**setup.sample["DY"][channel].getYieldFromDraw(selectionString=cut_onZ_0b, weightString=weight)) * setup.dataLumi[channel] / 1000 ) R = yield_offZ_1b / yield_onZ_0b if yield_onZ_0b > 0 else 0 # Calculate data-other onZ for 0 b-jets region yield_data = u_float( **setup.sample["Data"][channel].getYieldFromDraw(selectionString=cut_data_onZ_0b, weightString="(1)") ) yield_other = ( sum( u_float( **setup.sample[s][channel].getYieldFromDraw(selectionString=cut_onZ_0b, weightString=weight) ) for s in ["TTJets", "TTZ", "other"] ) * setup.dataLumi[channel] / 1000 ) normRegYield = yield_data - yield_other # Calculate DY estimate in 1 b-jet region (and scale back to MC lumi) estimate = R * normRegYield * setup.lumi[channel] / setup.dataLumi[channel] logger.info( "Calculating data-driven DY estimate in channel " + channel + " using lumi " + str(setup.dataLumi[channel]) + ":" ) logger.info("yield DY offZ/1b: " + str(yield_offZ_1b)) logger.info("yield DY onZ/0b: " + str(yield_onZ_0b)) logger.info("R: " + str(R)) logger.info("yield data onZ/0b: " + str(yield_data)) logger.info("yield other onZ/0b: " + str(yield_other)) logger.info("yield (data-other) onZ/0b: " + str(normRegYield)) logger.info("yield expected DY onZ/1b: " + str(normRegYield * R)) if normRegYield < 0 and yield_data > 0: logger.warn("Negative normalization region yield!") logger.info( "Estimate for DY in " + channel + " channel (lumi=" + str(setup.lumi[channel]) + "/pb): " + str(estimate) + (" (negative estimated being replaced by 0)" if estimate < 0 else "") ) return estimate if estimate > 0 else u_float(0, 0)
def _estimate(self, region, channel, setup): printHeader("DD TTZ prediction for '%s' channel %s" %(self.name, channel)) #Sum of all channels for 'all' if channel=='all': return sum( [ self.cachedEstimate(region, c, channel, setup) for c in ['MuMu', 'EE', 'EMu'] ] ) else: #Data driven for EE, EMu and MuMu. preSelection = setup.preselection('MC', channel=channel) #check lumi consistency assert abs(1.-setup.lumi[channel]/setup.sample['Data'][channel]['lumi'])<0.01, "Lumi specified in setup %f does not match lumi in data sample %f in channel %s"%(setup.lumi[channel], setup.sample['Data'][channel]['lumi'], channel) selection_MC_2l = "&&".join([region.cutString(setup.sys['selectionModifier']), preSelection['cut']]) weight = preSelection['weightStr'] yield_MC_2l = setup.lumi[channel]/1000.*u_float(getYieldFromChain(setup.sample['TTZ'][channel]['chain'], cutString = selection_MC_2l, weight=weight, returnError = True) ) if setup.verbose: print "yield_MC_2l: %s"%yield_MC_2l muonSelection_loosePt = looseMuIDString(ptCut=10) electronSelection_loosePt = looseEleIDString(ptCut=10) #mu_mu_mu MuMuMuSelection = "nGoodMuons>=2" + '&&' + muonSelection_loosePt + "==3" if setup.parameters['useTriggers']: MuMuMuSelection += '&&HLT_3mu' #e_e_e EEESelection = "nGoodElectrons>=2" + '&&' + electronSelection_loosePt + "==3" if setup.parameters['useTriggers']: EEESelection += '&&HLT_3e' #e_e_mu EEMuSelection = "(nGoodMuons+nGoodElectrons)>=2" + "&&" + electronSelection_loosePt + "==2&&" + muonSelection_loosePt + "==1" if setup.parameters['useTriggers']: EEMuSelection += '&&HLT_2e1mu' #mu_mu_e MuMuESelection = "(nGoodMuons+nGoodElectrons)>=2" + "&&" + electronSelection_loosePt + "==1&&" + muonSelection_loosePt + "==2" if setup.parameters['useTriggers']: MuMuESelection += '&&HLT_2mu1e' MC_hadronSelection = setup.selection('MC', hadronicSelection = True, **setup.defaultParameters(update={'nJets': self.nJets, 'nBTags':self.nMediumBTags, 'metMin': 0., 'metSigMin':0., 'dPhiJetMet':0. }) )['cut'] data_hadronSelection = setup.selection('Data', hadronicSelection = True, **setup.defaultParameters(update={'nJets': self.nJets, 'nBTags':self.nMediumBTags, 'metMin': 0., 'metSigMin':0., 'dPhiJetMet':0. }) )['cut'] #loose bjet selection added here if self.nLooseBTags[0]>=0: MC_hadronSelection += '&&Sum$(Jet_pt>30&&abs(Jet_eta)<2.4&&Jet_id&&Jet_btagCSV>0.605)>='+str(self.nLooseBTags[0]) data_hadronSelection += '&&Sum$(Jet_pt>30&&abs(Jet_eta)<2.4&&Jet_id&&Jet_btagCSV>0.605)>='+str(self.nLooseBTags[0]) if self.nLooseBTags[1]>=0: MC_hadronSelection += '&&Sum$(Jet_pt>30&&abs(Jet_eta)<2.4&&Jet_id&&Jet_btagCSV>0.605)<='+str(self.nLooseBTags[1]) data_hadronSelection += '&&Sum$(Jet_pt>30&&abs(Jet_eta)<2.4&&Jet_id&&Jet_btagCSV>0.605)<='+str(self.nLooseBTags[1]) MC_MuMuMu = "&&".join([ MC_hadronSelection, MuMuMuSelection, "abs(mlmZ_mass-91.2)<10" ]) MC_EEE = "&&".join([ MC_hadronSelection, EEESelection, "abs(mlmZ_mass-91.2)<10" ]) MC_EEMu = "&&".join([ MC_hadronSelection, EEMuSelection, "abs(mlmZ_mass-91.2)<10" ]) MC_MuMuE = "&&".join([ MC_hadronSelection, MuMuESelection, "abs(mlmZ_mass-91.2)<10" ]) MC_3l = "(("+MC_MuMuMu+")||("+MC_EEE+")||("+MC_EEMu+")||("+MC_MuMuE+"))" data_MuMuMu = "&&".join([ data_hadronSelection, MuMuMuSelection, "abs(mlmZ_mass-91.2)<10" ]) data_EEE = "&&".join([ data_hadronSelection, EEESelection, "abs(mlmZ_mass-91.2)<10" ]) data_EEMu = "&&".join([ data_hadronSelection, EEMuSelection, "abs(mlmZ_mass-91.2)<10" ]) data_MuMuE = "&&".join([ data_hadronSelection, MuMuESelection, "abs(mlmZ_mass-91.2)<10" ]) ######yield_MC_3l computed for ALL channels but lumi changes slightly here depending on channel yield_MC_3l = setup.lumi[channel]/1000.*u_float( getYieldFromChain(setup.sample['TTZ'][channel]['chain'], cutString = MC_3l, weight=weight, returnError = True)) if setup.verbose: print "yield_MC_looseSelection_3l: %s"%yield_MC_3l yield_data_MuMuMu = u_float( getYieldFromChain(setup.sample['Data']['MuMu']['chain'], cutString = data_MuMuMu, weight=weight, returnError = True)) if setup.verbose: print "yield_data_looseSelection_MuMuMu: %s"%yield_data_MuMuMu yield_data_EEE = u_float( getYieldFromChain(setup.sample['Data']['EE']['chain'], cutString = data_EEE, weight=weight, returnError = True)) if setup.verbose: print "yield_data_looseSelection_EEE: %s"%yield_data_EEE yield_data_EMu = u_float( getYieldFromChain(setup.sample['Data']['EMu']['chain'], cutString = "(("+data_MuMuE+')||('+data_EEMu+'))', weight=weight, returnError = True)) if setup.verbose: print "yield_data_looseSelection_EMu: %s"%yield_data_EMu yield_data_3l = yield_data_MuMuMu+yield_data_EEE+yield_data_EMu if setup.verbose: print "yield_data_3l: %s"%yield_data_3l #electroweak subtraction print "\n Substracting electroweak backgrounds from data: \n" yield_other = u_float(0., 0.) for s in ['TTJets' , 'DY', 'other']: yield_other+= setup.lumi[channel]/1000.* u_float(getYieldFromChain(setup.sample[s][channel]['chain'], cutString = MC_3l, weight=weight, returnError=True)) if setup.verbose: print "yield_looseSelection_other %s added, now: %s"%(s, yield_other) normRegYield = yield_data_3l - yield_other if normRegYield.val<0: print "\n !!!Warning!!! \n Negative normalization region yield data: (%s), MC: (%s) \n"%(yield_data_3l, yield_other) print "normRegYield", normRegYield print "\n Control Region predictys ", normRegYield, " TTZ events in data; ", yield_MC_3l, " TTZ events in MC. Ratio ---> ", (normRegYield/yield_MC_3l) print "DD-TTZ ---> ", (normRegYield/yield_MC_3l)*yield_MC_2l return (normRegYield/yield_MC_3l)*yield_MC_2l
def _estimate(self, region, channel, setup): printHeader("DD TTZ prediction for '%s' channel %s" % (self.name, channel)) #Sum of all channels for 'all' if channel == 'all': return sum([ self.cachedEstimate(region, c, channel, setup) for c in ['MuMu', 'EE', 'EMu'] ]) else: #Data driven for EE, EMu and MuMu. preSelection = setup.preselection('MC', channel=channel) #check lumi consistency assert abs( 1. - setup.lumi[channel] / setup.sample['Data'][channel]['lumi'] ) < 0.01, "Lumi specified in setup %f does not match lumi in data sample %f in channel %s" % ( setup.lumi[channel], setup.sample['Data'][channel]['lumi'], channel) selection_MC_2l = "&&".join([ region.cutString(setup.sys['selectionModifier']), preSelection['cut'] ]) weight = preSelection['weightStr'] yield_MC_2l = setup.lumi[channel] / 1000. * u_float( getYieldFromChain(setup.sample['TTZ'][channel]['chain'], cutString=selection_MC_2l, weight=weight, returnError=True)) if setup.verbose: print "yield_MC_2l: %s" % yield_MC_2l muonSelection_loosePt = looseMuIDString(ptCut=10) electronSelection_loosePt = looseEleIDString(ptCut=10) #mu_mu_mu MuMuMuSelection = "nGoodMuons>=2" + '&&' + muonSelection_loosePt + "==3" if setup.parameters['useTriggers']: MuMuMuSelection += '&&HLT_3mu' #e_e_e EEESelection = "nGoodElectrons>=2" + '&&' + electronSelection_loosePt + "==3" if setup.parameters['useTriggers']: EEESelection += '&&HLT_3e' #e_e_mu EEMuSelection = "(nGoodMuons+nGoodElectrons)>=2" + "&&" + electronSelection_loosePt + "==2&&" + muonSelection_loosePt + "==1" if setup.parameters['useTriggers']: EEMuSelection += '&&HLT_2e1mu' #mu_mu_e MuMuESelection = "(nGoodMuons+nGoodElectrons)>=2" + "&&" + electronSelection_loosePt + "==1&&" + muonSelection_loosePt + "==2" if setup.parameters['useTriggers']: MuMuESelection += '&&HLT_2mu1e' MC_hadronSelection = setup.selection( 'MC', hadronicSelection=True, **setup.defaultParameters( update={ 'nJets': self.nJets, 'nBTags': self.nMediumBTags, 'metMin': 0., 'metSigMin': 0., 'dPhiJetMet': 0. }))['cut'] data_hadronSelection = setup.selection( 'Data', hadronicSelection=True, **setup.defaultParameters( update={ 'nJets': self.nJets, 'nBTags': self.nMediumBTags, 'metMin': 0., 'metSigMin': 0., 'dPhiJetMet': 0. }))['cut'] #loose bjet selection added here if self.nLooseBTags[0] >= 0: MC_hadronSelection += '&&Sum$(Jet_pt>30&&abs(Jet_eta)<2.4&&Jet_id&&Jet_btagCSV>0.605)>=' + str( self.nLooseBTags[0]) data_hadronSelection += '&&Sum$(Jet_pt>30&&abs(Jet_eta)<2.4&&Jet_id&&Jet_btagCSV>0.605)>=' + str( self.nLooseBTags[0]) if self.nLooseBTags[1] >= 0: MC_hadronSelection += '&&Sum$(Jet_pt>30&&abs(Jet_eta)<2.4&&Jet_id&&Jet_btagCSV>0.605)<=' + str( self.nLooseBTags[1]) data_hadronSelection += '&&Sum$(Jet_pt>30&&abs(Jet_eta)<2.4&&Jet_id&&Jet_btagCSV>0.605)<=' + str( self.nLooseBTags[1]) MC_MuMuMu = "&&".join([ MC_hadronSelection, MuMuMuSelection, "abs(mlmZ_mass-91.2)<10" ]) MC_EEE = "&&".join( [MC_hadronSelection, EEESelection, "abs(mlmZ_mass-91.2)<10"]) MC_EEMu = "&&".join( [MC_hadronSelection, EEMuSelection, "abs(mlmZ_mass-91.2)<10"]) MC_MuMuE = "&&".join( [MC_hadronSelection, MuMuESelection, "abs(mlmZ_mass-91.2)<10"]) MC_3l = "((" + MC_MuMuMu + ")||(" + MC_EEE + ")||(" + MC_EEMu + ")||(" + MC_MuMuE + "))" data_MuMuMu = "&&".join([ data_hadronSelection, MuMuMuSelection, "abs(mlmZ_mass-91.2)<10" ]) data_EEE = "&&".join( [data_hadronSelection, EEESelection, "abs(mlmZ_mass-91.2)<10"]) data_EEMu = "&&".join([ data_hadronSelection, EEMuSelection, "abs(mlmZ_mass-91.2)<10" ]) data_MuMuE = "&&".join([ data_hadronSelection, MuMuESelection, "abs(mlmZ_mass-91.2)<10" ]) ######yield_MC_3l computed for ALL channels but lumi changes slightly here depending on channel yield_MC_3l = setup.lumi[channel] / 1000. * u_float( getYieldFromChain(setup.sample['TTZ'][channel]['chain'], cutString=MC_3l, weight=weight, returnError=True)) if setup.verbose: print "yield_MC_looseSelection_3l: %s" % yield_MC_3l yield_data_MuMuMu = u_float( getYieldFromChain(setup.sample['Data']['MuMu']['chain'], cutString=data_MuMuMu, weight=weight, returnError=True)) if setup.verbose: print "yield_data_looseSelection_MuMuMu: %s" % yield_data_MuMuMu yield_data_EEE = u_float( getYieldFromChain(setup.sample['Data']['EE']['chain'], cutString=data_EEE, weight=weight, returnError=True)) if setup.verbose: print "yield_data_looseSelection_EEE: %s" % yield_data_EEE yield_data_EMu = u_float( getYieldFromChain(setup.sample['Data']['EMu']['chain'], cutString="((" + data_MuMuE + ')||(' + data_EEMu + '))', weight=weight, returnError=True)) if setup.verbose: print "yield_data_looseSelection_EMu: %s" % yield_data_EMu yield_data_3l = yield_data_MuMuMu + yield_data_EEE + yield_data_EMu if setup.verbose: print "yield_data_3l: %s" % yield_data_3l #electroweak subtraction print "\n Substracting electroweak backgrounds from data: \n" yield_other = u_float(0., 0.) for s in ['TTJets', 'DY', 'other']: yield_other += setup.lumi[channel] / 1000. * u_float( getYieldFromChain(setup.sample[s][channel]['chain'], cutString=MC_3l, weight=weight, returnError=True)) if setup.verbose: print "yield_looseSelection_other %s added, now: %s" % ( s, yield_other) normRegYield = yield_data_3l - yield_other if normRegYield.val < 0: print "\n !!!Warning!!! \n Negative normalization region yield data: (%s), MC: (%s) \n" % ( yield_data_3l, yield_other) print "normRegYield", normRegYield print "\n Control Region predictys ", normRegYield, " TTZ events in data; ", yield_MC_3l, " TTZ events in MC. Ratio ---> ", ( normRegYield / yield_MC_3l) print "DD-TTZ ---> ", (normRegYield / yield_MC_3l) * yield_MC_2l return (normRegYield / yield_MC_3l) * yield_MC_2l
def _estimate(self, region, channel, setup): logger.info("Data-driven TTZ estimate for region " + str(region) + " in channel " + channel + " and setup " + str(setup.sys) + ":") #Sum of all channels for 'all' if channel == 'all': estimate = sum([ self.cachedEstimate(region, c, setup) for c in ['MuMu', 'EE', 'EMu'] ]) else: zWindow = 'allZ' if channel == 'EMu' else 'offZ' preSelection = setup.preselection('MC', zWindow=zWindow, channel=channel) MC_2l = "&&".join([ region.cutString(setup.sys['selectionModifier']), preSelection['cut'] ]) weight = setup.weightString() logger.info("weight: %s", weight) yield_ttZ_2l = setup.lumi[channel] / 1000. * self.yieldFromCache( setup, 'TTZ', channel, MC_2l, weight) logger.info("yield_MC_2l: %s" % yield_ttZ_2l) if self.useTop16009: sysError = max((abs(x) for x in self.sysErrTop16009 )) # not sure yet to handle assymetric errors statError = max((abs(x) for x in self.statErrTop16009)) error = sqrt(sysError * sysError + statError * statError) return u_float(self.ratioTop16009, error) * yield_ttZ_2l else: # pt leptons > 30, 20, 10 GeV useTrigger = False # setup.parameters['useTriggers'] # better not to use three lepton triggers, seems to be too inefficient lllSelection = {} lllSelection['MuMu'] = "&&".join([ getLeptonString(3, 0), getPtThresholdString(30, 20, 10) ]) + ("&&HLT_3mu" if useTrigger else "") lllSelection['MuMuE'] = "&&".join([ getLeptonString(2, 1), getPtThresholdString(30, 20, 10) ]) + ("&&HLT_2mu1e" if useTrigger else "") lllSelection['MuEE'] = "&&".join([ getLeptonString(1, 2), getPtThresholdString(30, 20, 10) ]) + ("&&HLT_2e1mu" if useTrigger else "") lllSelection['EE'] = "&&".join([ getLeptonString(0, 3), getPtThresholdString(30, 20, 10) ]) + ("&&HLT_3e" if useTrigger else "") lllSelection['EMu'] = "((" + lllSelection[ 'MuMuE'] + ")||(" + lllSelection['MuEE'] + "))" bJetSelectionM = "(Sum$(JetGood_pt>30&&abs(JetGood_eta)<2.4&&JetGood_id&&JetGood_btagCSV>0.890))" bJetSelectionL = "(Sum$(JetGood_pt>30&&abs(JetGood_eta)<2.4&&JetGood_id&&JetGood_btagCSV>0.605))" zMassSelection = "abs(mlmZ_mass-91.1876)<10" # Start from base hadronic selection and add loose b-tag and Z-mass requirement selection = {} for dataOrMC in ["Data", "MC"]: selection[dataOrMC] = setup.selection( dataOrMC, hadronicSelection=True, **setup.defaultParameters( update={ 'nJets': self.nJets, 'nBTags': self.nMediumBTags, 'metMin': 0., 'metSigMin': 0., 'dPhiJetMet': 0. }))['cut'] selection[dataOrMC] += "&&" + bJetSelectionL + ">=" + str( self.nLooseBTags[0]) selection[dataOrMC] += "&&" + zMassSelection logger.info("Selection " + dataOrMC + ": " + selection[dataOrMC]) # Calculate yields (take together channels together) channels = ['MuMu', 'EMu', 'EE'] yield_ttZ_3l = sum( self.yieldFromCache( setup, 'TTZ', c, "&&".join( [lllSelection[c], selection["MC"]]), weight) * setup.dataLumi[channel] / 1000 for c in ['MuMu', 'EMu', 'EE']) yield_other = sum( self.yieldFromCache( setup, s, c, "&&".join( [lllSelection[c], selection["MC"]]), weight) * setup.dataLumi[channel] / 1000 for c in ['MuMu', 'EMu', 'EE'] for s in ['TTJets', 'DY', 'other']) yield_data_3l = sum( self.yieldFromCache( setup, 'Data', c, "&&".join( [lllSelection[c], selection["Data"]]), "(1)") for c in ['MuMu', 'EMu', 'EE']) if not yield_ttZ_3l > 0: logger.warn("No yield for 3l selection") estimate = u_float(0, 0) yield_ttZ_data = yield_data_3l - yield_other if yield_ttZ_data < 0: logger.warn("Data-driven ratio is negative!") yield_ttZ_data = u_float(0, 0) logger.info("Control region predictions: ") logger.info(" data: " + str(yield_data_3l)) logger.info(" MC other: " + str(yield_other)) logger.info(" TTZ (MC): " + str(yield_ttZ_3l)) logger.info(" TTZ (data): " + str(yield_ttZ_data)) logger.info(" TTZ (ratio): " + str(yield_ttZ_data / yield_ttZ_3l)) estimate = (yield_ttZ_data / yield_ttZ_3l) * yield_ttZ_2l logger.info(" --> " + str(estimate)) return estimate
def _estimate(self, region, channel, setup): #Sum of all channels for 'all' if channel == 'all': estimate = sum([ self.cachedEstimate(region, c, setup) for c in ['MuMu', 'EE', 'EMu'] ]) #MC based for 'EMu' elif channel == 'EMu': weight = setup.weightString() preSelection = setup.preselection('MC', zWindow='allZ', channel=channel) cut = "&&".join([ region.cutString(setup.sys['selectionModifier']), preSelection['cut'] ]) estimate = setup.lumi[channel] / 1000. * u_float( **setup.sample['DY'][channel].getYieldFromDraw( selectionString=cut, weightString=weight)) #Data driven for EE and MuMu (calculate for data luminosity) else: weight = setup.weightString() cut_offZ_1b = "&&".join([ region.cutString(setup.sys['selectionModifier']), setup.selection( 'MC', channel=channel, zWindow='offZ', **setup.defaultParameters(update={'nBTags': (1, -1)}))['cut'] ]) cut_onZ_0b = "&&".join([ region.cutString(setup.sys['selectionModifier']), setup.selection( 'MC', channel=channel, zWindow='onZ', **setup.defaultParameters(update={'nBTags': (0, 0)}))['cut'] ]) cut_data_onZ_0b = "&&".join([ region.cutString(), setup.selection( 'Data', channel=channel, zWindow='onZ', **setup.defaultParameters(update={'nBTags': (0, 0)}))['cut'] ]) # Calculate ratio (offZ,1b)/(onZ,0b) yield_offZ_1b = u_float( **setup.sample['DY'][channel].getYieldFromDraw( selectionString=cut_offZ_1b, weightString=weight)) * setup.dataLumi[channel] / 1000 yield_onZ_0b = u_float( **setup.sample['DY'][channel].getYieldFromDraw( selectionString=cut_onZ_0b, weightString=weight)) * setup.dataLumi[channel] / 1000 R = yield_offZ_1b / yield_onZ_0b if yield_onZ_0b > 0 else 0 # Calculate data-other onZ for 0 b-jets region yield_data = u_float( **setup.sample['Data'][channel].getYieldFromDraw( selectionString=cut_data_onZ_0b, weightString="(1)")) yield_other = sum( u_float(**setup.sample[s][channel].getYieldFromDraw( selectionString=cut_onZ_0b, weightString=weight)) for s in ['TTJets', 'TTZ', 'other']) * setup.dataLumi[channel] / 1000 normRegYield = yield_data - yield_other # Calculate DY estimate in 1 b-jet region (and scale back to MC lumi) estimate = R * normRegYield * setup.lumi[channel] / setup.dataLumi[ channel] logger.info("Calculating data-driven DY estimate in channel " + channel + " using lumi " + str(setup.dataLumi[channel]) + ":") logger.info("yield DY offZ/1b: " + str(yield_offZ_1b)) logger.info("yield DY onZ/0b: " + str(yield_onZ_0b)) logger.info("R: " + str(R)) logger.info("yield data onZ/0b: " + str(yield_data)) logger.info("yield other onZ/0b: " + str(yield_other)) logger.info("yield (data-other) onZ/0b: " + str(normRegYield)) logger.info("yield expected DY onZ/1b: " + str(normRegYield * R)) if normRegYield < 0 and yield_data > 0: logger.warn("Negative normalization region yield!") logger.info('Estimate for DY in ' + channel + ' channel (lumi=' + str(setup.lumi[channel]) + '/pb): ' + str(estimate) + (" (negative estimated being replaced by 0)" if estimate < 0 else "")) return estimate if estimate > 0 else u_float(0, 0)
def _estimate(self, region, channel, setup): #Sum of all channels for 'all' if channel == 'all': return sum([ self.cachedEstimate(region, c, channel, setup) for c in ['MuMu', 'EE', 'EMu'] ]) else: #Data driven for EE, EMu and MuMu. zWindow = 'allZ' if channel == 'EMu' else 'offZ' preSelection = setup.preselection('MC', zWindow=zWindow, channel=channel) #check lumi consistency assert abs( 1. - setup.lumi[channel] / setup.sample['Data'][channel]['lumi'] ) < 0.01, "Lumi specified in setup %f does not match lumi in data sample %f in channel %s" % ( setup.lumi[channel], setup.sample['Data'][channel]['lumi'], channel) MC_2l = "&&".join([ region.cutString(setup.sys['selectionModifier']), preSelection['cut'] ]) weight = preSelection['weightStr'] logger.debug("weight: %s", weight) yield_MC_2l = setup.lumi[channel] / 1000. * u_float( getYieldFromChain(setup.sample['TTZ'][channel]['chain'], cutString=selection_MC_2l, weight=weight, returnError=True)) if setup.verbose: print "yield_MC_2l: %s" % yield_MC_2l # pt leptons > 30, 20, 10 GeV useTrigger = False # setup.parameters['useTriggers'] # better not to use three lepton triggers, seems to be too inefficient mumumuSelection = "&&".join([ getLeptonString(3, 0), getPtThresholdString(30, 20, 10) ]) + ("&&HLT_3mu" if useTrigger else "") mumueSelection = "&&".join([ getLeptonString(2, 1), getPtThresholdString(30, 20, 10) ]) + ("&&HLT_2mu1e" if useTrigger else "") mueeSelection = "&&".join([ getLeptonString(1, 2), getPtThresholdString(30, 20, 10) ]) + ("&&HLT_2e1mu" if useTrigger else "") eeeSelection = "&&".join([ getLeptonString(0, 3), getPtThresholdString(30, 20, 10) ]) + ("&&HLT_3e" if useTrigger else "") lllSelection = "((" + ")||(".join([ mumumuSelection, mumueSelection, mueeSelection, eeeSelection ]) + "))" bJetSelectionM = "(Sum$(JetGood_pt>30&&abs(JetGood_eta)<2.4&&JetGood_id&&JetGood_btagCSV>0.890))" bJetSelectionL = "(Sum$(JetGood_pt>30&&abs(JetGood_eta)<2.4&&JetGood_id&&JetGood_btagCSV>0.605))" zMassSelection = "abs(mlmZ_mass-91.1876)<10" # Start from base hadronic selection and add loose b-tag and Z-mass requirement selection = {} for dataOrMC in ["Data", "MC"]: selection[dataOrMC] = setup.selection( dataOrMC, hadronicSelection=True, **setup.defaultParameters( update={ 'nJets': self.nJets, 'nBTags': self.nMediumBTags, 'metMin': 0., 'metSigMin': 0., 'dPhiJetMet': 0. }))['cut'] selection[dataOrMC] += bJetSelectionL + ">=" + str( self.nLooseBTags[0]) selection[dataOrMC] += zMassSelection MC_3l = lllSelection + "&&" + selection["MC"] data_mumumu = mumumuSelection + "&&" + selection["Data"] data_mumue = mumueSelection + "&&" + selection["Data"] data_muee = mueeSelection + "&&" + selection["Data"] data_eee = eeeSelection + "&&" + selection["Data"] # Calculate yields (take together) yield_ttZ_2l = setup.lumi[channel] / 1000. * u_float( getYieldFromChain(setup.sample['TTZ'][channel]['chain'], cutString=MC_2l, weight=weight, returnError=True)) yield_ttZ_3l = setup.lumi[channel] / 1000. * u_float( getYieldFromChain(setup.sample['TTZ'][channel]['chain'], cutString=MC_3l, weight=weight, returnError=True)) yield_data_mumumu = u_float( getYieldFromChain(setup.sample['Data']['MuMu']['chain'], cutString=data_mumumu, weight=weight, returnError=True)) yield_data_eee = u_float( getYieldFromChain(setup.sample['Data']['EE']['chain'], cutString=data_eee, weight=weight, returnError=True)) yield_data_mue = u_float( getYieldFromChain(setup.sample['Data']['EMu']['chain'], cutString="((" + data_mumue + ')||(' + data_muee + '))', weight=weight, returnError=True)) yield_data_3l = yield_data_mumumu + yield_data_mue + yield_data_eee #electroweak subtraction yield_other = u_float(0., 0.) for s in ['TTJets', 'DY', 'other']: yield_other += setup.lumi[channel] / 1000. * u_float( getYieldFromChain(setup.sample[s][channel]['chain'], cutString=MC_3l, weight=weight, returnError=True)) yield_ttZ_data = yield_data_3l - yield_other if normRegYield.val < 0: logger.warn("Data-driven estimate is negative!") logger.info("Control region predictions: ") logger.info(" data: " + str(yield_data_3l)) logger.info(" MC other: " + str(yield_other)) logger.info(" TTZ (MC): " + str(yield_ttZ_3l)) logger.info(" TTZ (data): " + str(yield_ttZ_data)) logger.info(" TTZ (ratio): " + str(yield_ttZ_data / yield_ttZ_3l)) return (yield_ttZ_data / yield_ttZ_3l) * yield_MC_2l
def _estimate(self, region, channel, setup): logger.info("Data-driven TTZ estimate for region " + str(region) + " in channel " + channel + " and setup " + str(setup.sys) + ":") #Sum of all channels for 'all' if channel=='all': estimate = sum([self.cachedEstimate(region, c, setup) for c in ['MuMu', 'EE', 'EMu']]) else: zWindow= 'allZ' if channel=='EMu' else 'offZ' preSelection = setup.preselection('MC', zWindow=zWindow, channel=channel) MC_2l = "&&".join([region.cutString(setup.sys['selectionModifier']), preSelection['cut']]) weight = setup.weightString() logger.info("weight: %s", weight) yield_ttZ_2l = setup.lumi[channel]/1000.*self.yieldFromCache(setup, 'TTZ', channel, MC_2l, weight) logger.info("yield_MC_2l: %s"%yield_ttZ_2l) if self.useTop16009: sysError = max((abs(x) for x in self.sysErrTop16009)) # not sure yet to handle assymetric errors statError = max((abs(x) for x in self.statErrTop16009)) error = sqrt(sysError*sysError+statError*statError) return u_float(self.ratioTop16009, error)*yield_ttZ_2l else: # pt leptons > 30, 20, 10 GeV useTrigger = False # setup.parameters['useTriggers'] # better not to use three lepton triggers, seems to be too inefficient lllSelection = {} lllSelection['MuMu'] = "&&".join([getLeptonString(3, 0), getPtThresholdString(30, 20, 10)]) + ("&&HLT_3mu" if useTrigger else "") lllSelection['MuMuE'] = "&&".join([getLeptonString(2, 1), getPtThresholdString(30, 20, 10)]) + ("&&HLT_2mu1e" if useTrigger else "") lllSelection['MuEE'] = "&&".join([getLeptonString(1, 2), getPtThresholdString(30, 20, 10)]) + ("&&HLT_2e1mu" if useTrigger else "") lllSelection['EE'] = "&&".join([getLeptonString(0, 3), getPtThresholdString(30, 20, 10)]) + ("&&HLT_3e" if useTrigger else "") lllSelection['EMu'] = "(("+lllSelection['MuMuE']+")||("+lllSelection['MuEE']+"))" bJetSelectionM = "(Sum$(JetGood_pt>30&&abs(JetGood_eta)<2.4&&JetGood_id&&JetGood_btagCSV>0.890))" bJetSelectionL = "(Sum$(JetGood_pt>30&&abs(JetGood_eta)<2.4&&JetGood_id&&JetGood_btagCSV>0.605))" zMassSelection = "abs(mlmZ_mass-91.1876)<10" # Start from base hadronic selection and add loose b-tag and Z-mass requirement selection = {} for dataOrMC in ["Data", "MC"]: selection[dataOrMC] = setup.selection(dataOrMC, hadronicSelection = True, **setup.defaultParameters(update={'nJets': self.nJets, 'nBTags':self.nMediumBTags, 'metMin': 0., 'metSigMin':0., 'dPhiJetMet':0. }))['cut'] selection[dataOrMC] += "&&" + bJetSelectionL+">="+str(self.nLooseBTags[0]) selection[dataOrMC] += "&&" + zMassSelection logger.info("Selection " + dataOrMC + ": " + selection[dataOrMC]) # Calculate yields (take together channels together) channels = ['MuMu','EMu','EE'] yield_ttZ_3l = sum(self.yieldFromCache(setup, 'TTZ', c, "&&".join([lllSelection[c], selection["MC"]]), weight)*setup.dataLumi[channel]/1000 for c in ['MuMu','EMu','EE']) yield_other = sum(self.yieldFromCache(setup, s, c, "&&".join([lllSelection[c], selection["MC"]]), weight)*setup.dataLumi[channel]/1000 for c in ['MuMu','EMu','EE'] for s in ['TTJets', 'DY', 'other']) yield_data_3l = sum(self.yieldFromCache(setup, 'Data', c, "&&".join([lllSelection[c], selection["Data"]]), "(1)") for c in ['MuMu','EMu','EE']) if not yield_ttZ_3l > 0: logger.warn("No yield for 3l selection") estimate = u_float(0, 0) yield_ttZ_data = yield_data_3l - yield_other if yield_ttZ_data < 0: logger.warn("Data-driven ratio is negative!") yield_ttZ_data = u_float(0, 0) logger.info("Control region predictions: ") logger.info(" data: " + str(yield_data_3l)) logger.info(" MC other: " + str(yield_other)) logger.info(" TTZ (MC): " + str(yield_ttZ_3l)) logger.info(" TTZ (data): " + str(yield_ttZ_data)) logger.info(" TTZ (ratio): " + str(yield_ttZ_data/yield_ttZ_3l)) estimate = (yield_ttZ_data/yield_ttZ_3l)*yield_ttZ_2l logger.info(" --> " + str(estimate)) return estimate
def _estimate(self, region, channel, setup): #Sum of all channels for 'all' if channel=='all': return sum( [ self.cachedEstimate(region, c, channel, setup) for c in ['MuMu', 'EE', 'EMu'] ] ) else: #Data driven for EE, EMu and MuMu. zWindow= 'allZ' if channel=='EMu' else 'offZ' preSelection = setup.preselection('MC', zWindow=zWindow, channel=channel) #check lumi consistency assert abs(1.-setup.lumi[channel]/setup.sample['Data'][channel]['lumi'])<0.01, "Lumi specified in setup %f does not match lumi in data sample %f in channel %s"%(setup.lumi[channel], setup.sample['Data'][channel]['lumi'], channel) MC_2l = "&&".join([region.cutString(setup.sys['selectionModifier']), preSelection['cut']]) weight = preSelection['weightStr'] logger.debug("weight: %s", weight) yield_MC_2l = setup.lumi[channel]/1000.*u_float(getYieldFromChain(setup.sample['TTZ'][channel]['chain'], cutString = selection_MC_2l, weight=weight, returnError = True) ) if setup.verbose: print "yield_MC_2l: %s"%yield_MC_2l # pt leptons > 30, 20, 10 GeV useTrigger = False # setup.parameters['useTriggers'] # better not to use three lepton triggers, seems to be too inefficient mumumuSelection = "&&".join([getLeptonString(3, 0), getPtThresholdString(30, 20, 10)]) + ("&&HLT_3mu" if useTrigger else "") mumueSelection = "&&".join([getLeptonString(2, 1), getPtThresholdString(30, 20, 10)]) + ("&&HLT_2mu1e" if useTrigger else "") mueeSelection = "&&".join([getLeptonString(1, 2), getPtThresholdString(30, 20, 10)]) + ("&&HLT_2e1mu" if useTrigger else "") eeeSelection = "&&".join([getLeptonString(0, 3), getPtThresholdString(30, 20, 10)]) + ("&&HLT_3e" if useTrigger else "") lllSelection = "((" + ")||(".join([mumumuSelection, mumueSelection, mueeSelection, eeeSelection]) + "))" bJetSelectionM = "(Sum$(JetGood_pt>30&&abs(JetGood_eta)<2.4&&JetGood_id&&JetGood_btagCSV>0.890))" bJetSelectionL = "(Sum$(JetGood_pt>30&&abs(JetGood_eta)<2.4&&JetGood_id&&JetGood_btagCSV>0.605))" zMassSelection = "abs(mlmZ_mass-91.1876)<10" # Start from base hadronic selection and add loose b-tag and Z-mass requirement selection = {} for dataOrMC in ["Data", "MC"]: selection[dataOrMC] = setup.selection(dataOrMC, hadronicSelection = True, **setup.defaultParameters(update={'nJets': self.nJets, 'nBTags':self.nMediumBTags, 'metMin': 0., 'metSigMin':0., 'dPhiJetMet':0. }))['cut'] selection[dataOrMC] += bJetSelectionL+">="+str(self.nLooseBTags[0]) selection[dataOrMC] += zMassSelection MC_3l = lllSelection + "&&" + selection["MC"] data_mumumu = mumumuSelection + "&&" + selection["Data"] data_mumue = mumueSelection + "&&" + selection["Data"] data_muee = mueeSelection + "&&" + selection["Data"] data_eee = eeeSelection + "&&" + selection["Data"] # Calculate yields (take together) yield_ttZ_2l = setup.lumi[channel]/1000.*u_float(getYieldFromChain(setup.sample['TTZ'][channel]['chain'], cutString = MC_2l, weight=weight, returnError = True)) yield_ttZ_3l = setup.lumi[channel]/1000.*u_float(getYieldFromChain(setup.sample['TTZ'][channel]['chain'], cutString = MC_3l, weight=weight, returnError = True)) yield_data_mumumu = u_float(getYieldFromChain(setup.sample['Data']['MuMu']['chain'], cutString = data_mumumu, weight=weight, returnError = True)) yield_data_eee = u_float(getYieldFromChain(setup.sample['Data']['EE']['chain'], cutString = data_eee, weight=weight, returnError = True)) yield_data_mue = u_float(getYieldFromChain(setup.sample['Data']['EMu']['chain'], cutString = "(("+data_mumue+')||('+data_muee+'))', weight=weight, returnError = True)) yield_data_3l = yield_data_mumumu + yield_data_mue + yield_data_eee #electroweak subtraction yield_other = u_float(0., 0.) for s in ['TTJets' , 'DY', 'other']: yield_other+= setup.lumi[channel]/1000.* u_float(getYieldFromChain(setup.sample[s][channel]['chain'], cutString = MC_3l, weight=weight, returnError=True)) yield_ttZ_data = yield_data_3l - yield_other if normRegYield.val<0: logger.warn("Data-driven estimate is negative!") logger.info("Control region predictions: ") logger.info(" data: " + str(yield_data_3l)) logger.info(" MC other: " + str(yield_other)) logger.info(" TTZ (MC): " + str(yield_ttZ_3l)) logger.info(" TTZ (data): " + str(yield_ttZ_data)) logger.info(" TTZ (ratio): " + str(yield_ttZ_data/yield_ttZ_3l)) return (yield_ttZ_data/yield_ttZ_3l)*yield_MC_2l