Пример #1
0
def makePileupAnalysisSequence(dataType,
                               userPileupConfigs=[],
                               userLumicalcFiles=[],
                               autoConfig=False):
    """Create a PRW analysis algorithm sequence

    Keyword arguments:
      dataType -- The data type to run on ("data", "mc" or "afii")
    """

    if dataType not in ["data", "mc", "afii"]:
        raise ValueError("invalid data type: " + dataType)

    # Create the analysis algorithm sequence object:
    seq = AnaAlgSequence("PileupAnalysisSequence")

    muMcFiles = userPileupConfigs[:]
    if autoConfig:
        from PileupReweighting.AutoconfigurePRW import getLumiCalcFiles, getMCMuFiles
        userLumicalcFiles = getLumiCalcFiles()
        if len(muMcFiles) == 0:
            muMcFiles = getMCMuFiles()
        else:
            from AthenaCommon import Logging
            prwlog = Logging.logging.getLogger('makePileupAnalysisSequence')
            prwlog.warning('Sent autoconfig and userPileupConfigs=' +
                           str(userPileupConfigs))
            prwlog.warning(
                'Ignoring autoconfig and keeping user-specified files')

    if userLumicalcFiles == []:
        muDataFiles = [
            "GoodRunsLists/data15_13TeV/20170619/PHYS_StandardGRL_All_Good_25ns_276262-284484_OflLumi-13TeV-008.root",
            "GoodRunsLists/data16_13TeV/20180129/PHYS_StandardGRL_All_Good_25ns_297730-311481_OflLumi-13TeV-009.root",
            "GoodRunsLists/data17_13TeV/20180619/physics_25ns_Triggerno17e33prim.lumicalc.OflLumi-13TeV-010.root",
            "GoodRunsLists/data18_13TeV/20190708/ilumicalc_histograms_None_348885-364292_OflLumi-13TeV-010.root"
        ]
    else:
        muDataFiles = userLumicalcFiles[:]

    # Set up the only algorithm of the sequence:
    alg = createAlgorithm('CP::PileupReweightingAlg', 'PileupReweightingAlg')
    addPrivateTool(alg, 'pileupReweightingTool', 'CP::PileupReweightingTool')
    alg.pileupReweightingTool.ConfigFiles = muMcFiles
    alg.pileupReweightingTool.LumiCalcFiles = muDataFiles

    seq.append(alg,
               inputPropName='eventInfo',
               outputPropName='eventInfoOut',
               affectingSystematics='(^PRW_.*)')

    # Return the sequence:
    return seq
Пример #2
0
def makeTriggerAnalysisSequence(dataType,
                                triggerChains=[],
                                prescaleLumiCalcFiles=[]):
    """Create a basic trigger analysis algorithm sequence

    Keyword arguments:
      dataType -- The data type to run on ("data", "mc" or "afii")
      triggerChains -- a list of trigger chains
      prescaleLumiCalcFiles -- a list of lumicalc files to calculate trigger prescales
    """

    if dataType not in ["data", "mc", "afii"]:
        raise ValueError("invalid data type: " + dataType)

    # Create the analysis algorithm sequence object:
    seq = AnaAlgSequence("TriggerAnalysisSequence")

    # Create public trigger tools
    xAODConfTool = createPublicTool('TrigConf::xAODConfigTool',
                                    'xAODConfigTool')
    decisionTool = createPublicTool('Trig::TrigDecisionTool',
                                    'TrigDecisionTool')
    decisionTool.ConfigTool = '%s/%s' % \
        ( xAODConfTool.getType(), xAODConfTool.getName() )

    seq.addPublicTool(xAODConfTool)
    seq.addPublicTool(decisionTool)

    if triggerChains:
        # Set up the trigger selection:
        alg = createAlgorithm('CP::TrigEventSelectionAlg',
                              'TrigEventSelectorAlg')
        alg.tool = '%s/%s' % \
            ( decisionTool.getType(), decisionTool.getName() )
        alg.triggers = list(triggerChains)
        alg.selectionDecoration = 'trigPassed'

        seq.append(alg, inputPropName=None)

        # Calculate trigger prescales
        if dataType == 'data' and prescaleLumiCalcFiles:
            alg = createAlgorithm('CP::TrigPrescalesAlg', 'TrigPrescalesAlg')
            addPrivateTool(alg, 'pileupReweightingTool',
                           'CP::PileupReweightingTool')
            alg.pileupReweightingTool.LumiCalcFiles = prescaleLumiCalcFiles
            alg.pileupReweightingTool.TrigDecisionTool = '%s/%s' % \
                ( decisionTool.getType(), decisionTool.getName() )
            alg.triggers = [
                lumicalc.split(':')[-1] for lumicalc in prescaleLumiCalcFiles
                if ':' in lumicalc
            ]
            alg.triggersAll = list(triggerChains)
            alg.prescaleDecoration = 'prescale'

            seq.append(alg, inputPropName=None)

    # Return the sequence:
    return seq
Пример #3
0
def makeEventSelectionAnalysisSequence(dataType,
                                       runPrimaryVertexSelection=True,
                                       runEventCleaning=False,
                                       userGRLFiles=[]):
    """Create a basic event selection analysis algorithm sequence

    Keyword arguments:
      dataType -- The data type to run on ("data", "mc" or "afii")
      runPrimaryVertexSelection -- whether to run primary vertex selection
      runEventCleaning -- wether to run event cleaning
      userGRLFiles -- a list of GRL files to select data from
    """

    if dataType not in ["data", "mc", "afii"]:
        raise ValueError("invalid data type: " + dataType)

    # Create the analysis algorithm sequence object:
    seq = AnaAlgSequence("EventSelectionAnalysisSequence")

    if dataType == 'data':
        grlFiles = userGRLFiles[:]

        # Set up the GRL selection:
        alg = createAlgorithm('GRLSelectorAlg', 'GRLSelectorAlg')
        addPrivateTool(alg, 'Tool', 'GoodRunsListSelectionTool')
        alg.Tool.GoodRunsListVec = grlFiles

        seq.append(alg, inputPropName=None)

    # Skip events with no primary vertex:
    if runPrimaryVertexSelection:
        alg = createAlgorithm('CP::VertexSelectionAlg',
                              'PrimaryVertexSelectorAlg')
        alg.VertexContainer = 'PrimaryVertices'
        alg.MinVertices = 1

        seq.append(alg, inputPropName=None)

    # Set up the event cleaning selection:
    if runEventCleaning:
        alg = createAlgorithm('CP::EventFlagSelectionAlg',
                              'EventFlagSelectorAlg')
        alg.selectionFlags = ['DFCommonJets_eventClean_LooseBad,as_char']

        seq.append(alg, inputPropName=None)

    # Return the sequence:
    return seq
Пример #4
0
def makeGeneratorAnalysisSequence(dataType,
                                  saveCutBookkeepers=False,
                                  runNumber=0,
                                  cutBookkeepersSystematics=False):
    """Create a generator analysis algorithm sequence

    Keyword arguments:
      dataType -- The data type to run on ("mc" or "afii")
      saveCutBookkeepers -- save cut bokkeepers information into output file
      runNumber -- MC run number
      cutBookkeepersSystematics -- store CutBookkeepers systematics
    """

    if dataType not in ["mc", "afii"]:
        raise ValueError("invalid data type: " + dataType)

    if saveCutBookkeepers and not runNumber:
        raise ValueError("invalid run number: " + 0)

    # Create the analysis algorithm sequence object:
    seq = AnaAlgSequence("GeneratorAnalysisSequence")

    # Set up the CutBookkeepers algorithm:
    if saveCutBookkeepers:
        alg = createAlgorithm('CP::AsgCutBookkeeperAlg', 'CutBookkeeperAlg')
        alg.runNumber = runNumber
        alg.enableSystematics = cutBookkeepersSystematics
        addPrivateTool(alg, 'truthWeightTool', 'PMGTools::PMGTruthWeightTool')
        seq.append(alg, inputPropName=None)

    # Set up the weights algorithm:
    alg = createAlgorithm('CP::PMGTruthWeightAlg', 'PMGTruthWeightAlg')
    addPrivateTool(alg, 'truthWeightTool', 'PMGTools::PMGTruthWeightTool')
    alg.decoration = 'generatorWeight_%SYS%'
    alg.decorationRegex = '(^GEN_.*)'

    seq.append(alg,
               inputPropName='eventInfo',
               affectingSystematics='(^GEN_.*)')

    # Return the sequence:
    return seq
