Esempio n. 1
0
    def initialize(self,config_name):
        """
        Initialize the selection (before looping the events)

        @param config_name   Name of the configuration to use (e.g., 'miniSL')
        """
        self.cfg_name = config_name

        logging.getLogger('share/{0}.log'.format(self.cfg_name))
        self.loggingLEVEL = logging.getLogger().getEffectiveLevel() # DEBUG, INFO, ERROR, etc.
        logging.info("")
        logging.critical(" -- In file 'SelectionBase.py'\n")
        logging.info("  ------------  ")

        parser_cutsfile_name = self.parser.get(self.cfg_name,'cutsfile') # default
        if not self.cutsfile:
            self.cutsfile = parser_cutsfile_name
        self.cuts = config.processCuts(self.cutsfile)

        ## We only need to load the cuts files once 
        ## (the cuts don't change from event-to-event!)
        self.object_level_cuts    = ObjectCuts(self.parser,self.cuts)
        self.event_level_cuts     = EventCuts(self.parser,self.cuts)
        self.build_custom_objects = (self.parser.get(self.cfg_name,'new_objects'))
        self.btag_WP              = info.btagging_WP(self.parser.get(self.cfg_name,'btag_wkpt'))

        return
Esempio n. 2
0
class SelectionBase(object):
    """
    Class for applying a custom selection on an existing set of ntuples.
    This is meant to be the base class that applies cuts on our objects and 
    event-level quantities in a modular way.  You can use this file with different
    cuts files, or inherit from it to build your own selection.
    """
    def __init__(self,cfg_file,_cutsfile=''):
        """
        Initialize the class.

        @param cfg_file   configuration file 
        @param _cutsfile  cuts file to use for selection (empty by default)
        """
        self.parser   = cfg_file   # settings
        self.cutsfile = _cutsfile  # to pass a different cuts file (e.g., from pyDataMC)

        self.build_lepton = lepBase    # setup the lepton
        self.build_met    = metBase    # setup the MET
        self.build_nu     = nuBase     # setup the neutrino
        self.build_jets   = jetBase    # setup the jets
        self.build_tjets  = tjetBase   # setup the track jets
        self.build_ljets  = fjBase     # setup the Fat Jets

        return



#----------------------------------------------------------------------------------------#

    def initialize(self,config_name):
        """
        Initialize the selection (before looping the events)

        @param config_name   Name of the configuration to use (e.g., 'miniSL')
        """
        self.cfg_name = config_name

        logging.getLogger('share/{0}.log'.format(self.cfg_name))
        self.loggingLEVEL = logging.getLogger().getEffectiveLevel() # DEBUG, INFO, ERROR, etc.
        logging.info("")
        logging.critical(" -- In file 'SelectionBase.py'\n")
        logging.info("  ------------  ")

        parser_cutsfile_name = self.parser.get(self.cfg_name,'cutsfile') # default
        if not self.cutsfile:
            self.cutsfile = parser_cutsfile_name
        self.cuts = config.processCuts(self.cutsfile)

        ## We only need to load the cuts files once 
        ## (the cuts don't change from event-to-event!)
        self.object_level_cuts    = ObjectCuts(self.parser,self.cuts)
        self.event_level_cuts     = EventCuts(self.parser,self.cuts)
        self.build_custom_objects = (self.parser.get(self.cfg_name,'new_objects'))
        self.btag_WP              = info.btagging_WP(self.parser.get(self.cfg_name,'btag_wkpt'))

        return



#----------------------------------------------------------------------------------------#

    def execute(self,T,F):
        """ 
        Function to setup each file.

        @param T          Root Ttree
        @param f          Root file object (not just the string)
        """
        self.t    = T          # root ttree
        self.file = F          # root file  (not used...)

        return


