Example #1
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
Example #2
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
Example #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
Example #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
Example #5
0
def makeRScanJetAnalysisSequence(seq,
                                 cutlist,
                                 cutlength,
                                 dataType,
                                 jetCollection,
                                 jetInput,
                                 radius,
                                 postfix=''):
    """Add algorithms for the R-scan jets.

      Keyword arguments
        seq -- The sequence to add the algorithms to
        cutlist -- Insert any cuts into this
        cutlength -- Insert the lengths of any cuts into this
        dataType -- The data type to run on ("data", "mc" or "afii")
        jetCollection -- The jet container to run on.
        jetInput -- The type of input used, read from the collection name.
        radius -- The radius of the r-scan jets.
        postfix -- String to be added to the end of all public names.
    """
    if jetInput != "LCTopo":
        raise ValueError(
            "Unsupported input type '{0}' for R-scan jets!".format(jetInput))
    # Prepare the jet calibration algorithm
    alg = createAlgorithm('CP::JetCalibrationAlg',
                          'JetCalibrationAlg' + postfix)
    addPrivateTool(alg, 'calibrationTool', 'JetCalibrationTool')
    alg.calibrationTool.JetCollection = jetCollection[:-4]
    alg.calibrationTool.ConfigFile = \
        "JES_MC16Recommendation_Rscan{0}LC_18Dec2018_R21.config".format(radius)
    if dataType == 'data':
        alg.calibrationTool.CalibSequence = "JetArea_Residual_EtaJES_GSC_Insitu"
    else:
        alg.calibrationTool.CalibSequence = "JetArea_Residual_EtaJES_GSC"
    alg.calibrationTool.IsData = (dataType == 'data')
    seq.append(alg,
               inputPropName='jets',
               outputPropName='jetsOut',
               stageName='calibration')
    # Logging would be good
    print("WARNING: uncertainties for R-Scan jets are not yet released!")
Example #6
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
Example #7
0
def makeLargeRJetAnalysisSequence(seq,
                                  cutlist,
                                  cutlength,
                                  dataType,
                                  jetCollection,
                                  jetInput,
                                  postfix='',
                                  largeRMass="Comb"):
    """Add algorithms for the R=1.0 jets.

      Keyword arguments
        seq -- The sequence to add the algorithms to
        cutlist -- Insert any cuts into this
        cutlength -- Insert the lengths of any cuts into this
        dataType -- The data type to run on ("data", "mc" or "afii")
        jetCollection -- The jet container to run on.
        jetInput -- The type of input used, read from the collection name.
        postfix -- String to be added to the end of all public names.
        largeRMass -- Which large-R mass definition to use. Ignored if not running on large-R jets ("Comb", "Calo", "TCC", "TA")
    """

    if largeRMass not in ["Comb", "Calo", "TCC", "TA"]:
        raise ValueError(
            "Invalid large-R mass defintion {0}!".format(largeRMass))

    if jetInput not in ["LCTopo", "TrackCaloCluster"]:
        raise ValueError(
            "Unsupported input type '{0}' for large-R jets!".format(jetInput))
    if jetInput == "TrackCaloCluster":
        # Only one mass defintion supported
        if largeRMass != "Calo":
            raise ValueError(
                "Unsupported large-R TCC jet mass '{0}'!".format(largeRMass))
        configFile = "JES_MC16recommendation_FatJet_TCC_JMS_calo_30Oct2018.config"
    else:
        if largeRMass == "Comb":
            configFile = "JES_MC16recommendation_FatJet_Trimmed_JMS_comb_17Oct2018.config"
        elif largeRMass == "Calo":
            configFile = "JES_MC16recommendation_FatJet_Trimmed_JMS_calo_12Oct2018.config"
        elif largeRMass == "TCC":
            configFile = "JES_MC16recommendation_FatJet_TCC_JMS_calo_30Oct2018.config"
        else:
            configFile = "JES_MC16recommendation_FatJet_Trimmed_JMS_TA_12Oct2018.config"
    # Prepare the jet calibration algorithm
    alg = createAlgorithm('CP::JetCalibrationAlg',
                          'JetCalibrationAlg' + postfix)
    addPrivateTool(alg, 'calibrationTool', 'JetCalibrationTool')
    alg.calibrationTool.JetCollection = jetCollection[:-4]
    alg.calibrationTool.ConfigFile = configFile
    alg.calibrationTool.CalibSequence = "EtaJES_JMS"
    alg.calibrationTool.IsData = 0
    seq.append(alg,
               inputPropName='jets',
               outputPropName='jetsOut',
               stageName='calibration')

    # Jet uncertainties
    alg = createAlgorithm('CP::JetUncertaintiesAlg',
                          'JetUncertaintiesAlg' + postfix)
    # R=1.0 jets have a validity range
    alg.outOfValidity = 2  # SILENT
    alg.outOfValidityDeco = 'outOfValidity'
    addPrivateTool(alg, 'uncertaintiesTool', 'JetUncertaintiesTool')
    alg.uncertaintiesTool.JetDefinition = jetCollection[:-4]
    alg.uncertaintiesTool.ConfigFile = \
        "rel21/Moriond2018/R10_{0}Mass_all.config".format(largeRMass)
    alg.uncertaintiesTool.MCType = "MC16a"
    alg.uncertaintiesTool.IsData = (dataType == "data")
    seq.append(alg,
               inputPropName='jets',
               outputPropName='jetsOut',
               affectingSystematics=largeRSysts,
               stageName='calibration')

    cutlist.append('outOfValidity')
    cutlength.append(1)
