コード例 #1
0
ファイル: systematics.py プロジェクト: wardVD/Copy
 def initCache(self, cacheDir):
     if cacheDir:
         self.cacheDir = cacheDir
         cacheFileName = os.path.join(cacheDir, self.name + '.pkl')
         if not os.path.exists(os.path.dirname(cacheFileName)):
             os.makedirs(os.path.dirname(cacheFileName))
         self.cache = Cache(cacheFileName, verbosity=2)
     else:
         self.cache = None
コード例 #2
0
    def __init__(self, name, cacheDir=None, useTop16009=False):
        super(DataDrivenTTZEstimate, self).__init__(name, cacheDir=cacheDir)
        self.nJets = (3, -1)  # jet selection (min, max)
        self.nLooseBTags = (2, -1)  # loose bjet selection (min, max)
        self.nMediumBTags = (0, -1)  # bjet selection (min, max)

        self.useTop16009 = useTop16009
        self.ratioTop16009 = 1.27  #
        self.sysErrTop16009 = (-0.17, +0.20)
        self.statErrTop16009 = (-0.37, +0.42)

        # Because we are going to reuse a lot of yields which otherwise will be terribly slow
        self.helperCacheName = os.path.join('.', 'helperCache.pkl')
        self.helperCache = Cache(self.helperCacheName, verbosity=2)
コード例 #3
0
 def initCache(self, cacheDir):
     if cacheDir:
         self.cacheDir=cacheDir
         cacheFileName = os.path.join(cacheDir, self.name+'.pkl')
         if not os.path.exists(os.path.dirname(cacheFileName)):
             os.makedirs(os.path.dirname(cacheFileName))
         self.cache = Cache(cacheFileName, verbosity=2)
     else:
         self.cache=None
コード例 #4
0
    def __init__(self, name, cacheDir=None, useTop16009=False):
        super(DataDrivenTTZEstimate, self).__init__(name, cacheDir=cacheDir)
        self.nJets        = (3,-1) # jet selection (min, max)
        self.nLooseBTags  = (2,-1) # loose bjet selection (min, max)
        self.nMediumBTags = (0,-1) # bjet selection (min, max)

        self.useTop16009       = useTop16009
        self.ratioTop16009     = 1.27 #
        self.sysErrTop16009    = (-0.17, +0.20)
        self.statErrTop16009   = (-0.37, +0.42)

        # Because we are going to reuse a lot of yields which otherwise will be terribly slow
        self.helperCacheName = os.path.join('.', 'helperCache.pkl')
        self.helperCache     = Cache(self.helperCacheName, verbosity=2)
コード例 #5
0
from StopsDilepton.analysis.u_float import u_float
from math import sqrt
##https://twiki.cern.ch/twiki/bin/viewauth/CMS/SUSYSignalSystematicsRun2
from StopsDilepton.tools.user import combineReleaseLocation
from StopsDilepton.tools.cardFileWriter import cardFileWriter

limitPrefix = options.regions
limitDir = os.path.join(setup.analysis_results, setup.prefix(), 'cardFiles',
                        limitPrefix)
overWrite = False
useCache = True
verbose = True

if not os.path.exists(limitDir): os.makedirs(limitDir)
cacheFileName = os.path.join(limitDir, 'calculatedLimits.pkl')
limitCache = Cache(cacheFileName, verbosity=2)


def wrapper(s):
    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('topPt', 'lnN')
        c.addUncertainty('JEC', 'lnN')
        c.addUncertainty('JER', 'lnN')
        c.addUncertainty('SFb', 'lnN')
