As a first exercise let us get set up to implement our CP algorithms, we
suggest creating a new algorithm like we did in the
beginner’s tutorial. A skeleton algorithm can be found
/afs/cern.ch/work/a/aparker/public/AlgorithmSkeleton/source that you can
copy across to your working area. As it was mentioned earlier, there are
example/test jobs for all object types, but for this tutorial we’ll focus mostly on the muons.
The idea of the common CP algorithms is to use a ready made selection sequence for each object that would be used in an analysis. This means consistency between analysis frameworks and also using ‘good’ objects. However, the sequence can be configured differently for tests and the needs of the analysis.
For example, a snippet of the muon analysis sequence is shown below, take your time to read each part and figure out what is happening. The full file can be found HERE
# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration # AnaAlgorithm import(s): from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence from AnaAlgorithm.DualUseConfig import createAlgorithm, addPrivateTool import ROOT def makeMuonAnalysisSequence( dataType, workingPoint, deepCopyOutput = False, shallowViewOutput = True, postfix = '', ptSelectionOutput = 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. """ if not dataType 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 if splitWP == 'Tight' : quality = ROOT.xAOD.Muon.Tight pass elif splitWP == 'Medium' : quality = ROOT.xAOD.Muon.Medium pass elif splitWP == 'Loose' : quality = ROOT.xAOD.Muon.Loose pass elif splitWP == 'VeryLoose' : quality = ROOT.xAOD.Muon.VeryLoose pass elif splitWP == 'HighPt' : quality = 4 pass elif splitWP == 'LowPtEfficiency' : quality = 5 pass else : raise ValueError ("invalid muon quality: \"" + splitWP + "\", allowed values are Tight, Medium, Loose, " + "VeryLoose, HighPt, LowPtEfficiency") if not splitWP in ["Iso", "NonIso"] : raise ValueError ('invalid muon isolation \"' + splitWP + '\", allowed values are Iso, NonIso') # Create the analysis algorithm sequence object: seq = AnaAlgSequence( "MuonAnalysisSequence" + postfix ) # Variables keeping track of the selections being applied. selectionDecorNames =  selectionDecorCount =  # Set up the eta-cut on all muons prior to everything else alg = createAlgorithm( 'CP::AsgSelectionAlg', 'MuonEtaCutAlg' + postfix ) alg.preselection = "&&".join (selectionDecorNames) 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' ) selectionDecorNames.append( alg.selectionDecoration ) selectionDecorCount.append( 2 ) # Set up the track selection algorithm: alg = createAlgorithm( 'CP::AsgLeptonTrackSelectionAlg', 'MuonTrackSelectionAlg' + postfix ) alg.preselection = "&&".join (selectionDecorNames) alg.selectionDecoration = 'trackSelection' + postfix + ',as_bits' alg.maxD0Significance = 3 alg.maxDeltaZ0SinTheta = 0.5 seq.append( alg, inputPropName = 'particles', stageName = 'selection' ) selectionDecorNames.append( alg.selectionDecoration ) selectionDecorCount.append( 3 ) ... # Set up the the pt selection ptSelectionDecoration = 'selectPt' + postfix + ',as_bits' alg = createAlgorithm( 'CP::AsgSelectionAlg', 'MuonPtCutAlg' + postfix ) alg.preselection = "&&".join (selectionDecorNames) alg.selectionDecoration = ptSelectionDecoration addPrivateTool( alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool' ) alg.selectionTool.minPt = 3e3 seq.append( alg, inputPropName = 'particles', stageName = 'selection' ) selectionDecorNames.append( alg.selectionDecoration ) selectionDecorCount.append( 2 ) ... ... # Set up an algorithm dumping the properties of the muons, for debugging: alg = createAlgorithm( 'CP::KinematicHistAlg', 'MuonKinematicDumperAlg' + postfix ) alg.histPattern = 'muon' + postfix + '_%VAR%_%SYS%' seq.append( alg, inputPropName = 'input', stageName = 'selection' ) ... # Return the sequence: return seq
Do not worry if this is a little confusing; even though we are implementing a very simple example of the common CP algorithms, some things may appear complicated for a beginner. Hopefully they become clearer as you go along.
Some things to note here:
This file is designed to describe the algorithm chain all muons in your analysis should follow.
The algorithm itself can be configured later with the
postfix string to make sure different configurations are unique.
Some parts of this algorithm setup are just examples of good practice and aren’t strictly necessary (but you should still follow)