Example #8
0
def makeSmallRJetAnalysisSequence(seq,
                                  cutlist,
                                  cutlength,
                                  dataType,
                                  jetCollection,
                                  jetInput,
                                  postfix='',
                                  runJvtUpdate=True,
                                  runFJvtUpdate=True,
                                  runJvtSelection=True,
                                  runFJvtSelection=True,
                                  runJvtEfficiency=True,
                                  runFJvtEfficiency=True,
                                  reduction="Global",
                                  JEROption="Simple"):
    """Add algorithms for the R=0.4 jets.

      Keyword arguments
        seq -- The sequence to add the algorithms to
        cutlist -- Insert any cuts into this
        cutlength -- Insert the lengths of any cuts into this
        dataType -- The data type to run on ("data", "mc" or "afii")
        jetCollection -- The jet container to run on.
        jetInput -- The type of input used, read from the collection name.
        postfix -- String to be added to the end of all public names.
        runJvtUpdate -- Determines whether or not to update JVT on the jets
        runFJvtUpdate -- Determines whether or not to update forward JVT on the jets
        runJvtSelection -- Determines whether or not to run JVT selection on the jets
        runFJvtSelection -- Determines whether or not to run forward JVT selection on the jets
        runJvtEfficiency -- Determines whether or not to calculate the JVT efficiency
        runFJvtEfficiency -- Determines whether or not to calculate the forward JVT efficiency
        reduction -- Which NP reduction scheme should be used (All, Global, Category, Scenario)
        JEROption -- Which variant of the reduction should be used (All, Full, Simple). Note that not all combinations of reduction and JEROption are valid!
    """
    if jetInput not in ["EMTopo", "EMPFlow"]:
        raise ValueError(
            "Unsupported input type '{0}' for R=0.4 jets!".format(jetInput))

    # Prepare the jet calibration algorithm
    alg = createAlgorithm('CP::JetCalibrationAlg',
                          'JetCalibrationAlg' + postfix)
    addPrivateTool(alg, 'calibrationTool', 'JetCalibrationTool')
    alg.calibrationTool.JetCollection = jetCollection[:-4]
    # Get the correct string to use in the config file name
    if dataType == 'afii':
        configFile = "JES_MC16Recommendation_AFII_{0}_Apr2019_Rel21.config"
    else:
        configFile = "JES_MC16Recommendation_Consolidated_{0}_Apr2019_Rel21.config"
    if jetInput == "EMPFlow":
        configFile = configFile.format("PFlow")
    else:
        configFile = configFile.format(jetInput)
    alg.calibrationTool.ConfigFile = configFile
    if dataType == 'data':
        alg.calibrationTool.CalibSequence = 'JetArea_Residual_EtaJES_GSC_Insitu'
    else:
        alg.calibrationTool.CalibSequence = 'JetArea_Residual_EtaJES_GSC_Smear'
    alg.calibrationTool.IsData = (dataType == 'data')
    seq.append(alg,
               inputPropName='jets',
               outputPropName='jetsOut',
               stageName='calibration')

    # Jet uncertainties
    # Prepare the config file
    if reduction == "All" and JEROption == "All":
        alg.uncertaintiesTool.ConfigFile = "R4_AllNuisanceParameters_AllJERNP.config"
    elif "Scenario" in reduction:
        if JEROption != "Simple":
            raise ValueError(
                "Invalid uncertainty configuration - Scenario* reductions can "
                "only be used together with the Simple JEROption")
        configFile = "R4_{0}_SimpleJER.config".format(reduction)
    elif reduction in ["Global", "Category"
                       ] and JEROption in ["Simple", "Full"]:
        configFile = "R4_{0}Reduction_{1}JER.config".format(
            reduction, JEROption)
    else:
        raise ValueError(
            "Invalid combination of reduction and JEROption settings: "
            "reduction: {0}, JEROption: {1}".format(reduction, JEROption))

    alg = createAlgorithm('CP::JetUncertaintiesAlg',
                          'JetUncertaintiesTool' + postfix)
    addPrivateTool(alg, 'uncertaintiesTool', 'JetUncertaintiesTool')
    alg.uncertaintiesTool.JetDefinition = jetCollection[:-4]
    # Add the correct directory on the front
    alg.uncertaintiesTool.ConfigFile = "rel21/Fall2018/" + configFile
    alg.uncertaintiesTool.MCType = "AFII" if dataType == "afii" else "MC16"
    alg.uncertaintiesTool.IsData = (dataType == 'data')
    seq.append(alg,
               inputPropName='jets',
               outputPropName='jetsOut',
               affectingSystematics=smallRSysts,
               stageName='calibration')

    # Set up the JVT update algorithm:
    if runJvtUpdate:
        alg = createAlgorithm('CP::JvtUpdateAlg', 'JvtUpdateAlg' + postfix)
        addPrivateTool(alg, 'jvtTool', 'JetVertexTaggerTool')
        seq.append(alg,
                   inputPropName='jets',
                   outputPropName='jetsOut',
                   stageName='selection')

    if runFJvtUpdate:
        alg = createAlgorithm('CP::JetModifierAlg', 'JetModifierAlg' + postfix)
        addPrivateTool(alg, 'modifierTool', 'JetForwardJvtTool')
        alg.modifierTool.OutputDec = "passFJVT"  #Output decoration
        # fJVT WPs depend on the MET WP
        # see https://twiki.cern.ch/twiki/bin/view/AtlasProtected/EtmissRecommendationsRel21p2#fJVT_and_MET
        alg.modifierTool.UseTightOP = 1  # 1 = Tight, 0 = Loose
        alg.modifierTool.EtaThresh = 2.5  # Eta dividing central from forward jets
        alg.modifierTool.ForwardMaxPt = 120.0e3  #Max Pt to define fwdJets for JVT
        seq.append(alg,
                   inputPropName='jets',
                   outputPropName='jetsOut',
                   stageName='selection')
        pass

    # Set up the jet efficiency scale factor calculation algorithm
    # Change the truthJetCollection property to AntiKt4TruthWZJets if preferred
    if runJvtSelection:
        alg = createAlgorithm('CP::JvtEfficiencyAlg',
                              'JvtEfficiencyAlg' + postfix)
        addPrivateTool(alg, 'efficiencyTool', 'CP::JetJvtEfficiency')
        if jetInput == 'EMPFlow':
            alg.efficiencyTool.SFFile = 'JetJvtEfficiency/Moriond2018/JvtSFFile_EMPFlow.root'
            alg.efficiencyTool.MaxPtForJvt = 60e3
        else:
            alg.efficiencyTool.SFFile = 'JetJvtEfficiency/Moriond2018/JvtSFFile_EMTopoJets.root'
            alg.efficiencyTool.MaxPtForJvt = 120e3
        alg.efficiencyTool.WorkingPoint = 'Tight' if jetInput == 'EMPFlow' else 'Medium'
        alg.selection = 'jvt_selection'
        alg.scaleFactorDecoration = 'jvt_effSF_%SYS%'
        alg.scaleFactorDecorationRegex = jvtSysts
        # Disable scale factor decorations if running on data
        # We still want to run the JVT selection
        if not runJvtEfficiency or dataType == 'data':
            alg.scaleFactorDecoration = ''
            alg.truthJetCollection = ''
        alg.outOfValidity = 2
        alg.outOfValidityDeco = 'no_jvt'
        alg.skipBadEfficiency = 0
        seq.append(alg,
                   inputPropName='jets',
                   affectingSystematics=jvtSysts,
                   stageName='selection')

    if runFJvtSelection:
        alg = createAlgorithm('CP::JvtEfficiencyAlg',
                              'ForwardJvtEfficiencyAlg')
        addPrivateTool(alg, 'efficiencyTool', 'CP::JetJvtEfficiency')
        alg.efficiencyTool.SFFile = 'JetJvtEfficiency/Moriond2018/fJvtSFFile.root'
        alg.efficiencyTool.WorkingPoint = 'Tight'
        alg.dofJVT = True
        alg.fJVTStatus = 'passFJVT,as_char'
        alg.selection = 'fjvt_selection'
        alg.scaleFactorDecoration = 'fjvt_effSF_%SYS%'
        alg.scaleFactorDecorationRegex = fjvtSysts
        # Disable scale factor decorations if running on data
        # We still want to run the JVT selection
        if not runFJvtEfficiency or dataType == 'data':
            alg.scaleFactorDecoration = ''
            alg.truthJetCollection = ''
        alg.outOfValidity = 2
        alg.outOfValidityDeco = 'no_fjvt'
        alg.skipBadEfficiency = 0
        seq.append(alg,
                   inputPropName='jets',
                   affectingSystematics=fjvtSysts,
                   stageName='selection')

    # Return the sequence:
    return seq, cutlist, cutlength
