diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/PhotonEfficiencyCorrectionAlg.h b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/PhotonEfficiencyCorrectionAlg.h index 9603550541dd93c57b0e66182765791915b2a10a..f2a9ef7f13bef524327a8d0447f7741927ae1c10 100644 --- a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/PhotonEfficiencyCorrectionAlg.h +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/PhotonEfficiencyCorrectionAlg.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration */ /// @author Nils Krumnack @@ -12,10 +12,10 @@ #include <AnaAlgorithm/AnaAlgorithm.h> #include <EgammaAnalysisInterfaces/IAsgPhotonEfficiencyCorrectionTool.h> #include <SelectionHelpers/OutOfValidityHelper.h> -#include <SystematicsHandles/SysCopyHandle.h> #include <SelectionHelpers/SysReadSelectionHandle.h> #include <SystematicsHandles/SysListHandle.h> #include <SystematicsHandles/SysReadHandle.h> +#include <SystematicsHandles/SysWriteDecorHandle.h> namespace CP { @@ -47,7 +47,7 @@ namespace CP /// \brief the photon collection we run on private: - SysCopyHandle<xAOD::PhotonContainer> m_photonHandle { + SysReadHandle<xAOD::PhotonContainer> m_photonHandle { this, "photons", "Photons", "the photon collection to run on"}; /// \brief the preselection we apply to our input @@ -61,11 +61,8 @@ namespace CP /// \brief the decoration for the photon scale factor private: - std::string m_scaleFactorDecoration; - - /// \brief the accessor for \ref m_scaleFactorDecoration - private: - std::unique_ptr<const SG::AuxElement::Accessor<float> > m_scaleFactorAccessor; + SysWriteDecorHandle<float> m_scaleFactorDecoration { + this, "scaleFactorDecoration", "", "the decoration for the photon efficiency scale factor"}; }; } diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/PhotonEfficiencyCorrectionAlg.cxx b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/PhotonEfficiencyCorrectionAlg.cxx index 81b1c7684cff871dafa1d4c367ad5fadba87f742..d75697652fd19fbf1f73f24df0f40eb389f8328f 100644 --- a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/PhotonEfficiencyCorrectionAlg.cxx +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/PhotonEfficiencyCorrectionAlg.cxx @@ -1,5 +1,5 @@ /* - Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration */ /// @author Nils Krumnack @@ -24,8 +24,7 @@ namespace CP : AnaAlgorithm (name, pSvcLocator) , m_efficiencyCorrectionTool ("AsgPhotonEfficiencyCorrectionTool", this) { - declareProperty ("efficiencyCorrectionTool", m_efficiencyCorrectionTool, "the calibration and smearing tool we apply"); - declareProperty ("scaleFactorDecoration", m_scaleFactorDecoration, "the decoration for the photon scale factor"); + declareProperty ("efficiencyCorrectionTool", m_efficiencyCorrectionTool, "the efficiency correction tool we apply"); } @@ -38,14 +37,15 @@ namespace CP ANA_MSG_ERROR ("no scale factor decoration name set"); return StatusCode::FAILURE; } - m_scaleFactorAccessor = std::make_unique<SG::AuxElement::Accessor<float> > (m_scaleFactorDecoration); ANA_CHECK (m_efficiencyCorrectionTool.retrieve()); ANA_CHECK (m_photonHandle.initialize (m_systematicsList)); ANA_CHECK (m_preselection.initialize (m_systematicsList, m_photonHandle, SG::AllowEmpty)); + ANA_CHECK (m_scaleFactorDecoration.initialize(m_systematicsList, m_photonHandle)); ANA_CHECK (m_systematicsList.addSystematics (*m_efficiencyCorrectionTool)); ANA_CHECK (m_systematicsList.initialize()); ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; } @@ -57,15 +57,17 @@ namespace CP for (const auto& sys : m_systematicsList.systematicsVector()) { ANA_CHECK (m_efficiencyCorrectionTool->applySystematicVariation (sys)); - xAOD::PhotonContainer *photons = nullptr; - ANA_CHECK (m_photonHandle.getCopy (photons, sys)); - for (xAOD::Photon *photon : *photons) + const xAOD::PhotonContainer *photons = nullptr; + ANA_CHECK (m_photonHandle.retrieve (photons, sys)); + for (const xAOD::Photon *photon : *photons) { if (m_preselection.getBool (*photon, sys)) { double sf = 0; ANA_CHECK_CORRECTION (m_outOfValidity, *photon, m_efficiencyCorrectionTool->getEfficiencyScaleFactor (*photon, sf)); - (*m_scaleFactorAccessor) (*photon) = sf; + m_scaleFactorDecoration.set (*photon, sf, sys); + } else { + m_scaleFactorDecoration.set (*photon, invalidScaleFactor(), sys); } } } diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/EgammaAnalysisAlgorithmsTest.py b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/EgammaAnalysisAlgorithmsTest.py index 8be90d6c4cc15105d9fa73b54d30a965fa499cb3..a07177388a4f0d1a499071c9912f441839656800 100644 --- a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/EgammaAnalysisAlgorithmsTest.py +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/EgammaAnalysisAlgorithmsTest.py @@ -41,7 +41,7 @@ def makeSequence (dataType, likelihood=True) : from EgammaAnalysisAlgorithms.PhotonAnalysisSequence import \ makePhotonAnalysisSequence photonSequence = makePhotonAnalysisSequence( dataType, 'Tight.FixedCutTight', postfix = 'tight', - recomputeIsEM=True, enableCutflow=True, enableKinematicHistograms=True ) + recomputeIsEM=True, enableCleaning=False, enableCutflow=True, enableKinematicHistograms=True ) photonSequence.configure( inputName = 'Photons', outputName = 'AnalysisPhotons_%SYS%' ) algSeq += photonSequence diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/PhotonAnalysisSequence.py b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/PhotonAnalysisSequence.py index 1a75951b18c18072be00815f6cb625249aebdd07..ea77aac70f35b8817997fb4a887dedc342831464 100644 --- a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/PhotonAnalysisSequence.py +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/PhotonAnalysisSequence.py @@ -12,7 +12,11 @@ def makePhotonAnalysisSequence( dataType, workingPoint, deepCopyOutput = False, shallowViewOutput = True, postfix = '', + crackVeto = False, + enableCleaning = True, + cleaningAllowLate = False, recomputeIsEM = False, + ptSelectionOutput = False, enableCutflow = False, enableKinematicHistograms = False ): """Create a photon analysis algorithm sequence @@ -28,7 +32,12 @@ def makePhotonAnalysisSequence( dataType, workingPoint, names. this is mostly used/needed when using this sequence with multiple working points to ensure all names are unique. + crackVeto -- Whether or not to perform eta crack veto + enableCleaning -- Enable photon cleaning + cleaningAllowLate -- Whether to ignore timing information in cleaning. recomputeIsEM -- Whether to rerun the cut-based selection. If not, use derivation flags + 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 """ @@ -48,9 +57,13 @@ def makePhotonAnalysisSequence( dataType, workingPoint, seq.addMetaConfigDefault ("selectionDecorNamesOutput", []) seq.addMetaConfigDefault ("selectionDecorCount", []) - makePhotonCalibrationSequence (seq, dataType, postfix=postfix) - makePhotonWorkingPointSequence (seq, dataType, workingPoint, postfix=postfix, - recomputeIsEM = recomputeIsEM) + makePhotonCalibrationSequence (seq, dataType, postfix = postfix, + crackVeto = crackVeto, + enableCleaning = enableCleaning, cleaningAllowLate = cleaningAllowLate, + recomputeIsEM = recomputeIsEM, + ptSelectionOutput = ptSelectionOutput) + makePhotonWorkingPointSequence (seq, dataType, workingPoint, postfix = postfix, + recomputeIsEM = recomputeIsEM ) makeSharedObjectSequence (seq, deepCopyOutput = deepCopyOutput, shallowViewOutput = shallowViewOutput, postfix = '_Photon' + postfix, @@ -65,7 +78,12 @@ def makePhotonAnalysisSequence( dataType, workingPoint, def makePhotonCalibrationSequence( seq, dataType, - postfix = ''): + postfix = '', + crackVeto = False, + enableCleaning = True, + cleaningAllowLate = False, + recomputeIsEM = False, + ptSelectionOutput = False ): """Create photon calibration analysis algorithms This makes all the algorithms that need to be run first befor @@ -78,25 +96,77 @@ def makePhotonCalibrationSequence( seq, dataType, names. this is mostly used/needed when using this sequence with multiple working points to ensure all names are unique. + crackVeto -- Whether or not to perform eta crack veto + enableCleaning -- Enable photon cleaning + cleaningAllowLate -- Whether to ignore timing information in cleaning. + recomputeIsEM -- Whether to rerun the cut-based selection. If not, use derivation flags + ptSelectionOutput -- Whether or not to apply pt selection when creating + output containers. """ # Make sure we received a valid data type. if dataType not in [ 'data', 'mc', 'afii' ]: raise ValueError( 'Invalid data type: %s' % dataType ) - # Select electrons only with good object quality. + cleaningWP = 'NoTime' if cleaningAllowLate else '' + + # Set up the eta-cut on all photons prior to everything else + alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonEtaCutAlg' + postfix ) + alg.selectionDecoration = 'selectEta' + postfix + ',as_bits' + addPrivateTool( alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool' ) + alg.selectionTool.maxEta = 2.37 + 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', + metaConfig = {'selectionDecorNames' : [alg.selectionDecoration], + 'selectionDecorNamesOutput' : [alg.selectionDecoration], + 'selectionDecorCount' : [5 if crackVeto else 4]}, + dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} ) + + # Setup shower shape fudge + if recomputeIsEM and dataType == 'mc': + alg = createAlgorithm( 'CP::PhotonShowerShapeFudgeAlg', + 'PhotonShowerShapeFudgeAlg' + postfix ) + addPrivateTool( alg, 'showerShapeFudgeTool', + 'ElectronPhotonShowerShapeFudgeTool' ) + alg.showerShapeFudgeTool.Preselection = 22 # Rel 21 + alg.showerShapeFudgeTool.FFCalibFile = \ + 'ElectronPhotonShowerShapeFudgeTool/v2/PhotonFudgeFactors.root' # only for rel21 + seq.append( alg, inputPropName = 'photons', outputPropName = 'photonsOut', + stageName = 'calibration', + dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} ) + pass + + # Select photons only with good object quality. alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonObjectQualityAlg' + postfix ) - alg.selectionDecoration = 'goodOQ' + alg.selectionDecoration = 'goodOQ,as_bits' addPrivateTool( alg, 'selectionTool', 'CP::EgammaIsGoodOQSelectionTool' ) alg.selectionTool.Mask = ROOT.xAOD.EgammaParameters.BADCLUSPHOTON - seq.append( alg, inputPropName = 'particles', outputPropName = 'particlesOut', + seq.append( alg, inputPropName = 'particles', stageName = 'calibration', metaConfig = {'selectionDecorNames' : [alg.selectionDecoration], 'selectionDecorNamesOutput' : [alg.selectionDecoration], 'selectionDecorCount' : [1]}, dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} ) - # Set up the calibration ans smearing algorithm. + # Select clean photons + if enableCleaning: + alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonCleaningAlg' + postfix) + addPrivateTool( alg, 'selectionTool', 'CP::AsgFlagSelectionTool' ) + alg.selectionDecoration = 'isClean,as_bits' + alg.selectionTool.selectionFlags = ['DFCommonPhotonsCleaning' + cleaningWP] + seq.append( alg, inputPropName = 'particles', + stageName = 'calibration', + metaConfig = {'selectionDecorNames' : [alg.selectionDecoration], + 'selectionDecorNamesOutput' : [alg.selectionDecoration], + 'selectionDecorCount' : [1]}, + dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} ) + + # Do calibration alg = createAlgorithm( 'CP::EgammaCalibrationAndSmearingAlg', 'PhotonCalibrationAndSmearingAlg' + postfix ) addPrivateTool( alg, 'calibrationAndSmearingTool', @@ -112,16 +182,17 @@ def makePhotonCalibrationSequence( seq, dataType, stageName = 'calibration', dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} ) - # should this be applied to data? or to AFII? - alg = createAlgorithm( 'CP::PhotonShowerShapeFudgeAlg', - 'PhotonShowerShapeFudgeAlg' + postfix ) - addPrivateTool( alg, 'showerShapeFudgeTool', - 'ElectronPhotonShowerShapeFudgeTool' ) - alg.showerShapeFudgeTool.Preselection = 22 # Rel 21 - alg.showerShapeFudgeTool.FFCalibFile = \ - 'ElectronPhotonShowerShapeFudgeTool/v2/PhotonFudgeFactors.root' #only for rel21 - seq.append( alg, inputPropName = 'photons', outputPropName = 'photonsOut', - stageName = 'calibration' ) + # Set up the the pt selection + alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonPtCutAlg' + postfix ) + alg.selectionDecoration = 'selectPt' + postfix + ',as_bits' + addPrivateTool( alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool' ) + alg.selectionTool.minPt = 10e3 + 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"])} ) # Set up the isolation correction algorithm. alg = createAlgorithm( 'CP::EgammaIsolationCorrectionAlg', @@ -143,7 +214,7 @@ def makePhotonCalibrationSequence( seq, dataType, def makePhotonWorkingPointSequence( seq, dataType, workingPoint, postfix = '', - recomputeIsEM = False): + recomputeIsEM = False ): """Create photon analysis algorithms for a single working point Keywrod arguments: @@ -178,7 +249,7 @@ def makePhotonWorkingPointSequence( seq, dataType, workingPoint, postfix = '', # Set up the photon selection algorithm: alg = createAlgorithm( 'CP::AsgSelectionAlg', 'PhotonIsEMSelectorAlg' + postfix ) - alg.selectionDecoration = 'selectEM' + alg.selectionDecoration = 'selectEM,as_bits' if recomputeIsEM: # Rerun the cut-based ID addPrivateTool( alg, 'selectionTool', 'AsgPhotonIsEMSelector' ) @@ -192,7 +263,6 @@ def makePhotonWorkingPointSequence( seq, dataType, workingPoint, postfix = '', alg.selectionTool.selectionFlags = [ dfFlag ] pass seq.append( alg, inputPropName = 'particles', - outputPropName = 'particlesOut', stageName = 'calibration', metaConfig = {'selectionDecorNames' : [alg.selectionDecoration], 'selectionDecorNamesOutput' : [alg.selectionDecoration], @@ -200,12 +270,26 @@ def makePhotonWorkingPointSequence( seq, dataType, workingPoint, postfix = '', dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} ) # 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', + if isolationWP != 'NonIso' : + alg = createAlgorithm( 'CP::EgammaIsolationSelectionAlg', + 'PhotonIsolationSelectionAlg' + postfix ) + alg.selectionDecoration = 'isolated' + postfix + ',as_bits' + addPrivateTool( alg, 'selectionTool', 'CP::IsolationSelectionTool' ) + alg.selectionTool.PhotonWP = isolationWP + seq.append( alg, inputPropName = 'egammas', + stageName = 'selection', + metaConfig = {'selectionDecorNames' : [alg.selectionDecoration], + 'selectionDecorNamesOutput' : [alg.selectionDecoration], + 'selectionDecorCount' : [1]}, + dynConfig = {'preselection' : lambda meta : "&&".join (meta["selectionDecorNames"])} ) + pass + + # Set up an algorithm used for decorating baseline photon selection: + alg = createAlgorithm( 'CP::AsgSelectionAlg', + 'PhotonSelectionSummary' + postfix ) + addPrivateTool( alg, 'selectionTool', 'CP::AsgFlagSelectionTool' ) + alg.selectionDecoration = 'baselineSelection' + postfix + ',as_char' + seq.append( alg, inputPropName = 'particles', stageName = 'selection', metaConfig = {'selectionDecorNames' : [alg.selectionDecoration], 'selectionDecorNamesOutput' : [alg.selectionDecoration], @@ -217,9 +301,7 @@ def makePhotonWorkingPointSequence( seq, dataType, workingPoint, postfix = '', 'PhotonEfficiencyCorrectionAlg' + postfix ) addPrivateTool( alg, 'efficiencyCorrectionTool', 'AsgPhotonEfficiencyCorrectionTool' ) - alg.scaleFactorDecoration = 'effSF' + postfix - alg.efficiencyCorrectionTool.MapFilePath = \ - 'PhotonEfficiencyCorrection/2015_2017/rel21.2/Winter2018_Prerec_v1/map0.txt' + alg.scaleFactorDecoration = 'ph_effSF' + postfix + '_%SYS%' if dataType == 'afii': alg.efficiencyCorrectionTool.ForceDataType = \ ROOT.PATCore.ParticleDataType.Fast @@ -231,7 +313,6 @@ def makePhotonWorkingPointSequence( seq, dataType, workingPoint, postfix = '', alg.outOfValidityDeco = 'bad_eff' + postfix if dataType != 'data': seq.append( alg, inputPropName = 'photons', - outputPropName = 'photonsOut', stageName = 'efficiency', metaConfig = {'selectionDecorNames' : [alg.outOfValidityDeco], 'selectionDecorNamesOutput' : [alg.outOfValidityDeco],