コード例 #6
0
class DataDrivenTTZEstimate(SystematicEstimator):
    def __init__(self, name, cacheDir=None, useTop16009=False):
        super(DataDrivenTTZEstimate, self).__init__(name, cacheDir=cacheDir)
        self.nJets = (3, -1)  # jet selection (min, max)
        self.nLooseBTags = (2, -1)  # loose bjet selection (min, max)
        self.nMediumBTags = (0, -1)  # bjet selection (min, max)

        self.useTop16009 = useTop16009
        self.ratioTop16009 = 1.27  #
        self.sysErrTop16009 = (-0.17, +0.20)
        self.statErrTop16009 = (-0.37, +0.42)

        # Because we are going to reuse a lot of yields which otherwise will be terribly slow
        self.helperCacheName = os.path.join('.', 'helperCache.pkl')
        self.helperCache = Cache(self.helperCacheName, verbosity=2)

    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

    #Concrete implementation of abstract method 'estimate' as defined in Systematic
    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
コード例 #7
0
class SystematicEstimator:
    __metaclass__ = abc.ABCMeta

    def __init__(self, name, cacheDir=None):
        self.name = name
        self.initCache(cacheDir)

    def initCache(self, cacheDir):
        if cacheDir:
            self.cacheDir=cacheDir
            cacheFileName = os.path.join(cacheDir, self.name+'.pkl')
            if not os.path.exists(os.path.dirname(cacheFileName)):
                os.makedirs(os.path.dirname(cacheFileName))
            self.cache = Cache(cacheFileName, verbosity=2)
        else:
            self.cache=None

    def uniqueKey(self, region, channel, setup):
        return region, channel, json.dumps(setup.sys, sort_keys=True), json.dumps(setup.parameters, sort_keys=True), json.dumps(setup.lumi, sort_keys=True)

    def cachedEstimate(self, region, channel, setup, save=True):
        key =  self.uniqueKey(region, channel, setup)
        if self.cache and self.cache.contains(key):
            res = self.cache.get(key)
            logger.debug( "Loading cached %s result for %r : %r"%(self.name, key, res) )
            return res
        elif self.cache:
            return self.cache.add( key, self._estimate( region, channel, setup), save=save)
        else:
            return self._estimate( region, channel, setup)

    @abc.abstractmethod
    def _estimate(self, region, channel, setup):
        '''Estimate yield in 'region' using setup'''
        return

    def PUSystematic(self, region, channel, setup):
        ref  = self.cachedEstimate(region, channel, setup)
        up   = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightPUUp']}))
        down = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightPUDown']}))
        return 0.5*(up-down)/ref

    def topPtSystematic(self, region, channel, setup):
        ref   = self.cachedEstimate(region, channel, setup)
        up   = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightTopPt']}))
        return 0.5*(up-ref)/ref

    def JERSystematic(self, region, channel, setup):
        ref   = self.cachedEstimate(region, channel, setup)
        up   = self.cachedEstimate(region, channel, setup.sysClone({'selectionModifier':'JERUp'}))
        down = self.cachedEstimate(region, channel, setup.sysClone({'selectionModifier':'JERDown'}))
        return 0.5*(up-down)/ref

    def JECSystematic(self, region, channel, setup):
        ref   = self.cachedEstimate(region, channel, setup)
        up   = self.cachedEstimate(region, channel, setup.sysClone({'selectionModifier':'JECUp'}))
        down = self.cachedEstimate(region, channel, setup.sysClone({'selectionModifier':'JECDown'}))
        return 0.5*(up-down)/ref

    def leptonFSSystematic(self, region, channel, setup):
        ref  = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSF']}))
        up   = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSFUp']}))
        down = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSFDown']}))
        return 0.5*(up-down)/ref

    def btaggingSFbSystematic(self, region, channel, setup):
        ref     = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightBTag_SF']}))
        up      = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightBTag_SF_b_Up']}))
        down    = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightBTag_SF_b_Down']}))
        return 0.5*(up-down)/ref

    def btaggingSFlSystematic(self, region, channel, setup):
        ref     = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightBTag_SF']}))
        up      = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightBTag_SF_l_Up']}))
        down    = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightBTag_SF_l_Down']}))
        return 0.5*(up-down)/ref

    def btaggingSFFSSystematic(self, region, channel, setup):
        ref     = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightBTag_SF']}))
        up      = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightBTag_SF_FS_Up']}))
        down    = self.cachedEstimate(region, channel, setup.sysClone({'reweight':['reweightBTag_SF_FS_Down']}))
        return 0.5*(up-down)/ref

    def getBkgSysJobs(self, region, channel, setup):
        l = [
            (region, channel, setup.sysClone({'reweight':['reweightPUUp']})),
            (region, channel, setup.sysClone({'reweight':['reweightPUDown']})),

            (region, channel, setup.sysClone({'reweight':['reweightTopPt']})),

            (region, channel, setup.sysClone({'selectionModifier':'JERUp'})),
            (region, channel, setup.sysClone({'selectionModifier':'JERDown'})),

            (region, channel, setup.sysClone({'selectionModifier':'JECUp'})),
            (region, channel, setup.sysClone({'selectionModifier':'JECDown'})),


            (region, channel, setup.sysClone({'reweight':['reweightBTag_SF']})),
            (region, channel, setup.sysClone({'reweight':['reweightBTag_SF_b_Up']})),
            (region, channel, setup.sysClone({'reweight':['reweightBTag_SF_b_Down']})),
            (region, channel, setup.sysClone({'reweight':['reweightBTag_SF_l_Up']})),
            (region, channel, setup.sysClone({'reweight':['reweightBTag_SF_l_Down']})),

        ]
        return l

    def getSigSysJobs(self, region, channel, setup, isFastSim = False):
        l = self.getBkgSysJobs(region = region, channel = channel, setup = setup)
        if isFastSim:
            l.extend( [\
                (region, channel, setup.sysClone({'reweight':['reweightBTag_SF_FS_Up']})),
                (region, channel, setup.sysClone({'reweight':['reweightBTag_SF_FS_Down']})),
                (region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSF']})),
                (region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSFUp']})),
                (region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSFDown']})),
            ] )
        return l
コード例 #8
0
ファイル: systematics.py プロジェクト: wardVD/Copy
class SystematicBaseClass:
    __metaclass__ = abc.ABCMeta

    def __init__(self, name, cacheDir=None):
        self.name = name
        self.initCache(cacheDir)

    def initCache(self, cacheDir):
        if cacheDir:
            self.cacheDir = cacheDir
            cacheFileName = os.path.join(cacheDir, self.name + '.pkl')
            if not os.path.exists(os.path.dirname(cacheFileName)):
                os.makedirs(os.path.dirname(cacheFileName))
            self.cache = Cache(cacheFileName, verbosity=2)
        else:
            self.cache = None

    def uniqueKey(self, region, channel, setup):
        return region, channel, json.dumps(
            setup.sys, sort_keys=True), json.dumps(setup.parameters,
                                                   sort_keys=True), json.dumps(
                                                       setup.lumi,
                                                       sort_keys=True)

    def cachedEstimate(self, region, channel, setup, save=True):
        key = self.uniqueKey(region, channel, setup)
        if self.cache and self.cache.contains(key):
            res = self.cache.get(key)
            if setup.verbose:
                print "Loading cached %s result for %r : %r" % (self.name, key,
                                                                res)
            return res
        elif self.cache:
            return self.cache.add(key,
                                  self._estimate(region, channel, setup),
                                  save=save)
        else:
            return self._estimate(region, channel, setup)

    @abc.abstractmethod
    def _estimate(self, region, channel, setup):
        '''Estimate yield in 'region' using setup'''
        return

    def PUSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup)
        up = self.cachedEstimate(region, channel,
                                 setup.sysClone({'weight': 'weightPUUp'}))
        down = self.cachedEstimate(region, channel,
                                   setup.sysClone({'weight': 'weightPUDown'}))
        return 0.5 * (up - down) / ref

    def topPtSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup)
        up = self.cachedEstimate(
            region, channel, setup.sysClone({'reweight': ['reweightTopPt']}))
        return 0.5 * (up - ref) / ref

    def JERSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup)
        up = self.cachedEstimate(
            region, channel, setup.sysClone({'selectionModifier': 'JERUp'}))
        down = self.cachedEstimate(
            region, channel, setup.sysClone({'selectionModifier': 'JERDown'}))
        return 0.5 * (up - down) / ref

    def JECSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup)
        up = self.cachedEstimate(
            region, channel, setup.sysClone({'selectionModifier': 'JECUp'}))
        down = self.cachedEstimate(
            region, channel, setup.sysClone({'selectionModifier': 'JECDown'}))
        return 0.5 * (up - down) / ref

    def leptonFSSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(
            region, channel,
            setup.sysClone({'reweight': ['reweightLeptonFastSimSF']}))
        up = self.cachedEstimate(
            region, channel,
            setup.sysClone({'reweight': ['reweightLeptonFastSimSFUp']}))
        down = self.cachedEstimate(
            region, channel,
            setup.sysClone({'reweight': ['reweightLeptonFastSimSFDown']}))
        return 0.5 * (up - down) / ref

    def btaggingSFbSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel,
                                  setup.sysClone({'useBTagWeights': 'SF'}))
        up = self.cachedEstimate(region, channel,
                                 setup.sysClone({'useBTagWeights': 'SF_b_Up'}))
        down = self.cachedEstimate(
            region, channel, setup.sysClone({'useBTagWeights': 'SF_b_Down'}))
        return 0.5 * (up - down) / ref

    def btaggingSFlSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel,
                                  setup.sysClone({'useBTagWeights': 'SF'}))
        up = self.cachedEstimate(region, channel,
                                 setup.sysClone({'useBTagWeights': 'SF_l_Up'}))
        down = self.cachedEstimate(
            region, channel, setup.sysClone({'useBTagWeights': 'SF_l_Down'}))
        return 0.5 * (up - down) / ref

    def btaggingSFFSSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel,
                                  setup.sysClone({'useBTagWeights': 'SF'}))
        up = self.cachedEstimate(
            region, channel, setup.sysClone({'useBTagWeights': 'SF_FS_Up'}))
        down = self.cachedEstimate(
            region, channel, setup.sysClone({'useBTagWeights': 'SF_FS_Down'}))
        return 0.5 * (up - down) / ref

    def getBkgSysJobs(self, region, channel, setup):
        return [
            (region, channel, setup.sysClone({'weight': 'weightPUUp'})),
            (region, channel, setup.sysClone({'weight': 'weightPUDown'})),
            (region, channel, setup.sysClone({'reweight': ['reweightTopPt']})),
            (region, channel, setup.sysClone({'selectionModifier': 'JERUp'})),
            (region, channel, setup.sysClone({'selectionModifier':
                                              'JERDown'})),
            (region, channel, setup.sysClone({'selectionModifier': 'JECUp'})),
            (region, channel, setup.sysClone({'selectionModifier':
                                              'JECDown'})),

            #      (region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSF']})),
            #      (region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSFUp']})),
            #      (region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSFDown']})),
            (region, channel, setup.sysClone({'useBTagWeights': 'SF'})),
            (region, channel, setup.sysClone({'useBTagWeights': 'SF_b_Up'})),
            (region, channel, setup.sysClone({'useBTagWeights': 'SF_b_Down'})),
            (region, channel, setup.sysClone({'useBTagWeights': 'SF'})),
            (region, channel, setup.sysClone({'useBTagWeights': 'SF_l_Up'})),
            (region, channel, setup.sysClone({'useBTagWeights': 'SF_l_Down'})),
            (region, channel, setup.sysClone({'useBTagWeights': 'SF'})),
            #      (region, channel, setup.sysClone({'useBTagWeights':'SF_FS_Up'})),
            #      (region, channel, setup.sysClone({'useBTagWeights':'SF_FS_Down'})),
        ]

    def getSigSysJobs(self, region, channel, setup):
        return [
            (region, channel,
             setup.sysClone({'reweight': ['reweightLeptonFastSimSF']})),
            (region, channel,
             setup.sysClone({'reweight': ['reweightLeptonFastSimSFUp']})),
            (region, channel,
             setup.sysClone({'reweight': ['reweightLeptonFastSimSFDown']})),
            (region, channel, setup.sysClone({'useBTagWeights': 'SF_FS_Up'})),
            (region, channel, setup.sysClone({'useBTagWeights':
                                              'SF_FS_Down'})),
        ]