#----------------------------------------------------------------------------------------#

    def event_loop(self,Entry):
        """Running the event selection for a single event."""
        self.entry = Entry
        self.t.GetEntry(self.entry)

        if not self.entry%1000:
            print "  -> Entry {0}".format(self.entry)

        ## Initialize these in case stuff fails we can return empty values
        passedSelection     = False
        savedEventVariables = {'fatjets':   [],\
                               'rcjets':    [],\
                               'resjets':   [],\
                               'bjets':     [],\
                               'jets':      [],\
                               'lepton':    False,\
                               'nu':        False,\
                               'MET':       0,\
                               'HT':        0,\
                               'MC':        {},\
                               'eventinfo': {}}

        # ---------------- #
        # Physics Objects  #
        # ---------------- #
        self.initializeObjects()


        # ---------------- #
        # Cuts             #
        # ---------------- #
        ## Cutting on truth objects? DeltaR matching?
        if any('truth' in i for i in self.cuts):
            truth_objs = truthBase(self.t)
            for truth_obj in truth_objs.keys():
                self.objects[truth_obj] = truth_objs[truth_obj]

        ## -- cuts on objects
        c_objlevel = self.objectLevelCuts()  # function below
        if not c_objlevel['result']:
            return {'objects':savedEventVariables,'result':passedSelection}
        self.objects = c_objlevel['objects']  # update our dictionary of objects

        ## -- cuts on event-level quantities (HT, DeltaR(x,y), etc.)
        c_evtlevel = self.eventLevelCuts()   # function below
        if not c_evtlevel['result']:
            return {'objects':savedEventVariables,'result':passedSelection}
        self.objects = c_evtlevel['objects']

        ## -- record HT if it hasn't been saved or used
        if not self.objects.get('ht'):
            self.objects['ht'] = vlq.calcHT(self.objects)

        # ---------------- #
        # Event Info       #
        # ---------------- #
        signal_dsids = info.dsids()['signal']['TTS'].keys()
        ttbar_dsids  = info.dsids()['background']['ttbar'].keys()
        if self.t.mcChannelNumber in signal_dsids+ttbar_dsids:
            # setup the truth (after cuts and only for signal & ttbar)
            self.MC = truthBase(self.t)
        else:
            self.MC = {}

        boostedEvent   = (len(self.objects['fatjets'])>0)
        resolvedEvent  = (not boostedEvent)

        eventInfo = {'mcWeight':        self.t.weight_mc,\
                     'pileupWeight':    self.t.weight_pileup,\
                     'eventNumber':     self.t.eventNumber,\
                     'runNumber':       self.t.runNumber,\
                     'mcChannelNumber': self.t.mcChannelNumber,\
                     'mu':              self.t.mu,\
                     'weight_btag_track_70': self.t.weight_btag_track_70,\
                     'weight_btag_60':  self.t.weight_btag_60,\
                     'weight_btag_70':  self.t.weight_btag_70,\
                     'weight_btag_77':  self.t.weight_btag_77,\
                     'weight_btag_85':  self.t.weight_btag_85,\
                     'weight_lep_eff':  self.t.weight_lept_eff,\
                     'nAMI':            self.t.AMI,\
                     'isBoosted':       boostedEvent,\
                     'isResolved':      resolvedEvent,\
                     'mujets':          self.t.mujets,\
                     'ejets':           self.t.ejets,\
                     'nbtags':          self.t.btags_n,\
                     'KFactor':         self.t.KFactor,\
                     'XSection':        self.t.XSection,\
                     'vlq_tag':         self.t.vlq_evtype,\
                     'FilterEff':       self.t.FilterEff}

       # ------------------------------------------------------------- #
       # Log the results for inspection later                          #    
       # ------------------------------------------------------------- #
        if self.loggingLEVEL >= 20:
            self.logResults()

       # ------------------------------------------------------------- #
       # Return the results to miniSL.py                               #    
       # ------------------------------------------------------------- #
        passedSelection     = True
        savedEventVariables = {'fatjets':   self.objects['fatjets'],\
                               'rcjets':    self.objects['rcjets'],\
                               'resjets':   self.objects['resjets'],\
                               'lepton':    self.objects['lepton'],\
                               'nu':        self.objects['nu'],\
                               'jets':      self.objects['jets'],\
                               'tjets':     self.objects['tjets'],\
                               'met':       self.objects['met'],\
                               'HT':        self.objects['ht'],\
                               'MC':        self.MC,\
                               'eventinfo': eventInfo}

        ## Analysis-specific custom object :: need to remove this hard-coding...
        if self.objects.get('TTbar'):
            savedEventVariables['TTbar'] = self.objects['TTbar']
        else:
            savedEventVariables['TTbar'] = []


        return {'objects':savedEventVariables,'result':passedSelection}