Example #9
0
def makeSequence(dataType):
    algSeq = AlgSequence()

    # Set up the systematics loader/handler algorithm:
    sysLoader = createAlgorithm('CP::SysListLoaderAlg', 'SysLoaderAlg')
    sysLoader.sigmaRecommended = 1
    algSeq += sysLoader

    # Include, and then set up the jet analysis algorithm sequence:
    from JetAnalysisAlgorithms.JetAnalysisSequence import makeJetAnalysisSequence
    jetContainer = 'AntiKt4EMPFlowJets'
    jetSequence = makeJetAnalysisSequence(dataType, jetContainer)
    jetSequence.configure(inputName=jetContainer,
                          outputName='AnalysisJets_%SYS%')

    # Add all algorithms to the job:
    algSeq += jetSequence

    # Set up a selection alg for demonstration purposes
    # Also to avoid warnings from building MET with very soft electrons
    selalg = createAlgorithm('CP::AsgSelectionAlg', 'METEleSelAlg')
    addPrivateTool(selalg, 'selectionTool', 'CP::AsgPtEtaSelectionTool')
    selalg.selectionTool.minPt = 10e3
    selalg.selectionTool.maxEta = 2.47
    selalg.selectionDecoration = 'selectPtEta'
    selalg.particles = 'Electrons'
    # We need to copy here, because w/o an output container, it's assumed
    # that the input container is non-const
    selalg.particlesOut = 'DecorElectrons_%SYS%'
    algSeq += selalg

    # Now make a view container holding only the electrons for the MET calculation
    viewalg = createAlgorithm('CP::AsgViewFromSelectionAlg', 'METEleViewAlg')
    viewalg.selection = ['selectPtEta']
    viewalg.input = 'DecorElectrons_%SYS%'
    viewalg.output = 'METElectrons_%SYS%'
    algSeq += viewalg

    # Include, and then set up the met analysis algorithm sequence:
    from MetAnalysisAlgorithms.MetAnalysisSequence import makeMetAnalysisSequence
    metSequence = makeMetAnalysisSequence(dataType,
                                          metSuffix=jetContainer[:-4])
    metSequence.configure(inputName={
        'jets': 'AnalysisJets_%SYS%',
        'muons': 'Muons',
        'electrons': 'METElectrons_%SYS%'
    },
                          outputName='AnalysisMET_%SYS%',
                          affectingSystematics={
                              'jets': jetSequence.affectingSystematics(),
                              'muons': '(^$)',
                              'electrons': '(^$)'
                          })

    # Add the sequence to the job:
    algSeq += metSequence

    # Write the freshly produced MET object(s) to an output file:
    treeMaker = createAlgorithm('CP::TreeMakerAlg', 'TreeMaker')
    treeMaker.TreeName = 'met'
    algSeq += treeMaker
    ntupleMaker = createAlgorithm('CP::AsgxAODNTupleMakerAlg', 'NTupleMaker')
    ntupleMaker.TreeName = 'met'
    ntupleMaker.Branches = [
        'EventInfo.runNumber     -> runNumber',
        'EventInfo.eventNumber   -> eventNumber',
        'AnalysisMET_%SYS%.mpx   -> met_%SYS%_mpx',
        'AnalysisMET_%SYS%.mpy   -> met_%SYS%_mpy',
        'AnalysisMET_%SYS%.sumet -> met_%SYS%_sumet',
        'AnalysisMET_%SYS%.name  -> met_%SYS%_name',
    ]
    ntupleMaker.systematicsRegex = '.*'
    algSeq += ntupleMaker
    treeFiller = createAlgorithm('CP::TreeFillerAlg', 'TreeFiller')
    treeFiller.TreeName = 'met'
    algSeq += treeFiller

    return algSeq