コード例 #9
0
ファイル: systematics.py プロジェクト: wardVD/StopsDilepton
class SystematicBaseClass:
    __metaclass__ = abc.ABCMeta

    def __init__(self, name, cacheDir=None):
        self.name = name
        self.initCache(cacheDir)

    def initCache(self, cacheDir):
        if cacheDir:
            self.cacheDir = cacheDir
            cacheFileName = os.path.join(cacheDir, self.name + ".pkl")
            if not os.path.exists(os.path.dirname(cacheFileName)):
                os.makedirs(os.path.dirname(cacheFileName))
            self.cache = Cache(cacheFileName, verbosity=2)
        else:
            self.cache = None

    def uniqueKey(self, region, channel, setup):
        return (
            region,
            channel,
            json.dumps(setup.sys, sort_keys=True),
            json.dumps(setup.parameters, sort_keys=True),
            json.dumps(setup.lumi, sort_keys=True),
        )

    def cachedEstimate(self, region, channel, setup, save=True):
        key = self.uniqueKey(region, channel, setup)
        if self.cache and self.cache.contains(key):
            res = self.cache.get(key)
            if setup.verbose:
                print "Loading cached %s result for %r : %r" % (self.name, key, res)
            return res
        elif self.cache:
            return self.cache.add(key, self._estimate(region, channel, setup), save=save)
        else:
            return self._estimate(region, channel, setup)

    @abc.abstractmethod
    def _estimate(self, region, channel, setup):
        """Estimate yield in 'region' using setup"""
        return

    def PUSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup)
        up = self.cachedEstimate(region, channel, setup.sysClone({"weight": "weightPUUp"}))
        down = self.cachedEstimate(region, channel, setup.sysClone({"weight": "weightPUDown"}))
        return 0.5 * (up - down) / ref

    def topPtSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup)
        up = self.cachedEstimate(region, channel, setup.sysClone({"reweight": ["reweightTopPt"]}))
        return 0.5 * (up - ref) / ref

    def JERSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup)
        up = self.cachedEstimate(region, channel, setup.sysClone({"selectionModifier": "JERUp"}))
        down = self.cachedEstimate(region, channel, setup.sysClone({"selectionModifier": "JERDown"}))
        return 0.5 * (up - down) / ref

    def JECSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup)
        up = self.cachedEstimate(region, channel, setup.sysClone({"selectionModifier": "JECUp"}))
        down = self.cachedEstimate(region, channel, setup.sysClone({"selectionModifier": "JECDown"}))
        return 0.5 * (up - down) / ref

    def leptonFSSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup.sysClone({"reweight": ["reweightLeptonFastSimSF"]}))
        up = self.cachedEstimate(region, channel, setup.sysClone({"reweight": ["reweightLeptonFastSimSFUp"]}))
        down = self.cachedEstimate(region, channel, setup.sysClone({"reweight": ["reweightLeptonFastSimSFDown"]}))
        return 0.5 * (up - down) / ref

    def btaggingSFbSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup.sysClone({"useBTagWeights": "SF"}))
        up = self.cachedEstimate(region, channel, setup.sysClone({"useBTagWeights": "SF_b_Up"}))
        down = self.cachedEstimate(region, channel, setup.sysClone({"useBTagWeights": "SF_b_Down"}))
        return 0.5 * (up - down) / ref

    def btaggingSFlSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup.sysClone({"useBTagWeights": "SF"}))
        up = self.cachedEstimate(region, channel, setup.sysClone({"useBTagWeights": "SF_l_Up"}))
        down = self.cachedEstimate(region, channel, setup.sysClone({"useBTagWeights": "SF_l_Down"}))
        return 0.5 * (up - down) / ref

    def btaggingSFFSSystematic(self, region, channel, setup):
        ref = self.cachedEstimate(region, channel, setup.sysClone({"useBTagWeights": "SF"}))
        up = self.cachedEstimate(region, channel, setup.sysClone({"useBTagWeights": "SF_FS_Up"}))
        down = self.cachedEstimate(region, channel, setup.sysClone({"useBTagWeights": "SF_FS_Down"}))
        return 0.5 * (up - down) / ref

    def getBkgSysJobs(self, region, channel, setup):
        return [
            (region, channel, setup.sysClone({"weight": "weightPUUp"})),
            (region, channel, setup.sysClone({"weight": "weightPUDown"})),
            (region, channel, setup.sysClone({"reweight": ["reweightTopPt"]})),
            (region, channel, setup.sysClone({"selectionModifier": "JERUp"})),
            (region, channel, setup.sysClone({"selectionModifier": "JERDown"})),
            (region, channel, setup.sysClone({"selectionModifier": "JECUp"})),
            (region, channel, setup.sysClone({"selectionModifier": "JECDown"})),
            #      (region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSF']})),
            #      (region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSFUp']})),
            #      (region, channel, setup.sysClone({'reweight':['reweightLeptonFastSimSFDown']})),
            (region, channel, setup.sysClone({"useBTagWeights": "SF"})),
            (region, channel, setup.sysClone({"useBTagWeights": "SF_b_Up"})),
            (region, channel, setup.sysClone({"useBTagWeights": "SF_b_Down"})),
            (region, channel, setup.sysClone({"useBTagWeights": "SF"})),
            (region, channel, setup.sysClone({"useBTagWeights": "SF_l_Up"})),
            (region, channel, setup.sysClone({"useBTagWeights": "SF_l_Down"})),
            (region, channel, setup.sysClone({"useBTagWeights": "SF"})),
            #      (region, channel, setup.sysClone({'useBTagWeights':'SF_FS_Up'})),
            #      (region, channel, setup.sysClone({'useBTagWeights':'SF_FS_Down'})),
        ]

    def getSigSysJobs(self, region, channel, setup):
        return [
            (region, channel, setup.sysClone({"reweight": ["reweightLeptonFastSimSF"]})),
            (region, channel, setup.sysClone({"reweight": ["reweightLeptonFastSimSFUp"]})),
            (region, channel, setup.sysClone({"reweight": ["reweightLeptonFastSimSFDown"]})),
            (region, channel, setup.sysClone({"useBTagWeights": "SF_FS_Up"})),
            (region, channel, setup.sysClone({"useBTagWeights": "SF_FS_Down"})),
        ]
コード例 #10
0
class DataDrivenTTZEstimate(SystematicEstimator):
    def __init__(self, name, cacheDir=None, useTop16009=False):
        super(DataDrivenTTZEstimate, self).__init__(name, cacheDir=cacheDir)
        self.nJets        = (3,-1) # jet selection (min, max)
        self.nLooseBTags  = (2,-1) # loose bjet selection (min, max)
        self.nMediumBTags = (0,-1) # bjet selection (min, max)

        self.useTop16009       = useTop16009
        self.ratioTop16009     = 1.27 #
        self.sysErrTop16009    = (-0.17, +0.20)
        self.statErrTop16009   = (-0.37, +0.42)

        # Because we are going to reuse a lot of yields which otherwise will be terribly slow
        self.helperCacheName = os.path.join('.', 'helperCache.pkl')
        self.helperCache     = Cache(self.helperCacheName, verbosity=2)

    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

    #Concrete implementation of abstract method 'estimate' as defined in Systematic
    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