Skip to content
Snippets Groups Projects
  • Nils Krumnack's avatar
    c028e73e
    copy over PhysicsAnalysis/Algorithms from 21.2 · c028e73e
    Nils Krumnack authored
    Originally I had tried sweeping/cherry-picking this from 21.2, but
    with all the three-way merges and commits that involve other
    packages/directories that was rather painful, so this is now just a
    direct copy from the current state in 21.2.
    c028e73e
    History
    copy over PhysicsAnalysis/Algorithms from 21.2
    Nils Krumnack authored
    Originally I had tried sweeping/cherry-picking this from 21.2, but
    with all the three-way merges and commits that involve other
    packages/directories that was rather painful, so this is now just a
    direct copy from the current state in 21.2.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
PhotonAnalysisSequence.py 9.66 KiB
# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration

# Framework import(s):
import ROOT

# AnaAlgorithm import(s):
from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence
from AnaAlgorithm.DualUseConfig import createAlgorithm, addPrivateTool

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 = ROOT.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