Пример #5
0
def makeElectronAnalysisSequence(dataType,
                                 workingPoint,
                                 deepCopyOutput=False,
                                 shallowViewOutput=True,
                                 postfix='',
                                 recomputeLikelihood=False,
                                 chargeIDSelection=False,
                                 isolationCorrection=False,
                                 crackVeto=False,
                                 ptSelectionOutput=False,
                                 enableCutflow=False,
                                 enableKinematicHistograms=False):
    """Create an electron analysis algorithm sequence

    Keyword arguments:
      dataType -- The data type to run on ("data", "mc" or "afii")
      workingPoint -- The working point to use
      deepCopyOutput -- If set to 'True', the output containers will be
                        standalone, deep copies (slower, but needed for xAOD
                        output writing)
      shallowViewOutput -- Create a view container if required
      postfix -- a postfix to apply to decorations and algorithm
                 names.  this is mostly used/needed when using this
                 sequence with multiple working points to ensure all
                 names are unique.
      recomputeLikelihood -- Whether to rerun the LH. If not, use derivation flags
      chargeIDSelection -- Whether or not to perform charge ID/flip selection
      isolationCorrection -- Whether or not to perform isolation correction
      crackVeto -- Whether or not to perform eta crack veto
      ptSelectionOutput -- Whether or not to apply pt selection when creating
                           output containers.
      enableCutflow -- Whether or not to dump the cutflow
      enableKinematicHistograms -- Whether or not to dump the kinematic histograms
    """

    # Make sure we received a valid data type.
    if dataType not in ['data', 'mc', 'afii']:
        raise ValueError('Invalid data type: %' % dataType)

    if postfix != '':
        postfix = '_' + postfix
        pass

    # Make sure selection options make sense
    if deepCopyOutput and shallowViewOutput:
        raise ValueError(
            "deepCopyOutput and shallowViewOutput can't both be true!")

    splitWP = workingPoint.split('.')
    if len(splitWP) != 2:
        raise ValueError(
            'working point should be of format "likelihood.isolation", not ' +
            workingPoint)

    likelihoodWP = splitWP[0]
    isolationWP = splitWP[1]

    # Create the analysis algorithm sequence object:
    seq = AnaAlgSequence("ElectronAnalysisSequence" + postfix)

    # Variables keeping track of the selections being applied.
    selectionDecorNames = []
    selectionDecorCount = []

    # Set up the eta-cut on all electrons prior to everything else
    alg = createAlgorithm('CP::AsgSelectionAlg', 'ElectronEtaCutAlg' + postfix)
    alg.preselection = "&&".join(selectionDecorNames)
    alg.selectionDecoration = 'selectEta' + postfix + ',as_bits'
    addPrivateTool(alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool')
    alg.selectionTool.maxEta = 2.47
    if crackVeto:
        alg.selectionTool.etaGapLow = 1.37
        alg.selectionTool.etaGapHigh = 1.52
    alg.selectionTool.useClusterEta = True
    seq.append(alg,
               inputPropName='particles',
               outputPropName='particlesOut',
               stageName='calibration')
    selectionDecorNames.append(alg.selectionDecoration)
    if crackVeto:
        selectionDecorCount.append(5)
    else:
        selectionDecorCount.append(4)

    # Set up the track selection algorithm:
    alg = createAlgorithm('CP::AsgLeptonTrackSelectionAlg',
                          'ElectronTrackSelectionAlg' + postfix)
    alg.preselection = "&&".join(selectionDecorNames)
    alg.selectionDecoration = 'trackSelection' + postfix + ',as_bits'
    alg.maxD0Significance = 5
    alg.maxDeltaZ0SinTheta = 0.5
    seq.append(alg, inputPropName='particles', stageName='selection')
    selectionDecorNames.append(alg.selectionDecoration)
    selectionDecorCount.append(3)

    # Set up the likelihood ID selection algorithm
    # It is safe to do this before calibration, as the cluster E is used
    alg = createAlgorithm('CP::AsgSelectionAlg',
                          'ElectronLikelihoodAlg' + postfix)
    alg.preselection = "&&".join(selectionDecorNames)
    alg.selectionDecoration = 'selectLikelihood' + postfix + ',as_bits'
    selectionDecorNames.append(alg.selectionDecoration)
    if recomputeLikelihood:
        # Rerun the likelihood ID
        addPrivateTool(alg, 'selectionTool', 'AsgElectronLikelihoodTool')
        alg.selectionTool.primaryVertexContainer = 'PrimaryVertices'
        alg.selectionTool.WorkingPoint = likelihoodWP
        selectionDecorCount.append(7)
    else:
        # Select from Derivation Framework flags
        addPrivateTool(alg, 'selectionTool', 'CP::AsgFlagSelectionTool')
        dfFlag = "DFCommonElectronsLH" + likelihoodWP.split('LH')[0]
        alg.selectionTool.selectionFlags = [dfFlag]
        selectionDecorCount.append(1)
    seq.append(alg, inputPropName='particles', stageName='selection')

    # Select electrons only with good object quality.
    alg = createAlgorithm('CP::AsgSelectionAlg',
                          'ElectronObjectQualityAlg' + postfix)
    alg.preselection = "&&".join(selectionDecorNames)
    alg.selectionDecoration = 'goodOQ' + postfix + ',as_bits'
    addPrivateTool(alg, 'selectionTool', 'CP::EgammaIsGoodOQSelectionTool')
    alg.selectionTool.Mask = xAOD.EgammaParameters.BADCLUSELECTRON
    seq.append(alg, inputPropName='particles', stageName='calibration')
    selectionDecorNames.append(alg.selectionDecoration)
    selectionDecorCount.append(1)

    # Set up the calibration and smearing algorithm:
    alg = createAlgorithm('CP::EgammaCalibrationAndSmearingAlg',
                          'ElectronCalibrationAndSmearingAlg' + postfix)
    alg.preselection = "&&".join(selectionDecorNames)
    addPrivateTool(alg, 'calibrationAndSmearingTool',
                   'CP::EgammaCalibrationAndSmearingTool')
    alg.calibrationAndSmearingTool.ESModel = 'es2018_R21_v0'
    alg.calibrationAndSmearingTool.decorrelationModel = '1NP_v1'
    if dataType == 'afii':
        alg.calibrationAndSmearingTool.useAFII = 1
    else:
        alg.calibrationAndSmearingTool.useAFII = 0
        pass
    seq.append(alg,
               inputPropName='egammas',
               outputPropName='egammasOut',
               affectingSystematics='(^EG_RESOLUTION_.*)|(^EG_SCALE_.*)',
               stageName='calibration')

    # Set up the the pt selection
    ptSelectionDecoration = 'selectPt' + postfix + ',as_bits'
    alg = createAlgorithm('CP::AsgSelectionAlg', 'ElectronPtCutAlg' + postfix)
    alg.preselection = "&&".join(selectionDecorNames)
    alg.selectionDecoration = ptSelectionDecoration
    addPrivateTool(alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool')
    alg.selectionTool.minPt = 4.5e3
    seq.append(alg, inputPropName='particles', stageName='selection')
    selectionDecorNames.append(alg.selectionDecoration)
    selectionDecorCount.append(2)

    # Set up the isolation correction algorithm:
    if isolationCorrection:
        alg = createAlgorithm('CP::EgammaIsolationCorrectionAlg',
                              'ElectronIsolationCorrectionAlg' + postfix)
        alg.preselection = "&&".join(selectionDecorNames)
        addPrivateTool(alg, 'isolationCorrectionTool',
                       'CP::IsolationCorrectionTool')
        if dataType == 'data':
            alg.isolationCorrectionTool.IsMC = 0
        else:
            alg.isolationCorrectionTool.IsMC = 1
            pass
        seq.append(alg,
                   inputPropName='egammas',
                   outputPropName='egammasOut',
                   stageName='calibration')

    # Set up the isolation selection algorithm:
    if isolationWP != 'NonIso':
        alg = createAlgorithm('CP::EgammaIsolationSelectionAlg',
                              'ElectronIsolationSelectionAlg' + postfix)
        alg.preselection = "&&".join(selectionDecorNames)
        alg.selectionDecoration = 'isolated' + postfix + ',as_bits'
        addPrivateTool(alg, 'selectionTool', 'CP::IsolationSelectionTool')
        alg.selectionTool.ElectronWP = isolationWP
        seq.append(alg, inputPropName='egammas', stageName='selection')
        selectionDecorNames.append(alg.selectionDecoration)
        selectionDecorCount.append(1)

    # Select electrons only if they don't appear to have flipped their charge.
    if chargeIDSelection:
        alg = createAlgorithm('CP::AsgSelectionAlg',
                              'ElectronChargeIDSelectionAlg' + postfix)
        alg.preselection = "&&".join(selectionDecorNames)
        alg.selectionDecoration = 'chargeID' + postfix + ',as_bits'
        addPrivateTool(alg, 'selectionTool', 'AsgElectronChargeIDSelectorTool')
        alg.selectionTool.TrainingFile = \
          'ElectronPhotonSelectorTools/ChargeID/ECIDS_20180731rel21Summer2018.root'
        alg.selectionTool.WorkingPoint = 'Loose'
        alg.selectionTool.CutOnBDT = -0.337671  # Loose 97%
        seq.append(alg, inputPropName='particles', stageName='selection')
        selectionDecorNames.append(alg.selectionDecoration)
        selectionDecorCount.append(1)
        pass

    # Set up an algorithm used for decorating baseline electron selection:
    alg = createAlgorithm('CP::AsgSelectionAlg',
                          'ElectronSelectionSummary' + postfix)
    addPrivateTool(alg, 'selectionTool', 'CP::AsgFlagSelectionTool')
    alg.selectionTool.selectionFlags = selectionDecorNames[:]
    alg.selectionDecoration = 'baselineSelection' + postfix + ',as_char'
    seq.append(alg, inputPropName='particles', stageName='selection')

    # Set up an algorithm used to create electron selection cutflow:
    if enableCutflow:
        alg = createAlgorithm('CP::ObjectCutFlowHistAlg',
                              'ElectronCutFlowDumperAlg' + postfix)
        alg.histPattern = 'electron_cflow_%SYS%' + postfix
        alg.selection = selectionDecorNames[:]
        alg.selectionNCuts = selectionDecorCount[:]
        seq.append(alg, inputPropName='input', stageName='selection')

    # Set up an algorithm dumping the kinematic properties of the electrons:
    if enableKinematicHistograms:
        alg = createAlgorithm('CP::KinematicHistAlg',
                              'ElectronKinematicDumperAlg' + postfix)
        alg.preselection = "&&".join(selectionDecorNames)
        alg.histPattern = 'electron_%VAR%_%SYS%' + postfix
        seq.append(alg, inputPropName='input', stageName='selection')

    # Set up the output selection
    if shallowViewOutput or deepCopyOutput:
        selectionDecorNamesOutput = selectionDecorNames[:]
        if not ptSelectionOutput:
            selectionDecorNamesOutput.remove(ptSelectionDecoration)

    # Set up an algorithm that makes a view container using the selections
    # performed previously:
    if shallowViewOutput:
        alg = createAlgorithm('CP::AsgViewFromSelectionAlg',
                              'ElectronViewFromSelectionAlg' + postfix)
        alg.selection = selectionDecorNamesOutput[:]
        seq.append(alg,
                   inputPropName='input',
                   outputPropName='output',
                   stageName='selection')
        pass

    # Set up the electron efficiency correction algorithm:
    alg = createAlgorithm('CP::ElectronEfficiencyCorrectionAlg',
                          'ElectronEfficiencyCorrectionAlg' + postfix)
    alg.preselection = "&&".join(selectionDecorNames)
    addPrivateTool(alg, 'efficiencyCorrectionTool',
                   'AsgElectronEfficiencyCorrectionTool')
    alg.scaleFactorDecoration = 'effSF' + postfix + '_%SYS%'
    alg.scaleFactorDecorationRegex = '(^EL_EFF_Reco.*)'
    alg.efficiencyCorrectionTool.RecoKey = "Reconstruction"
    alg.efficiencyCorrectionTool.CorrelationModel = "TOTAL"
    if dataType == 'afii':
        alg.efficiencyCorrectionTool.ForceDataType = \
          ROOT.PATCore.ParticleDataType.Fast
    elif dataType == 'mc':
        alg.efficiencyCorrectionTool.ForceDataType = \
          ROOT.PATCore.ParticleDataType.Full
        pass
    alg.outOfValidity = 2  #silent
    alg.outOfValidityDeco = 'bad_eff' + postfix
    if dataType != 'data':
        seq.append(alg,
                   inputPropName='electrons',
                   affectingSystematics='(^EL_EFF_Reco.*)',
                   stageName='efficiency')
        pass

    # Set up a final deep copy making algorithm if requested:
    if deepCopyOutput:
        alg = createAlgorithm('CP::AsgViewFromSelectionAlg',
                              'ElectronDeepCopyMaker' + postfix)
        alg.selection = selectionDecorNamesOutput[:]
        alg.deepCopy = True
        seq.append(alg,
                   inputPropName='input',
                   outputPropName='output',
                   stageName='selection')
        pass

    # Return the sequence:
    return seq
Пример #6
0
def makeJetAnalysisSequence(dataType,
                            jetCollection,
                            postfix='',
                            deepCopyOutput=False,
                            shallowViewOutput=True,
                            runGhostMuonAssociation=True,
                            enableCutflow=False,
                            enableKinematicHistograms=False,
                            **kwargs):
    """Create a jet analysis algorithm sequence
      The jet collection is interpreted and selects the correct function to call, 
      makeSmallRJetAnalysisSequence, makeRScanJetAnalysisSequence or 
      makeLargeRJetAnalysisSequence

      Keyword arguments
        dataType -- The data type to run on ("data", "mc" or "afii")
        jetCollection -- The jet container to run on.
        postfix -- String to be added to the end of all public names.
        deepCopyOutput -- Whether or not to deep copy the output
        shallowViewOutput -- Whether or not to output a shallow view as the output
        enableCutflow -- Whether or not to dump the cutflow
        enableKinematicHistograms -- Whether or not to dump the kinematic histograms
        Other keyword arguments are forwarded to the other functions.
    """
    if dataType not in ["data", "mc", "afii"]:
        raise ValueError("invalid data type: " + dataType)

    # Setup the postfix
    if postfix != '':
        postfix = "_" + postfix

    # Make sure selection options make sense
    if deepCopyOutput and shallowViewOutput:
        raise ValueError(
            "deepCopyOutput and shallowViewOutput can't both be true!")

    # Remove b-tagging calibration from the container name
    btIndex = jetCollection.find('_BTagging')
    if btIndex != -1:
        jetCollection = jetCollection[:btIndex]

    # interpret the jet collection
    collection_pattern = re.compile(
        r"AntiKt(\d+)(EMTopo|EMPFlow|LCTopo|TrackCaloCluster)(TrimmedPtFrac5SmallR20)?Jets"
    )
    match = collection_pattern.match(jetCollection)
    if not match:
        raise ValueError(
            "Jet collection {0} does not match expected pattern!".format(
                jetCollection))
    radius = int(match.group(1))
    if radius not in [2, 4, 6, 10]:
        raise ValueError(
            "Jet collection has an unsupported radius '{0}'!".format(radius))
    jetInput = match.group(2)

    # Create the analysis algorithm sequence object.
    seq = AnaAlgSequence("JetAnalysisSequence" + postfix)
    # Relink original jets in case of b-tagging calibration
    if btIndex != -1:
        alg = createAlgorithm('CP::AsgOriginalObjectLinkAlg',
                              'JetOriginalObjectLinkAlg' + postfix)
        alg.baseContainerName = jetCollection
        seq.append(alg,
                   inputPropName='particles',
                   outputPropName='particlesOut',
                   stageName='calibration')

    # Set up the jet ghost muon association algorithm:
    if runGhostMuonAssociation:
        alg = createAlgorithm('CP::JetGhostMuonAssociationAlg',
                              'JetGhostMuonAssociationAlg' + postfix)
        seq.append(alg,
                   inputPropName='jets',
                   outputPropName='jetsOut',
                   stageName='calibration')

    # record all the selections each subfunction makes
    cutlist = []
    cutlength = []

    if radius == 4:
        makeSmallRJetAnalysisSequence(seq,
                                      cutlist,
                                      cutlength,
                                      dataType,
                                      jetCollection,
                                      jetInput=jetInput,
                                      postfix=postfix,
                                      **kwargs)
    elif radius in [2, 6]:
        makeRScanJetAnalysisSequence(seq,
                                     cutlist,
                                     cutlength,
                                     dataType,
                                     jetCollection,
                                     jetInput=jetInput,
                                     radius=radius,
                                     postfix=postfix,
                                     **kwargs)
    else:
        trim = match.group(3)
        if trim == "":
            raise ValueError("Untrimmed large-R jets are not supported!")
        makeLargeRJetAnalysisSequence(seq,
                                      cutlist,
                                      cutlength,
                                      dataType,
                                      jetCollection,
                                      jetInput=jetInput,
                                      postfix=postfix,
                                      **kwargs)

    # Set up an algorithm used to create jet selection cutflow:
    if enableCutflow:
        alg = createAlgorithm('CP::ObjectCutFlowHistAlg',
                              'JetCutFlowDumperAlg' + postfix)
        alg.histPattern = 'jet_cflow_%SYS%' + postfix
        alg.selection = cutlist
        alg.selectionNCuts = cutlength
        seq.append(alg, inputPropName='input', stageName='selection')

    # Set up an algorithm dumping the kinematic properties of the jets:
    if enableKinematicHistograms:
        alg = createAlgorithm('CP::KinematicHistAlg',
                              'JetKinematicDumperAlg' + postfix)
        alg.preselection = "&&".join(cutlist)
        alg.histPattern = 'jet_%VAR%_%SYS%' + postfix
        seq.append(alg, inputPropName='input', stageName='selection')

    if shallowViewOutput:
        # Set up an algorithm that makes a view container using the selections
        # performed previously:
        alg = createAlgorithm('CP::AsgViewFromSelectionAlg',
                              'JetViewFromSelectionAlg' + postfix)
        alg.selection = cutlist
        seq.append(alg,
                   inputPropName='input',
                   outputPropName='output',
                   stageName='selection')

    # Set up a final deep copy making algorithm if requested:
    if deepCopyOutput:
        alg = createAlgorithm('CP::AsgViewFromSelectionAlg',
                              'JetDeepCopyMaker' + postfix)
        alg.deepCopy = True
        seq.append(alg,
                   inputPropName='input',
                   outputPropName='output',
                   stageName='selection')

    return seq
Пример #7
0
def makeMetAnalysisSequence(dataType,
                            metSuffix,
                            postfix='',
                            useFJVT=True,
                            treatPUJets=True):
    """Create a met analysis algorithm sequence

    After creating the sequence object, it needs to be configured with a call
    like:

       metSequence.configure( inputName = {
                                 'jets'      : 'AntiKt4EMPFlowJets_%SYS%',
                                 'electrons' : 'AnalysisElectrons_%SYS%',
                                 'photons'   : 'AnalysisPhotons_%SYS%',
                                 'muons'     : 'AnalysisMuons_%SYS%',
                                 'taus'      : 'AnalysisTaus_%STS%',
                              },
                              outputName = 'AnalysisMET_%SYS%',
                              affectingSystematics = {
                                 'jets'      : '(^$)|(^JET_.*)',
                                 'electrons' : '(^$)|(^EG_.*)|(^EL_.*)',
                                 'photons'   : '(^$)|(^EG_.*)|(^PH_.*)',
                                 'muons'     : '(^$)|(^MUON_.*)',
                                 'taus'      : '(^$)|(^TAUS_.*)',
                              } )

    Note that defining a jet container is mandatory, but all other input
    containers are optional.

    Keyword arguments:
      dataType -- The data type to run on ("data", "mc" or "afii")
      metSuffix -- Suffix for the (core) MET objects to use from the input
                   (file)
      useFJVT -- Use FJVT decision for the calculation
      treatPUJets -- Treat pile-up jets in the MET significance calculation
    """

    if dataType not in ["data", "mc", "afii"]:
        raise ValueError("invalid data type: " + dataType)

    if not useFJVT and treatPUJets:
        raise ValueError("MET significance pile-up treatment requires fJVT")

    # Remove b-tagging calibration from the MET suffix name
    btIndex = metSuffix.find('_BTagging')
    if btIndex != -1:
        metSuffix = metSuffix[:btIndex]

    # Create the analysis algorithm sequence object:
    seq = AnaAlgSequence("MetAnalysisSequence" + postfix)

    # Set up the met maker algorithm:
    alg = createAlgorithm('CP::MetMakerAlg', 'MetMakerAlg' + postfix)
    addPrivateTool(alg, 'makerTool', 'met::METMaker')
    alg.makerTool.DoPFlow = 'PFlow' in metSuffix
    if useFJVT:
        alg.makerTool.JetRejectionDec = 'passFJVT'
    alg.metCore = 'MET_Core_' + metSuffix
    alg.metAssociation = 'METAssoc_' + metSuffix
    seq.append(alg,
               inputPropName={
                   'jets': 'jets',
                   'electrons': 'electrons',
                   'photons': 'photons',
                   'muons': 'muons',
                   'taus': 'taus',
                   'invisible': 'invisible'
               },
               outputPropName='met',
               affectingSystematics='(^MET_.*)')

    if dataType != "data":
        alg = createAlgorithm('CP::MetSystematicsAlg',
                              'MetSystematicsAlg' + postfix)
        addPrivateTool(alg, 'systematicsTool', 'met::METSystematicsTool')
        seq.append(alg, inputPropName='met', affectingSystematics='(^MET_.*)')
        pass

    # Set up the met builder algorithm:
    alg = createAlgorithm('CP::MetBuilderAlg', 'MetBuilderAlg' + postfix)
    seq.append(alg, inputPropName='met')

    # Set up the met significance algorithm:
    alg = createAlgorithm('CP::MetSignificanceAlg',
                          'MetSignificanceAlg' + postfix)
    addPrivateTool(alg, 'significanceTool', 'met::METSignificance')
    alg.significanceTool.SoftTermParam = 0
    alg.significanceTool.TreatPUJets = treatPUJets
    alg.significanceTool.IsAFII = dataType == "afii"
    seq.append(alg, inputPropName='met')

    # Return the sequence:
    return seq
Пример #8
0
def makePhotonAnalysisSequence(dataType,
                               workingPoint,
                               deepCopyOutput=False,
                               postfix='',
                               recomputeIsEM=False,
                               enableCutflow=False,
                               enableKinematicHistograms=False):
    """Create a photon analysis algorithm sequence

    Keywrod arguments:
      dataType -- The data type to run on ("data", "mc" or "afii")
      workingPoint -- The working point to use
      deepCopyOutput -- If set to 'True', the output containers will be
                        standalone, deep copies (slower, but needed for xAOD
                        output writing)
      postfix -- a postfix to apply to decorations and algorithm
                 names.  this is mostly used/needed when using this
                 sequence with multiple working points to ensure all
                 names are unique.
      recomputeIsEM -- Whether to rerun the cut-based selection. If not, use derivation flags
      enableCutflow -- Whether or not to dump the cutflow
      enableKinematicHistograms -- Whether or not to dump the kinematic histograms
    """

    # Make sure we received a valid data type.
    if dataType not in ['data', 'mc', 'afii']:
        raise ValueError('Invalid data type: %' % dataType)

    if postfix != '':
        postfix = '_' + postfix
        pass

    splitWP = workingPoint.split('.')
    if len(splitWP) != 2:
        raise ValueError(
            'working point should be of format "quality.isolation", not ' +
            workingPoint)

    qualityWP = splitWP[0]
    isolationWP = splitWP[1]

    if qualityWP == 'Tight':
        quality = ROOT.egammaPID.PhotonTight
        pass
    elif qualityWP == 'Loose':
        quality = ROOT.egammaPID.PhotonLoose
        pass
    else:
        raise Exception('unknown photon quality working point "' + qualityWP +
                        '" should be Tight or Loose')

    # Create the analysis algorithm sequence object:
    seq = AnaAlgSequence("PhotonAnalysisSequence" + postfix)

    # Variables keeping track of the selections being applied.
    selectionDecorNames = []
    selectionDecorCount = []

    # Set up the photon selection algorithm:
    alg = createAlgorithm('CP::AsgSelectionAlg',
                          'PhotonIsEMSelectorAlg' + postfix)
    alg.selectionDecoration = 'selectEM'
    selectionDecorNames.append(alg.selectionDecoration)
    if recomputeIsEM:
        # Rerun the cut-based ID
        addPrivateTool(alg, 'selectionTool', 'AsgPhotonIsEMSelector')
        alg.selectionTool.isEMMask = quality
        alg.selectionTool.ConfigFile = \
          'ElectronPhotonSelectorTools/offline/20180116/PhotonIsEMTightSelectorCutDefs.conf'
        selectionDecorCount.append(32)
    else:
        # Select from Derivation Framework flags
        addPrivateTool(alg, 'selectionTool', 'CP::AsgFlagSelectionTool')
        dfFlag = 'DFCommonPhotonsIsEM' + qualityWP
        alg.selectionTool.selectionFlags = [dfFlag]
        selectionDecorCount.append(1)
        pass
    seq.append(alg,
               inputPropName='particles',
               outputPropName='particlesOut',
               stageName='calibration')

    # Select electrons only with good object quality.
    alg = createAlgorithm('CP::AsgSelectionAlg',
                          'PhotonObjectQualityAlg' + postfix)
    alg.selectionDecoration = 'goodOQ'
    addPrivateTool(alg, 'selectionTool', 'CP::EgammaIsGoodOQSelectionTool')
    alg.selectionTool.Mask = xAOD.EgammaParameters.BADCLUSPHOTON
    seq.append(alg,
               inputPropName='particles',
               outputPropName='particlesOut',
               stageName='calibration')
    selectionDecorNames.append(alg.selectionDecoration)
    selectionDecorCount.append(1)

    # Only run subsequent processing on the objects passing all of these cuts.
    # Since these are independent of the photon calibration, and this speeds
    # up the job.
    alg = createAlgorithm('CP::AsgViewFromSelectionAlg',
                          'PhotonPreSelViewFromSelectionAlg' + postfix)
    alg.selection = selectionDecorNames[:]
    seq.append(alg,
               inputPropName='input',
               outputPropName='output',
               stageName='calibration')

    # Set up the calibration ans smearing algorithm.
    alg = createAlgorithm('CP::EgammaCalibrationAndSmearingAlg',
                          'PhotonCalibrationAndSmearingAlg' + postfix)
    addPrivateTool(alg, 'calibrationAndSmearingTool',
                   'CP::EgammaCalibrationAndSmearingTool')
    alg.calibrationAndSmearingTool.ESModel = 'es2018_R21_v0'
    alg.calibrationAndSmearingTool.decorrelationModel = '1NP_v1'
    if dataType == 'afii':
        alg.calibrationAndSmearingTool.useAFII = 1
    else:
        alg.calibrationAndSmearingTool.useAFII = 0
        pass
    seq.append(alg,
               inputPropName='egammas',
               outputPropName='egammasOut',
               affectingSystematics='(^EG_RESOLUTION_.*)|(^EG_SCALE_.*)',
               stageName='calibration')

    # should this be applied to data?  or to AFII?
    alg = createAlgorithm('CP::PhotonShowerShapeFudgeAlg',
                          'PhotonShowerShapeFudgeAlg' + postfix)
    addPrivateTool(alg, 'showerShapeFudgeTool',
                   'ElectronPhotonShowerShapeFudgeTool')
    alg.showerShapeFudgeTool.Preselection = 21  # 21 = MC15
    alg.showerShapeFudgeTool.FFCalibFile = \
        'ElectronPhotonShowerShapeFudgeTool/v1/PhotonFudgeFactors.root' #only for rel21
    seq.append(alg,
               inputPropName='photons',
               outputPropName='photonsOut',
               stageName='calibration')

    # Set up the isolation correction algorithm.
    alg = createAlgorithm('CP::EgammaIsolationCorrectionAlg',
                          'PhotonIsolationCorrectionAlg' + postfix)
    addPrivateTool(alg, 'isolationCorrectionTool',
                   'CP::IsolationCorrectionTool')
    if dataType == 'data':
        alg.isolationCorrectionTool.IsMC = 0
    else:
        alg.isolationCorrectionTool.IsMC = 1
        pass
    seq.append(alg,
               inputPropName='egammas',
               outputPropName='egammasOut',
               stageName='selection')

    # Set up the isolation selection algorithm:
    alg = createAlgorithm('CP::EgammaIsolationSelectionAlg',
                          'PhotonIsolationSelectionAlg' + postfix)
    alg.selectionDecoration = 'isolated' + postfix
    addPrivateTool(alg, 'selectionTool', 'CP::IsolationSelectionTool')
    alg.selectionTool.PhotonWP = isolationWP
    seq.append(alg,
               inputPropName='egammas',
               outputPropName='egammasOut',
               stageName='selection')
    selectionDecorNames.append(alg.selectionDecoration)
    selectionDecorCount.append(1)

    # Set up the photon efficiency correction algorithm.
    alg = createAlgorithm('CP::PhotonEfficiencyCorrectionAlg',
                          'PhotonEfficiencyCorrectionAlg' + postfix)
    addPrivateTool(alg, 'efficiencyCorrectionTool',
                   'AsgPhotonEfficiencyCorrectionTool')
    alg.scaleFactorDecoration = 'effSF' + postfix
    alg.efficiencyCorrectionTool.MapFilePath = \
        'PhotonEfficiencyCorrection/2015_2017/rel21.2/Winter2018_Prerec_v1/map0.txt'
    if dataType == 'afii':
        alg.efficiencyCorrectionTool.ForceDataType = \
          ROOT.PATCore.ParticleDataType.Fast
    elif dataType == 'mc':
        alg.efficiencyCorrectionTool.ForceDataType = \
          ROOT.PATCore.ParticleDataType.Full
        pass
    alg.outOfValidity = 2  #silent
    alg.outOfValidityDeco = 'bad_eff' + postfix
    if dataType != 'data':
        seq.append(alg,
                   inputPropName='photons',
                   outputPropName='photonsOut',
                   affectingSystematics='(^PH_EFF_.*)',
                   stageName='efficiency')
        selectionDecorNames.append(alg.outOfValidityDeco)
        selectionDecorCount.append(1)
        pass

    # Set up an algorithm used to create photon selection cutflow:
    if enableCutflow:
        alg = createAlgorithm('CP::ObjectCutFlowHistAlg',
                              'PhotonCutFlowDumperAlg' + postfix)
        alg.histPattern = 'photon_cflow_%SYS%' + postfix
        alg.selection = selectionDecorNames[:]
        alg.selectionNCuts = selectionDecorCount[:]
        seq.append(alg, inputPropName='input', stageName='selection')

    # Set up an algorithm that makes a view container using the selections
    # performed previously:
    alg = createAlgorithm('CP::AsgViewFromSelectionAlg',
                          'PhotonViewFromSelectionAlg' + postfix)
    alg.selection = selectionDecorNames[:]
    seq.append(alg,
               inputPropName='input',
               outputPropName='output',
               stageName='selection')

    # Set up an algorithm dumping the kinematic properties of the photons:
    if enableKinematicHistograms:
        alg = createAlgorithm('CP::KinematicHistAlg',
                              'PhotonKinematicDumperAlg' + postfix)
        alg.preselection = "&&".join(selectionDecorNames)
        alg.histPattern = 'photon_%VAR%_%SYS%' + postfix
        seq.append(alg, inputPropName='input', stageName='selection')

    # Set up a final deep copy making algorithm if requested:
    if deepCopyOutput:
        alg = createAlgorithm('CP::AsgViewFromSelectionAlg',
                              'PhotonDeepCopyMaker' + postfix)
        alg.deepCopy = True
        seq.append(alg,
                   inputPropName='input',
                   outputPropName='output',
                   stageName='selection')
        pass

    # Return the sequence:
    return seq
Пример #9
0
def makeJetJvtAnalysisSequence(dataType,
                               jetCollection,
                               preselection='',
                               disableFJvt=False,
                               globalSF=True,
                               runSelection=True,
                               enableCutflow=False):
    """Create a jet JVT analysis algorithm sequence

    Keyword arguments:
      dataType -- The data type to run on ("data", "mc" or "afii")
      jetCollection -- The jet container to run on
      disableFJvt -- Whether to disable forward JVT calculations
      globalSF -- Whether to calculate per event scale factors
      runSelection -- Whether to run selection
      enableCutflow -- Whether or not to dump the cutflow
    """

    if dataType not in ["data", "mc", "afii"]:
        raise ValueError("invalid data type: " + dataType)

    if runSelection and not globalSF:
        raise ValueError(
            "per-event scale factors needs to be computed when doing a JVT selection"
        )

    # Create the analysis algorithm sequence object:
    seq = AnaAlgSequence("JetJVTAnalysisSequence")

    # Define a list of cuts to apply later on and the
    # number of bits in the corresponding TAccept
    cutlist = []
    cutlength = []

    # Set up the per-event jet efficiency scale factor calculation algorithm
    if dataType != 'data' and globalSF:
        from JetAnalysisSequence import jvtSysts, fjvtSysts

        alg = createAlgorithm('CP::AsgEventScaleFactorAlg',
                              'JvtEventScaleFactorAlg')
        alg.preselection = preselection + '&&no_jvt' if preselection else 'no_jvt'
        alg.scaleFactorInputDecoration = 'jvt_effSF_%SYS%'
        alg.scaleFactorInputDecorationRegex = jvtSysts
        alg.scaleFactorOutputDecoration = 'jvt_effSF_%SYS%'

        seq.append(alg,
                   affectingSystematics=jvtSysts,
                   inputPropName={
                       'jets': 'particles',
                       'eventInfo': 'eventInfo'
                   })

        if not disableFJvt:
            alg = createAlgorithm('CP::AsgEventScaleFactorAlg',
                                  'ForwardJvtEventScaleFactorAlg')
            alg.preselection = preselection + '&&no_fjvt' if preselection else 'no_fjvt'
            alg.scaleFactorInputDecoration = 'fjvt_effSF_%SYS%'
            alg.scaleFactorInputDecorationRegex = fjvtSysts
            alg.scaleFactorOutputDecoration = 'fjvt_effSF_%SYS%'

            seq.append(alg,
                       affectingSystematics=fjvtSysts,
                       inputPropName={
                           'jets': 'particles',
                           'eventInfo': 'eventInfo'
                       })

    if runSelection:
        cutlist.append('jvt_selection')
        cutlength.append(1)

        if not disableFJvt:
            cutlist.append('fjvt_selection')
            cutlength.append(1)

        # Set up an algorithm used to create jet JVT selection cutflow:
        if enableCutflow:
            alg = createAlgorithm('CP::ObjectCutFlowHistAlg',
                                  'JetJvtCutFlowDumperAlg')
            alg.histPattern = 'jet_cflow_jvt_%SYS%'
            alg.selection = cutlist
            alg.selectionNCuts = cutlength
            seq.append(alg, inputPropName={'jets': 'input'})

        # Set up an algorithm that makes a view container using the selections
        # performed previously:
        alg = createAlgorithm('CP::AsgViewFromSelectionAlg',
                              'JetJvtViewFromSelectionAlg')
        alg.selection = cutlist
        seq.append(alg,
                   inputPropName={'jets': 'input'},
                   outputPropName={'jets': 'output'})

    # Return the sequence:
    return seq
Пример #10
0
def makeDiTauAnalysisSequence( dataType, workingPoint,
                             deepCopyOutput = False, postfix = '' ):
    """Create a tau analysis algorithm sequence

    Keyword arguments:
      dataType -- The data type to run on ("data", "mc" or "afii")
      deepCopyOutput -- If set to 'True', the output containers will be
                        standalone, deep copies (slower, but needed for xAOD
                        output writing)
      postfix -- a postfix to apply to decorations and algorithm
                 names.  this is mostly used/needed when using this
                 sequence with multiple working points to ensure all
                 names are unique.
    """

    if dataType not in ["data", "mc", "afii"] :
        raise ValueError ("invalid data type: " + dataType)

    if postfix != '' :
        postfix = '_' + postfix
        pass

    splitWP = workingPoint.split ('.')
    if len (splitWP) != 1 :
        raise ValueError ('working point should be of format "quality", not ' + workingPoint)

    # using enum value from: https://gitlab.cern.ch/atlas/athena/blob/21.2/PhysicsAnalysis/TauID/TauAnalysisTools/TauAnalysisTools/Enums.h
    # the dictionary is missing in Athena, so hard-coding values here
    if splitWP[0] == 'Tight' :
        IDLevel = 4 # ROOT.TauAnalysisTools.JETIDBDTTIGHT
        pass
    elif splitWP[0] == 'Medium' :
        IDLevel = 3 # ROOT.TauAnalysisTools.JETIDBDTMEDIUM
        pass
    elif splitWP[0] == 'Loose' :
        IDLevel = 2 # ROOT.TauAnalysisTools.JETIDBDTLOOSE
        pass
    else :
        raise ValueError ("invalid tau quality: \"" + splitWP[0] +
                          "\", allowed values are Tight, Medium, Loose, " +
                          "VeryLoose")

    # Create the analysis algorithm sequence object:
    seq = AnaAlgSequence( "DiTauAnalysisSequence" + postfix )

    # Set up the tau 4-momentum smearing algorithm:
    alg = createAlgorithm( 'CP::DiTauSmearingAlg', 'DiTauSmearingAlg' + postfix )
    addPrivateTool( alg, 'smearingTool', 'TauAnalysisTools::DiTauSmearingTool' )
    seq.append( alg, inputPropName = 'taus', outputPropName = 'tausOut',
                affectingSystematics = '(^TAUS_TRUEHADDITAU_SME_TES_.*)',
                stageName = 'calibration' )

    # Set up an algorithm dumping the properties of the taus, for debugging:
    alg = createAlgorithm( 'CP::KinematicHistAlg', 'DiTauKinematicDumperAlg' + postfix )
    alg.histPattern = "tau_%VAR%_%SYS%"
    seq.append( alg, inputPropName = 'input',
                stageName = 'selection' )

    # Set up the algorithm calculating the efficiency scale factors for the
    # taus:
    alg = createAlgorithm( 'CP::DiTauEfficiencyCorrectionsAlg',
                           'DiTauEfficiencyCorrectionsAlg' + postfix )
    addPrivateTool( alg, 'efficiencyCorrectionsTool',
                    'TauAnalysisTools::DiTauEfficiencyCorrectionsTool' )
    alg.efficiencyCorrectionsTool.IDLevel = IDLevel
    alg.scaleFactorDecoration = 'tau_effSF' + postfix
    # alg.outOfValidity = 2 #silent
    # alg.outOfValidityDeco = "bad_eff"
    seq.append( alg, inputPropName = 'taus', outputPropName = 'tausOut',
                affectingSystematics = '(^TAUS_TRUEHADDITAU_EFF_JETID_.*)',
                stageName = 'efficiency' )

    # Set up the tau truth matching algorithm:
    if dataType != 'data':
        alg = createAlgorithm( 'CP::DiTauTruthMatchingAlg',
                               'DiTauTruthMatchingAlg' + postfix )
        addPrivateTool( alg, 'matchingTool',
                        'TauAnalysisTools::DiTauTruthMatchingTool' )
        alg.matchingTool.WriteTruthTaus = 1
        seq.append( alg, inputPropName = 'taus', outputPropName = 'tausOut',
                    stageName = 'selection' )
        pass

    # Set up a final deep copy making algorithm if requested:
    if deepCopyOutput:
        alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg',
                               'DiTauDeepCopyMaker' + postfix )
        alg.deepCopy = True
        seq.append( alg, inputPropName = 'input', outputPropName = 'output',
                    stageName = 'selection' )
        pass

    # Return the sequence:
    return seq
Пример #11
0
def makeOverlapAnalysisSequence( dataType,
                                 inputLabel = '', outputLabel = 'passesOR',
                                 linkOverlapObjects = False, doMuPFJetOR=False,
                                 doEleEleOR = False, doElectrons = True,
                                 doMuons = True, doJets = True, doTaus = True,
                                 doPhotons = True, doFatJets = False,
                                 bJetLabel = '',
                                 boostedLeptons = False,
                                 postfix = '',
                                 enableCutflow = False ):
    """Function creating the overlap removal algorithm sequence

    The function sets up a multi-input/multi-output analysis algorithm sequnce,
    which needs to be used in a quite particular way. First off you need to set
    the arguments of this function correctly.

    Then, you need to call the configure(...) method on the algorithm sequence
    returned by this function in the following way:

      overlapSequence.configure(
         inputName = {
            'electrons' : 'AnalysisElectrons_%SYS%',
            'photons'   : 'AnalysisPhotons_%SYS%',
            'muons'     : 'AnalysisMuons_%SYS%',
            'jets'      : 'AnalysisJets_%SYS%',
            'taus'      : 'AnalysisTauJets_%SYS%' },
         outputName = {
            'electrons' : 'AnalysisElectronsOR_%SYS%',
            'photons'   : 'AnalysisPhotonsOR_%SYS%',
            'muons'     : 'AnalysisMuonsOR_%SYS%',
            'jets'      : 'AnalysisJetsOR_%SYS%',
            'taus'      : 'AnalysisTauJetsOR_%SYS%' },
         affectingSystematics = {
            'electrons' : '(^$)|(^EG_.*)|(^EL_.*)',
            'photons'   : '(^$)|(^EG_.*)|(^PH_.*)',
            'muons'     : '(^$)|(^MUON_.*)',
            'jets'      : '(^$)|(^JET_.*)',
            'taus'      : '(^$)|(^TAUS_.*)' } )

    Where:
      - You need to provide input and output names in pairs, you must not skip
        specifying an output name if you specified an input name, and vice
        versa.
      - You only define inputs/outputs that your analysis uses. The "labels" of
        the possible inputs/outputs are: "electrons", "photons", "muons",
        "jets", "taus" and "fatJets".
      - You have to define with affectingSystematics which systematic variations
        are affecting the containers you passed to the sequence as inputs. If
        left empty, the configuration assumes that no systematic variation is
        affecting the input(s).

    Function keyword arguments:
      dataType -- The data type to run on ("data", "mc" or "afii")
      inputLabel -- Any possible label to pick up the selected objects with. If
                    left empty, all objects from the input containers are
                    considered.
      outputLabel -- Decoration put on the output variables. Set to "true" for
                     objects passing the overlap removal.
      linkOverlapObjects -- Set up an element link between overlapping objects
      doMuPFJetOR -- Set up overlap removal for PFlow jets that are acutally muons
      doEleEleOR -- Set up electron-electron overlap removal
      doXXXX     -- these flags enable/disable object types to
                    configure tools for: doElectrons, doMuons,
                    doJets, doTaus, doPhotons, doFatJets.
      bJetLabel -- Flag to select b-jets with. If left empty, no b-jets are used
                   in the overlap removal.
      boostedLeptons -- Set to True to enable boosted lepton overlap removal
      enableCutflow -- Whether or not to dump the cutflow
    """

    if dataType not in ["data", "mc", "afii"] :
        raise ValueError ("invalid data type: " + dataType)

    # Create the analysis algorithm sequence object:
    seq = AnaAlgSequence( 'OverlapAnalysisSequence' + postfix )

    # Create the overlap removal algorithm:
    alg = createAlgorithm( 'CP::OverlapRemovalAlg', 'OverlapRemovalAlg' + postfix )

    # Create its main tool, and set its basic properties:
    addPrivateTool( alg, 'overlapTool', 'ORUtils::OverlapRemovalTool' )
    alg.overlapTool.InputLabel = inputLabel
    alg.overlapTool.OutputLabel = outputLabel

    # By default the OverlapRemovalTool would flag objects that need to be
    # suppressed, with a "true" value. But since the analysis algorithms expect
    # the opposite behaviour from selection flags, we need to tell the tool
    # explicitly to use the "true" flag on objects that pass the overlap
    # removal.
    alg.overlapTool.OutputPassValue = True

    # Set up overlap removal for PFlow jets that are acutally muons, if requested.
    if doMuPFJetOR:
       addPrivateTool( alg, 'overlapTool.MuPFJetORT',
                       'ORUtils::MuPFJetOverlapTool' )
       alg.overlapTool.MuPFJetORT.InputLabel = inputLabel
       alg.overlapTool.MuPFJetORT.OutputLabel = outputLabel
       alg.overlapTool.MuPFJetORT.LinkOverlapObjects = linkOverlapObjects
       alg.overlapTool.MuPFJetORT.OutputPassValue = True
       pass

    # Set up the electron-electron overlap removal, if requested.
    if doElectrons and doEleEleOR:
        addPrivateTool( alg, 'overlapTool.EleEleORT',
                        'ORUtils::EleEleOverlapTool' )
        alg.overlapTool.EleEleORT.InputLabel = inputLabel
        alg.overlapTool.EleEleORT.OutputLabel = outputLabel
        alg.overlapTool.EleEleORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.EleEleORT.OutputPassValue = True
        pass

    # Set up the electron-muon overlap removal.
    if doElectrons and doMuons:
        addPrivateTool( alg, 'overlapTool.EleMuORT',
                        'ORUtils::EleMuSharedTrkOverlapTool' )
        alg.overlapTool.EleMuORT.InputLabel = inputLabel
        alg.overlapTool.EleMuORT.OutputLabel = outputLabel
        alg.overlapTool.EleMuORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.EleMuORT.OutputPassValue = True
        pass

    # Set up the electron-(narrow-)jet overlap removal.
    if doElectrons and doJets:
        addPrivateTool( alg, 'overlapTool.EleJetORT',
                        'ORUtils::EleJetOverlapTool' )
        alg.overlapTool.EleJetORT.InputLabel = inputLabel
        alg.overlapTool.EleJetORT.OutputLabel = outputLabel
        alg.overlapTool.EleJetORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.EleJetORT.BJetLabel = bJetLabel
        alg.overlapTool.EleJetORT.UseSlidingDR = boostedLeptons
        alg.overlapTool.EleJetORT.OutputPassValue = True
        pass

    # Set up the muon-(narrow-)jet overlap removal.
    if doMuons and doJets:
        addPrivateTool( alg, 'overlapTool.MuJetORT',
                        'ORUtils::MuJetOverlapTool' )
        alg.overlapTool.MuJetORT.InputLabel = inputLabel
        alg.overlapTool.MuJetORT.OutputLabel = outputLabel
        alg.overlapTool.MuJetORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.MuJetORT.BJetLabel = bJetLabel
        alg.overlapTool.MuJetORT.UseSlidingDR = boostedLeptons
        alg.overlapTool.MuJetORT.OutputPassValue = True
        pass

    # Set up the tau-electron overlap removal.
    if doTaus and doElectrons:
        addPrivateTool( alg, 'overlapTool.TauEleORT',
                        'ORUtils::DeltaROverlapTool' )
        alg.overlapTool.TauEleORT.InputLabel = inputLabel
        alg.overlapTool.TauEleORT.OutputLabel = outputLabel
        alg.overlapTool.TauEleORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.TauEleORT.DR = 0.2
        alg.overlapTool.TauEleORT.OutputPassValue = True
        pass

    # Set up the tau-muon overlap removal.
    if doTaus and doMuons:
        addPrivateTool( alg, 'overlapTool.TauMuORT',
                        'ORUtils::DeltaROverlapTool' )
        alg.overlapTool.TauMuORT.InputLabel = inputLabel
        alg.overlapTool.TauMuORT.OutputLabel = outputLabel
        alg.overlapTool.TauMuORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.TauMuORT.DR = 0.2
        alg.overlapTool.TauMuORT.OutputPassValue = True
        pass

    # Set up the tau-(narrow-)jet overlap removal.
    if doTaus and doJets:
        addPrivateTool( alg, 'overlapTool.TauJetORT',
                        'ORUtils::DeltaROverlapTool' )
        alg.overlapTool.TauJetORT.InputLabel = inputLabel
        alg.overlapTool.TauJetORT.OutputLabel = outputLabel
        alg.overlapTool.TauJetORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.TauJetORT.DR = 0.2
        alg.overlapTool.TauJetORT.OutputPassValue = True
        pass

    # Set up the photon-electron overlap removal.
    if doPhotons and doElectrons:
        addPrivateTool( alg, 'overlapTool.PhoEleORT',
                        'ORUtils::DeltaROverlapTool' )
        alg.overlapTool.PhoEleORT.InputLabel = inputLabel
        alg.overlapTool.PhoEleORT.OutputLabel = outputLabel
        alg.overlapTool.PhoEleORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.PhoEleORT.OutputPassValue = True
        pass

    # Set up the photon-muon overlap removal.
    if doPhotons and doMuons:
        addPrivateTool( alg, 'overlapTool.PhoMuORT',
                        'ORUtils::DeltaROverlapTool' )
        alg.overlapTool.PhoMuORT.InputLabel = inputLabel
        alg.overlapTool.PhoMuORT.OutputLabel = outputLabel
        alg.overlapTool.PhoMuORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.PhoMuORT.OutputPassValue = True
        pass

    # Set up the photon-(narrow-)jet overlap removal.
    if doPhotons and doJets:
        addPrivateTool( alg, 'overlapTool.PhoJetORT',
                        'ORUtils::DeltaROverlapTool' )
        alg.overlapTool.PhoJetORT.InputLabel = inputLabel
        alg.overlapTool.PhoJetORT.OutputLabel = outputLabel
        alg.overlapTool.PhoJetORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.PhoJetORT.OutputPassValue = True
        pass

    # Set up the electron-fat-jet overlap removal.
    if doElectrons and doFatJets:
        addPrivateTool( alg, 'overlapTool.EleFatJetORT',
                        'ORUtils::DeltaROverlapTool' )
        alg.overlapTool.EleFatJetORT.InputLabel = inputLabel
        alg.overlapTool.EleFatJetORT.OutputLabel = outputLabel
        alg.overlapTool.EleFatJetORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.EleFatJetORT.DR = 1.0
        alg.overlapTool.EleFatJetORT.OutputPassValue = True
        pass

    # Set up the (narrow-)jet-fat-jet overlap removal.
    if doJets and doFatJets:
        addPrivateTool( alg, 'overlapTool.JetFatJetORT',
                        'ORUtils::DeltaROverlapTool' )
        alg.overlapTool.JetFatJetORT.InputLabel = inputLabel
        alg.overlapTool.JetFatJetORT.OutputLabel = outputLabel
        alg.overlapTool.JetFatJetORT.LinkOverlapObjects = linkOverlapObjects
        alg.overlapTool.JetFatJetORT.DR = 1.0
        alg.overlapTool.JetFatJetORT.OutputPassValue = True
        pass

    # Add the algorithm to the analysis sequence.
    seq.append( alg,
                inputPropName = { 'electrons' : 'electrons',
                                  'muons'     : 'muons',
                                  'jets'      : 'jets',
                                  'taus'      : 'taus',
                                  'photons'   : 'photons',
                                  'fatJets'   : 'fatJets' },
                outputPropName = { 'electrons' : 'electronsOut',
                                   'muons'     : 'muonsOut',
                                   'jets'      : 'jetsOut',
                                   'taus'      : 'tausOut',
                                   'photons'   : 'photonsOut',
                                   'fatJets'   : 'fatJetsOut' } )

    # Add view container creation algorithms for all types.
    for container in [ ( 'electrons', doElectrons ),
                       ( 'muons',     doMuons ),
                       ( 'jets',      doJets ),
                       ( 'taus',      doTaus ),
                       ( 'photons',   doPhotons ),
                       ( 'fatJets',   doFatJets ) ]:

        # Skip setting up a view container if the type is not being processed.
        if not container[ 1 ]:
            continue

        # Set up a cutflow alg.
        if enableCutflow:
            alg = createAlgorithm( 'CP::ObjectCutFlowHistAlg',
                                   'OverlapRemovalCutFlowDumperAlg_%s' % container[ 0 ] + postfix )
            alg.histPattern = container[ 0 ] + postfix + '_OR_cflow_%SYS%'
            if inputLabel:
                alg.selection = [ '%s,as_char' % inputLabel,
                                  '%s,as_char' % outputLabel ]
                alg.selectionNCuts = [1, 1]
            else:
                alg.selection = [ '%s,as_char' % outputLabel ]
                alg.selectionNCuts = [1]
            seq.append( alg, inputPropName = { container[ 0 ] : 'input' } )

        # Set up a view container for the type.
        alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg',
                               'OverlapRemovalViewMaker_%s' % container[ 0 ] + postfix )
        alg.selection = [ '%s,as_char' % outputLabel ]
        seq.append( alg, inputPropName = { container[ 0 ] : 'input' },
                    outputPropName = { container[ 0 ] : 'output' } )
        pass

    # Return the sequence:
    return seq