#----------------------------------------------------------------------------------------#

    def initializeObjects(self):
        """
        One function to group other function calls to setup the physics objects.
        The truth information is called at the end of the event (to make sure
        that all of the cuts were passed, first.)

        Physics Objects (or 'Reconstructed Objets') in the analysis:
        - Lepton
        - MET (Neutrino)
        - small-radius jets
          :: light jets     (can be used to form 'resolved' W candidate)
          :: b-jets         (category for the two jets with highest mv2c20 weights)
        - large-radius jets
          :: nominal large-R jets
          :: re-clustered large-R jets (not the default)
        """
        lep     = self.build_lepton(self.t)    # setup the lepton
        met     = self.build_met(self.t)       # setup the MET
        nu      = self.build_nu(self.t)        # setup the neutrino
        jets    = self.build_jets(self.t)      # setup the jets
        tjets   = self.build_tjets(self.t)     # setup the track jets
        fatjets = self.build_ljets(self.t)     # setup the Fat Jets
        rcjets  = [] #rcBase(self.t)     # setup the re-clustered jets NOT THIS RELEASE
        resjets = [] #resBase(jets)      # setup the resolved jets     NOT ANYMORE

        num_btags = len([q for q in jets if q.mv2c20>self.btag_WP])

        jets.sort(   key=lambda x: x.Pt(), reverse=True) # [0] has the highest pT
        fatjets.sort(key=lambda x: x.Pt(), reverse=True)
        #rcjets.sort( key=lambda x: x.Pt(), reverse=True) # no RC jets in this production
        resjets.sort(key=lambda x: x.Pt(), reverse=True)
        tjets.sort(  key=lambda x: x.Pt(), reverse=True)

        self.objects = {'lepton': lep,\
                        'met':    met,\
                        'nu':     nu,\
                        'jets':   jets,\
                        'fatjets':fatjets,\
                        'rcjets': rcjets,\
                        'resjets':resjets,\
                        'tjets':  tjets,\
                        'nbtags': num_btags}

        self.objects['vlq_evtype'] = -1 if self.t.mcChannelNumber<=0 else self.t.vlq_evtype

        if self.build_custom_objects:
            self.custom_objects()
            # build TTbar

        return



#----------------------------------------------------------------------------------------#

    def objectLevelCuts(self):
        """
        Apply cuts to the physics objects in the event.
        Pass the dict of objects and dict of cuts to ObjectCuts.
        """
        obj_level_cuts    = self.object_level_cuts.applyCuts(self.objects)
        # object_level_cuts looks like: {'result':True/False,'objects':objects}
        # in case the objects were redefined (e.g., less fat jets after cuts)

        return obj_level_cuts



#----------------------------------------------------------------------------------------#

    def eventLevelCuts(self):
        """Apply cuts to the event-level quantities.
        Pass the dict of objects and dict of cuts to EventCuts.
        """
        evt_level_cuts   = self.event_level_cuts.applyCuts(self.objects)
        # evt_level_cuts looks like: return {'result':True/False,'objects':objects}
        # for things that were removed

        return evt_level_cuts



#----------------------------------------------------------------------------------------#

    def custom_objects(self):
        """
        Generate custom objects for the analysis.
        Assumes that the class you've written has the same name as the file, just
        capitalized, e.g., file: 'customObjectsBase.py' & class: 'CustomObjectsBase'.
        """
        cfg_new_objects = self.parser.get(self.cfg_name,'new_objects').split()
        obj_file = cfg_new_objects[0]
        if len(cfg_new_objects)>1:
            new_objects = cfg_new_objects[1]
            # new objects separated by commas
        else:
            new_objects = 'custom'

        obj_path,obj_filename = obj_file.split('/')
        obj_filename          = obj_filename.split('.')[0]
        obj_classname         = obj_filename[0].upper()+obj_filename[1:]

        # import the class that defines and makes your custom object(s)
        pyObjectsFile = importlib.import_module(obj_path+"."+obj_filename)
        pyObjects     = getattr(pyObjectsFile,obj_classname)

        for new_object in new_objects.split(','):
            if '(' in new_object:
                # the ttree name is different from the object's name
                new_object,ttree_object = config.parentheses(new_object)
            else:
                # the ttree name is the same as the object's name
                ttree_object = new_object

            newObjects            = pyObjects(new_object)
            newObjects.ttree_name = ttree_object

            self.objects = newObjects.getObject(event_objects=self.objects,ttree=self.t)
            # return the objects because we have added a new one, 
            # and may have modified others

        return