Example #10
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
Example #11
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
ROOT.SH.ScanDir().filePattern('DAOD_PHYS.21569875._001323.pool.root.1').scan(
    sh, inputFilePath)
sh.printContent()

# Create an EventLoop job.
job = ROOT.EL.Job()
job.sampleHandler(sh)
job.options().setDouble(ROOT.EL.Job.optMaxEvents, 500)
job.options().setString(ROOT.EL.Job.optSubmitDirMode, 'unique-link')

# Create the algorithm's configuration.
from AnaAlgorithm.DualUseConfig import createAlgorithm
from AnaAlgorithm.DualUseConfig import addPrivateTool

alg = createAlgorithm('MyxAODAnalysis', 'AnalysisAlg')
addPrivateTool(alg, 'grlTool', 'GoodRunsListSelectionTool')

# configure the properties of the GRL tool
fullGRLFilePath = os.getenv(
    "ALRB_TutorialData"
) + "/data16_13TeV.periodAllYear_DetStatus-v89-pro21-01_DQDefects-00-02-04_PHYS_StandardGRL_All_Good_25ns.xml"
alg.grlTool.GoodRunsListVec = [fullGRLFilePath]
alg.grlTool.PassThrough = 0  # if true (default) will ignore result of GRL and will just pass all events

# later on we'll add some configuration options for our algorithm that go here
alg.ElectronPtCut = 30000.0
alg.SampleName = 'Zee'

# Add our algorithm to the job
job.algsAdd(alg)
Example #13
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
Example #14
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
Example #15
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