Пример #12
0
def makeMuonAnalysisSequence(dataType,
                             workingPoint,
                             deepCopyOutput=False,
                             shallowViewOutput=True,
                             postfix='',
                             ptSelectionOutput=False,
                             qualitySelectionOutput=True,
                             enableCutflow=False,
                             enableKinematicHistograms=False):
    """Create a muon analysis algorithm sequence

    Keyword arguments:
      dataType -- The data type to run on ("data", "mc" or "afii")
      workingPoint -- The working point to use
      deepCopyOutput -- If set to 'True', the output containers will be
                        standalone, deep copies (slower, but needed for xAOD
                        output writing)
      shallowViewOutput -- Create a view container if required
      postfix -- a postfix to apply to decorations and algorithm
                 names.  this is mostly used/needed when using this
                 sequence with multiple working points to ensure all
                 names are unique.
      ptSelectionOutput -- Whether or not to apply pt selection when creating
                           output containers.
      qualitySelectionOutput -- Whether or not to apply muon quality selection
                                when creating output containers.
      enableCutflow -- Whether or not to dump the cutflow
      enableKinematicHistograms -- Whether or not to dump the kinematic histograms
    """

    if dataType not in ["data", "mc", "afii"]:
        raise ValueError("invalid data type: " + dataType)

    if postfix != '':
        postfix = '_' + postfix
        pass

    # Make sure selection options make sense
    if deepCopyOutput and shallowViewOutput:
        raise ValueError(
            "deepCopyOutput and shallowViewOutput can't both be true!")

    splitWP = workingPoint.split('.')
    if len(splitWP) != 2:
        raise ValueError(
            'working point should be of format "quality.isolation", not ' +
            workingPoint)

    sfWorkingPoint = splitWP[0]
    if splitWP[0] == 'Tight':
        quality = ROOT.xAOD.Muon.Tight
        pass
    elif splitWP[0] == 'Medium':
        quality = ROOT.xAOD.Muon.Medium
        pass
    elif splitWP[0] == 'Loose':
        quality = ROOT.xAOD.Muon.Loose
        pass
    elif splitWP[0] == 'VeryLoose':
        quality = ROOT.xAOD.Muon.VeryLoose
        pass
    elif splitWP[0] == 'HighPt':
        quality = 4
        pass
    elif splitWP[0] == 'LowPtEfficiency':
        quality = 5
        pass
    else:
        raise ValueError("invalid muon quality: \"" + splitWP[0] +
                         "\", allowed values are Tight, Medium, Loose, " +
                         "VeryLoose, HighPt, LowPtEfficiency")

    if not splitWP[1] in ["Iso", "NonIso"]:
        raise ValueError('invalid muon isolation \"' + splitWP[1] +
                         '\", allowed values are Iso, NonIso')

    # Create the analysis algorithm sequence object:
    seq = AnaAlgSequence("MuonAnalysisSequence" + postfix)

    seq.addMetaConfigDefault("selectionDecorNames", [])
    seq.addMetaConfigDefault("selectionDecorNamesOutput", [])
    seq.addMetaConfigDefault("selectionDecorCount", [])

    # Set up the eta-cut on all muons prior to everything else
    alg = createAlgorithm('CP::AsgSelectionAlg', 'MuonEtaCutAlg' + postfix)
    addPrivateTool(alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool')
    alg.selectionTool.maxEta = 2.5
    alg.selectionDecoration = 'selectEta' + postfix + ',as_bits'
    seq.append(alg,
               inputPropName='particles',
               outputPropName='particlesOut',
               stageName='selection',
               metaConfig={
                   'selectionDecorNames': [alg.selectionDecoration],
                   'selectionDecorNamesOutput': [alg.selectionDecoration],
                   'selectionDecorCount': [2]
               },
               dynConfig={
                   'preselection':
                   lambda meta: "&&".join(meta["selectionDecorNames"])
               })

    # Set up the track selection algorithm:
    alg = createAlgorithm('CP::AsgLeptonTrackSelectionAlg',
                          'MuonTrackSelectionAlg' + postfix)
    alg.selectionDecoration = 'trackSelection' + postfix + ',as_bits'
    alg.maxD0Significance = 3
    alg.maxDeltaZ0SinTheta = 0.5
    seq.append(alg,
               inputPropName='particles',
               stageName='selection',
               metaConfig={
                   'selectionDecorNames': [alg.selectionDecoration],
                   'selectionDecorNamesOutput': [alg.selectionDecoration],
                   'selectionDecorCount': [3]
               },
               dynConfig={
                   'preselection':
                   lambda meta: "&&".join(meta["selectionDecorNames"])
               })

    # Set up the muon calibration and smearing algorithm:
    alg = createAlgorithm('CP::MuonCalibrationAndSmearingAlg',
                          'MuonCalibrationAndSmearingAlg' + postfix)
    addPrivateTool(alg, 'calibrationAndSmearingTool',
                   'CP::MuonCalibrationPeriodTool')
    seq.append(alg,
               inputPropName='muons',
               outputPropName='muonsOut',
               affectingSystematics=
               '(^MUON_ID$)|(^MUON_MS$)|(^MUON_SAGITTA_.*)|(^MUON_SCALE$)',
               stageName='calibration',
               dynConfig={
                   'preselection':
                   lambda meta: "&&".join(meta["selectionDecorNames"])
               })

    # Set up the the pt selection
    alg = createAlgorithm('CP::AsgSelectionAlg', 'MuonPtCutAlg' + postfix)
    alg.selectionDecoration = 'selectPt' + postfix + ',as_bits'
    addPrivateTool(alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool')
    alg.selectionTool.minPt = 3e3
    seq.append(alg,
               inputPropName='particles',
               stageName='selection',
               metaConfig={
                   'selectionDecorNames': [alg.selectionDecoration],
                   'selectionDecorNamesOutput':
                   [alg.selectionDecoration] if ptSelectionOutput else [],
                   'selectionDecorCount': [2]
               },
               dynConfig={
                   'preselection':
                   lambda meta: "&&".join(meta["selectionDecorNames"])
               })

    # Setup the muon quality selection
    alg = createAlgorithm('CP::MuonSelectionAlgV2',
                          'MuonSelectionAlg' + postfix)
    addPrivateTool(alg, 'selectionTool', 'CP::MuonSelectionTool')
    alg.selectionTool.MuQuality = quality
    alg.selectionDecoration = 'good_muon' + postfix + ',as_bits'
    alg.badMuonVetoDecoration = 'is_bad' + postfix + ',as_char'
    seq.append(alg,
               inputPropName='muons',
               stageName='selection',
               metaConfig={
                   'selectionDecorNames': [alg.selectionDecoration],
                   'selectionDecorNamesOutput':
                   [alg.selectionDecoration] if qualitySelectionOutput else [],
                   'selectionDecorCount': [4]
               },
               dynConfig={
                   'preselection':
                   lambda meta: "&&".join(meta["selectionDecorNames"])
               })

    # Set up the isolation calculation algorithm:
    if splitWP[1] != 'NonIso':
        alg = createAlgorithm('CP::MuonIsolationAlg',
                              'MuonIsolationAlg' + postfix)
        addPrivateTool(alg, 'isolationTool', 'CP::IsolationSelectionTool')
        alg.isolationDecoration = 'isolated_muon' + postfix + ',as_bits'
        seq.append(alg,
                   inputPropName='muons',
                   outputPropName='muonsOut',
                   stageName='selection',
                   metaConfig={
                       'selectionDecorNames': [alg.isolationDecoration],
                       'selectionDecorNamesOutput': [alg.isolationDecoration],
                       'selectionDecorCount': [1]
                   },
                   dynConfig={
                       'preselection':
                       lambda meta: "&&".join(meta["selectionDecorNames"])
                   })
        pass

    # Set up an algorithm used for decorating baseline muon selection:
    alg = createAlgorithm('CP::AsgSelectionAlg',
                          'MuonSelectionSummary' + postfix)
    addPrivateTool(alg, 'selectionTool', 'CP::AsgFlagSelectionTool')
    alg.selectionDecoration = 'baselineSelection' + postfix + ',as_char'
    seq.append(alg,
               inputPropName='particles',
               stageName='selection',
               dynConfig={
                   'selectionTool.selectionFlags':
                   lambda meta: meta["selectionDecorNames"]
               })

    # Set up an algorithm used to create muon selection cutflow:
    if enableCutflow:
        alg = createAlgorithm('CP::ObjectCutFlowHistAlg',
                              'MuonCutFlowDumperAlg' + postfix)
        alg.histPattern = 'muon' + postfix + '_cflow_%SYS%'
        seq.append(alg,
                   inputPropName='input',
                   stageName='selection',
                   dynConfig={
                       'selection': lambda meta: meta["selectionDecorNames"],
                       'selectionNCuts':
                       lambda meta: meta["selectionDecorCount"]
                   })

    # Set up an algorithm that makes a view container using the selections
    # performed previously:
    if shallowViewOutput:
        alg = createAlgorithm('CP::AsgViewFromSelectionAlg',
                              'MuonViewFromSelectionAlg' + postfix)
        seq.append(alg,
                   inputPropName='input',
                   outputPropName='output',
                   stageName='selection',
                   dynConfig={
                       'selection':
                       lambda meta: meta["selectionDecorNamesOutput"]
                   })

    # Set up the efficiency scale factor calculation algorithm:
    alg = createAlgorithm('CP::MuonEfficiencyScaleFactorAlg',
                          'MuonEfficiencyScaleFactorAlg' + postfix)
    addPrivateTool(alg, 'efficiencyScaleFactorTool',
                   'CP::MuonEfficiencyScaleFactors')
    alg.scaleFactorDecoration = 'muon_effSF' + postfix + "_%SYS%"
    alg.scaleFactorDecorationRegex = '(^MUON_EFF_RECO.*)'
    alg.outOfValidity = 2  #silent
    alg.outOfValidityDeco = 'bad_eff' + postfix
    alg.efficiencyScaleFactorTool.WorkingPoint = sfWorkingPoint
    if dataType != 'data':
        seq.append(alg,
                   inputPropName='muons',
                   affectingSystematics='(^MUON_EFF_RECO.*)',
                   stageName='efficiency',
                   dynConfig={
                       'preselection':
                       lambda meta: "&&".join(meta["selectionDecorNames"])
                   })

    # Set up an algorithm dumping the kinematic properties of the muons:
    if enableKinematicHistograms:
        alg = createAlgorithm('CP::KinematicHistAlg',
                              'MuonKinematicDumperAlg' + postfix)
        alg.histPattern = 'muon' + postfix + '_%VAR%_%SYS%'
        seq.append(alg,
                   inputPropName='input',
                   stageName='selection',
                   dynConfig={
                       'preselection':
                       lambda meta: "&&".join(meta["selectionDecorNames"])
                   })

    # Set up a final deep copy making algorithm if requested:
    if deepCopyOutput:
        alg = createAlgorithm('CP::AsgViewFromSelectionAlg',
                              'MuonDeepCopyMaker' + postfix)
        alg.deepCopy = True
        seq.append(alg,
                   inputPropName='input',
                   outputPropName='output',
                   stageName='selection',
                   dynConfig={
                       'selection':
                       lambda meta: meta["selectionDecorNamesOutput"]
                   })
        pass

    # Return the sequence:
    return seq