#----------------------------------------------------------------------------------------#

    def PrintCutflow(self):
        """Print the cutflow."""
        return



#----------------------------------------------------------------------------------------#

    def logResults(self):

        logging.info(" ------------------- \n")
        logging.info(" ++ Event {0} Summary ++ \n".format(self.entry))


        objects_keys = self.objects.keys()

        if self.objects.get('fatjets'):
            for Wcand in self.objects['fatjets']:
                logging.info("\n     BOOSTED ")
                logging.info("     - Hadronic W  : pT  = {0}".format(Wcand.Pt()))
                logging.info("                   : M   = {0}".format(Wcand.M()))
                logging.info("                   : eta = {0}".format(Wcand.Eta()))
                logging.info("                   : phi = {0}".format(Wcand.Phi()))

        if self.objects.get('resjets'):
            for rWcand in self.objects['resjets']:
                logging.info("\n     RESOLVED ")
                logging.info("     - Hadronic W  : pT  = {0}".format(rWcand.Pt()))
                logging.info("                   : M   = {0}".format(rWcand.M()))
                logging.info("                   : eta = {0}".format(rWcand.Eta()))
                logging.info("                   : phi = {0}".format(rWcand.Phi()))

        if self.objects.get('rcjets'):
            for rcjet in self.objects['rcjets']:
                logging.info("     - Re-clustered Jet W {0}: pT  = {1}".format(1,rcjet.Pt()))
                logging.info("                   : M   = {0}".format(rcjet.M()))
                logging.info("                   : eta = {0}".format(rcjet.Eta()))
                logging.info("                   : phi = {0}".format(rcjet.Phi()))

        if self.objects.get('bjets'):
            for i,bjet in enumerate(self.objects['bjets']):
				logging.info("     - b-jet {0}     : pT  = {1}".format(i+1,bjet.Pt()))
				logging.info("                   : M   = {0}".format(bjet.M()))
				logging.info("                   : eta = {0}".format(bjet.Eta()))
				logging.info("                   : phi = {0}".format(bjet.Phi()))
				logging.info("                   : Mv2c20 = {0}".format(bjet.mv2c20))

        if self.objects.get('lepton'):
            logging.info("     - Lepton      : pT   = {0}".format(self.objects['lepton'].Pt()))
            logging.info("                   : E    = {0}".format(self.objects['lepton'].E()))
            logging.info("                   : eta  = {0}".format(self.objects['lepton'].Eta()))
            logging.info("                   : phi  = {0}\n".format(self.objects['lepton'].Phi()))

        if self.objects.get('nu'):
            logging.info("     - Neutrino    : phi = {0}".format(self.objects['nu'].Phi()))
            logging.info("                   : eta = {0}".format(self.objects['nu'].Eta()))
            logging.info("                   : pT  = {0}".format(self.objects['nu'].Pt()))
            logging.info("                   : E   = {0}\n".format(self.objects['nu'].E()))

        if self.objects.get('met'):
            logging.info("     - MET         : met = {0}".format(self.objects['met'].met))
            logging.info("                   : phi = {0}".format(self.objects['met'].phi))
            logging.info("                   : mtw = {0}\n".format(self.objects['met'].mtw))

        if self.objects.get('ht'):
            logging.info("     - HT          : HT  = {0}\n".format(self.objects['ht']))

        try:
            logging.info("     - Event Info  : mcWeight        = {0}".format(self.t.weight_mc))
            logging.info("                   : pileupWeight    = {0}".format(self.t.weight_pileup))
            logging.info("                   : AMI             = {0}\n".format(self.t.AMI))
        except AttributeError:
            logging.info("     - Event Info  : mcWeight        = 1.0")
            logging.info("                   : pileupWeight    = 1.0")
            logging.info("                   : AMI             = Not readily available\n")
        logging.info("                   : eventNumber     = {0}".format(self.t.eventNumber))
        logging.info("                   : runNumber       = {0}".format(self.t.runNumber))
        logging.info("                   : mcChannelNumber = {0}".format(self.t.mcChannelNumber))
        logging.info("                   : mu              = {0}".format(self.t.mu))

        return