diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithmsDict.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithmsDict.h new file mode 100644 index 0000000000000000000000000000000000000000..4a4318995cb2168c360ec4e132266ac6f86326d3 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithmsDict.h @@ -0,0 +1,33 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef ASG_ANALYSIS_ALGORITHMS__ASG_ANALYSIS_ALGORITHMS_DICT_H +#define ASG_ANALYSIS_ALGORITHMS__ASG_ANALYSIS_ALGORITHMS_DICT_H + +#include <AsgAnalysisAlgorithms/AsgFlagSelectionTool.h> +#include <AsgAnalysisAlgorithms/AsgPtEtaSelectionTool.h> +#include <AsgAnalysisAlgorithms/AsgCutBookkeeperAlg.h> +#include <AsgAnalysisAlgorithms/AsgEventScaleFactorAlg.h> +#include <AsgAnalysisAlgorithms/AsgLeptonTrackSelectionAlg.h> +#include <AsgAnalysisAlgorithms/AsgOriginalObjectLinkAlg.h> +#include <AsgAnalysisAlgorithms/AsgSelectionAlg.h> +#include <AsgAnalysisAlgorithms/AsgViewFromSelectionAlg.h> +#include <AsgAnalysisAlgorithms/AsgxAODNTupleMakerAlg.h> +#include <AsgAnalysisAlgorithms/EventFlagSelectionAlg.h> +#include <AsgAnalysisAlgorithms/EventSelectionByObjectFlagAlg.h> +#include <AsgAnalysisAlgorithms/IsolationCloseByCorrectionAlg.h> +#include <AsgAnalysisAlgorithms/KinematicHistAlg.h> +#include <AsgAnalysisAlgorithms/ObjectCutFlowHistAlg.h> +#include <AsgAnalysisAlgorithms/OverlapRemovalAlg.h> +#include <AsgAnalysisAlgorithms/PileupReweightingAlg.h> +#include <AsgAnalysisAlgorithms/PMGTruthWeightAlg.h> +#include <AsgAnalysisAlgorithms/SysListDumperAlg.h> +#include <AsgAnalysisAlgorithms/SysListLoaderAlg.h> +#include <AsgAnalysisAlgorithms/TreeFillerAlg.h> +#include <AsgAnalysisAlgorithms/TreeMakerAlg.h> + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgCutBookkeeperAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgCutBookkeeperAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..037aa61a2846f7ef7bcdbb03bc4596d3282fa9a4 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgCutBookkeeperAlg.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +#ifndef ASG_ANALYSIS_ALGORITHMS__ASG_CUT_BOOKKEEPER_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__ASG_CUT_BOOKKEEPER_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <PMGAnalysisInterfaces/IPMGTruthWeightTool.h> + +namespace CP +{ + /// \brief an algorithm for dumping the CutBookkeeper metadata + /// into a histogram + + class AsgCutBookkeeperAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + AsgCutBookkeeperAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + public: + /// \brief initialize + StatusCode initialize () override; + + public: + /// \brief run once on each file + StatusCode fileExecute () override; + + public: + /// \brief finalize + StatusCode finalize () override; + + /// \brief flag to enable systematics + private: + bool m_enableSystematics{false}; + + /// \brief the truth weight tool + private: + ToolHandle<PMGTools::IPMGTruthWeightTool> m_truthWeightTool; + + /// \brief run number we are processing + private: + uint32_t m_runNumber {}; + + /// \brief MC channel number we are processing + private: + uint32_t m_mcChannelNumber {}; + + /// \brief weights helper struct + private: + struct WeightsGroup + { + float nEventsProcessed {}; + float sumOfWeights {}; + float sumOfWeightsSquared {}; + }; + + /// \brief weights map + private: + std::unordered_map<size_t, WeightsGroup> m_weights; + + /// \brief the pattern for histogram names + private: + std::string m_histPattern {"CutBookkeeper_%DSID%_%RUN%_%SYS%"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgEventScaleFactorAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgEventScaleFactorAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..9d856927f482199795c8075226b73ca85a5aebdc --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgEventScaleFactorAlg.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +#ifndef ASG_ANALYSIS_ALGORITHMS__ASG_EVENT_SCALE_FACTOR_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__ASG_EVENT_SCALE_FACTOR_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysDecorationHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODBase/IParticleContainer.h> +#include <xAODEventInfo/EventInfo.h> + +namespace CP +{ + /// \brief an algorithm for calculating per-event scale factors + + class AsgEventScaleFactorAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + AsgEventScaleFactorAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the event info we run on (empty by default) + private: + SysCopyHandle<xAOD::EventInfo> m_eventInfoHandle { + this, "eventInfo", "EventInfo", "the event info object to run on"}; + + /// \brief the jet collection we run on + private: + SysCopyHandle<xAOD::IParticleContainer> m_particleHandle { + this, "particles", "", "the particle collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the decoration for reading the scale factor + private: + SysDecorationHandle<float> m_scaleFactorInputDecoration { + this, "scaleFactorInputDecoration", "", "the decoration for the input efficiency scale factor"}; + + /// \brief the decoration for writing the scale factor + private: + SysDecorationHandle<float> m_scaleFactorOutputDecoration { + this, "scaleFactorOutputDecoration", "", "the decoration for the output efficiency scale factor"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgFlagSelectionTool.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgFlagSelectionTool.h new file mode 100644 index 0000000000000000000000000000000000000000..77eb764d24a38526627dc00dd82a5ff8cc050ba6 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgFlagSelectionTool.h @@ -0,0 +1,89 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + */ + +/// @author Teng Jian Khoo + + + +#ifndef ASG_ANALYSIS_ALGORITHMS__ASG_FLAG_SELECTION_TOOL_H +#define ASG_ANALYSIS_ALGORITHMS__ASG_FLAG_SELECTION_TOOL_H + +#include <AsgTools/AsgTool.h> +#include <PATCore/IAsgSelectionTool.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <xAODBase/IParticle.h> +#include <memory> +#include <string> +#include <vector> + +namespace CP +{ + /// \brief an \ref IAsgSelectionTool that cuts on char decorations + /// + /// For ROOT I/O reasons, chars are commonly used to store boolean + /// properties, such as flags indicating whether particular criteria + /// have been passed. This tool provides a conversion of a list + /// of such decorations, interpreted as bools, into the SelectionType + /// encoding of TAccept, for use in AnaAlgSequence. + /// + /// A list of flags may be provided to the tool, and the output will + /// simply concatenate them into the TAccept. Each selection criterion + /// must be passed (no OR behaviour), but the flag logic may be + /// inverted, such that flags may be encoded as "passX" or !"failX". + + class AsgFlagSelectionTool final + : public asg::AsgTool, virtual public IAsgSelectionTool + { + // + // public interface + // + + // Create a proper constructor for Athena + ASG_TOOL_CLASS( AsgFlagSelectionTool, IAsgSelectionTool ) + + + /// \brief standard constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + public: + AsgFlagSelectionTool (const std::string& name); + + + + + // + // inherited interface + // + + virtual StatusCode initialize () override; + + virtual const Root::TAccept& getTAccept( ) const override; + + virtual const Root::TAccept& accept( const xAOD::IParticle* /*part*/ ) const override; + + + + // + // private interface + // + + /// tool properties + /// \{ + + std::vector<std::string> m_selFlags; + std::vector<bool> m_invertFlags; + std::vector<std::unique_ptr<ISelectionAccessor> > m_acc_selFlags; + + /// \} + + + /// \brief the \ref TAccept we are using + private: + mutable Root::TAccept m_accept; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgLeptonTrackSelectionAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgLeptonTrackSelectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..db25eee5813c6371294fc41a4518c4ceedc4f22d --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgLeptonTrackSelectionAlg.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef ASG_ANALYSIS_ALGORITHMS__ASG_LEPTON_TRACK_SELECTION_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__ASG_LEPTON_TRACK_SELECTION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <PATCore/IAsgSelectionTool.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for performing track-vertex selection on + /// leptons + /// + /// Originally I meant to implement this as an \ref + /// IAsgSelectionTool, but since this needs other objects besides + /// the lepton itself, I made it into an algorithm. Technically + /// this could also be addressed by retrieving those extra objects + /// in the seleciton tool, but this seemed like potential overkill, + /// given that the selection tools may be called very frequently and + /// are not really doing any form of heavy lifting at all. Still, + /// at some point we may decide to change this into a selection tool + /// instead (06 Aug 18). + + class AsgLeptonTrackSelectionAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + AsgLeptonTrackSelectionAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + /// algorithm properties + /// \{ + + private: + float m_maxD0Significance {0}; + float m_maxDeltaZ0SinTheta {0}; + int m_nMinPixelHits{-1}; + int m_nMaxPixelHits{-1}; + int m_nMinSCTHits{-1}; + int m_nMaxSCTHits{-1}; + std::string m_selectionDecoration {"trackSelection"}; + std::string m_eventInfo {"EventInfo"}; + std::string m_primaryVertices {"PrimaryVertices"}; + + /// \} + + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the particle continer we run on + private: + SysCopyHandle<xAOD::IParticleContainer> m_particlesHandle { + this, "particles", "", "the asg collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the accessor for \ref m_selectionDecoration + private: + std::unique_ptr<ISelectionAccessor> m_selectionAccessor; + + + /// \brief the \ref TAccept we are using + private: + Root::TAccept m_accept; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgOriginalObjectLinkAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgOriginalObjectLinkAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..a69f19ca7f2ac8f91fae573ef566a19fdf8ace69 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgOriginalObjectLinkAlg.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +#ifndef ASG_ANALYSIS_ALGORITHMS__ASG_ORIGINAL_OBJECT_LINK_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__ASG_ORIGINAL_OBJECT_LINK_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODBase/IParticleContainer.h> + + +namespace CP +{ + /// \brief an algorithm for relinking a shallow copy with it's base container + /// when this was not done originally + /// + /// In some cases we work with shallow copy containers that originally did + /// not have proper original object linking done when created. + /// Currently the client are b-tagging calibration shallow copies. + + class AsgOriginalObjectLinkAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + AsgOriginalObjectLinkAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + /// \brief base container name + private: + std::string m_baseContainerName {""}; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the particle container we run on + private: + SysCopyHandle<xAOD::IParticleContainer> m_particleHandle { + this, "particles", "", "the particle container to run on"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgPtEtaSelectionTool.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgPtEtaSelectionTool.h new file mode 100644 index 0000000000000000000000000000000000000000..f1cd65e237c9b906dc8dc06e0c3419fb5a926445 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgPtEtaSelectionTool.h @@ -0,0 +1,130 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef ASG_ANALYSIS_ALGORITHMS__ASG_PT_ETA_SELECTION_TOOL_H +#define ASG_ANALYSIS_ALGORITHMS__ASG_PT_ETA_SELECTION_TOOL_H + +#include <AsgTools/AsgTool.h> +#include <PATCore/IAsgSelectionTool.h> +#include <atomic> + +namespace CP +{ + /// \brief an \ref IAsgSelectionTool that performs basic pt and eta + /// cut (with an optional eta gap) + /// + /// This is a very basic selection that needs to happen on all + /// object types to some degree. Instead of doing this separately + /// for each type, it is just one basic tool for all \ref IParticle + /// implementations. Also, this is a tool, not an algorithm, + /// because we already have an algorithm wrapping generic selection + /// tools and there is no benefit to making it an algorithm. + /// + /// There may be some overlap with the individual selectors for the + /// given object types, but having a tool for this allows to apply + /// it at any point in the algorithm sequence. + + class AsgPtEtaSelectionTool final + : public asg::AsgTool, virtual public IAsgSelectionTool + { + // + // public interface + // + + // Create a proper constructor for Athena + ASG_TOOL_CLASS( AsgPtEtaSelectionTool, IAsgSelectionTool ) + + + /// \brief standard constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + public: + AsgPtEtaSelectionTool (const std::string& name); + + + + + // + // inherited interface + // + + virtual StatusCode initialize () override; + + virtual const Root::TAccept& getTAccept( ) const override; + + virtual const Root::TAccept& accept( const xAOD::IParticle* /*part*/ ) const override; + + + + // + // private interface + // + + /// tool properties + /// \{ + + private: + float m_minPt {0}; + float m_maxPt {0}; + float m_maxEta {0}; + float m_etaGapLow {0}; + float m_etaGapHigh {0}; + bool m_useClusterEta {false}; + bool m_printCastWarning {true}; + bool m_printClusterWarning {true}; + + /// \} + + /// Index for the minimum pT selection + int m_minPtCutIndex{ -1 }; + /// Index for the maximum pT selection + int m_maxPtCutIndex{ -1 }; + /// Index for the maximum eta selection + int m_maxEtaCutIndex{ -1 }; + /// Index for the eta gap selection + int m_etaGapCutIndex{ -1 }; + /// Index for the e/gamma casting + int m_egammaCastCutIndex{ -1 }; + /// Index for the e/gamma calo-cluster + int m_egammaClusterCutIndex{ -1 }; + + /// \brief a version of \ref m_printCastWarning that we modify + /// once we printed the warning + /// + /// I don't like modifying property values in the tool itself, so + /// I copy it over here and then modify once I print out. + /// + /// Technically this tool isn't thread-safe due to the use of + /// TAccept, but once we move to master this will be fixed, so + /// this member is already made thread-safe so that we don't trip + /// up on that later. + private: + mutable std::atomic<bool> m_shouldPrintCastWarning {true}; + + /// \brief a version of \ref m_printClusterWarning that we modify + /// once we printed the warning + /// + /// I don't like modifying property values in the tool itself, so + /// I copy it over here and then modify once I print out. + /// + /// Technically this tool isn't thread-safe due to the use of + /// TAccept, but once we move to master this will be fixed, so + /// this member is already made thread-safe so that we don't trip + /// up on that later. + private: + mutable std::atomic<bool> m_shouldPrintClusterWarning {true}; + + /// \brief the \ref TAccept we are using + private: + mutable Root::TAccept m_accept; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgSelectionAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgSelectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..5af9efe89ae17fd821b103f74e9357444af8b3b2 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgSelectionAlg.h @@ -0,0 +1,98 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef ASG_ANALYSIS_ALGORITHMS__ASG_SELECTION_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__ASG_SELECTION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <PATCore/IAsgSelectionTool.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IAsgSelectionTool + /// + /// There are two ways to implement this: The way I chose is to call + /// the IAsgSelectionTool on the members of an IParticleContainer. + /// Among several issues this has some inefficiencies, because it + /// relies on dynamic_cast inside the IAsgSelectionTool. Also, + /// currently \ref CopyHandle only supports specific xAOD types for + /// IParticleContainer (though in practice this only matters if + /// systematics are applied in this algorithm). + /// + /// The alternative would be to implement this as a template, with + /// one template argument for the tool interface type and a second + /// template argument for the container type to run on. Besides + /// improving some of the efficiences, it would also allow using + /// selector tools that don't implement the \ref IAsgSelectionTool + /// interface (though arguably they should support the + /// IAsgSelectionTool interface). The main downside of that + /// approach would be the need to support a templated algorithm, + /// which I'm not even sure we have dual-use support for at the + /// moment (19 Mar 18). + + class AsgSelectionAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + AsgSelectionAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IAsgSelectionTool> m_selectionTool; + + /// \brief the smearing tool cast to an ISystematicsTool + /// + /// Normally selection tools don't have systematics, but I believe + /// I have seen one or two with systematics, so I added that + /// possibility in. + private: + ISystematicsTool *m_systematicsTool {nullptr}; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the particle continer we run on + private: + SysCopyHandle<xAOD::IParticleContainer> m_particlesHandle { + this, "particles", "", "the asg collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the decoration for the asg selection + private: + std::string m_selectionDecoration; + + /// \brief the accessor for \ref m_selectionDecoration + private: + std::unique_ptr<ISelectionAccessor> m_selectionAccessor; + + /// \brief the bits to set for an object failing the preselection + private: + SelectionType m_setOnFail; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgViewFromSelectionAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgViewFromSelectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..117b6223351c8447381623b87b9e643fd72ebde2 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgViewFromSelectionAlg.h @@ -0,0 +1,102 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef ASG_ANALYSIS_ALGORITHMS__ASG_VIEW_FROM_SELECTION_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__ASG_VIEW_FROM_SELECTION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <xAODBase/IParticleContainer.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SystematicsHandles/SysReadHandle.h> +#include <SystematicsHandles/SysWriteHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <limits> + +namespace CP +{ + /// \brief create a view container based on selection decorations + /// + /// This is a generic algorithm that works for all object types to + /// read our standard selection decorations and create a view + /// container. This avoids the need for the algorithm/tool to read + /// the selection decoration on the input, instead it can just + /// assume that all its input objects are meant to be processed. + + class AsgViewFromSelectionAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + AsgViewFromSelectionAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the input collection we run on + private: + SysReadHandle<xAOD::IParticleContainer> m_inputHandle { + this, "input", "", "the input collection to run on"}; + + /// \brief the output view container we produce + private: + SysWriteHandle<xAOD::IParticleContainer> m_outputHandle { + this, "output", "", "the output view container to produce"}; + + private: + std::vector<std::string> m_selection; + + private: + std::vector<SelectionType> m_ignore; + + /// \brief Sort the output (view) container by pT + private: + bool m_sortPt {false}; + + /// \brief Allow the input container to be missing + private: + bool m_allowMissing {false}; + + /// \brief Perform a deep copy for creating the output container + private: + bool m_deepCopy {false}; + + private: + std::size_t m_sizeLimit {std::numeric_limits<std::size_t>::max()}; + + /// the list of accessors and cut ignore list + private: + std::vector<std::pair<std::unique_ptr<ISelectionAccessor>,SelectionType> > m_accessors; + + /// \brief the templated version of execute for a single systematic + private: + template<typename Type> StatusCode + executeTemplate (const CP::SystematicSet& sys); + + /// \brief the version of execute to find the type + private: + StatusCode executeFindType (const CP::SystematicSet& sys); + + /// \brief The version of execute for missing input containers + private: + StatusCode executeMissing (const CP::SystematicSet& sys); + + private: + StatusCode (AsgViewFromSelectionAlg::* m_function) (const CP::SystematicSet& sys) {&AsgViewFromSelectionAlg::executeFindType}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgxAODNTupleMakerAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgxAODNTupleMakerAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..50df447893fa03b765a021bac14a4d08ee35fba9 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/AsgxAODNTupleMakerAlg.h @@ -0,0 +1,368 @@ +// Dear emacs, this is -*- c++ -*- +// +// Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +// +#ifndef ASGANALYSISALGORITHMS_ASGXAODNTUPLEMAKERALG_H +#define ASGANALYSISALGORITHMS_ASGXAODNTUPLEMAKERALG_H + +// System include(s): +#include <unordered_map> +#include <string> +#include <vector> +#include <memory> +#include <list> + +// Framework include(s): +#include "AsgTools/AsgMessaging.h" +#include "AnaAlgorithm/AnaAlgorithm.h" +#include "SystematicsHandles/SysListHandle.h" + +// EDM include(s): +#include "AthContainersInterfaces/IAuxTypeVector.h" +#include "AthContainers/AuxElement.h" + +// Forward declaration(s): +class TClass; +class TTree; +class TVirtualCollectionProxy; +namespace SG { + class AuxVectorBase; + class IAuxTypeVectorFactory; +} + +namespace CP { + + /// Algorithm that can write a simple ntuple from xAOD objects/variables + /// + /// This is meant as a simple tool for creating small ntuples in analyses, + /// using a simple job configuration. It can create branches from any xAOD + /// variables that are possible to write as an "xAOD variable" to begin with. + /// + /// It is *not* meant as a general purpose DAOD -> NTuple dumper however. + /// It should only be used to create small ntuples, with highly processed + /// variables. + /// + /// It's "main" property ("Branches") can be filled with entries of the form: + /// + /// <code> + /// writer = ...<br/> + /// writer.Branches = [ "<SG key>.<aux variable> -> <branch name>", ... ] + /// </code> + /// + /// , where each entry sets up one branch for the output tree. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + class AsgxAODNTupleMakerAlg : public EL::AnaAlgorithm { + + public: + /// Algorithm constructor + AsgxAODNTupleMakerAlg( const std::string& name, ISvcLocator* svcLoc ); + + /// @name Functions inherited from @c EL::AnaAlgorithm + /// @{ + + /// Function executed as part of the job initialisation + StatusCode initialize() override; + + /// Function executed once per event + StatusCode execute() override; + + /// Function executed as part of the job finalisation + StatusCode finalize() override; + + /// @} + + private: + /// Function setting up the internal data structures on the first event + StatusCode setupTree(); + + /// Function setting up an individual branch on the first event + StatusCode setupBranch( const std::string &branchDecl, + const CP::SystematicSet &sys ); + + /// @name Algorithm properties + /// @{ + + /// The name of the output tree to write + std::string m_treeName; + /// The branches to write into this output tree + std::vector< std::string > m_branches; + + /// @} + + /// Class writing all variables from one standalone object + /// + /// It is designed to work with any type inheriting from + /// @c SG::AuxElement. Like @c xAOD::EventInfo. Which is its main user + /// at the moment... + /// + class ElementProcessor : public asg::AsgMessaging { + + public: + /// Default constructor + /// + /// We have to have a default constructor to initialise the + /// @c asg::AsgMessaging base class correctly. Members of this class + /// would not need an explicit constructor themselves. + /// + ElementProcessor(); + + /// Process the object + /// + /// This function is called during the event processing to extract + /// all configured variables from a standalone xAOD object into the + /// output variables set up using @c ElementProcessor::addBranch. + /// + /// @param element The xAOD (interface) object to process + /// @return The usual @c StatusCode values + /// + StatusCode process( const SG::AuxElement& element ); + + /// Add one branch to the output tree + /// + /// This function is used during the setup of the output tree to create + /// one branch in it, from one specific auxiliary variable. The type of + /// the variable is figured out at runtime using the auxiliary store + /// infrastructure. + /// + /// @param tree The tree to create the branch in + /// @param auxName Name of the auxiliary variable to create the branch + /// from + /// @param branchName The name of the branch to create in the tree + /// @param allowMissing Set to @c true to print an error message in case + /// of a failure + /// @param created Used to store if the branch was actually created + /// @return The usual @c StatusCode values + /// + StatusCode addBranch( TTree& tree, const std::string& auxName, + const std::string& branchName, + bool allowMissing, + bool &created ); + + private: + /// Class writing one variable from an xAOD object into a branch + /// + /// It is used for both setting up the branch in the outut @c TTree + /// during the setup of the tree, and then to fill the "output + /// variable" with the right payload during the event processing. + /// + /// Note that since we may have a *lot* of such objects, I didn't want + /// to make it inherit from @c asg::AsgMessaging. Which means that all + /// of the class's functions need to receive its parent's message + /// stream object to be able to log error messages "nicely". + /// + /// Also note that since this is very much an internal class, all of + /// its members are public. Since the owner of such objects should know + /// perfectly well how they behave. + /// + class BranchProcessor { + + public: + /// Function setting up the object, and the branch + /// + /// This is pretty much the constructor of the class. I just decided + /// to implement it as a regular function and not a "real" + /// constructor, to be able to return a @c StatusCode value from the + /// call. Since the setup of the object may very well fail. + /// + /// @param tree The tree to set up the new branch in + /// @param auxName The name of the auxiliary variable to create + /// a branch from + /// @param branchName Name of the branch to create in the tree + /// @param msg Reference to the parent's @c MsgStream object + /// @return The usual @c StatusCode values + /// + StatusCode setup( TTree& tree, const std::string& auxName, + const std::string& branchName, + MsgStream& msg ); + + /// Function processing the object, filling the variable + /// + /// This function is called by @c ElementProcessor, to extract one + /// variable from the standalone object, and move its payload into + /// the memory address from which the output tree is writing its + /// branch. + /// + /// @param element The standalone object to get the auxiliary + /// variable from + /// @param msg Reference to the parent's @c MsgStream object + /// @return The usual @c StatusCode values + /// + StatusCode process( const SG::AuxElement& element, + MsgStream& msg ); + + /// Name of the branch being written + std::string m_branchName; + /// Object accessing the variable in question + std::unique_ptr< SG::AuxElement::TypelessConstAccessor > m_acc; + /// Pointer to the helper object that handles this variable + const SG::IAuxTypeVectorFactory* m_factory = nullptr; + /// The object managing the memory of the written variable + std::unique_ptr< SG::IAuxTypeVector > m_data; + /// Helper variable, pointing at the object to be written + void* m_dataPtr = nullptr; + + }; // class BranchProcessor + + /// List of branch processors set up for this xAOD object + /// + /// Note that when we set up a branch, we tell @c TTree to remember a + /// physical address in memory. To make sure that the address of the + /// object held by the branch processors are not moved in memory after + /// their construction, we have to use an @c std::list container here. + /// @c std::vector would not work. (As it can relocate objects when + /// increasing the size of the container.) + /// + std::list< BranchProcessor > m_branches; + + }; // class ElementProcessor + + /// Class writing all variables from one @c DataVector container + /// + /// It is designed to work with *any* @c DataVector<SG::AuxElement> type, + /// it doesn't have to be an @c xAOD::IParticleContainer. But of course + /// that is the main use case for it... + /// + /// It expects an @c SG::AuxVectorBase object from the caller, iterates + /// over the elements of that container using the ROOT dictionary of the + /// type, and writes individual variables from the elements of the + /// container using the same machinery that @c ElementProcessor employs. + /// + class ContainerProcessor : public asg::AsgMessaging { + + public: + /// Default constructor + /// + /// We have to have a default constructor to initialise the + /// @c asg::AsgMessaging base class correctly. Members of this class + /// would not need an explicit constructor themselves. + /// + ContainerProcessor(); + + /// Process the container + /// + /// This function is called during the event processing to extract + /// all configured variables from an xAOD container into the + /// output variables set up using @c ContainerProcessor::addBranch. + /// + /// @param container The xAOD (interface) container to process + /// @return The usual @c StatusCode values + /// + StatusCode process( const SG::AuxVectorBase& container ); + + /// Add one branch to the output tree + /// + /// This function is used during the setup of the output tree to create + /// one branch in it, from one specific auxiliary variable. The type of + /// the variable is figured out at runtime using the auxiliary store + /// infrastructure. + /// + /// @param tree The tree to create the branch in + /// @param auxName Name of the auxiliary variable to create the branch + /// from + /// @param branchName The name of the branch to create in the tree + /// @param allowMissing Set to @c true to print an error message in case + /// of a failure + /// @param created Used to store if the branch was actually created + /// @return The usual @c StatusCode values + /// + StatusCode addBranch( TTree& tree, const std::string& auxName, + const std::string& branchName, + bool allowMissing, + bool &created ); + + private: + /// Class writing one variable from an xAOD object into a branch + /// + /// It is used for both setting up the branch in the outut @c TTree + /// during the setup of the tree, and then to fill the "output + /// variable" with the right payload during the event processing. + /// + /// Note that since we may have a *lot* of such objects, I didn't want + /// to make it inherit from @c asg::AsgMessaging. Which means that all + /// of the class's functions need to receive its parent's message + /// stream object to be able to log error messages "nicely". + /// + /// Also note that since this is very much an internal class, all of + /// its members are public. Since the owner of such objects should know + /// perfectly well how they behave. + /// + /// Finally, note that it is more complicated than the + /// @c ElementProcessor::BranchProcessor class. Since in this case we + /// need to explicitly deal with @c std::vector types, which we need to + /// fill explicitly when extracting the variables from the xAOD + /// objects. + /// + class BranchProcessor { + + public: + /// Function setting up the object, and the branch + StatusCode setup( TTree& tree, const std::string& auxName, + const std::string& branchName, + MsgStream& msg ); + /// Function (re)sizing the variable for a new event + StatusCode resize( size_t size, MsgStream& msg ); + /// Function processing the object, filling the variable + StatusCode process( const SG::AuxElement& element, size_t index, + MsgStream& msg ); + + /// Name of the branch being written + std::string m_branchName; + /// Object accessing the variable in question + std::unique_ptr< SG::AuxElement::TypelessConstAccessor > m_acc; + /// Pointer to the helper object that handles this variable + const SG::IAuxTypeVectorFactory* m_factory = nullptr; + /// The object managing the memory of the written variable + std::unique_ptr< SG::IAuxTypeVector > m_data; + /// Helper variable, pointing at the object to be written + void* m_dataPtr = nullptr; + + }; // class BranchProcessor + + /// List of branch processors set up for this xAOD object + /// + /// Note that when we set up a branch, we tell @c TTree to remember a + /// physical address in memory. To make sure that the address of the + /// object held by the branch processors are not moved in memory after + /// their construction, we have to use an @c std::list container here. + /// @c std::vector would not work. (As it can relocate objects when + /// increasing the size of the container.) + /// + std::list< BranchProcessor > m_branches; + /// Collection proxy used for iterating over the container + TVirtualCollectionProxy* m_collProxy = nullptr; + /// Offset of the element type to @c SG::AuxElement + int m_auxElementOffset = -1; + + }; // class ContainerProcessor + + /// @name Variables used for the TTree filling + /// @{ + + /// The tree being written + TTree* m_tree = nullptr; + + /// Objects to write branches from + std::unordered_map< std::string, ElementProcessor > m_elements; + /// Containers to write branches from + std::unordered_map< std::string, ContainerProcessor > m_containers; + + /// Internal status flag, showing whether the algorithm is initialised + /// + /// This is necessary because we can only set up the output @c TTree while + /// processing the first event, we can't do it in + /// @c CP::AsgxAODNTupleMakerAlg::initialize. + /// + bool m_isInitialized = false; + + /// The systematic list to consider during execution + SysListHandle m_systematicsList{ this }; + + /// @} + + }; // class AsgxAODNTupleMakerAlg + +} // namespace CP + +#endif // ASGANALYSISALGORITHMS_ASGXAODNTUPLEMAKERALG_H diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/EventFlagSelectionAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/EventFlagSelectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..3d75ba62d7c485f872c4a87596283344ef846d80 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/EventFlagSelectionAlg.h @@ -0,0 +1,42 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + +#ifndef ASG_ANALYSIS_ALGORITHMS__EVENT_FLAG_SELECTION_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__EVENT_FLAG_SELECTION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AnaAlgorithm/FilterReporterParams.h> +#include <SelectionHelpers/ISelectionAccessor.h> + +namespace CP +{ + /// \brief an algorithm for selecting events by flag + class EventFlagSelectionAlg final : public EL::AnaAlgorithm + { + public: + EventFlagSelectionAlg(const std::string &name, + ISvcLocator *svcLoc = nullptr); + + virtual StatusCode initialize() final; + virtual StatusCode execute() final; + virtual StatusCode finalize() final; + + private: + /// \brief flags that we want to select events with + std::vector<std::string> m_selFlags; + + /// \brief invert flags + std::vector<bool> m_invertFlags; + + /// \brief a vector of accessors to read the flags + std::vector<std::unique_ptr<ISelectionAccessor>> m_accessors; + + /// \brief the filter reporter parameters + EL::FilterReporterParams m_filterParams {this, "event flag selection"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/EventSelectionByObjectFlagAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/EventSelectionByObjectFlagAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..671020270bc1d123dcb59fd9a3c672ed05b9dc34 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/EventSelectionByObjectFlagAlg.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Miha Muskinja + +#ifndef ASG_ANALYSIS_ALGORITHMS__EVENT_SELECTION_BY_OBJECT_FLAG_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__EVENT_SELECTION_BY_OBJECT_FLAG_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysDecorationHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysFilterReporterParams.h> +#include <SystematicsHandles/SysListHandle.h> +#include <SystematicsHandles/SysReadHandle.h> +#include <xAODBase/IParticleContainer.h> +#include <xAODEventInfo/EventInfo.h> + +namespace CP { +/// \brief an algorithm for selecting events based on object flags +/// (e.g. bad muon veto or b-jet veto) +class EventSelectionByObjectFlagAlg final : public EL::AnaAlgorithm { + public: + EventSelectionByObjectFlagAlg(const std::string &name, + ISvcLocator *svcLoc = nullptr); + + public: + StatusCode initialize() override; + + public: + StatusCode execute() override; + + public: + StatusCode finalize() override; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList{this}; + + /// \brief the filter reporter + private: + SysFilterReporterParams m_filterParams {this, "object flag selection"}; + + /// \brief the particle collection we run on + private: + SysReadHandle<xAOD::IParticleContainer> m_particleHandle{ + this, "particles", "", "the particle collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection{this, "preselection", "", "the preselection to apply"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_veto{this, "veto", "", "selection upon which events are vetoed"}; +}; + +} // namespace CP + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/IsolationCloseByCorrectionAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/IsolationCloseByCorrectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..670aeaa975af9cbbd0959833bfbd816af29bb316 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/IsolationCloseByCorrectionAlg.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef ASG_ANALYSIS_ALGORITHMS__ISOLATION_CLOSE_BY_CORRECTION_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__ISOLATION_CLOSE_BY_CORRECTION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <IsolationSelection/IIsolationCloseByCorrectionTool.h> +#include <SelectionHelpers/OutOfValidityEventHelper.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IIsolationCloseByCorrectionTool + + class IsolationCloseByCorrectionAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + IsolationCloseByCorrectionAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// The OR toolbox + private: + ToolHandle<IIsolationCloseByCorrectionTool> m_isolationCorrectionTool { + "CP::IsolationCloseByCorrectionTool", this}; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + private: + SysCopyHandle<xAOD::ElectronContainer> m_electronsHandle { + this, "electrons", "", "the electrons container to use"}; + SysCopyHandle<xAOD::MuonContainer> m_muonsHandle { + this, "muons", "", "the muons container to use"}; + SysCopyHandle<xAOD::PhotonContainer> m_photonsHandle { + this, "photons", "", "the photons container to use"}; + + private: + int m_topoEtConeModel {IIsolationCloseByCorrectionTool::TopoConeCorrectionModel::DirectCaloClusters}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityEventHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/KinematicHistAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/KinematicHistAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..c9c1598f7027050c5e0eb67c34f32a1886f61c8a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/KinematicHistAlg.h @@ -0,0 +1,83 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef ASG_ANALYSIS_ALGORITHMS__KINEMATIC_HIST_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__KINEMATIC_HIST_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysReadHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODBase/IParticleContainer.h> + +namespace CP +{ + /// \brief an algorithm for dumping the kinematics of an IParticle + /// container into histograms + /// + /// This is mostly meant as a temporary helper algorithm to debug + /// the common CP algorithms as they get developed. + + class KinematicHistAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + KinematicHistAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysReadHandle<xAOD::IParticleContainer> m_inputHandle { + this, "input", "", "the input collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the pattern for histogram names + private: + std::string m_histPattern {"%VAR%_%SYS%"}; + + + /// \brief the histograms we fill per systematic and object + private: + struct HistSubgroup + { + TH1 *pt = nullptr; + TH1 *eta = nullptr; + TH1 *phi = nullptr; + }; + + + /// \brief the histograms we fill per systematic + private: + struct HistGroup + { + TH1 *multiplicity = nullptr; + std::vector<HistSubgroup> perObject; + }; + + /// \brief the created histograms + private: + std::unordered_map<CP::SystematicSet,HistGroup> m_hist; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/ObjectCutFlowHistAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/ObjectCutFlowHistAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..426f79cd003e470e914e4b647d62359b1a5e7b21 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/ObjectCutFlowHistAlg.h @@ -0,0 +1,85 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef ASG_ANALYSIS_ALGORITHMS__OBJECT_CUT_FLOW_HIST_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__OBJECT_CUT_FLOW_HIST_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysReadHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODBase/IParticleContainer.h> + +namespace CP +{ + /// \brief an algorithm for dumping the kinematics of an IParticle + /// container into histograms + /// + /// This is mostly meant as a temporary helper algorithm to debug + /// the common CP algorithms as they get developed. + + class ObjectCutFlowHistAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + ObjectCutFlowHistAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysReadHandle<xAOD::IParticleContainer> m_inputHandle { + this, "input", "", "the input collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the pattern for histogram names + private: + std::string m_histPattern {"cutflow_%SYS%"}; + + + private: + std::vector<std::string> m_selection; + + private: + std::vector<unsigned> m_selectionNCuts; + + /// the list of accessors and cut ignore list + private: + std::vector<std::pair<std::unique_ptr<ISelectionAccessor>,unsigned> > m_accessors; + + /// \brief the total number of cuts configured (needed to + /// configure histograms) + private: + unsigned m_allCutsNum = 0; + + /// \brief the created histograms + private: + std::unordered_map<CP::SystematicSet,TH1*> m_hist; + + /// \brief histogram bin labels + private: + std::vector<std::string> m_labels; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/OverlapRemovalAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/OverlapRemovalAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..10274653e53253077d4fa66027a33fceaa3c8fd5 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/OverlapRemovalAlg.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef ASG_ANALYSIS_ALGORITHMS__OVERLAP_REMOVAL_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__OVERLAP_REMOVAL_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AssociationUtils/ToolBox.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IPileupReweightingTool + + class OverlapRemovalAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + OverlapRemovalAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// The OR toolbox + private: + ToolHandle<ORUtils::IOverlapRemovalTool> m_overlapTool { + "ORUtils::OverlapRemovalTool", this}; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + private: + SysCopyHandle<xAOD::ElectronContainer> m_electronsHandle { + this, "electrons", "", "the electrons container to use"}; + SysCopyHandle<xAOD::MuonContainer> m_muonsHandle { + this, "muons", "", "the muons container to use"}; + SysCopyHandle<xAOD::JetContainer> m_jetsHandle { + this, "jets", "", "the jets container to use"}; + SysCopyHandle<xAOD::TauJetContainer> m_tausHandle { + this, "taus", "", "the taus container to use"}; + SysCopyHandle<xAOD::PhotonContainer> m_photonsHandle { + this, "photons", "", "the photons container to use"}; + SysCopyHandle<xAOD::JetContainer> m_fatJetsHandle { + this, "fatJets", "", "the fat jets container to use"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/PMGTruthWeightAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/PMGTruthWeightAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..d053643e9aca303af920e20f79d12ca759ab08c0 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/PMGTruthWeightAlg.h @@ -0,0 +1,55 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +#ifndef ASG_ANALYSIS_ALGORITHMS__PMG_TRUTH_WEIGHT_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__PMG_TRUTH_WEIGHT_ALG_H + +#include <xAODEventInfo/EventInfo.h> +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <PMGAnalysisInterfaces/IPMGTruthWeightTool.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysDecorationHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IPMGTruthWeightTool + class PMGTruthWeightAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + PMGTruthWeightAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + /// \brief the tool + private: + ToolHandle<PMGTools::IPMGTruthWeightTool> m_truthWeightTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the event info we decorate + private: + SysCopyHandle<xAOD::EventInfo> m_eventInfoHandle { + this, "eventInfo", "EventInfo", "the event info object to run on"}; + + /// \brief the decoration for the truth weights + private: + SysDecorationHandle<float> m_decoration { + this, "decoration", "", "the decoration for the truth weights"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/PileupReweightingAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/PileupReweightingAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..57846bf217a5c4014b044c68c54fa8f0ca911cca --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/PileupReweightingAlg.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef ASG_ANALYSIS_ALGORITHMS__PILEUP_REWEIGHTING_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__PILEUP_REWEIGHTING_ALG_H + +#include <xAODEventInfo/EventInfo.h> +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgAnalysisInterfaces/IPileupReweightingTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IPileupReweightingTool + + class PileupReweightingAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + PileupReweightingAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IPileupReweightingTool> m_pileupReweightingTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysCopyHandle<xAOD::EventInfo> m_eventInfoHandle { + this, "eventInfo", "EventInfo", "the event info object to run on"}; + + /// \brief the decoration for the corrected and scaled average interactions per crossing + private: + std::string m_correctedScaledAverageMuDecoration; + + /// \brief the decoration for the corrected actual interactions per crossing + private: + std::string m_correctedActualMuDecoration; + + /// \brief the decoration for the corrected and scaled actual interactions per crossing + private: + std::string m_correctedScaledActualMuDecoration; + + /// \brief the accessor for \ref m_correctedScaledAverageMuDecoration + private: + std::unique_ptr<const SG::AuxElement::Accessor<float> > m_correctedScaledAverageMuAccessor; + + /// \brief the accessor for \ref m_correctedActualMuDecoration + private: + std::unique_ptr<const SG::AuxElement::Accessor<float> > m_correctedActualMuAccessor; + + /// \brief the accessor for \ref m_correctedScaledAverageMuDecoration + private: + std::unique_ptr<const SG::AuxElement::Accessor<float> > m_correctedScaledActualMuAccessor; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/SysListDumperAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/SysListDumperAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..6b0f3d775ac5beda2ddff8213a69963ca549a301 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/SysListDumperAlg.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +#ifndef ASG_ANALYSIS_ALGORITHMS__SYS_LIST_DUMPER_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__SYS_LIST_DUMPER_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief Dump systematics names into a histogram + + class SysListDumperAlg final : public EL::AnaAlgorithm + { + /// \brief standard constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + public: + SysListDumperAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + public: + virtual ::StatusCode initialize () override; + + public: + virtual ::StatusCode execute () override; + + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the name of the histogram to use + private: + std::string m_histogramName {sysListDefaultName()}; + + /// \brief whether the next event will be the first event + private: + bool m_firstEvent = true; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/SysListLoaderAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/SysListLoaderAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..aa6beb74e7dc94eeb4c9180d44704e4b04c446f7 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/SysListLoaderAlg.h @@ -0,0 +1,84 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef ASG_ANALYSIS_ALGORITHMS__SYS_LIST_LOADER_ALG_H +#define ASG_ANALYSIS_ALGORITHMS__SYS_LIST_LOADER_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <PATInterfaces/SystematicSet.h> +#include <SystematicsHandles/SysListType.h> + +namespace CP +{ + /// \todo add documentation + + class SysListLoaderAlg final : public EL::AnaAlgorithm + { + // + // public interface + // + + /// \brief standard constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + public: + SysListLoaderAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + + // + // inherited interface + // + + public: + virtual ::StatusCode initialize () override; + + public: + virtual ::StatusCode execute () override; + + + + // + // private interface + // + + /// \brief the name under which to store the systematics in the + /// event store + private: + std::string m_systematicsName {sysListDefaultName()}; + + /// \brief the names of the systematics to request + private: + std::vector<std::string> m_systematicsList; + + /// \brief the regular expression for filterinf systematics + private: + std::string m_systematicsRegex {"(.*)"}; + + /// \brief load all recommended systematics at the given number of + /// sigmas + /// + /// The idea here is that this allows to run a simple analysis by + /// itself without having to generate the list of systematics + /// manually. + private: + float m_sigmaRecommended = 0; + + /// \brief the list of actual systematics + private: + std::vector<CP::SystematicSet> m_systematicsVector; + + /// \brief whether the next event will be the first event + private: + bool m_firstEvent = true; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/TreeFillerAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/TreeFillerAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..d845bedb3bf74b782b01b4e77b790ade1ddf70b6 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/TreeFillerAlg.h @@ -0,0 +1,84 @@ +// Dear emacs, this is -*- c++ -*- +// +// Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +// +#ifndef ASGANALYSISALGORITHMS_TREEFILLERALG_H +#define ASGANALYSISALGORITHMS_TREEFILLERALG_H + +// System include(s): +#include <unordered_map> +#include <string> +#include <vector> +#include <memory> +#include <list> + +// Framework include(s): +#include "AsgTools/AsgMessaging.h" +#include "AnaAlgorithm/AnaAlgorithm.h" +#include "SystematicsHandles/SysListHandle.h" + +// EDM include(s): +#include "AthContainersInterfaces/IAuxTypeVector.h" +#include "AthContainers/AuxElement.h" + +// Forward declaration(s): +class TClass; +class TTree; +class TVirtualCollectionProxy; +namespace SG { + class AuxVectorBase; + class IAuxTypeVectorFactory; +} + +namespace CP { + + /// Algorithm that writes events to a tree filled by preceding + /// algorithms to fill + /// + /// This is meant in conjunction with \ref TreeMakerAlg and one or + /// more of tree-variable filler algorithms in-between. The idea + /// behind this specific design is that it allows multiple + /// implementations of tree-variable filler algorithms to work + /// together in filling different variables in the same tree, as + /// well as making the configuration for each tree-variable filler + /// algorithm simpler. + /// + /// @author Nils Krumnack <Nils.Erik.Krumnack@cern.ch> + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + + class TreeFillerAlg : public EL::AnaAlgorithm { + + public: + /// Algorithm constructor + TreeFillerAlg( const std::string& name, ISvcLocator* svcLoc ); + + /// @name Functions inherited from @c EL::AnaAlgorithm + /// @{ + + /// Function executed once per event + StatusCode execute() override; + + /// @} + + private: + /// @name Algorithm properties + /// @{ + + /// The name of the output tree to write + std::string m_treeName; + + /// @} + + /// @name Variables used for the TTree filling + /// @{ + + /// The tree being written + TTree* m_tree = nullptr; + + /// @} + + }; // class TreeFillerAlg + +} // namespace CP + +#endif // ASGANALYSISALGORITHMS_TREEFILLERALG_H diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/TreeMakerAlg.h b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/TreeMakerAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..a5b4a671d52e43c7ccf621b135c69a6601f8ecae --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/TreeMakerAlg.h @@ -0,0 +1,68 @@ +// Dear emacs, this is -*- c++ -*- +// +// Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +// +#ifndef ASGANALYSISALGORITHMS_TREEMAKERALG_H +#define ASGANALYSISALGORITHMS_TREEMAKERALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> + +class TTree; + +namespace CP { + + /// Algorithm that creates an empty tree for subsequent algorithms + /// to fill + /// + /// This is meant in conjunction with \ref TreeFillerAlg and one or + /// more of tree-variable filler algorithms in-between. The idea + /// behind this specific design is that it allows multiple + /// implementations of tree-variable filler algorithms to work + /// together in filling different variables in the same tree, as + /// well as making the configuration for each tree-variable filler + /// algorithm simpler. + /// + /// @author Nils Krumnack <Nils.Erik.Krumnack@cern.ch> + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + class TreeMakerAlg : public EL::AnaAlgorithm { + + public: + /// Algorithm constructor + TreeMakerAlg( const std::string& name, ISvcLocator* svcLoc ); + + /// @name Functions inherited from @c EL::AnaAlgorithm + /// @{ + + /// Function executed once per event + StatusCode execute() override; + + /// @} + + private: + /// Function setting up the internal data structures on the first event + StatusCode setupTree(); + + /// @name Algorithm properties + /// @{ + + /// The name of the output tree to write + std::string m_treeName; + /// Flust setting for the output tree + int m_treeAutoFlush; + + /// @} + + /// @name Helper variables + /// @{ + + /// Configured tree status + bool m_treeConfigured{false}; + + /// @} + + }; // class TreeMakerAlg + +} // namespace CP + +#endif // ASGANALYSISALGORITHMS_TREEMAKERALG_H diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/selection.xml b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..bd28958853419777730a150fa06ad7a694ca698d --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/AsgAnalysisAlgorithms/selection.xml @@ -0,0 +1,26 @@ +<lcgdict> + + <class name="CP::AsgFlagSelectionTool" /> + <class name="CP::AsgPtEtaSelectionTool" /> + + <class name="CP::AsgCutBookkeeperAlg" /> + <class name="CP::AsgEventScaleFactorAlg" /> + <class name="CP::AsgLeptonTrackSelectionAlg" /> + <class name="CP::AsgOriginalObjectLinkAlg" /> + <class name="CP::AsgSelectionAlg" /> + <class name="CP::AsgViewSelectionAlg" /> + <class name="CP::AsgxAODNTupleMakerAlg" /> + <class name="CP::EventFlagSelectionAlg" /> + <class name="CP::EventSelectionByObjectFlagAlg" /> + <class name="CP::IsolationCloseByCorrectionAlg" /> + <class name="CP::KinematicHistAlg" /> + <class name="CP::ObjectCutFlowHistAlg" /> + <class name="CP::OverlapRemovalAlg" /> + <class name="CP::PileupReweightingAlg" /> + <class name="CP::PMGTruthWeightAlg" /> + <class name="CP::SysListDumperAlg" /> + <class name="CP::SysListLoaderAlg" /> + <class name="CP::TreeFillerAlg" /> + <class name="CP::TreeMakerAlg" /> + +</lcgdict> diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/CMakeLists.txt b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..7a14cc76e80c0a01fc95a4c66032042d4e071b02 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/CMakeLists.txt @@ -0,0 +1,113 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +atlas_subdir( AsgAnalysisAlgorithms ) + +atlas_depends_on_subdirs( + PUBLIC + Control/AthContainers + Control/AthContainersInterfaces + Control/AthToolSupport/AsgTools + Event/xAOD/xAODBase + Event/xAOD/xAODCutFlow + Event/xAOD/xAODEventInfo + Event/xAOD/xAODMetaData + PhysicsAnalysis/Algorithms/SelectionHelpers + PhysicsAnalysis/Algorithms/SystematicsHandles + PhysicsAnalysis/AnalysisCommon/PATCore + PhysicsAnalysis/AnalysisCommon/PATInterfaces + PhysicsAnalysis/AnalysisCommon/IsolationSelection + PhysicsAnalysis/D3PDTools/AnaAlgorithm + PhysicsAnalysis/Interfaces/AsgAnalysisInterfaces + PhysicsAnalysis/Interfaces/PMGAnalysisInterfaces + PRIVATE + Event/xAOD/xAODCore + Event/xAOD/xAODJet + Event/xAOD/xAODMuon + Event/xAOD/xAODTau + Event/xAOD/xAODEgamma + Event/xAOD/xAODTracking + Event/xAOD/xAODTruth + PhysicsAnalysis/D3PDTools/RootCoreUtils ) + +atlas_add_library( AsgAnalysisAlgorithmsLib + AsgAnalysisAlgorithms/*.h AsgAnalysisAlgorithms/*.icc Root/*.cxx + PUBLIC_HEADERS AsgAnalysisAlgorithms + LINK_LIBRARIES AthContainers AthContainersInterfaces AsgTools xAODBase + xAODEventInfo SelectionHelpersLib SystematicsHandlesLib PATCoreLib + PATInterfaces AnaAlgorithmLib AsgAnalysisInterfaces AssociationUtilsLib + IsolationSelectionLib + PRIVATE_LINK_LIBRARIES xAODCore xAODCutFlow xAODMetaData xAODJet xAODMuon xAODTau xAODEgamma xAODTracking xAODTruth + RootCoreUtils ) + +atlas_add_dictionary( AsgAnalysisAlgorithmsDict + AsgAnalysisAlgorithms/AsgAnalysisAlgorithmsDict.h + AsgAnalysisAlgorithms/selection.xml + LINK_LIBRARIES AsgAnalysisAlgorithmsLib ) + +if( NOT XAOD_STANDALONE ) + atlas_add_component( AsgAnalysisAlgorithms + src/*.h src/*.cxx src/components/*.cxx + LINK_LIBRARIES GaudiKernel AsgAnalysisAlgorithmsLib ) +endif() + +atlas_install_python_modules( python/*.py ) +atlas_install_joboptions( share/*_jobOptions.py ) +atlas_install_scripts( share/*_eljob.py ) + +if( XAOD_STANDALONE ) + atlas_add_test( EventAlgsTestJobData + SCRIPT EventAlgorithmsTest_eljob.py --data-type data --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( EventAlgsTestJobFullSim + SCRIPT EventAlgorithmsTest_eljob.py --data-type mc --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( EventAlgsTestJobFastSim + SCRIPT EventAlgorithmsTest_eljob.py --data-type afii --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( OverlapRemovalTestJobData + SCRIPT OverlapAlgorithmsTest_eljob.py --data-type data --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( OverlapRemovalTestJobFullSim + SCRIPT OverlapAlgorithmsTest_eljob.py --data-type mc --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( OverlapRemovalTestJobFastSim + SCRIPT OverlapAlgorithmsTest_eljob.py --data-type afii --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( GeneratorAlgsTestJobFullSim + SCRIPT GeneratorAlgorithmsTest_eljob.py --data-type mc --unit-test + PROPERTIES TIMEOUT 600 ) +else() + atlas_add_test( EventAlgsTestJobData + SCRIPT athena.py + AsgAnalysisAlgorithms/EventAlgorithmsTest_jobOptions.py - --data-type data + PROPERTIES TIMEOUT 600 ) + atlas_add_test( EventAlgsTestJobFullSim + SCRIPT athena.py + AsgAnalysisAlgorithms/EventAlgorithmsTest_jobOptions.py - --data-type mc + PROPERTIES TIMEOUT 600 ) + atlas_add_test( EventAlgsTestJobFastSim + SCRIPT athena.py + AsgAnalysisAlgorithms/EventAlgorithmsTest_jobOptions.py - --data-type afii + PROPERTIES TIMEOUT 600 ) + atlas_add_test( GeneratorAlgsTestJob + SCRIPT athena.py + AsgAnalysisAlgorithms/GeneratorAlgorithmsTest_jobOptions.py - --data-type mc + PROPERTIES TIMEOUT 600 ) + + if( NOT "${CMAKE_PROJECT_NAME}" STREQUAL "AthDerivation" ) + atlas_add_test( OverlapRemovalTestJobData + SCRIPT athena.py + AsgAnalysisAlgorithms/OverlapAlgorithmsTest_jobOptions.py - --data-type data + PROPERTIES TIMEOUT 600 ) + atlas_add_test( OverlapRemovalTestJobFullSim + SCRIPT athena.py + AsgAnalysisAlgorithms/OverlapAlgorithmsTest_jobOptions.py - --data-type mc + PROPERTIES TIMEOUT 600 ) + atlas_add_test( OverlapRemovalTestJobFastSim + SCRIPT athena.py + AsgAnalysisAlgorithms/OverlapAlgorithmsTest_jobOptions.py - --data-type afii + PROPERTIES TIMEOUT 600 ) + endif() +endif() diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgCutBookkeeperAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgCutBookkeeperAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..129c116eed7e4985ac8cade819cab5f88f427cfd --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgCutBookkeeperAlg.cxx @@ -0,0 +1,218 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + +// +// includes +// + +#include <AsgAnalysisAlgorithms/AsgCutBookkeeperAlg.h> +#include <SystematicsHandles/Helpers.h> + +#include <RootCoreUtils/StringUtil.h> +#include <TH1.h> + +#include <xAODCutFlow/CutBookkeeper.h> +#include <xAODCutFlow/CutBookkeeperContainer.h> +#include <xAODMetaData/FileMetaData.h> +#include <xAODTruth/TruthMetaData.h> +#include <xAODTruth/TruthMetaDataContainer.h> + +#include <regex> + +// +// method implementations +// + +namespace CP +{ + AsgCutBookkeeperAlg :: + AsgCutBookkeeperAlg (const std::string &name, + ISvcLocator *pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_truthWeightTool ("PMGTools::PMGTruthWeightTool", this) + { + declareProperty ("runNumber", m_runNumber, "the run number we are processing"); + declareProperty ("histPattern", m_histPattern, "the pattern for histogram names"); + declareProperty ("truthWeightTool", m_truthWeightTool, "the truth weight tool"); + declareProperty ("enableSystematics", m_enableSystematics, "enable systematics"); + } + + + + StatusCode AsgCutBookkeeperAlg :: + initialize () + { + if (m_runNumber == 0) + { + ANA_MSG_ERROR ("Run number should be set"); + return StatusCode::FAILURE; + } + + ANA_CHECK (requestFileExecute ()); + + // Read the channel number from FileMetaData + const xAOD::FileMetaData *fmd{}; + ANA_CHECK (inputMetaStore()->retrieve(fmd, "FileMetaData")); + + float _flt_channel_number{}; + if (fmd->value(xAOD::FileMetaData::mcProcID, _flt_channel_number)) + { + m_mcChannelNumber = static_cast<uint32_t>(_flt_channel_number); + } + if (m_mcChannelNumber == 0) + { + ANA_MSG_WARNING ("MC channel number could not be read from the FileMetaData."); + + // Try also TruthMetaData + const xAOD::TruthMetaDataContainer *tmd{}; + if (inputMetaStore()->contains<xAOD::TruthMetaDataContainer>("TruthMetaData")) + { + ATH_CHECK (inputMetaStore()->retrieve(tmd, "TruthMetaData")); + ATH_MSG_DEBUG("Loaded xAOD::TruthMetaDataContainer"); + + // If we only have one metadata item take MC channel from there if needed + if (tmd->size() == 1) { + m_mcChannelNumber = tmd->at(0)->mcChannelNumber(); + ATH_MSG_WARNING("... MC channel number taken from the metadata as " << m_mcChannelNumber); + } + } + } + + // Prepare for systematics + ANA_CHECK (m_truthWeightTool.retrieve()); + + return StatusCode::SUCCESS; + } + + + + StatusCode AsgCutBookkeeperAlg :: + fileExecute () + { + ANA_MSG_DEBUG ("Updating CutBookkeeper information"); + + // Update MC channel number if needed + if (m_mcChannelNumber == 0) + { + const xAOD::FileMetaData *fmd{}; + ANA_CHECK (inputMetaStore()->retrieve(fmd, "FileMetaData")); + + float _flt_channel_number{}; + if (fmd->value(xAOD::FileMetaData::mcProcID, _flt_channel_number)) { + m_mcChannelNumber = static_cast<uint32_t>(_flt_channel_number); + } + } + + // Retrieve complete CutBookkeeperContainer + const xAOD::CutBookkeeperContainer *completeCBC{}; + ANA_CHECK (inputMetaStore()->retrieve(completeCBC, "CutBookkeepers")); + + // Find the max cycle + int maxCycle{-1}; + const xAOD::CutBookkeeper *allEvents{}; + for (const xAOD::CutBookkeeper *cbk : *completeCBC) + { + ANA_MSG_DEBUG ("Complete cbk name: " << cbk->name() << " - stream: " << cbk->inputStream()); + + if (cbk->cycle() > maxCycle && cbk->name() == "AllExecutedEvents" && cbk->inputStream() == "StreamAOD") + { + allEvents = cbk; + maxCycle = cbk->cycle(); + } + } + + if (allEvents == nullptr) + { + ANA_MSG_ERROR ("Could not find AllExecutedEvents CutBookkeeper information."); + return StatusCode::FAILURE; + } + + size_t counter{}; + for (const xAOD::CutBookkeeper *cbk : *completeCBC) + { + if (cbk->cycle() == maxCycle && cbk->name().find("AllExecutedEvents") == 0 && cbk->inputStream() == "StreamAOD") + { + static const std::regex re ("AllExecutedEvents.*_([0-9]+)"); + // Get the CBK index + size_t index{0}; + std::smatch match; + if (std::regex_match(cbk->name(), match, re)) + { + index = std::stoi(match[1]); + } + + uint64_t nEventsProcessed = cbk->nAcceptedEvents(); + double sumOfWeights = cbk->sumOfEventWeights(); + double sumOfWeightsSquared = cbk->sumOfEventWeightsSquared(); + + // Write CutBookkeeper information to the info + ANA_MSG_VERBOSE ("CutBookkeeper information from the current file for index " << index << ":"); + ANA_MSG_VERBOSE ("Initial events = " << nEventsProcessed); + ANA_MSG_VERBOSE ("Initial sum of weights = " << sumOfWeights); + ANA_MSG_VERBOSE ("Initial sum of weights squared = " << sumOfWeightsSquared); + + auto it = m_weights.emplace(index, WeightsGroup()).first; + it->second.nEventsProcessed += nEventsProcessed; + it->second.sumOfWeights += sumOfWeights; + it->second.sumOfWeightsSquared += sumOfWeightsSquared; + + counter++; + } + } + + if (counter == 1 && m_enableSystematics) { + ANA_MSG_WARNING ("This sample does not support CutBookkeeper systematics. Disabling..."); + m_enableSystematics = false; + } + + return StatusCode::SUCCESS; + } + + + + StatusCode AsgCutBookkeeperAlg :: + finalize () + { + // Temporarily handle systematics directly here + std::vector<CP::SystematicSet> systematics; + systematics.emplace_back(); + if (m_enableSystematics) + { + for (const CP::SystematicVariation &variation : m_truthWeightTool->affectingSystematics()) + { + systematics.emplace_back(CP::SystematicSet({variation})); + } + } + + for (const CP::SystematicSet &sys : systematics) + { + std::string name = RCU::substitute(m_histPattern, "%DSID%", std::to_string(m_mcChannelNumber)); + name = RCU::substitute(name, "%RUN%", std::to_string(m_runNumber)); + name = makeSystematicsName (name, sys); + + ANA_CHECK (book(TH1F(name.c_str(), "CutBookkeeper Information", 3, 0.5, 3.5))); + TH1 *h = hist(name); + assert(h != nullptr); + + h->GetXaxis()->SetBinLabel (1, "Initial events"); + h->GetXaxis()->SetBinLabel (2, "Initial sum of weights"); + h->GetXaxis()->SetBinLabel (3, "Initial sum of weights squared"); + + ANA_MSG_INFO ("CutBookkeeper information will be stored in " << name); + + ANA_CHECK (m_truthWeightTool->applySystematicVariation (sys)); + + ANA_MSG_VERBOSE ("Running systematics " << sys.name() << " with index " << m_truthWeightTool->getSysWeightIndex()); + + const WeightsGroup &weights = m_weights.at (m_truthWeightTool->getSysWeightIndex()); + h->SetBinContent (1, weights.nEventsProcessed); + h->SetBinContent (2, weights.sumOfWeights); + h->SetBinContent (3, weights.sumOfWeightsSquared); + } + + return StatusCode::SUCCESS; + } +} // namespace CP diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgEventScaleFactorAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgEventScaleFactorAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..58a9cb24f8d710f83a1d062146f940b6777dd1a8 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgEventScaleFactorAlg.cxx @@ -0,0 +1,75 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/AsgEventScaleFactorAlg.h> + +// #include <SelectionHelpers/SelectionHelpers.h> + +// +// method implementations +// + +namespace CP +{ + AsgEventScaleFactorAlg :: + AsgEventScaleFactorAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + } + + + + StatusCode AsgEventScaleFactorAlg :: + initialize () + { + if (m_scaleFactorInputDecoration.empty() || m_scaleFactorOutputDecoration.empty()) + { + ANA_MSG_ERROR ("no scale factor decoration name set"); + return StatusCode::FAILURE; + } + + m_systematicsList.addHandle (m_particleHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + + return StatusCode::SUCCESS; + } + + + + StatusCode AsgEventScaleFactorAlg :: + execute () + { + ANA_CHECK (m_scaleFactorOutputDecoration.preExecute (m_systematicsList)); + + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::EventInfo *eventInfo = nullptr; + ANA_CHECK (m_eventInfoHandle.getCopy (eventInfo, sys)); + + xAOD::IParticleContainer *particles = nullptr; + ANA_CHECK (m_particleHandle.getCopy (particles, sys)); + + float scaleFactor = 1; + for (xAOD::IParticle *particle : *particles) + { + if (m_preselection.getBool (*particle)) + { + scaleFactor *= m_scaleFactorInputDecoration.get (*particle, sys); + } + } + + m_scaleFactorOutputDecoration.set (*eventInfo, scaleFactor, sys); + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgFlagSelectionTool.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgFlagSelectionTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ac9c2aab0f408f2becebc509a276dc2d23ee861a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgFlagSelectionTool.cxx @@ -0,0 +1,88 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + */ + +/// @author Teng Jian Khoo + + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/AsgFlagSelectionTool.h> + +#include <cmath> + +// +// method implementations +// + +namespace CP +{ + AsgFlagSelectionTool :: + AsgFlagSelectionTool (const std::string& name) + : AsgTool (name) + { + declareProperty ("selectionFlags", m_selFlags, "list of flags to use as selection criteria"); + declareProperty ("invertFlags", m_invertFlags, "toggles for inverting the selection (index-parallel to selectionFlags)"); + } + + + + StatusCode AsgFlagSelectionTool :: + initialize () + { + if(m_invertFlags.size()!=m_selFlags.size() && !m_invertFlags.empty()) { + ATH_MSG_ERROR("Property invertFlags has different size to selectionFlags. Please check your configuration"); + return StatusCode::FAILURE; + } + // Could also warn if there are fewer values, but we don't have to force users to set where irrelevant. + // Maybe warn unless the size is 0, in which case assume all default? + + for(size_t index=0; index<m_selFlags.size(); ++index) { + const std::string& thisflag = m_selFlags[index]; + if (thisflag.empty()) { + ATH_MSG_ERROR("Empty string passed as selection flag!"); + return StatusCode::FAILURE; + } else { + // Extend m_invertFlags until the size matches m_selectionFlags + // Only done in the case that m_invert was empty + if(m_invertFlags.size()<index+1) {m_invertFlags.push_back(false);} + std::string doInvertStr = m_invertFlags[index] ? "!" : ""; + m_accept.addCut (doInvertStr + thisflag, doInvertStr + thisflag); + std::unique_ptr<ISelectionAccessor> accessor; + ATH_CHECK (makeSelectionAccessor (thisflag, accessor, true)); + m_acc_selFlags.push_back (std::move (accessor)); + } + } + + return StatusCode::SUCCESS; + } + + + + const Root::TAccept& AsgFlagSelectionTool :: + getTAccept () const + { + return m_accept; + } + + + + const Root::TAccept& AsgFlagSelectionTool :: + accept (const xAOD::IParticle *particle) const + { + m_accept.clear(); + for(std::size_t cutIndex=0; cutIndex<m_accept.getNCuts(); ++cutIndex) { + // Test against the opposite of the invert value + bool testval = !m_invertFlags[cutIndex]; + ATH_MSG_VERBOSE("Now testing flag \"" << m_selFlags[cutIndex] << "\" requiring value " << testval); + m_accept.setCutResult (cutIndex, m_acc_selFlags[cutIndex]->getBool (*particle)==testval); + } + ATH_MSG_VERBOSE(" Result: " << m_accept); + + return m_accept; + } +} + diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgLeptonTrackSelectionAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgLeptonTrackSelectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..57f4fed9f244d93ae04b458c80891a1592ca927f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgLeptonTrackSelectionAlg.cxx @@ -0,0 +1,194 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/AsgLeptonTrackSelectionAlg.h> + +#include <xAODEgamma/Electron.h> +#include <xAODEventInfo/EventInfo.h> +#include <xAODMuon/Muon.h> +#include <xAODTracking/TrackParticlexAODHelpers.h> +#include <xAODTracking/VertexContainer.h> + +// +// method implementations +// + +namespace CP +{ + AsgLeptonTrackSelectionAlg :: + AsgLeptonTrackSelectionAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + declareProperty ("maxD0Significance", m_maxD0Significance, "maximum d0 significance (or 0 for no cut)"); + declareProperty ("maxDeltaZ0SinTheta", m_maxDeltaZ0SinTheta, "maximum Delta z0 sin theta (or 0 for no cut)"); + declareProperty ("nMinPixelHits", m_nMinPixelHits, "minimum number of required Pixel hits (or -1 for no cut)"); + declareProperty ("nMaxPixelHits", m_nMaxPixelHits, "minimum number of required Pixel hits (or -1 for no cut)"); + declareProperty ("nMinSCTHits", m_nMinSCTHits, "minimum number of required SCT hits (or -1 for no cut)"); + declareProperty ("nMaxSCTHits", m_nMaxSCTHits, "minimum number of required SCT hits (or -1 for no cut)"); + declareProperty ("selectionDecoration", m_selectionDecoration, "the decoration for the asg selection"); + declareProperty ("eventInfo", m_eventInfo, "the name of the EventInfo object to retrieve"); + declareProperty ("primaryVertices", m_primaryVertices, "the name of the PrimaryVertex container to retrieve"); + } + + + + StatusCode AsgLeptonTrackSelectionAlg :: + initialize () + { + if (m_selectionDecoration.empty()) + { + ANA_MSG_ERROR ("no selection decoration name set"); + return StatusCode::FAILURE; + } + ANA_CHECK (makeSelectionAccessor (m_selectionDecoration, m_selectionAccessor)); + + if (m_maxD0Significance < 0 || !std::isfinite (m_maxD0Significance)) + { + ATH_MSG_ERROR ("invalid value of maxD0Significance: " << m_maxD0Significance); + return StatusCode::FAILURE; + } + if (m_maxDeltaZ0SinTheta < 0 || !std::isfinite (m_maxDeltaZ0SinTheta)) + { + ATH_MSG_ERROR ("invalid value of maxDeltaZ0SinTheta: " << m_maxDeltaZ0SinTheta); + return StatusCode::FAILURE; + } + + m_accept.addCut ("trackRetrieval", "whether the track retrieval failed"); + if (m_maxD0Significance > 0) + m_accept.addCut ("maxD0Significance", "maximum D0 significance cut"); + if (m_maxDeltaZ0SinTheta > 0) + m_accept.addCut ("maxDeltaZ0SinTheta", "maximum Delta z0 sin theta cut"); + if (m_nMinPixelHits != -1 || m_nMaxPixelHits != -1) + m_accept.addCut ("numPixelHits", "Minimum and/or maxiumum Pixel hits"); + if (m_nMinSCTHits != -1 || m_nMaxSCTHits != -1) + m_accept.addCut ("numSCTHits", "Minimum and/or maxiumum SCT hits"); + + m_systematicsList.addHandle (m_particlesHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode AsgLeptonTrackSelectionAlg :: + execute () + { + const xAOD::EventInfo *eventInfo {nullptr}; + if (m_maxD0Significance > 0) + ANA_CHECK (evtStore()->retrieve (eventInfo, m_eventInfo)); + + const xAOD::Vertex *primaryVertex {nullptr}; + if (m_maxDeltaZ0SinTheta > 0) + { + const xAOD::VertexContainer *vertices {nullptr}; + ANA_CHECK (evtStore()->retrieve (vertices, m_primaryVertices)); + for (const xAOD::Vertex *vertex : *vertices) + { + if (vertex->vertexType() == xAOD::VxType::PriVtx) + { + // The default "PrimaryVertex" container is ordered in + // sum-pt, and the tracking group recommends to pick the one + // with the maximum sum-pt, so this will do the right thing. + // If the user needs a different primary vertex, he needs to + // provide a reordered primary vertex container and point + // this algorithm to it. Currently there is no central + // algorithm to do that, so users will have to write their + // own (15 Aug 18). + if (primaryVertex == nullptr) + { + primaryVertex = vertex; + break; + } + } + } + } + + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::IParticleContainer *particles = nullptr; + ANA_CHECK (m_particlesHandle.getCopy (particles, sys)); + for (xAOD::IParticle *particle : *particles) + { + m_accept.clear(); + + if (m_preselection.getBool (*particle)) + { + std::size_t cutIndex {0}; + + const xAOD::TrackParticle *track {nullptr}; + if (const xAOD::Muon *muon = dynamic_cast<xAOD::Muon*>(particle)) + track = muon->primaryTrackParticle(); + else if (const xAOD::Electron *electron = dynamic_cast<xAOD::Electron*>(particle)) + track = electron->trackParticle(); + else + { + ANA_MSG_ERROR ("failed to cast input to electron or muon"); + return StatusCode::FAILURE; + } + + m_accept.setCutResult (cutIndex ++, track != nullptr); + if (track != nullptr) + { + if (m_maxD0Significance > 0) + { + try + { + const float d0sig = xAOD::TrackingHelpers::d0significance + (track, eventInfo->beamPosSigmaX(), eventInfo->beamPosSigmaY(), + eventInfo->beamPosSigmaXY()); + m_accept.setCutResult (cutIndex ++, fabs( d0sig ) < m_maxD0Significance); + } catch (const std::runtime_error &) { + m_accept.setCutResult (cutIndex ++, false); + } + } + if (m_maxDeltaZ0SinTheta > 0) + { + const double vertex_z = primaryVertex ? primaryVertex->z() : 0; + const float deltaZ0SinTheta + = (track->z0() + track->vz() - vertex_z) * sin (particle->p4().Theta()); + m_accept.setCutResult (cutIndex ++, fabs (deltaZ0SinTheta) < m_maxDeltaZ0SinTheta); + } + if (m_nMinPixelHits != -1 || m_nMaxPixelHits != -1) { + uint8_t nPixelHits; + track->summaryValue(nPixelHits, xAOD::numberOfPixelHits); + bool accept = true; + if(m_nMinPixelHits != -1) { + accept &= nPixelHits >= m_nMinPixelHits; + } + if(m_nMaxPixelHits != -1) { + accept &= nPixelHits <= m_nMaxPixelHits; + } + m_accept.setCutResult (cutIndex++, accept); + } + if (m_nMinSCTHits != -1 || m_nMaxSCTHits != -1) { + uint8_t nSCTHits; + track->summaryValue(nSCTHits, xAOD::numberOfSCTHits); + bool accept = true; + if(m_nMinSCTHits != -1) { + accept &= nSCTHits >= m_nMinSCTHits; + } + if(m_nMaxSCTHits != -1) { + accept &= nSCTHits <= m_nMaxSCTHits; + } + m_accept.setCutResult (cutIndex++, accept); + } + } + } + + m_selectionAccessor->setBits + (*particle, selectionFromAccept (m_accept)); + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgOriginalObjectLinkAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgOriginalObjectLinkAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fa93b7f58c4d500225a7f5b97724da559143f904 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgOriginalObjectLinkAlg.cxx @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/AsgOriginalObjectLinkAlg.h> + +// +// method implementations +// + +namespace CP +{ + AsgOriginalObjectLinkAlg :: + AsgOriginalObjectLinkAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + declareProperty ("baseContainerName", m_baseContainerName, "base particle container name"); + } + + + + StatusCode AsgOriginalObjectLinkAlg :: + initialize () + { + if (m_baseContainerName.empty()) + { + ANA_MSG_ERROR ("Base particle container name should not be empty."); + return StatusCode::FAILURE; + } + + m_systematicsList.addHandle (m_particleHandle); + ANA_CHECK (m_systematicsList.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode AsgOriginalObjectLinkAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::IParticleContainer *particles = nullptr; + ANA_CHECK (m_particleHandle.getCopy (particles, sys)); + + const xAOD::IParticleContainer *baseParticles = nullptr; + ANA_CHECK (evtStore()->retrieve(baseParticles, m_baseContainerName)); + + if (!xAOD::setOriginalObjectLink (*baseParticles, *particles)) + { + ATH_MSG_ERROR ("Cannot set original object links for container named " << m_baseContainerName); + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgPtEtaSelectionTool.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgPtEtaSelectionTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..32f936c0242b08979bdc41bdde7575b6a1a496b2 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgPtEtaSelectionTool.cxx @@ -0,0 +1,174 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/AsgPtEtaSelectionTool.h> + +#include <xAODEgamma/Egamma.h> +#include <xAODBase/IParticle.h> +#include <cmath> + +// +// method implementations +// + +namespace CP +{ + AsgPtEtaSelectionTool :: + AsgPtEtaSelectionTool (const std::string& name) + : AsgTool (name) + { + declareProperty ("minPt", m_minPt, "minimum pt to require (or 0 for no pt cut)"); + declareProperty ("maxPt", m_maxPt, "maximum pt to require (or 0 for no pt cut)"); + declareProperty ("maxEta", m_maxEta, "maximum abs(eta) to allow (or 0 for no eta cut)"); + declareProperty ("etaGapLow", m_etaGapLow, "low end of the eta gap"); + declareProperty ("etaGapHigh", m_etaGapHigh, "high end of the eta gap (or 0 for no eta gap)"); + declareProperty ("useClusterEta", m_useClusterEta, "whether to use the cluster eta (for electrons only)"); + declareProperty ("printCastWarning", m_printCastWarning, "whether to print a warning/error when the cast fails"); + declareProperty ("printClusterWarning", m_printClusterWarning, "whether to print a warning/error when the cluster is missing"); + } + + + + StatusCode AsgPtEtaSelectionTool :: + initialize () + { + if (m_minPt < 0 || !std::isfinite (m_minPt)) + { + ATH_MSG_ERROR ("invalid value of minPt: " << m_minPt); + return StatusCode::FAILURE; + } + if (m_maxPt < 0 || !std::isfinite (m_maxPt)) + { + ATH_MSG_ERROR ("invalid value of m_maxPt: " << m_maxPt); + return StatusCode::FAILURE; + } + if (m_maxEta < 0 || !std::isfinite (m_maxEta)) + { + ATH_MSG_ERROR ("invalid value of maxEta: " << m_maxEta); + return StatusCode::FAILURE; + } + if (m_etaGapLow < 0 || !std::isfinite (m_etaGapLow)) + { + ATH_MSG_ERROR ("invalid value of etaGapLow: " << m_etaGapLow); + return StatusCode::FAILURE; + } + if (m_etaGapHigh < 0 || !std::isfinite (m_etaGapHigh)) + { + ATH_MSG_ERROR ("invalid value of etaGapHigh: " << m_etaGapHigh); + return StatusCode::FAILURE; + } + if (m_etaGapHigh > 0 && m_etaGapLow >= m_etaGapHigh) + { + ATH_MSG_ERROR ("invalid eta gap: " << m_etaGapLow << " to " << m_etaGapHigh); + return StatusCode::FAILURE; + } + if (m_etaGapHigh > 0 && m_maxEta > 0 && m_etaGapHigh >= m_maxEta) + { + ATH_MSG_ERROR ("etaGapHigh=" << m_etaGapHigh << " >= maxEta=" << m_maxEta); + return StatusCode::FAILURE; + } + + if (m_minPt > 0) { + ATH_MSG_DEBUG( "Performing pt >= " << m_minPt << " MeV selection" ); + m_minPtCutIndex = m_accept.addCut ("minPt", "minimum pt cut"); + } + if (m_maxPt > 0) { + ATH_MSG_DEBUG( "Performing pt < " << m_maxPt << " MeV selection" ); + m_maxPtCutIndex = m_accept.addCut ("maxPt", "maximum pt cut"); + } + if (m_useClusterEta) { + ATH_MSG_DEBUG( "Performing eta cut on the e/gamma cluster" ); + m_egammaCastCutIndex = m_accept.addCut ("castEgamma", "cast to egamma"); + m_egammaClusterCutIndex = m_accept.addCut ("caloCluster", "egamma object has cluster"); + } + if (m_maxEta > 0) { + ATH_MSG_DEBUG( "Performing |eta| < " << m_maxEta << " selection" ); + m_maxEtaCutIndex = m_accept.addCut ("maxEta", "maximum eta cut"); + } + if (m_etaGapHigh > 0) { + ATH_MSG_DEBUG( "Performing !( " << m_etaGapLow << " < |eta| < " + << m_etaGapHigh << " ) selection" ); + m_etaGapCutIndex = m_accept.addCut ("etaGap", "eta gap cut"); + } + m_shouldPrintCastWarning = m_printCastWarning; + m_shouldPrintClusterWarning = m_printClusterWarning; + + return StatusCode::SUCCESS; + } + + + + const Root::TAccept& AsgPtEtaSelectionTool :: + getTAccept () const + { + return m_accept; + } + + + + const Root::TAccept& AsgPtEtaSelectionTool :: + accept (const xAOD::IParticle *particle) const + { + m_accept.clear(); + + // Perform the tranverse momentum cuts. + if (m_minPtCutIndex >= 0) { + m_accept.setCutResult (m_minPtCutIndex, particle->pt() >= m_minPt); + } + if (m_maxPtCutIndex >= 0) { + m_accept.setCutResult (m_maxPtCutIndex, particle->pt() < m_maxPt); + } + + // Perform the eta cut(s). + if (m_maxEtaCutIndex >= 0 || m_etaGapCutIndex >= 0) + { + float absEta = 0; + + if (m_useClusterEta == true) + { + const xAOD::Egamma *egamma + = dynamic_cast<const xAOD::Egamma*>(particle); + if (egamma == nullptr) + { + if (m_shouldPrintCastWarning) + ANA_MSG_ERROR ("failed to cast input particle to electron"); + m_shouldPrintCastWarning = false; + return m_accept; + } + m_accept.setCutResult (m_egammaCastCutIndex, true); + const xAOD::CaloCluster *const caloCluster {egamma->caloCluster()}; + if (!caloCluster) + { + if (m_shouldPrintClusterWarning) + ANA_MSG_ERROR ("no calo-cluster associated with e-gamma object"); + m_shouldPrintClusterWarning = false; + return m_accept; + } + m_accept.setCutResult (m_egammaClusterCutIndex, true); + absEta = std::abs (caloCluster->etaBE(2)); + } else + { + absEta = std::abs (particle->eta()); + } + + if (m_maxEtaCutIndex >= 0) { + m_accept.setCutResult (m_maxEtaCutIndex, absEta <= m_maxEta); + } + if (m_etaGapCutIndex >= 0) { + m_accept.setCutResult (m_etaGapCutIndex, (absEta < m_etaGapLow || + absEta > m_etaGapHigh)); + } + } + + return m_accept; + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgSelectionAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgSelectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..80951862530a149f949932585731d0577a9b2e46 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgSelectionAlg.cxx @@ -0,0 +1,89 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/AsgSelectionAlg.h> + +#include <PATInterfaces/ISystematicsTool.h> + +// +// method implementations +// + +namespace CP +{ + AsgSelectionAlg :: + AsgSelectionAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_selectionTool ("", this) + { + declareProperty ("selectionTool", m_selectionTool, "the selection tool we apply"); + declareProperty ("selectionDecoration", m_selectionDecoration, "the decoration for the asg selection"); + } + + + + StatusCode AsgSelectionAlg :: + initialize () + { + if (m_selectionDecoration.empty()) + { + ANA_MSG_ERROR ("no selection decoration name set"); + return StatusCode::FAILURE; + } + ANA_CHECK (makeSelectionAccessor (m_selectionDecoration, m_selectionAccessor)); + + ANA_CHECK (m_selectionTool.retrieve()); + m_systematicsTool = dynamic_cast<ISystematicsTool*>(&*m_selectionTool); + if (m_systematicsTool) + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_systematicsTool->affectingSystematics())); + + m_systematicsList.addHandle (m_particlesHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + + Root::TAccept blankAccept = m_selectionTool->getTAccept(); + // Just in case this isn't initially set up as a failure clear it this one + // time. This only calls reset on the bitset + blankAccept.clear(); + m_setOnFail = selectionFromAccept(blankAccept); + + return StatusCode::SUCCESS; + } + + + + StatusCode AsgSelectionAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + if (m_systematicsTool) + ANA_CHECK (m_systematicsTool->applySystematicVariation (sys)); + + xAOD::IParticleContainer *particles = nullptr; + ANA_CHECK (m_particlesHandle.getCopy (particles, sys)); + for (xAOD::IParticle *particle : *particles) + { + if (m_preselection.getBool (*particle)) + { + m_selectionAccessor->setBits + (*particle, selectionFromAccept (m_selectionTool->accept (particle))); + } + else + { + m_selectionAccessor->setBits(*particle, m_setOnFail); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgViewFromSelectionAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgViewFromSelectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..07f99decf502c5e6019aefc62d1f55cbb072048d --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgViewFromSelectionAlg.cxx @@ -0,0 +1,228 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/AsgViewFromSelectionAlg.h> + +#include <CxxUtils/fpcompare.h> +#include <xAODCore/AuxContainerBase.h> +#include <xAODEgamma/PhotonContainer.h> +#include <xAODEgamma/ElectronContainer.h> +#include <xAODJet/JetContainer.h> +#include <xAODMuon/MuonContainer.h> +#include <xAODTau/TauJetContainer.h> +#include <xAODTau/DiTauJetContainer.h> +#include <xAODTracking/TrackParticleContainer.h> +#include <xAODTruth/TruthParticleContainer.h> + +// +// method implementations +// + +namespace CP +{ + template<typename Type> StatusCode AsgViewFromSelectionAlg :: + executeTemplate (const CP::SystematicSet& sys) + { + const Type *input = nullptr; + ANA_CHECK (evtStore()->retrieve (input, m_inputHandle.getName (sys))); + auto viewCopy = std::make_unique<Type> (SG::VIEW_ELEMENTS); + for (const auto particle : *input) + { + bool keep = true; + for (const auto& accessor : m_accessors) + { + if ((accessor.first->getBits (*particle) | accessor.second) != selectionAccept()) + { + keep = false; + break; + } + } + if (keep) + { + typename Type::value_type particleNC = + const_cast<typename Type::value_type>(particle); + viewCopy->push_back (particleNC); + } + } + + if (m_sortPt) + { + std::sort (viewCopy->begin(), viewCopy->end(), [] (const xAOD::IParticle *a, const xAOD::IParticle *b) {return CxxUtils::fpcompare::greater (a->pt(), b->pt());}); + } + + // If anyone might be concerned about efficiency here, this will + // add/sort a couple more entries than needed only to remove them + // from the vector afterwards, so there is a slight efficiency + // loss. However, this option is not expected to be used very + // often and the algorithm is still expected to run quickly, so I + // decided to keep the code above simpler and just do this as a + // separate step, instead of trying to optimize this by + // integrating it with the code above. + if (viewCopy->size() > m_sizeLimit) + viewCopy->resize (m_sizeLimit); + + // In case we want to output a view copy, do that here. + if (!m_deepCopy) + { + ANA_CHECK (evtStore()->record (viewCopy.release(), + m_outputHandle.getName (sys))); + return StatusCode::SUCCESS; + } + + // Apparently we want to make a deep copy. So set that one up. + auto deepCopy = std::make_unique<Type> (); + auto aux = std::make_unique<xAOD::AuxContainerBase> (); + deepCopy->setStore (aux.get()); + deepCopy->reserve (viewCopy->size()); + for (auto particle : *viewCopy) + { + typename Type::value_type pcopy = new typename Type::base_value_type(); + deepCopy->push_back (pcopy); + *pcopy = *particle; + } + + // Record the deep copy into the event store. + ANA_CHECK (evtStore()->record (deepCopy.release(), + m_outputHandle.getName (sys))); + ANA_CHECK (evtStore()->record (aux.release(), + m_outputHandle.getName (sys) + "Aux.")); + + return StatusCode::SUCCESS; + } + + + + + StatusCode AsgViewFromSelectionAlg :: + executeFindType (const CP::SystematicSet& sys) + { + if( m_allowMissing ) { + const std::string& name = m_inputHandle.getName( sys ); + if( ! evtStore()->contains< xAOD::IParticleContainer >( name ) ) { + m_function = &AsgViewFromSelectionAlg::executeMissing; + return StatusCode::SUCCESS; + } + } + + const xAOD::IParticleContainer *input = nullptr; + ANA_CHECK (m_inputHandle.retrieve (input, sys)); + + if (dynamic_cast<const xAOD::ElectronContainer*> (input)) + { + m_function = + &AsgViewFromSelectionAlg::executeTemplate<xAOD::ElectronContainer>; + } + else if (dynamic_cast<const xAOD::PhotonContainer*> (input)) + { + m_function = + &AsgViewFromSelectionAlg::executeTemplate<xAOD::PhotonContainer>; + } + else if (dynamic_cast<const xAOD::JetContainer*> (input)) + { + m_function = + &AsgViewFromSelectionAlg::executeTemplate<xAOD::JetContainer>; + } + else if (dynamic_cast<const xAOD::MuonContainer*> (input)) { + m_function = + &AsgViewFromSelectionAlg::executeTemplate<xAOD::MuonContainer>; + } + else if (dynamic_cast<const xAOD::TauJetContainer*> (input)) + { + m_function = + &AsgViewFromSelectionAlg::executeTemplate<xAOD::TauJetContainer>; + } + else if (dynamic_cast<const xAOD::DiTauJetContainer*> (input)) + { + m_function = + &AsgViewFromSelectionAlg::executeTemplate<xAOD::DiTauJetContainer>; + } + else if (dynamic_cast<const xAOD::TrackParticleContainer*> (input)) + { + m_function = + &AsgViewFromSelectionAlg::executeTemplate<xAOD::TrackParticleContainer>; + } + else if (dynamic_cast<const xAOD::TruthParticleContainer*> (input)) + { + m_function = + &AsgViewFromSelectionAlg::executeTemplate<xAOD::TruthParticleContainer>; + } + else + { + ANA_MSG_ERROR ("unknown type contained in AsgViewFromSelectionAlg, please extend it"); + return StatusCode::FAILURE; + } + + return (this->*m_function) (sys); + } + + + + StatusCode AsgViewFromSelectionAlg :: + executeMissing (const CP::SystematicSet&) + { + return StatusCode::SUCCESS; + } + + + + AsgViewFromSelectionAlg :: + AsgViewFromSelectionAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + /// \todo this would probably better be an std::map, but this + /// isn't supported as a property type for AnaAlgorithm right now + declareProperty ("selection", m_selection, "the list of selection decorations"); + declareProperty ("ignore", m_ignore, "the list of cuts to *ignore* for each selection"); + declareProperty ("sortPt", m_sortPt, "whether to sort objects in pt"); + declareProperty ("allowMissing", m_allowMissing, + "Allow the input container to be missing"); + declareProperty ("sizeLimit", m_sizeLimit, "the limit on the size of the output container"); + declareProperty ("deepCopy", m_deepCopy, "perform a deep copy"); + } + + + + StatusCode AsgViewFromSelectionAlg :: + initialize () + { + m_systematicsList.addHandle (m_inputHandle); + m_systematicsList.addHandle (m_outputHandle); + ANA_CHECK (m_systematicsList.initialize()); + + if (m_ignore.size() > m_selection.size()) + { + ANA_MSG_ERROR ("ignore property can't have more properties than selection property"); + return StatusCode::FAILURE; + } + for (std::size_t iter = 0, end = m_selection.size(); iter != end; ++ iter) + { + SelectionType ignore = 0; + if (iter < m_ignore.size()) + ignore = m_ignore[iter]; + std::unique_ptr<ISelectionAccessor> accessor; + ANA_CHECK (makeSelectionAccessor (m_selection[iter], accessor)); + m_accessors.push_back (std::make_pair (std::move (accessor), ignore)); + } + + return StatusCode::SUCCESS; + } + + + + StatusCode AsgViewFromSelectionAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + return (this->*m_function) (sys);}); + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgxAODNTupleMakerAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgxAODNTupleMakerAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8ff21f3eeecd24a876c44798e1f557379efa5026 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/AsgxAODNTupleMakerAlg.cxx @@ -0,0 +1,953 @@ +// Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +// Local include(s): +#include "AsgAnalysisAlgorithms/AsgxAODNTupleMakerAlg.h" + +// EDM include(s): +#include "AthContainersInterfaces/IAuxTypeVectorFactory.h" +#include "AthContainers/AuxElement.h" +#include "AthContainers/AuxVectorBase.h" +#include "AthContainers/normalizedTypeinfoName.h" + +// Framework include(s): +#include "SystematicsHandles/Helpers.h" + +// ROOT include(s): +#include <TClass.h> +#include <TTree.h> +#include <TBranch.h> +#include <TVirtualCollectionProxy.h> + +// System include(s): +#include <regex> +#include <algorithm> +#include <functional> +#include <sstream> + +namespace { + +#ifdef XAOD_STANDALONE + + /// Get an xAOD container from the event store + /// + /// This is the "standalone implementation" of the function. + /// + /// @param key The name of the container in the event store + /// @param evtStore The value of evtStore() from the algorithm + /// @param allowMissing Set to @c true to print an error message in case + /// of a failure + /// @param msg Reference to the caller's @c MsgStream object + /// @return A pointer to the container if successful, @c nullptr if not + /// + const SG::AuxVectorBase* getVector( const std::string& key, + asg::SgTEvent& evtStore, + bool allowMissing, + MsgStream& msg ) { + if( allowMissing && + ( ! evtStore.contains< const SG::AuxVectorBase >( key ) ) ) { + return nullptr; + } + const SG::AuxVectorBase* c = nullptr; + if( ! evtStore.retrieve( c, key ).isSuccess() ) { + msg << MSG::ERROR << "Couldn't retrieve container with key \"" << key + << "\"" << endmsg; + return nullptr; + } + return c; + } + + /// Get a standalone xAOD object from the event store + /// + /// This is the "standalone implementation" of the function. + /// + /// @param key The name of the container in the event store + /// @param evtStore The value of evtStore() from the algorithm + /// @param allowMissing Set to @c true to print an error message in case + /// of a failure + /// @param msg Reference to the caller's @c MsgStream object + /// @return A pointer to the container if successful, @c nullptr if not + /// + const SG::AuxElement* getElement( const std::string& key, + asg::SgTEvent& evtStore, + bool allowMissing, + MsgStream& msg ) { + if( allowMissing && + ( ! evtStore.contains< const SG::AuxElement >( key ) ) ) { + return nullptr; + } + const SG::AuxElement* e = nullptr; + if( ! evtStore.retrieve( e, key ).isSuccess() ) { + msg << MSG::ERROR << "Couldn't retrieve object with key \"" << key + << "\"" << endmsg; + return nullptr; + } + return e; + } + +#else + + /// Predicate for finding a proxy with a given name + class ProxyWithName { + public: + /// Type of the predicate's argument + typedef const SG::DataProxy* argument_type; + /// Constructor with key/name + ProxyWithName( const std::string& name ) : m_name( name ) {} + /// Operator evaluating whether this is a good proxy or not + bool operator()( argument_type proxy ) const { + return ( proxy->name() == m_name ); + } + private: + std::string m_name; ///< Name for the proxy to find + }; // class ProxyWithName + + /// Get an xAOD container from the event store + /// + /// This is the "Athena implementation" of the function. + /// + /// @param key The name of the container in the event store + /// @param evtStore The value of evtStore() from the algorithm + /// @param allowMissing Set to @c true to print an error message in case + /// of a failure + /// @param msg Reference to the caller's @c MsgStream object + /// @return A pointer to the container if successful, @c nullptr if not + /// + const SG::AuxVectorBase* getVector( const std::string& key, + IProxyDict& evtStore, + bool allowMissing, + MsgStream& msg ) { + + // Find all proxies with this key: + auto proxies = evtStore.proxies(); + proxies.erase( std::remove_if( proxies.begin(), proxies.end(), + std::not1( ProxyWithName( key ) ) ), + proxies.end() ); + // Now iterate over them: + for( const SG::DataProxy* proxy : proxies ) { + // We need a non-const version of it... :-( + SG::DataProxy* proxy_nc = const_cast< SG::DataProxy* >( proxy ); + // Try to get the right object out of it. + DataBucketBase* bucket = + dynamic_cast< DataBucketBase* >( proxy_nc->accessData() ); + if( ! bucket ) { + // This is a big problem in the job. Return right away. + msg << MSG::ERROR + << "Couldn't access data object as a data bucket?!?" << endmsg; + return nullptr; + } + // Get the dictionary for the type: + TClass* cl = TClass::GetClass( bucket->tinfo() ); + if( ! cl ) { + if( msg.level() <= MSG::VERBOSE ) { + msg << MSG::VERBOSE << "No dictionary found for: " + << bucket->tinfo().name() << endmsg; + } + continue; + } + // Check whether the object inherits from AuxVectorBase: + if( ! cl->InheritsFrom( "SG::AuxVectorBase" ) ) { + if( msg.level() <= MSG::VERBOSE ) { + msg << MSG::VERBOSE << "Object \"" << key << "/" << cl->GetName() + << "\" does not inherit from SG::AuxVectorBase" << endmsg; + } + continue; + } + // If all is well, just assume that the inheritance is direct/simple: + const SG::AuxVectorBase* result = + reinterpret_cast< const SG::AuxVectorBase* >( bucket->object() ); + return result; + } + + // Apparently we failed... + if( ! allowMissing ) { + msg << MSG::ERROR << "Couldn't retrieve object \"" << key + << "\" as SG::AuxVectorBase" << endmsg; + } + return nullptr; + } + + /// Get a standalone xAOD object from the event store + /// + /// This is the "Athena implementation" of the function. + /// + /// @param key The name of the container in the event store + /// @param evtStore The value of evtStore() from the algorithm + /// @param allowMissing Set to @c true to print an error message in case + /// of a failure + /// @param msg Reference to the caller's @c MsgStream object + /// @return A pointer to the container if successful, @c nullptr if not + /// + const SG::AuxElement* getElement( const std::string& key, + IProxyDict& evtStore, + bool allowMissing, + MsgStream& msg ) { + + // Find all proxies with this key: + auto proxies = evtStore.proxies(); + proxies.erase( std::remove_if( proxies.begin(), proxies.end(), + std::not1( ProxyWithName( key ) ) ), + proxies.end() ); + // Now iterate over them: + for( const SG::DataProxy* proxy : proxies ) { + // We need a non-const version of it... :-( + SG::DataProxy* proxy_nc = const_cast< SG::DataProxy* >( proxy ); + // Try to get the right object out of it. + DataBucketBase* bucket = + dynamic_cast< DataBucketBase* >( proxy_nc->accessData() ); + if( ! bucket ) { + // This is a big problem in the job. Return right away. + msg << MSG::ERROR + << "Couldn't access data object as a data bucket?!?" << endmsg; + return nullptr; + } + // Get the dictionary for the type: + TClass* cl = TClass::GetClass( bucket->tinfo() ); + if( ! cl ) { + if( msg.level() <= MSG::VERBOSE ) { + msg << MSG::VERBOSE << "No dictionary found for: " + << bucket->tinfo().name() << endmsg; + } + continue; + } + // Check whether the object inherits from AuxVectorBase: + if( ! cl->InheritsFrom( "SG::AuxElement" ) ) { + if( msg.level() <= MSG::VERBOSE ) { + msg << MSG::VERBOSE << "Object \"" << key << "/" << cl->GetName() + << "\" does not inherit from SG::AuxElement" << endmsg; + } + continue; + } + // If all is well, just assume that the inheritance is direct/simple: + return reinterpret_cast< const SG::AuxElement* >( bucket->object() ); + } + + // Apparently we failed... + if( ! allowMissing ) { + msg << MSG::ERROR << "Couldn't retrieve object \"" << key + << "\" as SG::AuxElement" << endmsg; + } + return nullptr; + } +#endif // XAOD_STANDALONE + + /// This function is used internally in the code when creating primitive + /// branches. I just took the code from xAODRootAccess, which itself too it + /// from SFrame... :-P + /// + /// @param typeidType The type name coming from typeid(...).name() + /// @param msg The caller's @c MsgStream object + /// @return The character describing this type for @c TTree::Branch + /// + char rootType( char typeidType, MsgStream& msg ) { + + // Do the hard-coded translation: + switch( typeidType ) { + + case 'c': + return 'B'; + break; + case 'h': + return 'b'; + break; + case 's': + return 'S'; + break; + case 't': + return 's'; + break; + case 'i': + return 'I'; + break; + case 'j': + return 'i'; + break; + case 'f': + return 'F'; + break; + case 'd': + return 'D'; + break; + case 'x': + return 'L'; + break; + case 'y': + case 'm': // Not sure how platform-independent this one is... + return 'l'; + break; + case 'b': + return 'O'; + break; + default: + // If we didn't find this type: + msg << MSG::ERROR << "Received an unknown type: " << typeidType + << endmsg; + return '\0'; + break; + } + } + + /// Check if an aux item exists in the aux store + /// + /// @param key The name of the container in the event store + /// @return True if branch exists, false if not + /// + bool auxItemExists( const std::string& key ) { + // Get a pointer to the vector factory. + const SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + + // Try to find the aux item + return reg.findAuxID( key ) != SG::null_auxid; + } +} // private namespace + +namespace CP { + + AsgxAODNTupleMakerAlg::AsgxAODNTupleMakerAlg( const std::string& name, + ISvcLocator* svcLoc ) + : EL::AnaAlgorithm( name, svcLoc ) { + + // Declare the algorithm's properties. + declareProperty( "TreeName", m_treeName = "physics", + "Name of the tree to write" ); + declareProperty( "Branches", m_branches, + "Branches to write to the output tree" ); + } + + StatusCode AsgxAODNTupleMakerAlg::initialize() { + + // Check that at least one branch is configured. + if( m_branches.empty() ) { + ATH_MSG_ERROR( "No branches set up for writing" ); + return StatusCode::FAILURE; + } + + // Set up the systematics list. + ATH_CHECK( m_systematicsList.initialize() ); + + // Reset the initialisation flag: + m_isInitialized = false; + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode AsgxAODNTupleMakerAlg::execute() { + + // Initialise the processor objects on the first event. + if( ! m_isInitialized ) { + // Initialise the output tree. + m_tree = tree( m_treeName ); + if( ! m_tree ) { + ATH_MSG_ERROR( "Could not find output tree \"" << m_treeName + << "\"" ); + return StatusCode::FAILURE; + } + // Call the setup function. + ATH_CHECK( setupTree() ); + // The processor objects are now set up. + m_isInitialized = true; + } + + // Process the standalone objects: + for( auto& element_itr : m_elements ) { + // Retrieve the object: + static const bool ALLOW_MISSING = false; + const SG::AuxElement* el = getElement( element_itr.first, + *( evtStore() ), + ALLOW_MISSING, msg() ); + if( ! el ) { + ATH_MSG_ERROR( "Failed to retrieve object \"" << element_itr.first + << "\"" ); + return StatusCode::FAILURE; + } + // Process it: + ATH_CHECK( element_itr.second.process( *el ) ); + } + + // Process the container objects: + for( auto& container_itr : m_containers ) { + // Retrieve the container: + static const bool ALLOW_MISSING = false; + const SG::AuxVectorBase* vec = getVector( container_itr.first, + *( evtStore() ), + ALLOW_MISSING, msg() ); + if( ! vec ) { + ATH_MSG_ERROR( "Failed to retrieve container \"" + << container_itr.first << "\"" ); + return StatusCode::FAILURE; + } + // Process it. + ATH_CHECK( container_itr.second.process( *vec ) ); + } + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode AsgxAODNTupleMakerAlg::finalize() { + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode AsgxAODNTupleMakerAlg::setupTree() { + + // First process nominal + CP::SystematicSet nominal{}; + for( const std::string& branchDecl : m_branches ) { + ATH_CHECK( setupBranch( branchDecl, nominal ) ); + } + + // Consider all systematics but skip the nominal one + for( const auto& sys : m_systematicsList.systematicsVector() ) { + // Nominal already processed + if( sys.empty() ) { + continue; + } + + // Iterate over the branch specifications. + for( const std::string& branchDecl : m_branches ) { + ATH_CHECK( setupBranch( branchDecl, sys ) ); + } + } + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode AsgxAODNTupleMakerAlg::setupBranch( const std::string &branchDecl, + const CP::SystematicSet &sys ) { + + // The regular expression used to extract the needed info. The logic + // is supposed to be: + // + // (match[1]).(match[2])<any whitespace>-><any whitespace>(match[3]) + // + // Like: + // "Electrons.eta -> el_eta" + // + // , where we would pick up "Electrons", "eta" and "el_eta" as the + // three words using this regexp. + static const std::regex + re( "\\s*([\\w%]+)\\.([\\w%]+)\\s*->\\s*([\\w%]+)" ); + + // Interpret this branch declaration. + std::smatch match; + if( ! std::regex_match( branchDecl, match, re ) ) { + ATH_MSG_ERROR( "Expression \"" << branchDecl + << "\" doesn't match \"<object>.<variable> ->" + " <branch>\"" ); + return StatusCode::FAILURE; + } + + // Check if we are running nominal + bool nominal = sys.empty(); + + // Event store key for the object under consideration. + const std::string key = makeSystematicsName( match[ 1 ], sys ); + // Auxiliary variable name for the object under consideration. + const std::string auxName = makeSystematicsName( match[ 2 ], + sys ); + // Branch name for the variable. + const std::string brName = makeSystematicsName( match[ 3 ], + sys ); + + // If the %SYS% pattern was not used in this setup, then stop + // on non-nominal systematic. + if( ! nominal && + ( key == match[ 1 ] ) && ( auxName == match[ 2 ] ) && + ( brName == match[ 3 ] ) ) { + return StatusCode::SUCCESS; + } + + // Check that we use the %SYS% pattern reasonably in the names. + if( ( ( key == match[ 1 ] ) && ( auxName == match[ 2 ] ) && + ( brName != match[ 3 ] ) ) || + ( ( ( key != match[ 1 ] ) || ( auxName != match[ 2 ] ) ) && + ( brName == match[ 3 ] ) ) ) { + ATH_MSG_ERROR( "The systematic variation pattern is used " + "inconsistently in: \"" << branchDecl + << "\"" ); + return StatusCode::FAILURE; + } + + // Flag keeping track whether any branch was set up for this rule. + bool branchCreated = false; + + // Decide whether the specified key belongs to a container or + // a standalone object. + static const bool ALLOW_MISSING = true; + if( getVector( key, *( evtStore() ), ALLOW_MISSING, + msg() ) ) { + bool created = false; + ATH_CHECK( m_containers[ key ].addBranch( *m_tree, + auxName, + brName, + ALLOW_MISSING, + created ) ); + if( created ) { + ATH_MSG_DEBUG( "Writing branch \"" << brName + << "\" from container/variable \"" << key + << "." << auxName << "\"" ); + branchCreated = true; + } else { + ATH_MSG_DEBUG( "Skipping branch \"" << brName + << "\" from container/variable \"" << key + << "." << auxName << "\"" ); + } + } else if( getElement( key, *( evtStore() ), + ALLOW_MISSING, msg() ) ) { + bool created = false; + ATH_CHECK( m_elements[ key ].addBranch( *m_tree, + auxName, + brName, + ALLOW_MISSING, + created ) ); + if( created ) { + ATH_MSG_DEBUG( "Writing branch \"" << brName + << "\" from object/variable \"" << key + << "." << auxName << "\"" ); + branchCreated = true; + } else { + ATH_MSG_DEBUG( "Skipping branch \"" << brName + << "\" from object/variable \"" << key + << "." << auxName << "\"" ); + } + } else { + ATH_MSG_DEBUG( "Container \"" << key + << "\" not readable for expression: \"" + << branchDecl << "\"" ); + } + + // Check if the rule was meaningful or not: + if( nominal && ! branchCreated && key == match[ 1 ] ) { + ATH_MSG_ERROR( "No branch was created for rule: \"" + << branchDecl << "\"" ); + return StatusCode::FAILURE; + } + + // Return gracefully. + return StatusCode::SUCCESS; + } + + AsgxAODNTupleMakerAlg::ElementProcessor::ElementProcessor() + : asg::AsgMessaging( "CP::AsgxAODNTupleMakerAlg::ElementProcessor" ) { + + } + + StatusCode AsgxAODNTupleMakerAlg::ElementProcessor:: + process( const SG::AuxElement& element ) { + + // Process all branches. + for( BranchProcessor& p : m_branches ) { + ATH_CHECK( p.process( element, msg() ) ); + } + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode AsgxAODNTupleMakerAlg::ElementProcessor:: + addBranch( TTree& tree, const std::string& auxName, + const std::string& branchName, + bool allowMissing, + bool &created ) { + + /// Helper class for finding an already existing branch processor. + class BranchFinder { + public: + /// Type of the predicate's argument + typedef const BranchProcessor& argument_type; + /// Constructor with key/name + BranchFinder( const std::string& branchName ) : m_name( branchName ) {} + /// Operator evaluating whether this is the branch we're looking for + bool operator()( argument_type bp ) const { + return ( bp.m_branchName == m_name ); + } + private: + std::string m_name; ///< Name of the branch + }; // class BranchFinder + + // Check if the corresponding aux item exists + bool validAuxItem = auxItemExists( auxName ); + if( ! validAuxItem ) { + if( allowMissing ) { + // Return gracefully. + ATH_MSG_DEBUG( "Aux item \"" << auxName + << "\" not readable for branch \"" + << branchName << "\"" ); + return StatusCode::SUCCESS; + } else { + // Return gracefully. + ATH_MSG_ERROR( "Aux item \"" << auxName + << "\" not readable for branch \"" + << branchName << "\"" ); + return StatusCode::FAILURE; + } + } + + // Check whether this branch is already set up: + auto itr = std::find_if( m_branches.begin(), m_branches.end(), + BranchFinder( branchName ) ); + if( itr != m_branches.end() ) { + ATH_MSG_WARNING( "Duplicate setup received for branch: " << branchName ); + return StatusCode::SUCCESS; + } + + created = true; + + // Set up the new branch. + m_branches.emplace_back(); + ATH_CHECK( m_branches.back().setup( tree, auxName, branchName, msg() ) ); + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode + AsgxAODNTupleMakerAlg::ElementProcessor::BranchProcessor:: + setup( TTree& tree, const std::string& auxName, + const std::string& branchName, MsgStream& msg ) { + + // Remember the branch name. + m_branchName = branchName; + + // Create the accessor. + m_acc.reset( new SG::AuxElement::TypelessConstAccessor( auxName ) ); + + // Get a pointer to the vector factory. + const SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + const std::type_info* ti = reg.getType( m_acc->auxid() ); + if( ! ti ) { + msg << MSG::ERROR + << "No std::type_info available for auxiliary variable: " + << auxName << endmsg; + return StatusCode::FAILURE; + } + m_factory = reg.getFactory( *ti ); + if( ! m_factory ) { + msg << MSG::ERROR << "No factory found for auxiliary variable: " + << auxName << endmsg; + return StatusCode::FAILURE; + } + + // Create the data object. + m_data.reset( m_factory->create( 1, 1 ) ); + + // Pointer to the branch, to be created. + TBranch* br = nullptr; + + // Decide whether we're dealing with a "primitive" or an "object" branch. + if( strlen( ti->name() ) == 1 ) { + + // This is a "primitive" variable... + + // Get the type identifier for it that ROOT will understand. + const char rType = rootType( ti->name()[ 0 ], msg ); + if( rType == '\0' ) { + msg << MSG::ERROR << "Type not recognised for variable: " + << branchName << endmsg; + return StatusCode::FAILURE; + } + + // Construct the type description. + std::ostringstream typeDesc; + typeDesc << branchName << "/" << rType; + + // Create the primitive branch. + br = tree.Branch( branchName.c_str(), m_data->toPtr(), + typeDesc.str().c_str() ); + + } else { + + // This is an "object" variable... + + // Get a proper type name for the variable. + const std::string typeName = SG::normalizedTypeinfoName( *ti ); + + // Access the dictionary for the type. + TClass* cl = TClass::GetClass( *ti ); + if( ! cl ) { + cl = TClass::GetClass( typeName.c_str() ); + } + if( ! cl ) { + msg << MSG::ERROR << "Couldn't find dictionary for type: " + << typeName << endmsg; + return StatusCode::FAILURE; + } + if( ! cl->GetStreamerInfo() ) { + msg << MSG::ERROR << "No streamer info available for type: " + << cl->GetName() << endmsg; + return StatusCode::FAILURE; + } + + // Create the object branch. + m_dataPtr = m_data->toPtr(); + br = tree.Branch( branchName.c_str(), cl->GetName(), &m_dataPtr ); + + } + + // Check that the branch creation succeeded. + if( ! br ) { + msg << MSG::ERROR << "Failed to create branch: " << branchName + << endmsg; + return StatusCode::FAILURE; + } + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode + AsgxAODNTupleMakerAlg::ElementProcessor::BranchProcessor:: + process( const SG::AuxElement& element, MsgStream& msg ) { + + // A security check. + if( ( ! m_acc ) || ( ! m_factory ) || ( ! m_data ) ) { + msg << MSG::FATAL << "Internal logic error detected" << endmsg; + return StatusCode::FAILURE; + } + + // Get the data out of the xAOD object. + const void* auxData = ( *m_acc )( element ); + + // Copy it into the output variable. + m_factory->copy( m_data->toPtr(), 0, auxData, 0 ); + + // Return gracefully. + return StatusCode::SUCCESS; + } + + AsgxAODNTupleMakerAlg::ContainerProcessor::ContainerProcessor() + : asg::AsgMessaging( "CP::AsgxAODNTupleMakerAlg::ContainerProcessor" ) { + + } + + StatusCode AsgxAODNTupleMakerAlg::ContainerProcessor:: + process( const SG::AuxVectorBase& container ) { + + // Get the collection proxy for the type if it's not available yet. + if( ! m_collProxy ) { + + // Try to get the dictionary for the type. + TClass* cl = TClass::GetClass( typeid( container ) ); + if( ! cl ) { + ATH_MSG_ERROR( "No dictionary found for container" ); + return StatusCode::FAILURE; + } + + // Get the collection proxy from the dictionary. + m_collProxy = cl->GetCollectionProxy(); + if( ! m_collProxy ) { + ATH_MSG_ERROR( "No collection proxy provided by type: " + << cl->GetName() ); + return StatusCode::FAILURE; + } + + // Get the offset that one needs to use to get from the element + // pointers to SG::AuxElement pointers. + static const TClass* auxElementClass = + TClass::GetClass( typeid( SG::AuxElement ) ); + m_auxElementOffset = + m_collProxy->GetValueClass()->GetBaseClassOffset( auxElementClass ); + if( m_auxElementOffset < 0 ) { + ATH_MSG_ERROR( "Vector element type \"" + << m_collProxy->GetValueClass()->GetName() + << "\" doesn't seem to inherit from \"" + << auxElementClass->GetName() << "\"" ); + return StatusCode::FAILURE; + } + } + + // Set up the iteration over the elements of the container. In a really + // low level / ugly way... + void* cPtr = + const_cast< void* >( static_cast< const void* >( &container ) ); + TVirtualCollectionProxy::TPushPop helper( m_collProxy, cPtr ); + const UInt_t cSize = m_collProxy->Size(); + + // Tell all branch processors to resize their variables. + for( BranchProcessor& p : m_branches ) { + ATH_CHECK( p.resize( cSize, msg() ) ); + } + + // Now iterate over the container. + for( UInt_t i = 0; i < cSize; ++i ) { + + // Get the element. + char* elPtr = static_cast< char* >( m_collProxy->At( i ) ); + if( ! elPtr ) { + ATH_MSG_ERROR( "Failed to get element " << i << " from container" ); + return StatusCode::FAILURE; + } + const SG::AuxElement* element = + reinterpret_cast< const SG::AuxElement* >( elPtr + + m_auxElementOffset ); + + // Execute all branch processors on this element. + for( BranchProcessor& p : m_branches ) { + ATH_CHECK( p.process( *element, i, msg() ) ); + } + } + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode AsgxAODNTupleMakerAlg::ContainerProcessor:: + addBranch( TTree& tree, const std::string& auxName, + const std::string& branchName, + bool allowMissing, + bool &created ) { + + /// Helper class for finding an already existing branch processor. + class BranchFinder { + public: + /// Type of the predicate's argument + typedef const BranchProcessor& argument_type; + /// Constructor with key/name + BranchFinder( const std::string& branchName ) : m_name( branchName ) {} + /// Operator evaluating whether this is the branch we're looking for + bool operator()( argument_type bp ) const { + return ( bp.m_branchName == m_name ); + } + private: + std::string m_name; ///< Name of the branch + }; // class BranchFinder + + // Check if the corresponding aux item exists + bool validAuxItem = auxItemExists( auxName ); + if( ! validAuxItem ) { + if( allowMissing ) { + // Return gracefully. + ATH_MSG_DEBUG( "Aux item \"" << auxName + << "\" not readable for branch \"" + << branchName << "\"" ); + return StatusCode::SUCCESS; + } else { + // Return gracefully. + ATH_MSG_ERROR( "Aux item \"" << auxName + << "\" not readable for branch \"" + << branchName << "\"" ); + return StatusCode::FAILURE; + } + } + + // Check whether this branch is already set up: + auto itr = std::find_if( m_branches.begin(), m_branches.end(), + BranchFinder( branchName ) ); + if( itr != m_branches.end() ) { + ATH_MSG_WARNING( "Duplicate setup received for branch: " << branchName ); + return StatusCode::SUCCESS; + } + + created = true; + + // Set up the new branch. + m_branches.emplace_back(); + ATH_CHECK( m_branches.back().setup( tree, auxName, branchName, msg() ) ); + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode AsgxAODNTupleMakerAlg::ContainerProcessor::BranchProcessor:: + setup( TTree& tree, const std::string& auxName, + const std::string& branchName, MsgStream& msg ) { + + // Remember the branch name. + m_branchName = branchName; + + // Create the accessor. + m_acc.reset( new SG::AuxElement::TypelessConstAccessor( auxName ) ); + + // Get a pointer to the vector factory. + const SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + const std::type_info* ti = reg.getType( m_acc->auxid() ); + const std::type_info* vecTi = reg.getVecType( m_acc->auxid() ); + if( ( ! ti ) || ( ! vecTi ) ) { + msg << MSG::ERROR + << "No std::type_info available for auxiliary variable: " + << auxName << endmsg; + return StatusCode::FAILURE; + } + m_factory = reg.getFactory( *ti ); + if( ! m_factory ) { + msg << MSG::ERROR << "No factory found for auxiliary variable: " + << auxName << endmsg; + return StatusCode::FAILURE; + } + + // Create the data object. + m_data.reset( m_factory->create( 0, 0 ) ); + + // Get a proper type name for the variable. + const std::string typeName = SG::normalizedTypeinfoName( *vecTi ); + + // Access the dictionary for the type. + TClass* cl = TClass::GetClass( *vecTi ); + if( ! cl ) { + cl = TClass::GetClass( typeName.c_str() ); + } + if( ! cl ) { + msg << MSG::ERROR << "Couldn't find dictionary for type: " + << typeName << endmsg; + return StatusCode::FAILURE; + } + if( ! cl->GetStreamerInfo() ) { + msg << MSG::ERROR << "No streamer info available for type: " + << cl->GetName() << endmsg; + return StatusCode::FAILURE; + } + + // Create the branch. + m_dataPtr = m_data->toVector(); + TBranch* br = tree.Branch( branchName.c_str(), cl->GetName(), + &m_dataPtr ); + if( ! br ) { + msg << MSG::ERROR << "Failed to create branch: " << branchName + << endmsg; + return StatusCode::FAILURE; + } + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode AsgxAODNTupleMakerAlg::ContainerProcessor::BranchProcessor:: + resize( size_t size, MsgStream& msg ) { + + // A security check. + if( ! m_data ) { + msg << MSG::FATAL << "Internal logic error detected" << endmsg; + return StatusCode::FAILURE; + } + + // Do the deed. + m_data->resize( 0 ); + m_data->resize( size ); + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode AsgxAODNTupleMakerAlg::ContainerProcessor::BranchProcessor:: + process( const SG::AuxElement& element, size_t index, MsgStream& msg ) { + + // A security check. + if( ( ! m_acc ) || ( ! m_factory ) || ( ! m_data ) ) { + msg << MSG::FATAL << "Internal logic error detected" << endmsg; + return StatusCode::FAILURE; + } + + // Get the data out of the xAOD object. + const void* auxData = ( *m_acc )( element ); + + // Copy it into the output variable. + m_factory->copy( m_data->toPtr(), index, auxData, 0 ); + + // Return gracefully. + return StatusCode::SUCCESS; + } + +} // namespace CP diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/EventFlagSelectorAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/EventFlagSelectorAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c2a3b94c59205c0ccbf270b4a79c9db155a21cab --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/EventFlagSelectorAlg.cxx @@ -0,0 +1,75 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + +#include "AnaAlgorithm/FilterReporter.h" +#include <AsgAnalysisAlgorithms/EventFlagSelectionAlg.h> +#include <xAODEventInfo/EventInfo.h> + +CP::EventFlagSelectionAlg::EventFlagSelectionAlg(const std::string &name, + ISvcLocator *svcLoc) + : EL::AnaAlgorithm(name, svcLoc) +{ + declareProperty ("selectionFlags", m_selFlags, "list of flags to use as selection criteria"); + declareProperty ("invertFlags", m_invertFlags, "toggles for inverting the selection (index-parallel to selectionFlags)"); +} + +StatusCode CP::EventFlagSelectionAlg::initialize() +{ + if (m_invertFlags.size() != m_selFlags.size() && !m_invertFlags.empty()) { + ATH_MSG_ERROR("Property invertFlags has different size to selectionFlags. Please check your configuration"); + return StatusCode::FAILURE; + } + + for (size_t index = 0; index < m_selFlags.size(); ++index) { + const std::string& thisflag = m_selFlags[index]; + if (thisflag.empty()) { + ATH_MSG_ERROR("Empty string passed as selection flag!"); + return StatusCode::FAILURE; + } else { + // Extend m_invertFlags until the size matches m_selectionFlags + // Only done in the case that m_invert was empty + if (m_invertFlags.size() < index + 1) { m_invertFlags.push_back(false); } + + std::unique_ptr<ISelectionAccessor> accessor; + ANA_CHECK (makeSelectionAccessor (m_selFlags[index], accessor)); + m_accessors.push_back(std::move(accessor)); + } + } + + return StatusCode::SUCCESS; +} + +StatusCode CP::EventFlagSelectionAlg::execute() +{ + EL::FilterReporter filter (m_filterParams, false); + + const xAOD::EventInfo *evtInfo = 0; + ANA_CHECK(evtStore()->retrieve(evtInfo, "EventInfo")); + + for (size_t index = 0; index < m_selFlags.size(); ++index) { + // Test against the opposite of the invert value + bool testval = !m_invertFlags[index]; + ATH_MSG_VERBOSE("Now testing flag \"" << m_selFlags[index] << "\" requiring value " << testval); + + if (m_accessors[index]->getBool(*evtInfo) != testval) { + ATH_MSG_VERBOSE("Event failed."); + filter.setPassed(false); + return StatusCode::SUCCESS; + } + } + + ATH_MSG_VERBOSE("Event passed all flags."); + filter.setPassed(true); + + return StatusCode::SUCCESS; +} + +StatusCode CP::EventFlagSelectionAlg::finalize() +{ + ANA_CHECK (m_filterParams.finalize()); + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/EventSelectionByObjectFlagAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/EventSelectionByObjectFlagAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..22ff1923a18952297f4e8b94b39b9a90a4e98086 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/EventSelectionByObjectFlagAlg.cxx @@ -0,0 +1,68 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Miha Muskinja + +// +// includes +// + +#include <AsgAnalysisAlgorithms/EventSelectionByObjectFlagAlg.h> +#include <SystematicsHandles/SysFilterReporter.h> +#include <SystematicsHandles/SysFilterReporterCombiner.h> + +// +// method implementations +// + +namespace CP { + +EventSelectionByObjectFlagAlg ::EventSelectionByObjectFlagAlg( + const std::string &name, ISvcLocator *pSvcLocator) + : AnaAlgorithm(name, pSvcLocator) {} + +StatusCode EventSelectionByObjectFlagAlg ::initialize() { + + m_systematicsList.addHandle(m_particleHandle); + ANA_CHECK(m_systematicsList.initialize()); + ANA_CHECK(m_preselection.initialize()); + ANA_CHECK(m_veto.initialize()); + ANA_CHECK(m_filterParams.initialize()); + + return StatusCode::SUCCESS; +} + +StatusCode EventSelectionByObjectFlagAlg ::execute() { + + SysFilterReporterCombiner filterCombiner (m_filterParams, m_systematicsList, true); + + // loop over systematics + return m_systematicsList.foreach ([&](const CP::SystematicSet &sys) -> StatusCode { + SysFilterReporter filter (filterCombiner, sys); + + // particle container + const xAOD::IParticleContainer *particles = nullptr; + ANA_CHECK(m_particleHandle.retrieve(particles, sys)); + + // reject events with any particle passing the input selection + for (const xAOD::IParticle *particle : *particles) { + if (m_preselection.getBool(*particle)) { + if (m_veto.getBool(*particle)) { + ATH_MSG_VERBOSE("Event failed."); + filter.setPassed (false); + break; + } + } + } + + return StatusCode::SUCCESS; + }); +} + +StatusCode EventSelectionByObjectFlagAlg ::finalize() { + ANA_CHECK (m_filterParams.finalize()); + return StatusCode::SUCCESS; +} + +} // namespace CP diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/IsolationCloseByCorrectionAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/IsolationCloseByCorrectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..70335657f4b1e656cbd36c8c3d27c2575d12005c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/IsolationCloseByCorrectionAlg.cxx @@ -0,0 +1,66 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/IsolationCloseByCorrectionAlg.h> + +// +// method implementations +// + +namespace CP +{ + IsolationCloseByCorrectionAlg :: + IsolationCloseByCorrectionAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + declareProperty ("isolationCorrectionTool", m_isolationCorrectionTool); + declareProperty ("topoEtConeModel", m_topoEtConeModel); + } + + + + StatusCode IsolationCloseByCorrectionAlg :: + initialize () + { + ANA_CHECK (m_isolationCorrectionTool.retrieve()); + if (m_electronsHandle) m_systematicsList.addHandle (m_electronsHandle); + if (m_muonsHandle) m_systematicsList.addHandle (m_muonsHandle); + if (m_photonsHandle) m_systematicsList.addHandle (m_photonsHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode IsolationCloseByCorrectionAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::ElectronContainer *electrons {nullptr}; + if (m_electronsHandle) + ANA_CHECK (m_electronsHandle.getCopy (electrons, sys)); + xAOD::MuonContainer *muons {nullptr}; + if (m_muonsHandle) + ANA_CHECK (m_muonsHandle.getCopy (muons, sys)); + xAOD::PhotonContainer *photons {nullptr}; + if (m_photonsHandle) + ANA_CHECK (m_photonsHandle.getCopy (photons, sys)); + + ANA_CHECK_CORRECTION_EVENT + (m_outOfValidity, m_isolationCorrectionTool->getCloseByIsoCorrection + (electrons, muons, photons, m_topoEtConeModel)); + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/KinematicHistAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/KinematicHistAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ab71365c73ad04500a6f0125388b29a7167da4c5 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/KinematicHistAlg.cxx @@ -0,0 +1,110 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/KinematicHistAlg.h> + +#include <RootCoreUtils/StringUtil.h> +#include <TH1.h> + +// +// method implementations +// + +namespace CP +{ + KinematicHistAlg :: + KinematicHistAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + declareProperty ("histPattern", m_histPattern, "the pattern for histogram names"); + } + + + + StatusCode KinematicHistAlg :: + initialize () + { + m_systematicsList.addHandle (m_inputHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode KinematicHistAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + const xAOD::IParticleContainer *input = nullptr; + ANA_CHECK (m_inputHandle.retrieve (input, sys)); + + auto histIter = m_hist.find (sys); + if (histIter == m_hist.end()) + { + std::string name; + HistGroup group; + + name = RCU::substitute (m_histPattern, "%VAR%", "multiplicity"); + name = makeSystematicsName (name, sys); + ANA_CHECK (book (TH1F (name.c_str(), "multiplicity", 20, 0, 20))); + group.multiplicity = hist (name); + + m_hist.insert (std::make_pair (sys, group)); + histIter = m_hist.find (sys); + assert (histIter != m_hist.end()); + } + + std::size_t count = 0; + for (std::size_t iter = 0; iter != input->size(); ++ iter) + { + const xAOD::IParticle *particle = (*input)[iter]; + if (m_preselection.getBool (*particle)) + { + while (histIter->second.perObject.size() <= count) + { + std::string name; + HistSubgroup group; + + name = RCU::substitute (m_histPattern, "%VAR%", "pt" + std::to_string(histIter->second.perObject.size())); + name = makeSystematicsName (name, sys); + ANA_CHECK (book (TH1F (name.c_str(), "pt", 20, 0, 200e3))); + group.pt = hist (name); + + name = RCU::substitute (m_histPattern, "%VAR%", "eta" + std::to_string(histIter->second.perObject.size())); + name = makeSystematicsName (name, sys); + ANA_CHECK (book (TH1F (name.c_str(), "eta", 20, -5, 5))); + group.eta = hist (name); + + name = RCU::substitute (m_histPattern, "%VAR%", "phi" + std::to_string(histIter->second.perObject.size())); + name = makeSystematicsName (name, sys); + ANA_CHECK (book (TH1F (name.c_str(), "phi", 20, -M_PI, M_PI))); + group.phi = hist (name); + + histIter->second.perObject.push_back (group); + } + + HistSubgroup& group = histIter->second.perObject[count]; + + group.pt->Fill (particle->pt()); + group.eta->Fill (particle->eta()); + group.phi->Fill (particle->phi()); + count += 1; + } + } + + histIter->second.multiplicity->Fill (count); + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/ObjectCutFlowHistAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/ObjectCutFlowHistAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ff58bd5a78a3b99531c6db0ad20650459665f350 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/ObjectCutFlowHistAlg.cxx @@ -0,0 +1,136 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/ObjectCutFlowHistAlg.h> + +#include <RootCoreUtils/StringUtil.h> +#include <TH1.h> + +// +// method implementations +// + +namespace CP +{ + ObjectCutFlowHistAlg :: + ObjectCutFlowHistAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + declareProperty ("histPattern", m_histPattern, "the pattern for histogram names"); + + declareProperty ("selection", m_selection, "the list of selection decorations"); + declareProperty ("selectionNCuts", m_selectionNCuts, "the number of cuts for each selection decoration"); + } + + + + StatusCode ObjectCutFlowHistAlg :: + initialize () + { + m_systematicsList.addHandle (m_inputHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + + if (m_selectionNCuts.size() != m_selection.size()) + { + ANA_MSG_ERROR ("selection and selectionNCuts properties need to be the same size"); + return StatusCode::FAILURE; + } + + // Total label + m_labels.push_back ("total"); + + for (std::size_t iter = 0, end = m_selection.size(); iter != end; ++ iter) + { + const unsigned ncuts = m_selectionNCuts[iter]; + if (ncuts == 0) + { + ANA_MSG_ERROR ("all entries of selectionNCuts need to be greater than 0"); + return StatusCode::FAILURE; + } + if (ncuts > 8 * sizeof (SelectionType)) + { + ANA_MSG_ERROR ("entries in selectionNCuts need to be less or equal to " << (8 * sizeof (SelectionType))); + return StatusCode::FAILURE; + } + std::unique_ptr<ISelectionAccessor> accessor; + ANA_CHECK (makeSelectionAccessor (m_selection[iter], accessor)); + m_accessors.push_back (std::make_pair (std::move (accessor), ncuts)); + for (unsigned i = 1; i <= ncuts; i++) + { + m_labels.push_back (m_accessors.back().first->label() + std::to_string(i)); + } + m_allCutsNum += ncuts; + } + + return StatusCode::SUCCESS; + } + + + + StatusCode ObjectCutFlowHistAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + const xAOD::IParticleContainer *input = nullptr; + ANA_CHECK (m_inputHandle.retrieve (input, sys)); + + auto histIter = m_hist.find (sys); + if (histIter == m_hist.end()) + { + const std::string name + = makeSystematicsName (m_histPattern, sys); + + ANA_CHECK (book (TH1F (name.c_str(), "object cut flow", m_allCutsNum+1, 0, m_allCutsNum+1))); + + m_hist.insert (std::make_pair (sys, hist (name))); + histIter = m_hist.find (sys); + assert (histIter != m_hist.end()); + + for (unsigned i = 0; i < m_allCutsNum+1; i++) + { + histIter->second->GetXaxis()->SetBinLabel(i + 1, m_labels[i].c_str()); + } + } + + for (const xAOD::IParticle *particle : *input) + { + if (m_preselection.getBool (*particle)) + { + bool keep = true; + unsigned cutIndex = 1; + histIter->second->Fill (0); + for (const auto& accessor : m_accessors) + { + const auto selection = accessor.first->getBits (*particle); + for (unsigned index = 0, end = accessor.second; + index != end; ++ index, ++ cutIndex) + { + if (selection & (1 << index)) + { + histIter->second->Fill (cutIndex); + } else + { + keep = false; + break; + } + } + if (!keep) + break; + } + } + } + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/OverlapRemovalAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/OverlapRemovalAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..02d98dedbdcb07034df655447e8d0ee10b1197df --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/OverlapRemovalAlg.cxx @@ -0,0 +1,75 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/OverlapRemovalAlg.h> + +// +// method implementations +// + +namespace CP +{ + OverlapRemovalAlg :: + OverlapRemovalAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + declareProperty ("overlapTool", m_overlapTool); + } + + + + StatusCode OverlapRemovalAlg :: + initialize () + { + ANA_CHECK (m_overlapTool.retrieve()); + if (m_electronsHandle) m_systematicsList.addHandle (m_electronsHandle); + if (m_muonsHandle) m_systematicsList.addHandle (m_muonsHandle); + if (m_jetsHandle) m_systematicsList.addHandle (m_jetsHandle); + if (m_tausHandle) m_systematicsList.addHandle (m_tausHandle); + if (m_photonsHandle) m_systematicsList.addHandle (m_photonsHandle); + if (m_fatJetsHandle) m_systematicsList.addHandle (m_fatJetsHandle); + ANA_CHECK (m_systematicsList.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode OverlapRemovalAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::ElectronContainer *electrons {nullptr}; + if (m_electronsHandle) + ANA_CHECK (m_electronsHandle.getCopy (electrons, sys)); + xAOD::MuonContainer *muons {nullptr}; + if (m_muonsHandle) + ANA_CHECK (m_muonsHandle.getCopy (muons, sys)); + xAOD::JetContainer *jets {nullptr}; + if (m_jetsHandle) + ANA_CHECK (m_jetsHandle.getCopy (jets, sys)); + xAOD::TauJetContainer *taus {nullptr}; + if (m_tausHandle) + ANA_CHECK (m_tausHandle.getCopy (taus, sys)); + xAOD::PhotonContainer *photons {nullptr}; + if (m_photonsHandle) + ANA_CHECK (m_photonsHandle.getCopy (photons, sys)); + xAOD::JetContainer *fatJets {nullptr}; + if (m_fatJetsHandle) + ANA_CHECK (m_fatJetsHandle.getCopy (fatJets, sys)); + + ATH_CHECK (m_overlapTool->removeOverlaps (electrons, muons, jets, taus, + photons, fatJets)); + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/PMGTruthWeightAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/PMGTruthWeightAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a3ee593b8d970b947eb06ba477386506e215bec6 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/PMGTruthWeightAlg.cxx @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/PMGTruthWeightAlg.h> + +// +// method implementations +// + +namespace CP +{ + PMGTruthWeightAlg :: + PMGTruthWeightAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_truthWeightTool ("PMGTools::PMGTruthWeightTool", this) + { + declareProperty ("truthWeightTool", m_truthWeightTool, "the truth weight tool"); + } + + + + StatusCode PMGTruthWeightAlg :: + initialize () + { + if (m_decoration.empty()) + { + ANA_MSG_ERROR ("no decoration name set"); + return StatusCode::FAILURE; + } + + ANA_CHECK (m_truthWeightTool.retrieve()); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_truthWeightTool->affectingSystematics())); + m_systematicsList.addHandle (m_eventInfoHandle); + ANA_CHECK (m_systematicsList.initialize()); + + return StatusCode::SUCCESS; + } + + + StatusCode PMGTruthWeightAlg :: + execute () + { + ANA_CHECK (m_decoration.preExecute (m_systematicsList)); + + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode + { + ANA_CHECK (m_truthWeightTool->applySystematicVariation (sys)); + xAOD::EventInfo *eventInfo = nullptr; + ANA_CHECK (m_eventInfoHandle.getCopy (eventInfo, sys)); + + m_decoration.set (*eventInfo, m_truthWeightTool->getSysWeight (), sys); + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/PileupReweightingAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/PileupReweightingAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..76432c7b31c9dd8c3e3d8590f1e234d995cdf9da --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/PileupReweightingAlg.cxx @@ -0,0 +1,119 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/PileupReweightingAlg.h> + +// +// method implementations +// + +namespace CP +{ + PileupReweightingAlg :: + PileupReweightingAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_pileupReweightingTool ("CP::PileupReweightingTool", this) + { + declareProperty ("pileupReweightingTool", m_pileupReweightingTool, "the pileup reweighting tool we apply"); + declareProperty ("correctedScaledAverageMuDecoration", m_correctedScaledAverageMuDecoration, "the decoration for the corrected and scaled average interactions per crossing"); + declareProperty ("correctedActualMuDecoration", m_correctedActualMuDecoration, "the decoration for the corrected actual interactions per crossing"); + declareProperty ("correctedScaledActualMuDecoration", m_correctedScaledActualMuDecoration, "the decoration for the corrected and scaled actual interactions per crossing"); + } + + + + StatusCode PileupReweightingAlg :: + initialize () + { + if (!m_correctedScaledAverageMuDecoration.empty()) + { + m_correctedScaledAverageMuAccessor = std::make_unique<SG::AuxElement::Accessor<float> > (m_correctedScaledAverageMuDecoration); + } + if (!m_correctedActualMuDecoration.empty()) + { + m_correctedActualMuAccessor = std::make_unique<SG::AuxElement::Accessor<float> > (m_correctedActualMuDecoration); + } + if (!m_correctedScaledActualMuDecoration.empty()) + { + m_correctedScaledActualMuAccessor = std::make_unique<SG::AuxElement::Accessor<float> > (m_correctedScaledActualMuDecoration); + } + + ANA_CHECK (m_pileupReweightingTool.retrieve()); + m_systematicsList.addHandle (m_eventInfoHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_pileupReweightingTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode PileupReweightingAlg :: + execute () + { + unsigned int nominalRandomRunNumber{}; + + ANA_CHECK (m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_pileupReweightingTool->applySystematicVariation (sys)); + xAOD::EventInfo *eventInfo = nullptr; + ANA_CHECK (m_eventInfoHandle.getCopy (eventInfo, sys)); + + ATH_CHECK (m_pileupReweightingTool->apply (*eventInfo)); + + // Add additional decorations + if (m_correctedScaledAverageMuAccessor) + { + (*m_correctedScaledAverageMuAccessor) (*eventInfo) + = m_pileupReweightingTool->getCorrectedAverageInteractionsPerCrossing (*eventInfo, true); + } + + if (m_correctedActualMuAccessor) + { + (*m_correctedActualMuAccessor) (*eventInfo) + = m_pileupReweightingTool->getCorrectedActualInteractionsPerCrossing (*eventInfo); + } + + if (m_correctedScaledActualMuAccessor) + { + (*m_correctedScaledActualMuAccessor) (*eventInfo) + = m_pileupReweightingTool->getCorrectedActualInteractionsPerCrossing (*eventInfo, true); + } + + //--- PRWHash to recalculate PU weights using analysis ntuples + //--- https://twiki.cern.ch/twiki/bin/view/AtlasProtected/ExtendedPileupReweighting#Using_PRWHash_to_change_pileup_w + + if (eventInfo->eventType (xAOD::EventInfo::IS_SIMULATION)) + { + eventInfo->auxdata<ULong64_t>("PRWHash") + = m_pileupReweightingTool->getPRWHash (*eventInfo); + } + + // In the case of nominal systematics store the RandomRunNumber for + // later. Event info can not be decorated at this point as the + // decoration will then also be present in subsequent shallow copies. + if (sys.empty()) + { + nominalRandomRunNumber = eventInfo->auxdecor<unsigned int> ("RandomRunNumber"); + } + + return StatusCode::SUCCESS; + })); + + // Must decorate the actual instance in the event store for + // the electron tool to work. The decoration is done out of the loop + // to avoid it being present in all subsequent shallow copies. + evtStore()->retrieve<const xAOD::EventInfo>("EventInfo") + ->auxdecor<unsigned int>("RandomRunNumber") = nominalRandomRunNumber; + + return StatusCode::SUCCESS; + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/SysListDumperAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/SysListDumperAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5ed2c57b46ac4e98bcc4d4512fbe9c83b68f745e --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/SysListDumperAlg.cxx @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +// +// includes +// + +#include <AsgAnalysisAlgorithms/SysListDumperAlg.h> +#include <SystematicsHandles/Helpers.h> +#include <TH1.h> + +// +// method implementations +// + +namespace CP +{ + SysListDumperAlg :: + SysListDumperAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + declareProperty ("histogramName", m_histogramName, "the name of the output histogram"); + } + + + + StatusCode SysListDumperAlg :: + initialize () + { + if (m_histogramName.empty()) + { + ANA_MSG_ERROR ("histogram name should not be empty"); + return StatusCode::FAILURE; + } + + ANA_CHECK (m_systematicsList.initialize()); + + return StatusCode::SUCCESS; + } + + + + StatusCode SysListDumperAlg :: + execute () + { + if (!m_firstEvent) + { + return StatusCode::SUCCESS; + } + + m_firstEvent = false; + + const std::unordered_set<CP::SystematicSet> systematics = m_systematicsList.systematicsVector(); + + ANA_CHECK (book (TH1F (m_histogramName.c_str(), "systematics", systematics.size(), 0, systematics.size()))); + TH1 *histogram = hist (m_histogramName); + + int i = 1; + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode + { + std::string name = sys.name(); + if (name.empty()) + name = nominalSystematicsName(); + + histogram->GetXaxis()->SetBinLabel(i, name.c_str()); + i++; + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/SysListLoaderAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/SysListLoaderAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..068697fa1fb374f1216c17e5d169b00576b85d35 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/SysListLoaderAlg.cxx @@ -0,0 +1,137 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <regex> + +#include <AsgAnalysisAlgorithms/SysListLoaderAlg.h> + +#include <AsgTools/MessageCheck.h> +#include <PATInterfaces/MakeSystematicsVector.h> +#include <PATInterfaces/SystematicRegistry.h> + +// +// method implementations +// + +namespace CP +{ + SysListLoaderAlg :: + SysListLoaderAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + declareProperty ("systematicsName", m_systematicsName, "the name of the systematics in the event store"); + declareProperty ("systematicsList", m_systematicsList, "the list of systematics to run"); + declareProperty ("systematicsRegex", m_systematicsRegex, "systematics filter regex"); + declareProperty ("sigmaRecommended", m_sigmaRecommended, "the sigma with which to run recommended systematics"); + } + + + + StatusCode SysListLoaderAlg :: + initialize () + { + if (m_systematicsName.empty()) + { + ANA_MSG_ERROR ("no name configured for the systematics list"); + return StatusCode::FAILURE; + } + + if (!std::isfinite (m_sigmaRecommended) || + m_sigmaRecommended < 0) + { + ANA_MSG_ERROR ("invalid value for sigmaRecommended: " << m_sigmaRecommended); + return StatusCode::FAILURE; + } + + if (m_sigmaRecommended != 0) + { + if (!m_systematicsList.empty()) + { + ANA_MSG_ERROR ("can't specify both sigmaRecommended and systematicsList"); + return StatusCode::FAILURE; + } + } else if (m_systematicsList.empty()) + { + // take an empty property as running just the central + // systematics set. implication is that you can't really run + // doing nothing, but that ought to be Ok. + m_systematicsVector.push_back (CP::SystematicSet ()); + } else + { + for (const std::string& sysName : m_systematicsList) + m_systematicsVector.push_back (CP::SystematicSet (sysName)); + } + return StatusCode::SUCCESS; + } + + + + StatusCode SysListLoaderAlg :: + execute () + { + if (m_firstEvent) + { + m_firstEvent = false; + const CP::SystematicSet recommended + = CP::SystematicRegistry::getInstance().recommendedSystematics(); + const CP::SystematicSet affecting + = CP::SystematicRegistry::getInstance().globalSystematics(); + + for (const CP::SystematicVariation& mysys : affecting) + { + // this logic checks whether a systematic is recommended and + // affecting, or only affecting. if it is only the later, it + // reports the systematic in parenthesis to set it apart. + if (recommended.find (mysys) == recommended.end()) + ANA_MSG_INFO ("found systematic: (" << mysys << ")"); + else + ANA_MSG_INFO ("found systematic: " << mysys); + } + bool error = false; + for (const CP::SystematicVariation& mysys : recommended) + { + if (affecting.find (mysys) == affecting.end()) + { + ANA_MSG_ERROR ("systematic is only registered as recommended, not affecting: " << mysys); + error = true; + } + } + if (error) + return StatusCode::FAILURE; + + + if (m_systematicsVector.empty()) + { + assert (m_sigmaRecommended > 0); + CP::MakeSystematicsVector sys; + sys.setSigma (m_sigmaRecommended); + sys.calc (recommended); + + std::regex expr (m_systematicsRegex); + for (const CP::SystematicSet& mysys : sys.result("")) + { + if (!regex_match (mysys.name(), expr)) + { + ANA_MSG_INFO ("skipping systematic: " << mysys.name()); + } else { + ANA_MSG_INFO ("configuring systematic: " << mysys.name()); + m_systematicsVector.push_back (mysys); + } + } + } + } + + std::unique_ptr<SysListType> list (new SysListType (m_systematicsVector)); + ANA_CHECK (evtStore()->record (list.release(), m_systematicsName)); + return StatusCode::SUCCESS; + } +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/TreeFillerAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/TreeFillerAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a91a87021a62d3aa58519789d503de0f7fbbac00 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/TreeFillerAlg.cxx @@ -0,0 +1,60 @@ +// Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +// Local include(s): +#include "AsgAnalysisAlgorithms/TreeFillerAlg.h" + +// EDM include(s): +#include "AthContainersInterfaces/IAuxTypeVectorFactory.h" +#include "AthContainers/AuxElement.h" +#include "AthContainers/AuxVectorBase.h" +#include "AthContainers/normalizedTypeinfoName.h" + +// Framework include(s): +#include "SystematicsHandles/Helpers.h" + +// ROOT include(s): +#include <TClass.h> +#include <TTree.h> +#include <TBranch.h> +#include <TVirtualCollectionProxy.h> + +// System include(s): +#include <regex> +#include <algorithm> +#include <functional> +#include <sstream> + +namespace CP { + + TreeFillerAlg::TreeFillerAlg( const std::string& name, + ISvcLocator* svcLoc ) + : EL::AnaAlgorithm( name, svcLoc ) { + + // Declare the algorithm's properties. + declareProperty( "TreeName", m_treeName = "physics", + "Name of the tree to write" ); + } + + StatusCode TreeFillerAlg::execute() { + // get the output tree for the first time + if( ! m_tree ) { + m_tree = tree( m_treeName ); + } + + if( ! m_tree ) { + ATH_MSG_ERROR( "Could not find output tree \"" << m_treeName + << "\"" ); + return StatusCode::FAILURE; + } + + // Fill the tree. + if( m_tree->Fill() < 0 ) { + ATH_MSG_ERROR( "Error while filling TTree" ); + return StatusCode::FAILURE; + } + + // Return gracefully. + return StatusCode::SUCCESS; + } + +} // namespace CP diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/TreeMakerAlg.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/TreeMakerAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3e41601569439c009ad521ac17cd9e5a3061828d --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/Root/TreeMakerAlg.cxx @@ -0,0 +1,44 @@ +// Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +// Local include(s): +#include "AsgAnalysisAlgorithms/TreeMakerAlg.h" + +// ROOT include(s): +#include <TTree.h> + +namespace CP { + + TreeMakerAlg::TreeMakerAlg( const std::string& name, + ISvcLocator* svcLoc ) + : EL::AnaAlgorithm( name, svcLoc ) { + + // Declare the algorithm's properties. + declareProperty( "TreeName", m_treeName = "physics", + "Name of the tree to write" ); + declareProperty( "TreeAutoFlush", m_treeAutoFlush = 200, + "AutoFlush value for the output tree" ); + } + + StatusCode TreeMakerAlg::execute() { + if( m_treeConfigured ) { + return StatusCode::SUCCESS; + } + + // Create the output tree. + ATH_CHECK( book( TTree( m_treeName.c_str(), "xAOD->NTuple tree" ) ) ); + TTree *mytree { tree( m_treeName ) }; + if( ! mytree ) { + ATH_MSG_ERROR( "Could not create output tree \"" << m_treeName + << "\"" ); + return StatusCode::FAILURE; + } + mytree->SetAutoFlush( m_treeAutoFlush ); + ATH_MSG_INFO( "Created xAOD->NTuple tree: " << m_treeName ); + + m_treeConfigured = true; + + // Return gracefully. + return StatusCode::SUCCESS; + } + +} // namespace CP diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/AsgAnalysisAlgorithmsTest.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/AsgAnalysisAlgorithmsTest.py new file mode 100644 index 0000000000000000000000000000000000000000..5d99638fa074f9ba76fab67d9d16cbeafeff43da --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/AsgAnalysisAlgorithmsTest.py @@ -0,0 +1,217 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack +# @author Tadej Novak + +from AnaAlgorithm.AlgSequence import AlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm + +def makeOverlapSequence (dataType) : + algSeq = AlgSequence() + + # Skip events with no primary vertex: + algSeq += createAlgorithm( 'CP::VertexSelectionAlg', + 'PrimaryVertexSelectorAlg' ) + algSeq.PrimaryVertexSelectorAlg.VertexContainer = 'PrimaryVertices' + algSeq.PrimaryVertexSelectorAlg.MinVertices = 1 + + # Set up the systematics loader/handler algorithm: + algSeq += createAlgorithm( 'CP::SysListLoaderAlg', 'SysLoaderAlg' ) + algSeq.SysLoaderAlg.sigmaRecommended = 1 + + # Include, and then set up the pileup analysis sequence: + from AsgAnalysisAlgorithms.PileupAnalysisSequence import \ + makePileupAnalysisSequence + pileupSequence = makePileupAnalysisSequence( dataType ) + pileupSequence.configure( inputName = 'EventInfo', outputName = 'EventInfo_%SYS%' ) + algSeq += pileupSequence + + # Include, and then set up the electron analysis sequence: + from EgammaAnalysisAlgorithms.ElectronAnalysisSequence import \ + makeElectronAnalysisSequence + electronSequence = makeElectronAnalysisSequence( dataType, 'LooseLHElectron.GradientLoose', + recomputeLikelihood = True ) + electronSequence.configure( inputName = 'Electrons', + outputName = 'AnalysisElectrons_%SYS%' ) + algSeq += electronSequence + + # Include, and then set up the photon analysis sequence: + from EgammaAnalysisAlgorithms.PhotonAnalysisSequence import \ + makePhotonAnalysisSequence + photonSequence = makePhotonAnalysisSequence( dataType, 'Tight.FixedCutTight', recomputeIsEM = True ) + photonSequence.configure( inputName = 'Photons', + outputName = 'AnalysisPhotons_%SYS%' ) + algSeq += photonSequence + + # Include, and then set up the muon analysis algorithm sequence: + from MuonAnalysisAlgorithms.MuonAnalysisSequence import makeMuonAnalysisSequence + muonSequence = makeMuonAnalysisSequence( dataType, 'Tight.Iso' ) + muonSequence.configure( inputName = 'Muons', + outputName = 'AnalysisMuons_%SYS%' ) + algSeq += muonSequence + + # Include, and then set up the jet analysis algorithm sequence: + jetContainer = 'AntiKt4EMPFlowJets' + from JetAnalysisAlgorithms.JetAnalysisSequence import makeJetAnalysisSequence + jetSequence = makeJetAnalysisSequence( dataType, jetContainer ) + jetSequence.configure( inputName = jetContainer, + outputName = 'AnalysisJets_%SYS%' ) + algSeq += jetSequence + + # Include, and then set up the tau analysis algorithm sequence: + from TauAnalysisAlgorithms.TauAnalysisSequence import makeTauAnalysisSequence + tauSequence = makeTauAnalysisSequence( dataType, 'Tight' ) + tauSequence.configure( inputName = 'TauJets', + outputName = 'AnalysisTauJets_%SYS%' ) + algSeq += tauSequence + + # Include, and then set up the overlap analysis algorithm sequence: + from AsgAnalysisAlgorithms.OverlapAnalysisSequence import \ + makeOverlapAnalysisSequence + overlapSequence = makeOverlapAnalysisSequence( dataType, doMuPFJetOR=True, enableCutflow=True ) + 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' : electronSequence.affectingSystematics(), + 'photons' : photonSequence.affectingSystematics(), + 'muons' : muonSequence.affectingSystematics(), + 'jets' : jetSequence.affectingSystematics(), + 'taus' : tauSequence.affectingSystematics() } ) + algSeq += overlapSequence + + # Set up an ntuple to check the job with: + treeMaker = createAlgorithm( 'CP::TreeMakerAlg', 'TreeMaker' ) + treeMaker.TreeName = 'particles' + algSeq += treeMaker + ntupleMaker = createAlgorithm( 'CP::AsgxAODNTupleMakerAlg', 'NTupleMaker' ) + ntupleMaker.TreeName = 'particles' + ntupleMaker.Branches = [ + 'EventInfo.runNumber -> runNumber', + 'EventInfo.eventNumber -> eventNumber', + 'AnalysisElectrons_%SYS%.eta -> el_%SYS%_eta', + 'AnalysisElectrons_%SYS%.phi -> el_%SYS%_phi', + 'AnalysisElectrons_%SYS%.pt -> el_%SYS%_pt', + 'AnalysisElectronsOR_%SYS%.eta -> el_OR_%SYS%_eta', + 'AnalysisElectronsOR_%SYS%.phi -> el_OR_%SYS%_phi', + 'AnalysisElectronsOR_%SYS%.pt -> el_OR_%SYS%_pt', + 'AnalysisPhotons_%SYS%.eta -> ph_%SYS%_eta', + 'AnalysisPhotons_%SYS%.phi -> ph_%SYS%_phi', + 'AnalysisPhotons_%SYS%.pt -> ph_%SYS%_pt', + 'AnalysisPhotonsOR_%SYS%.eta -> ph_OR_%SYS%_eta', + 'AnalysisPhotonsOR_%SYS%.phi -> ph_OR_%SYS%_phi', + 'AnalysisPhotonsOR_%SYS%.pt -> ph_OR_%SYS%_pt', + 'AnalysisMuons_%SYS%.eta -> mu_%SYS%_eta', + 'AnalysisMuons_%SYS%.phi -> mu_%SYS%_phi', + 'AnalysisMuons_%SYS%.pt -> mu_%SYS%_pt', + 'AnalysisMuonsOR_%SYS%.eta -> mu_OR_%SYS%_eta', + 'AnalysisMuonsOR_%SYS%.phi -> mu_OR_%SYS%_phi', + 'AnalysisMuonsOR_%SYS%.pt -> mu_OR_%SYS%_pt', + 'AnalysisJets_%SYS%.eta -> jet_%SYS%_eta', + 'AnalysisJets_%SYS%.phi -> jet_%SYS%_phi', + 'AnalysisJets_%SYS%.pt -> jet_%SYS%_pt', + 'AnalysisJetsOR_%SYS%.eta -> jet_OR_%SYS%_eta', + 'AnalysisJetsOR_%SYS%.phi -> jet_OR_%SYS%_phi', + 'AnalysisJetsOR_%SYS%.pt -> jet_OR_%SYS%_pt', + 'AnalysisTauJets_%SYS%.eta -> tau_%SYS%_eta', + 'AnalysisTauJets_%SYS%.phi -> tau_%SYS%_phi', + 'AnalysisTauJets_%SYS%.pt -> tau_%SYS%_pt', + 'AnalysisTauJetsOR_%SYS%.eta -> tau_OR_%SYS%_eta', + 'AnalysisTauJetsOR_%SYS%.phi -> tau_OR_%SYS%_phi', + 'AnalysisTauJetsOR_%SYS%.pt -> tau_OR_%SYS%_pt' ] + ntupleMaker.systematicsRegex = '.*' + algSeq += ntupleMaker + treeFiller = createAlgorithm( 'CP::TreeFillerAlg', 'TreeFiller' ) + treeFiller.TreeName = 'particles' + algSeq += treeFiller + + return algSeq + + +def makeEventAlgorithmsSequence (dataType) : + + # Config: + GRLFiles = ['GoodRunsLists/data16_13TeV/20180129/data16_13TeV.periodAllYear_DetStatus-v89-pro21-01_DQDefects-00-02-04_PHYS_StandardGRL_All_Good_25ns.xml'] + + algSeq = AlgSequence() + + # Set up the systematics loader/handler algorithm: + algSeq += createAlgorithm( 'CP::SysListLoaderAlg', 'SysLoaderAlg' ) + algSeq.SysLoaderAlg.sigmaRecommended = 1 + + # Include, and then set up the pileup analysis sequence: + from AsgAnalysisAlgorithms.EventSelectionAnalysisSequence import \ + makeEventSelectionAnalysisSequence + eventSelectionSequence = \ + makeEventSelectionAnalysisSequence( dataType, userGRLFiles=GRLFiles ) + algSeq += eventSelectionSequence + + # Set up an ntuple to check the job with: + treeMaker = createAlgorithm( 'CP::TreeMakerAlg', 'TreeMaker' ) + treeMaker.TreeName = 'events' + algSeq += treeMaker + ntupleMaker = createAlgorithm( 'CP::AsgxAODNTupleMakerAlg', 'NTupleMaker' ) + ntupleMaker.TreeName = 'events' + ntupleMaker.Branches = [ + 'EventInfo.runNumber -> runNumber', + 'EventInfo.eventNumber -> eventNumber', + ] + ntupleMaker.systematicsRegex = '.*' + algSeq += ntupleMaker + treeFiller = createAlgorithm( 'CP::TreeFillerAlg', 'TreeFiller' ) + treeFiller.TreeName = 'events' + algSeq += treeFiller + + return algSeq + + +def makeGeneratorAlgorithmsSequence (dataType) : + + algSeq = AlgSequence() + + # Set up the systematics loader/handler algorithm: + algSeq += createAlgorithm( 'CP::SysListLoaderAlg', 'SysLoaderAlg' ) + algSeq.SysLoaderAlg.sigmaRecommended = 1 + + # Include, and then set up the pileup analysis sequence (to make a copy): + from AsgAnalysisAlgorithms.PileupAnalysisSequence import \ + makePileupAnalysisSequence + pileupSequence = makePileupAnalysisSequence( dataType ) + pileupSequence.configure( inputName = 'EventInfo', outputName = 'EventInfo_%SYS%' ) + algSeq += pileupSequence + + # Include, and then set up the generator analysis sequence: + from AsgAnalysisAlgorithms.GeneratorAnalysisSequence import \ + makeGeneratorAnalysisSequence + generatorSequence = makeGeneratorAnalysisSequence( dataType, saveCutBookkeepers=True, runNumber=284500, cutBookkeepersSystematics=True ) + generatorSequence.configure( inputName = 'EventInfo_%SYS%', outputName = {} ) + algSeq += generatorSequence + + # Set up an ntuple to check the job with: + treeMaker = createAlgorithm( 'CP::TreeMakerAlg', 'TreeMaker' ) + treeMaker.TreeName = 'events' + algSeq += treeMaker + ntupleMaker = createAlgorithm( 'CP::AsgxAODNTupleMakerAlg', 'NTupleMaker' ) + ntupleMaker.TreeName = 'events' + ntupleMaker.Branches = [ + 'EventInfo_NOSYS.runNumber -> runNumber', + 'EventInfo_NOSYS.eventNumber -> eventNumber', + 'EventInfo_NOSYS.generatorWeight_%SYS% -> generatorWeight_%SYS%', + ] + ntupleMaker.systematicsRegex = '.*' + algSeq += ntupleMaker + treeFiller = createAlgorithm( 'CP::TreeFillerAlg', 'TreeFiller' ) + treeFiller.TreeName = 'events' + algSeq += treeFiller + + return algSeq diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/EventSelectionAnalysisSequence.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/EventSelectionAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..94f78652dea7d12a7272b787194301822d63fe79 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/EventSelectionAnalysisSequence.py @@ -0,0 +1,56 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Tadej Novak + +# AnaAlgorithm import(s): +from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm, addPrivateTool + + +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 diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/GeneratorAnalysisSequence.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/GeneratorAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..0a8e7ca75176b5147c1f78f1f34fd19b229f9b52 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/GeneratorAnalysisSequence.py @@ -0,0 +1,47 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +# AnaAlgorithm import(s): +from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm, addPrivateTool + +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 diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/OverlapAnalysisSequence.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/OverlapAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..d530ba9bb34aa136f2d2de60dea624f0211cfcb0 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/OverlapAnalysisSequence.py @@ -0,0 +1,287 @@ +# 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 + +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 diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/PileupAnalysisSequence.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/PileupAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..2198606ef20ae549b3ecf38a304b1d413341ef78 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/PileupAnalysisSequence.py @@ -0,0 +1,51 @@ +# 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 + +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 diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/SequencePostConfiguration.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/SequencePostConfiguration.py new file mode 100644 index 0000000000000000000000000000000000000000..4069de29a5a68e5b5aab0304df633c1bc09c693d --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/SequencePostConfiguration.py @@ -0,0 +1,32 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +def sequencePostConfiguration (sequence, inputContainer) : + currentContainer = inputContainer + inputRegex = "(^$)" + nextTemp = 0 + for alg in sequence : + config = alg["alg"] + config.__setattr__ (alg["in"], currentContainer) + config.__setattr__ (alg["in"] + "Regex", inputRegex) + + # need to make a shallow copy if we add systematics, or if this is + # the first algorithm, of if we are explicitly asked for an output + if "out" in alg and (inputContainer == currentContainer or "sys" in alg or ("needOut" in alg and alg["needOut"])) : + currentContainer = inputContainer + "_tmp" + str (nextTemp) + "_%SYS%" + nextTemp = nextTemp + 1 + config.__setattr__ (alg["out"], currentContainer) + if "sys" in alg : + inputRegex = inputRegex + "|" + alg["sys"] + pass + pass + + if "sys" in alg : + config.systematicsRegex = alg["sys"] + pass + + pass + + pass diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/__init__.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5ccb446532599c01cc3844e5b1b18db06f721002 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/python/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +__version__ = '1.0.0' diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/EventAlgorithmsTest_eljob.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/EventAlgorithmsTest_eljob.py new file mode 100755 index 0000000000000000000000000000000000000000..efd9a38e6f085e11fe37c43afbd85b069226766a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/EventAlgorithmsTest_eljob.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Tadej Novak + + +# Read the submission directory as a command line argument. You can +# extend the list of arguments with your private ones later on. +import optparse +parser = optparse.OptionParser() +parser.add_option( '-d', '--data-type', dest = 'data_type', + action = 'store', type = 'string', default = 'data', + help = 'Type of data to run over. Valid options are data, mc, afii' ) +parser.add_option( '-s', '--submission-dir', dest = 'submission_dir', + action = 'store', type = 'string', default = 'submitDir', + help = 'Submission directory for EventLoop' ) +parser.add_option( '-u', '--unit-test', dest='unit_test', + action = 'store_true', default = False, + help = 'Run the job in "unit test mode"' ) +( options, args ) = parser.parse_args() + +# Set up (Py)ROOT. +import ROOT +ROOT.xAOD.Init().ignore() + +# ideally we'd run over all of them, but we don't have a mechanism to +# configure per-sample right now + +dataType = options.data_type + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +if dataType not in ["data", "mc", "afii"] : + raise ValueError ("invalid data type: " + dataType) + +# Set up the sample handler object. See comments from the C++ macro +# for the details about these lines. +import os +sh = ROOT.SH.SampleHandler() +sh.setMetaString( 'nc_tree', 'CollectionTree' ) +sample = ROOT.SH.SampleLocal (dataType) +sample.add (os.getenv (inputfile[dataType])) +sh.add (sample) +sh.printContent() + +# Create an EventLoop job. +job = ROOT.EL.Job() +job.sampleHandler( sh ) +job.options().setDouble( ROOT.EL.Job.optMaxEvents, 500 ) + +from AsgAnalysisAlgorithms.AsgAnalysisAlgorithmsTest import makeEventAlgorithmsSequence +algSeq = makeEventAlgorithmsSequence (dataType) +print algSeq # For debugging +for alg in algSeq: + job.algsAdd( alg ) + pass + +# Set up an output file for the job: +job.outputAdd( ROOT.EL.OutputStream( 'ANALYSIS' ) ) + +# Find the right output directory: +submitDir = options.submission_dir +if options.unit_test: + import os + import tempfile + submitDir = tempfile.mkdtemp( prefix = 'evenTest_', dir = os.getcwd() ) + os.rmdir( submitDir ) + pass + +# Run the job using the direct driver. +driver = ROOT.EL.DirectDriver() +driver.submit( job, submitDir ) diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/EventAlgorithmsTest_jobOptions.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/EventAlgorithmsTest_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..348981c7f08479e492930eaedd2fd99c565ecdf7 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/EventAlgorithmsTest_jobOptions.py @@ -0,0 +1,44 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Tadej Novak + +# User options, which can be set from command line after a "-" character +# athena EventAlgorithmsTest_jobOptions.py - --myOption ... +from AthenaCommon.AthArgumentParser import AthArgumentParser +athArgsParser = AthArgumentParser() +athArgsParser.add_argument("--data-type", action = "store", dest = "data_type", + default = "mc", + help = "Type of input to run over. Valid options are 'data', 'mc', 'afii'") +athArgs = athArgsParser.parse_args() + +dataType = athArgs.data_type +if not dataType in ["data", "mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +print("Running on data type: " + dataType) + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +# Set up the reading of the input file: +import AthenaRootComps.ReadAthenaxAODHybrid +theApp.EvtMax = 500 +testFile = os.getenv ( inputfile[dataType] ) +svcMgr.EventSelector.InputCollections = [testFile] + +from AsgAnalysisAlgorithms.AsgAnalysisAlgorithmsTest import makeEventAlgorithmsSequence +algSeq = makeEventAlgorithmsSequence (dataType) +print algSeq # For debugging + +# Add all algorithms from the sequence to the job. +athAlgSeq += algSeq + +# Set up a histogram output file for the job: +ServiceMgr += CfgMgr.THistSvc() +ServiceMgr.THistSvc.Output += [ + "ANALYSIS DATAFILE='EventAlgorithmsTest." + dataType + ".hist.root' OPT='RECREATE'" + ] + +# Reduce the printout from Athena: +include( "AthAnalysisBaseComps/SuppressLogging.py" ) diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/GeneratorAlgorithmsTest_eljob.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/GeneratorAlgorithmsTest_eljob.py new file mode 100755 index 0000000000000000000000000000000000000000..2fff23fdec478b3167b3b0ead5892173ec57ce78 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/GeneratorAlgorithmsTest_eljob.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Tadej Novak + + +# Read the submission directory as a command line argument. You can +# extend the list of arguments with your private ones later on. +import optparse +parser = optparse.OptionParser() +parser.add_option( '-d', '--data-type', dest = 'data_type', + action = 'store', type = 'string', default = 'mc', + help = 'Type of data to run over. Valid options are mc, afii' ) +parser.add_option( '-s', '--submission-dir', dest = 'submission_dir', + action = 'store', type = 'string', default = 'submitDir', + help = 'Submission directory for EventLoop' ) +parser.add_option( '-u', '--unit-test', dest='unit_test', + action = 'store_true', default = False, + help = 'Run the job in "unit test mode"' ) +( options, args ) = parser.parse_args() + +# Set up (Py)ROOT. +import ROOT +ROOT.xAOD.Init().ignore() + +# ideally we'd run over all of them, but we don't have a mechanism to +# configure per-sample right now + +dataType = options.data_type + +inputfile = {"mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +if dataType not in ["mc", "afii"] : + raise ValueError ("invalid data type: " + dataType) + +# Set up the sample handler object. See comments from the C++ macro +# for the details about these lines. +import os +sh = ROOT.SH.SampleHandler() +sh.setMetaString( 'nc_tree', 'CollectionTree' ) +sample = ROOT.SH.SampleLocal (dataType) +sample.add (os.getenv (inputfile[dataType])) +sh.add (sample) +sh.printContent() + +# Create an EventLoop job. +job = ROOT.EL.Job() +job.sampleHandler( sh ) +job.options().setDouble( ROOT.EL.Job.optMaxEvents, 500 ) + +from AsgAnalysisAlgorithms.AsgAnalysisAlgorithmsTest import makeGeneratorAlgorithmsSequence +algSeq = makeGeneratorAlgorithmsSequence (dataType) +print algSeq # For debugging +for alg in algSeq: + job.algsAdd( alg ) + pass + +# Set up an output file for the job: +job.outputAdd( ROOT.EL.OutputStream( 'ANALYSIS' ) ) + +# Find the right output directory: +submitDir = options.submission_dir +if options.unit_test: + import os + import tempfile + submitDir = tempfile.mkdtemp( prefix = 'genTest_', dir = os.getcwd() ) + os.rmdir( submitDir ) + pass + +# Run the job using the direct driver. +driver = ROOT.EL.DirectDriver() +driver.submit( job, submitDir ) diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/GeneratorAlgorithmsTest_jobOptions.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/GeneratorAlgorithmsTest_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..f1c19a2b1063fb4dfac78a1721bcc8c5a0293b98 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/GeneratorAlgorithmsTest_jobOptions.py @@ -0,0 +1,43 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Tadej Novak + +# User options, which can be set from command line after a "-" character +# athena OverlapAlgorithmsTest_jobOptions.py - --myOption ... +from AthenaCommon.AthArgumentParser import AthArgumentParser +athArgsParser = AthArgumentParser() +athArgsParser.add_argument("--data-type", action = "store", dest = "data_type", + default = "mc", + help = "Type of input to run over. Valid options are 'mc', 'afii'") +athArgs = athArgsParser.parse_args() + +dataType = athArgs.data_type +if not dataType in ["mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +print("Running on data type: " + dataType) + +inputfile = {"mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +# Set up the reading of the input file: +import AthenaRootComps.ReadAthenaxAODHybrid +theApp.EvtMax = 500 +testFile = os.getenv ( inputfile[dataType] ) +svcMgr.EventSelector.InputCollections = [testFile] + +from AsgAnalysisAlgorithms.AsgAnalysisAlgorithmsTest import makeGeneratorAlgorithmsSequence +algSeq = makeGeneratorAlgorithmsSequence (dataType) +print algSeq # For debugging + +# Add all algorithms from the sequence to the job. +athAlgSeq += algSeq + +# Set up a histogram output file for the job: +ServiceMgr += CfgMgr.THistSvc() +ServiceMgr.THistSvc.Output += [ + "ANALYSIS DATAFILE='GeneratorAlgorithmsTest." + dataType + ".hist.root' OPT='RECREATE'" +] + +# Reduce the printout from Athena: +include( "AthAnalysisBaseComps/SuppressLogging.py" ) diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/OverlapAlgorithmsTest_eljob.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/OverlapAlgorithmsTest_eljob.py new file mode 100755 index 0000000000000000000000000000000000000000..a213be63996c107fb5039dd723c5701a854ca331 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/OverlapAlgorithmsTest_eljob.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# Read the submission directory as a command line argument. You can +# extend the list of arguments with your private ones later on. +import optparse +parser = optparse.OptionParser() +parser.add_option( '-d', '--data-type', dest = 'data_type', + action = 'store', type = 'string', default = 'data', + help = 'Type of data to run over. Valid options are data, mc, afii' ) +parser.add_option( '-s', '--submission-dir', dest = 'submission_dir', + action = 'store', type = 'string', default = 'submitDir', + help = 'Submission directory for EventLoop' ) +parser.add_option( '-u', '--unit-test', dest='unit_test', + action = 'store_true', default = False, + help = 'Run the job in "unit test mode"' ) +( options, args ) = parser.parse_args() + +# Set up (Py)ROOT. +import ROOT +ROOT.xAOD.Init().ignore() + +# ideally we'd run over all of them, but we don't have a mechanism to +# configure per-sample right now + +dataType = options.data_type + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +if dataType not in ["data", "mc", "afii"] : + raise ValueError ("invalid data type: " + dataType) + +# Set up the sample handler object. See comments from the C++ macro +# for the details about these lines. +import os +sh = ROOT.SH.SampleHandler() +sh.setMetaString( 'nc_tree', 'CollectionTree' ) +sample = ROOT.SH.SampleLocal (dataType) +sample.add (os.getenv (inputfile[dataType])) +sh.add (sample) +sh.printContent() + +# Create an EventLoop job. +job = ROOT.EL.Job() +job.sampleHandler( sh ) +job.options().setDouble( ROOT.EL.Job.optMaxEvents, 500 ) + +from AsgAnalysisAlgorithms.AsgAnalysisAlgorithmsTest import makeOverlapSequence +algSeq = makeOverlapSequence (dataType) +print algSeq # For debugging +for alg in algSeq : + job.algsAdd( alg ) + pass + + +# Set up an output file for the job: +job.outputAdd( ROOT.EL.OutputStream( 'ANALYSIS' ) ) + +# Find the right output directory: +submitDir = options.submission_dir +if options.unit_test: + import os + import tempfile + submitDir = tempfile.mkdtemp( prefix = 'overlapTest_', dir = os.getcwd() ) + os.rmdir( submitDir ) + pass + +# Run the job using the direct driver. +driver = ROOT.EL.DirectDriver() +driver.submit( job, submitDir ) diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/OverlapAlgorithmsTest_jobOptions.py b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/OverlapAlgorithmsTest_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..4e753b0d13576c1254c1e9c9eb84720854d8d647 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/share/OverlapAlgorithmsTest_jobOptions.py @@ -0,0 +1,44 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +# User options, which can be set from command line after a "-" character +# athena OverlapAlgorithmsTest_jobOptions.py - --myOption ... +from AthenaCommon.AthArgumentParser import AthArgumentParser +athArgsParser = AthArgumentParser() +athArgsParser.add_argument("--data-type", action = "store", dest = "data_type", + default = "data", + help = "Type of input to run over. Valid options are 'data', 'mc', 'afii'") +athArgs = athArgsParser.parse_args() + +dataType = athArgs.data_type +if not dataType in ["data", "mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +print("Running on data type: " + dataType) + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +# Set up the reading of the input file: +import AthenaRootComps.ReadAthenaxAODHybrid +theApp.EvtMax = 500 +testFile = os.getenv ( inputfile[dataType] ) +svcMgr.EventSelector.InputCollections = [testFile] + +from AsgAnalysisAlgorithms.AsgAnalysisAlgorithmsTest import makeOverlapSequence +algSeq = makeOverlapSequence (dataType) +print algSeq # For debugging + +# Add all algorithms from the sequence to the job. +athAlgSeq += algSeq + +# Set up a histogram output file for the job: +ServiceMgr += CfgMgr.THistSvc() +ServiceMgr.THistSvc.Output += [ + "ANALYSIS DATAFILE='OverlapAlgorithmsTest." + dataType + ".hist.root' OPT='RECREATE'" + ] + +# Reduce the printout from Athena: +include( "AthAnalysisBaseComps/SuppressLogging.py" ) diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/src/components/AsgAnalysisAlgorithms_entries.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/src/components/AsgAnalysisAlgorithms_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..14e40a32afaa936d47565f72dcec16591008ebaf --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/src/components/AsgAnalysisAlgorithms_entries.cxx @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#include <GaudiKernel/DeclareFactoryEntries.h> + +#include <AsgAnalysisAlgorithms/AsgFlagSelectionTool.h> +#include <AsgAnalysisAlgorithms/AsgPtEtaSelectionTool.h> +#include <AsgAnalysisAlgorithms/AsgCutBookkeeperAlg.h> +#include <AsgAnalysisAlgorithms/AsgEventScaleFactorAlg.h> +#include <AsgAnalysisAlgorithms/AsgLeptonTrackSelectionAlg.h> +#include <AsgAnalysisAlgorithms/AsgOriginalObjectLinkAlg.h> +#include <AsgAnalysisAlgorithms/AsgSelectionAlg.h> +#include <AsgAnalysisAlgorithms/AsgViewFromSelectionAlg.h> +#include <AsgAnalysisAlgorithms/AsgxAODNTupleMakerAlg.h> +#include <AsgAnalysisAlgorithms/EventFlagSelectionAlg.h> +#include <AsgAnalysisAlgorithms/EventSelectionByObjectFlagAlg.h> +#include <AsgAnalysisAlgorithms/IsolationCloseByCorrectionAlg.h> +#include <AsgAnalysisAlgorithms/KinematicHistAlg.h> +#include <AsgAnalysisAlgorithms/ObjectCutFlowHistAlg.h> +#include <AsgAnalysisAlgorithms/OverlapRemovalAlg.h> +#include <AsgAnalysisAlgorithms/PileupReweightingAlg.h> +#include <AsgAnalysisAlgorithms/PMGTruthWeightAlg.h> +#include <AsgAnalysisAlgorithms/SysListDumperAlg.h> +#include <AsgAnalysisAlgorithms/SysListLoaderAlg.h> +#include <AsgAnalysisAlgorithms/TreeFillerAlg.h> +#include <AsgAnalysisAlgorithms/TreeMakerAlg.h> + +DECLARE_NAMESPACE_TOOL_FACTORY (CP, AsgFlagSelectionTool) +DECLARE_NAMESPACE_TOOL_FACTORY (CP, AsgPtEtaSelectionTool) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, AsgCutBookkeeperAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, AsgEventScaleFactorAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, AsgLeptonTrackSelectionAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, AsgOriginalObjectLinkAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, AsgSelectionAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, AsgViewFromSelectionAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, AsgxAODNTupleMakerAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, EventFlagSelectionAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, EventSelectionByObjectFlagAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, IsolationCloseByCorrectionAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, KinematicHistAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, ObjectCutFlowHistAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, OverlapRemovalAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, PileupReweightingAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, PMGTruthWeightAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, SysListDumperAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, SysListLoaderAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, TreeFillerAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, TreeMakerAlg) + +DECLARE_FACTORY_ENTRIES(AsgAnalysisAlgorithms) { + DECLARE_NAMESPACE_ALGTOOL (CP, AsgFlagSelectionTool) + DECLARE_NAMESPACE_ALGTOOL (CP, AsgPtEtaSelectionTool) + DECLARE_NAMESPACE_ALGORITHM (CP, AsgCutBookkeeperAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, AsgEventScaleFactorAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, AsgLeptonTrackSelectionAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, AsgOriginalObjectLinkAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, AsgSelectionAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, AsgViewFromSelectionAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, AsgxAODNTupleMakerAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, EventFlagSelectionAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, EventSelectionByObjectFlagAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, IsolationCloseByCorrectionAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, KinematicHistAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, ObjectCutFlowHistAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, OverlapRemovalAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, PileupReweightingAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, PMGTruthWeightAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, SysListDumperAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, SysListLoaderAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, TreeFillerAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, TreeMakerAlg) +} diff --git a/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/src/components/AsgAnalysisAlgorithms_load.cxx b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/src/components/AsgAnalysisAlgorithms_load.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d9df74517d2afe019c514713e128a740f6e8a25c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/AsgAnalysisAlgorithms/src/components/AsgAnalysisAlgorithms_load.cxx @@ -0,0 +1,10 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(AsgAnalysisAlgorithms) diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/CMakeLists.txt b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..61b27027550c137b8154b169727b8ad21f38e5b0 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/CMakeLists.txt @@ -0,0 +1,65 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# The name of the package: +atlas_subdir( EgammaAnalysisAlgorithms ) + +# The package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Event/xAOD/xAODEgamma + PhysicsAnalysis/Algorithms/SelectionHelpers + PhysicsAnalysis/Algorithms/SystematicsHandles + PhysicsAnalysis/AnalysisCommon/IsolationSelection + PhysicsAnalysis/D3PDTools/AnaAlgorithm + PhysicsAnalysis/ElectronPhotonID/IsolationCorrections + PhysicsAnalysis/Interfaces/EgammaAnalysisInterfaces ) + +atlas_add_library( EgammaAnalysisAlgorithmsLib + EgammaAnalysisAlgorithms/*.h EgammaAnalysisAlgorithms/*.icc Root/*.cxx + PUBLIC_HEADERS EgammaAnalysisAlgorithms + LINK_LIBRARIES xAODEgamma SelectionHelpersLib SystematicsHandlesLib + IsolationSelectionLib AnaAlgorithmLib IsolationCorrectionsLib + EgammaAnalysisInterfacesLib ) + +atlas_add_dictionary( EgammaAnalysisAlgorithmsDict + EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithmsDict.h + EgammaAnalysisAlgorithms/selection.xml + LINK_LIBRARIES EgammaAnalysisAlgorithmsLib ) + +if( NOT XAOD_STANDALONE ) + atlas_add_component( EgammaAnalysisAlgorithms + src/*.h src/*.cxx src/components/*.cxx + LINK_LIBRARIES GaudiKernel EgammaAnalysisAlgorithmsLib ) +endif() + +atlas_install_python_modules( python/*.py ) +atlas_install_joboptions( share/*_jobOptions.py ) +atlas_install_scripts( share/*_eljob.py ) + +if( XAOD_STANDALONE ) + atlas_add_test( testJobData + SCRIPT EgammaAnalysisAlgorithmsTest_eljob.py --data-type data --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSim + SCRIPT EgammaAnalysisAlgorithmsTest_eljob.py --data-type mc --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSim + SCRIPT EgammaAnalysisAlgorithmsTest_eljob.py --data-type afii --unit-test + PROPERTIES TIMEOUT 600 ) +else() + atlas_add_test( testJobData + SCRIPT athena.py + EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithmsTest_jobOptions.py - --data-type data + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSim + SCRIPT athena.py + EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithmsTest_jobOptions.py - --data-type mc + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSim + SCRIPT athena.py + EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithmsTest_jobOptions.py - --data-type afii + PROPERTIES TIMEOUT 600 ) +endif() diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/CopyHelpers.h b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/CopyHelpers.h new file mode 100644 index 0000000000000000000000000000000000000000..fecb243d040131fba2678ef4931c7c33e1ec6124 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/CopyHelpers.h @@ -0,0 +1,50 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef EGAMMA_ANALYSIS_ALGORITHMS__COPY_HELPERS_H +#define EGAMMA_ANALYSIS_ALGORITHMS__COPY_HELPERS_H + +#include <SystematicsHandles/CopyHelpers.h> + +#include <xAODEgamma/EgammaContainer.h> + +namespace CP +{ + namespace detail + { + template<> + struct ShallowCopy<xAOD::EgammaContainer> + { + /// \brief the type of the event store we use + public: + typedef std::decay<decltype(*((EL::AnaAlgorithm*)0)->evtStore())>::type StoreType; + + static StatusCode + getCopy (MsgStream& msgStream, StoreType& store, + xAOD::EgammaContainer*& object, + const xAOD::EgammaContainer *inputObject, + const std::string& outputName, const std::string& auxName) + { + const auto msg = [&] (MSG::Level lvl) -> MsgStream& {msgStream << lvl; return msgStream;}; + + xAOD::IParticleContainer *subobject = nullptr; + if (!ShallowCopy<xAOD::IParticleContainer>::getCopy (msgStream, store, subobject, inputObject, outputName, auxName).isSuccess()) + return StatusCode::FAILURE; + if (!(object = dynamic_cast<xAOD::EgammaContainer*>(subobject))) + { + ANA_MSG_ERROR ("copy of EgammaContainer is not an EgammaContainer"); + ANA_MSG_ERROR ("check logic in CopyHelpers"); + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; + } + }; + } +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithmsDict.h b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithmsDict.h new file mode 100644 index 0000000000000000000000000000000000000000..6873d4560ca86ef2efaab2098ba4405ec1a43e7a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithmsDict.h @@ -0,0 +1,19 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef EGAMMA_ANALYSIS_ALGORITHMS__EGAMMA_ANALYSIS_ALGORITHMS_DICT_H +#define EGAMMA_ANALYSIS_ALGORITHMS__EGAMMA_ANALYSIS_ALGORITHMS_DICT_H + +#include <EgammaAnalysisAlgorithms/EgammaCalibrationAndSmearingAlg.h> +#include <EgammaAnalysisAlgorithms/EgammaIsGoodOQSelectionTool.h> +#include <EgammaAnalysisAlgorithms/EgammaIsolationCorrectionAlg.h> +#include <EgammaAnalysisAlgorithms/EgammaIsolationSelectionAlg.h> +#include <EgammaAnalysisAlgorithms/ElectronEfficiencyCorrectionAlg.h> +#include <EgammaAnalysisAlgorithms/PhotonEfficiencyCorrectionAlg.h> +#include <EgammaAnalysisAlgorithms/PhotonShowerShapeFudgeAlg.h> + +#endif diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaCalibrationAndSmearingAlg.h b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaCalibrationAndSmearingAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..bd361e9a53652ce0bd72ee5af02693decd908399 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaCalibrationAndSmearingAlg.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef EGAMMA_ANALYSIS_ALGORITHMS__EGAMMA_CALIBRATION_AND_SMEARING_ALG_H +#define EGAMMA_ANALYSIS_ALGORITHMS__EGAMMA_CALIBRATION_AND_SMEARING_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <EgammaAnalysisInterfaces/IEgammaCalibrationAndSmearingTool.h> +#include <EgammaAnalysisAlgorithms/CopyHelpers.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref + /// CP::IEgammaCalibrationAndSmearingTool + + class EgammaCalibrationAndSmearingAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + EgammaCalibrationAndSmearingAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<CP::IEgammaCalibrationAndSmearingTool> m_calibrationAndSmearingTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the egamma collection we run on + private: + SysCopyHandle<xAOD::EgammaContainer> m_egammaHandle { + this, "egammas", "Electrons", "the egamma collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaIsGoodOQSelectionTool.h b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaIsGoodOQSelectionTool.h new file mode 100644 index 0000000000000000000000000000000000000000..179e9b7fac68d5b9f26c772302b8722e880533eb --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaIsGoodOQSelectionTool.h @@ -0,0 +1,71 @@ +// Dear emacs, this is -*- c++ -*- +// +// Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +// +#ifndef EGAMMAANALYSISALGORITHMS_EGAMMAISGOODOQSELECTIONTOOL_H +#define EGAMMAANALYSISALGORITHMS_EGAMMAISGOODOQSELECTIONTOOL_H + +// Framework include(s): +#include "AsgTools/AsgTool.h" +#include "PATCore/IAsgSelectionTool.h" + +namespace CP { + + /// Tool selecting e/gamma objects based on their object quality flags + /// + /// This tool can be used in tandem with @c CP::AsgSelectionAlg to flag which + /// e/gamma objects pass a given object quality requirement. The idea is that + /// the mask to use by the tool should be taken from xAODEgamma's dictionary, + /// ideally using a PyROOT configuration. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + class EgammaIsGoodOQSelectionTool final : + public asg::AsgTool, virtual public IAsgSelectionTool { + + public: + /// Declare the tool's interface to Gaudi + ASG_TOOL_CLASS( EgammaIsGoodOQSelectionTool, IAsgSelectionTool ) + + /// AsgTool constructor + EgammaIsGoodOQSelectionTool( const std::string& name ); + + /// @name Interface inherited from @c IAsgSelectionTool + /// @{ + + /// Get the results for the last object processed + virtual const Root::TAccept& getTAccept() const override; + + /// Get the results for a given particle + virtual const Root::TAccept& + accept( const xAOD::IParticle* part ) const override; + + /// @} + + /// @name Interface inherited from @c asg::AsgTool + /// @{ + + /// Function initialising the tool + virtual StatusCode initialize() override; + + /// @} + + private: + /// @name Tool properties + /// @{ + + /// The mask to require good object quality with + int m_mask; + + /// @} + + /// Object handling the e/gamma selection decision + mutable Root::TAccept m_accept{ "EgammaOQ" }; + /// Index of the object quality cut + int m_oqCutIndex{ -1 }; + + }; // class EgammaIsGoodOQSelectionTool + +} // namespace CP + +#endif // EGAMMAANALYSISALGORITHMS_EGAMMAISGOODOQSELECTIONTOOL_H diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaIsolationCorrectionAlg.h b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaIsolationCorrectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..9c193c8a20e48f3a9d2be66c37386d808e96745c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaIsolationCorrectionAlg.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef EGAMMA_ANALYSIS_ALGORITHMS__EGAMMA_ISOLATION_CORRECTION_ALG_H +#define EGAMMA_ANALYSIS_ALGORITHMS__EGAMMA_ISOLATION_CORRECTION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <EgammaAnalysisAlgorithms/CopyHelpers.h> +#include <IsolationCorrections/IIsolationCorrectionTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref + /// CP::IIsolationCorrectionTool + + class EgammaIsolationCorrectionAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + EgammaIsolationCorrectionAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<CP::IIsolationCorrectionTool> m_isolationCorrectionTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the egamma collection we run on + private: + SysCopyHandle<xAOD::EgammaContainer> m_egammaHandle { + this, "egammas", "Electrons", "the egamma collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaIsolationSelectionAlg.h b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaIsolationSelectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..8b4503a8387eefb40355db16b27deb5a0d1e338a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/EgammaIsolationSelectionAlg.h @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef EGAMMA_ANALYSIS_ALGORITHMS__EGAMMA_ISOLATION_SELECTION_ALG_H +#define EGAMMA_ANALYSIS_ALGORITHMS__EGAMMA_ISOLATION_SELECTION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <IsolationSelection/IIsolationSelectionTool.h> +#include <EgammaAnalysisAlgorithms/CopyHelpers.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IIsolationSelectionTool + + class EgammaIsolationSelectionAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + EgammaIsolationSelectionAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the selection tool + private: + ToolHandle<IIsolationSelectionTool> m_selectionTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the particle continer we run on + private: + SysCopyHandle<xAOD::EgammaContainer> m_egammasHandle { + this, "egammas", "Electrons", "the egamma collection to run on"}; + + /// \brief the decoration for the asg selection + private: + std::string m_selectionDecoration {"isolated"}; + + /// \brief the accessor for \ref m_selectionDecoration + private: + std::unique_ptr<ISelectionAccessor> m_selectionAccessor; + + /// \brief the bits to set for an object failing the preselection + private: + SelectionType m_setOnFail; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/ElectronEfficiencyCorrectionAlg.h b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/ElectronEfficiencyCorrectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..a1fb77b32462b4c632533e83cc7a2da4178b712b --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/ElectronEfficiencyCorrectionAlg.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef ELECTRON_ANALYSIS_ALGORITHMS__ELECTRON_EFFICIENCY_SCALE_FACTOR_ALG_H +#define ELECTRON_ANALYSIS_ALGORITHMS__ELECTRON_EFFICIENCY_SCALE_FACTOR_ALG_H + +#include <xAODEgamma/ElectronContainer.h> +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <EgammaAnalysisInterfaces/IAsgElectronEfficiencyCorrectionTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysDecorationHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <SystematicsHandles/SysReadHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IElectronEfficiencyCorrectionTool + + class ElectronEfficiencyCorrectionAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + ElectronEfficiencyCorrectionAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IAsgElectronEfficiencyCorrectionTool> m_efficiencyCorrectionTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the electron collection we run on + private: + SysCopyHandle<xAOD::ElectronContainer> m_electronHandle { + this, "electrons", "Electrons", "the electron collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + + /// \brief the decoration for the electron scale factor + private: + SysDecorationHandle<float> m_scaleFactorDecoration { + this, "scaleFactorDecoration", "", "the decoration for the electron efficiency scale factor"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/PhotonEfficiencyCorrectionAlg.h b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/PhotonEfficiencyCorrectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..c9006d39dedce31c01046a1b7bd70237b65b337d --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/PhotonEfficiencyCorrectionAlg.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef ELECTRON_ANALYSIS_ALGORITHMS__PHOTON_EFFICIENCY_SCALE_FACTOR_ALG_H +#define ELECTRON_ANALYSIS_ALGORITHMS__PHOTON_EFFICIENCY_SCALE_FACTOR_ALG_H + +#include <xAODEgamma/PhotonContainer.h> +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <EgammaAnalysisInterfaces/IAsgPhotonEfficiencyCorrectionTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <SystematicsHandles/SysReadHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IPhotonEfficiencyCorrectionTool + + class PhotonEfficiencyCorrectionAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + PhotonEfficiencyCorrectionAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IAsgPhotonEfficiencyCorrectionTool> m_efficiencyCorrectionTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the photon collection we run on + private: + SysCopyHandle<xAOD::PhotonContainer> m_photonHandle { + this, "photons", "Photons", "the photon collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + + /// \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; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/PhotonShowerShapeFudgeAlg.h b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/PhotonShowerShapeFudgeAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..7ca1165f1840f13e239eef56612784db273de5c9 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/PhotonShowerShapeFudgeAlg.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef EGAMMA_ANALYSIS_ALGORITHMS__ELECTRON_PHOTON_SHOWER_SHAPE_FUDGE_ALG_H +#define EGAMMA_ANALYSIS_ALGORITHMS__ELECTRON_PHOTON_SHOWER_SHAPE_FUDGE_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <EgammaAnalysisInterfaces/IElectronPhotonShowerShapeFudgeTool.h> +#include <EgammaAnalysisAlgorithms/CopyHelpers.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODEgamma/PhotonContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref + /// IElectronPhotonShowerShapeFudgeTool for photons + + class PhotonShowerShapeFudgeAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + PhotonShowerShapeFudgeAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IElectronPhotonShowerShapeFudgeTool> m_showerShapeFudgeTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the photon collection we run on + private: + SysCopyHandle<xAOD::PhotonContainer> m_photonHandle { + this, "photons", "Photons", "the photon collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/selection.xml b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..b6f50af36ba3d4d12c880a2f9e86b1a08c9a9534 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/EgammaAnalysisAlgorithms/selection.xml @@ -0,0 +1,11 @@ +<lcgdict> + + <class name="CP::EgammaCalibrationAndSmearingAlg" /> + <class name="CP::EgammaIsGoodOQSelectionTool" /> + <class name="CP::EgammaIsolationCorrectionAlg" /> + <class name="CP::EgammaIsolationSelectionAlg" /> + <class name="CP::ElectronEfficiencyCorrectionAlg" /> + <class name="CP::PhotonEfficiencyCorrectionAlg" /> + <class name="CP::PhotonShowerShapeFudgeAlg" /> + +</lcgdict> diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/CopyHelpers.cxx b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/CopyHelpers.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0158e1bfd2511120625a6d2a0ec2971940d751a6 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/CopyHelpers.cxx @@ -0,0 +1,21 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <EgammaAnalysisAlgorithms/CopyHelpers.h> + +// +// method implementations +// + +namespace CP +{ +} diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaCalibrationAndSmearingAlg.cxx b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaCalibrationAndSmearingAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8fe486133a4d01c7165ceed397e53ccaff71f3c0 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaCalibrationAndSmearingAlg.cxx @@ -0,0 +1,63 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <EgammaAnalysisAlgorithms/EgammaCalibrationAndSmearingAlg.h> + +// +// method implementations +// + +namespace CP +{ + EgammaCalibrationAndSmearingAlg :: + EgammaCalibrationAndSmearingAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_calibrationAndSmearingTool ("CP::EgammaCalibrationAndSmearingTool", this) + { + declareProperty ("calibrationAndSmearingTool", m_calibrationAndSmearingTool, "the smearing tool we apply"); + } + + + + StatusCode EgammaCalibrationAndSmearingAlg :: + initialize () + { + ANA_CHECK (m_calibrationAndSmearingTool.retrieve()); + m_systematicsList.addHandle (m_egammaHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_calibrationAndSmearingTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode EgammaCalibrationAndSmearingAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_calibrationAndSmearingTool->applySystematicVariation (sys)); + xAOD::EgammaContainer *egammas = nullptr; + ANA_CHECK (m_egammaHandle.getCopy (egammas, sys)); + for (xAOD::Egamma *egamma : *egammas) + { + if (m_preselection.getBool (*egamma)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *egamma, m_calibrationAndSmearingTool->applyCorrection (*egamma)); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaIsGoodOQSelectionTool.cxx b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaIsGoodOQSelectionTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ba2b504cecca8274120b29dfc87096794860d222 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaIsGoodOQSelectionTool.cxx @@ -0,0 +1,67 @@ +// +// Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +// + +// Local include(s): +#include "EgammaAnalysisAlgorithms/EgammaIsGoodOQSelectionTool.h" + +// EDM include(s): +#include "xAODEgamma/Egamma.h" +#include "xAODEgamma/EgammaDefs.h" + +// System include(s): +#include <iomanip> + +namespace CP { + + EgammaIsGoodOQSelectionTool:: + EgammaIsGoodOQSelectionTool( const std::string& name ) + : asg::AsgTool( name ) { + + // Declare the tool's properties. + declareProperty( "Mask", m_mask = xAOD::EgammaParameters::ALLOQ, + "Mask to require passing object quality bits with" ); + } + + const Root::TAccept& EgammaIsGoodOQSelectionTool::getTAccept() const { + + // Return the internal object. + return m_accept; + } + + const Root::TAccept& EgammaIsGoodOQSelectionTool:: + accept( const xAOD::IParticle* part ) const { + + // Reset the decision object. + m_accept.clear(); + + // Cast the particle to an e/gamma type. + const xAOD::Egamma* eg = nullptr; + if( ( part->type() != xAOD::Type::Electron ) && + ( part->type() != xAOD::Type::Photon ) ) { + ATH_MSG_WARNING( "Non-e/gamma object received" ); + return m_accept; + } + eg = static_cast< const xAOD::Egamma* >( part ); + + // Calculate the decision. + m_accept.setCutResult( m_oqCutIndex, eg->isGoodOQ( m_mask ) ); + + // Return the internal object. + return m_accept; + } + + StatusCode EgammaIsGoodOQSelectionTool::initialize() { + + // Tell the user what is going to happen. + ATH_MSG_INFO( "Selecting e/gamma objects with OQ mask: 0x" + << std::hex << m_mask ); + + // Set up the TAccept object. + m_oqCutIndex = m_accept.addCut( "EgammaOQ", "Egamma object quality cut" ); + + // Return gracefully. + return StatusCode::SUCCESS; + } + +} // namespace CP diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaIsolationCorrectionAlg.cxx b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaIsolationCorrectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c9497dec62c32ed8f7843e6c7d328afba9b9e638 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaIsolationCorrectionAlg.cxx @@ -0,0 +1,63 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <EgammaAnalysisAlgorithms/EgammaIsolationCorrectionAlg.h> + +// +// method implementations +// + +namespace CP +{ + EgammaIsolationCorrectionAlg :: + EgammaIsolationCorrectionAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_isolationCorrectionTool ("CP::IsolationCorrectionTool", this) + { + declareProperty ("isolationCorrectionTool", m_isolationCorrectionTool, "the smearing tool we apply"); + } + + + + StatusCode EgammaIsolationCorrectionAlg :: + initialize () + { + ANA_CHECK (m_isolationCorrectionTool.retrieve()); + m_systematicsList.addHandle (m_egammaHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_isolationCorrectionTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode EgammaIsolationCorrectionAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_isolationCorrectionTool->applySystematicVariation (sys)); + xAOD::EgammaContainer *egammas = nullptr; + ANA_CHECK (m_egammaHandle.getCopy (egammas, sys)); + for (xAOD::Egamma *egamma : *egammas) + { + if (m_preselection.getBool (*egamma)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *egamma, m_isolationCorrectionTool->applyCorrection (*egamma)); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaIsolationSelectionAlg.cxx b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaIsolationSelectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..35a77e1e63ecc64bfcec4f7ab610e842cf215e0e --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/EgammaIsolationSelectionAlg.cxx @@ -0,0 +1,78 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <EgammaAnalysisAlgorithms/EgammaIsolationSelectionAlg.h> + +// +// method implementations +// + +namespace CP +{ + EgammaIsolationSelectionAlg :: + EgammaIsolationSelectionAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_selectionTool ("", this) + { + declareProperty ("selectionTool", m_selectionTool, "the selection tool we apply"); + declareProperty ("selectionDecoration", m_selectionDecoration, "the decoration for the asg selection"); + } + + + + StatusCode EgammaIsolationSelectionAlg :: + initialize () + { + if (m_selectionDecoration.empty()) + { + ANA_MSG_ERROR ("no selection decoration name set"); + return StatusCode::FAILURE; + } + ANA_CHECK (makeSelectionAccessor (m_selectionDecoration, m_selectionAccessor)); + ANA_CHECK (m_selectionTool.retrieve()); + + m_systematicsList.addHandle (m_egammasHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + + Root::TAccept blankAccept = m_selectionTool->getObjTAccept(); + // Just in case this isn't initially set up as a failure clear it this one + // time. This only calls reset on the bitset + blankAccept.clear(); + m_setOnFail = selectionFromAccept(blankAccept); + + return StatusCode::SUCCESS; + } + + + + StatusCode EgammaIsolationSelectionAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::EgammaContainer *egammas = nullptr; + ANA_CHECK (m_egammasHandle.getCopy (egammas, sys)); + for (xAOD::Egamma *egamma : *egammas) + { + if (m_preselection.getBool (*egamma)) + { + m_selectionAccessor->setBits + (*egamma, selectionFromAccept (m_selectionTool->accept (*egamma))); + } else { + m_selectionAccessor->setBits (*egamma, m_setOnFail); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/ElectronEfficiencyCorrectionAlg.cxx b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/ElectronEfficiencyCorrectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bf2d404d9386f964e857d5b3da632f2d07b6f005 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/ElectronEfficiencyCorrectionAlg.cxx @@ -0,0 +1,76 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <EgammaAnalysisAlgorithms/ElectronEfficiencyCorrectionAlg.h> + +// +// method implementations +// + +namespace CP +{ + ElectronEfficiencyCorrectionAlg :: + ElectronEfficiencyCorrectionAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_efficiencyCorrectionTool ("AsgElectronEfficiencyCorrectionTool", this) + { + declareProperty ("efficiencyCorrectionTool", m_efficiencyCorrectionTool, "the calibration and smearing tool we apply"); + } + + + + StatusCode ElectronEfficiencyCorrectionAlg :: + initialize () + { + if (m_scaleFactorDecoration.empty()) + { + ANA_MSG_ERROR ("no scale factor decoration name set"); + return StatusCode::FAILURE; + } + + ANA_CHECK (m_efficiencyCorrectionTool.retrieve()); + m_systematicsList.addHandle (m_electronHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_efficiencyCorrectionTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + + return StatusCode::SUCCESS; + } + + + + StatusCode ElectronEfficiencyCorrectionAlg :: + execute () + { + ANA_CHECK (m_scaleFactorDecoration.preExecute (m_systematicsList)); + + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_efficiencyCorrectionTool->applySystematicVariation (sys)); + xAOD::ElectronContainer *electrons = nullptr; + ANA_CHECK (m_electronHandle.getCopy (electrons, sys)); + for (xAOD::Electron *electron : *electrons) + { + if (m_preselection.getBool (*electron)) + { + double sf = 0; + ANA_CHECK_CORRECTION (m_outOfValidity, *electron, m_efficiencyCorrectionTool->getEfficiencyScaleFactor (*electron, sf)); + m_scaleFactorDecoration.set (*electron, sf, sys); + } else { + m_scaleFactorDecoration.set (*electron, invalidScaleFactor(), sys); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/PhotonEfficiencyCorrectionAlg.cxx b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/PhotonEfficiencyCorrectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..163a27762e0e0011f956b8072b6065ffd0309327 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/PhotonEfficiencyCorrectionAlg.cxx @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <EgammaAnalysisAlgorithms/PhotonEfficiencyCorrectionAlg.h> + +// +// method implementations +// + +namespace CP +{ + PhotonEfficiencyCorrectionAlg :: + PhotonEfficiencyCorrectionAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : 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"); + } + + + + StatusCode PhotonEfficiencyCorrectionAlg :: + initialize () + { + if (m_scaleFactorDecoration.empty()) + { + 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()); + m_systematicsList.addHandle (m_photonHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_efficiencyCorrectionTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode PhotonEfficiencyCorrectionAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_efficiencyCorrectionTool->applySystematicVariation (sys)); + xAOD::PhotonContainer *photons = nullptr; + ANA_CHECK (m_photonHandle.getCopy (photons, sys)); + for (xAOD::Photon *photon : *photons) + { + if (m_preselection.getBool (*photon)) + { + double sf = 0; + ANA_CHECK_CORRECTION (m_outOfValidity, *photon, m_efficiencyCorrectionTool->getEfficiencyScaleFactor (*photon, sf)); + (*m_scaleFactorAccessor) (*photon) = sf; + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/PhotonShowerShapeFudgeAlg.cxx b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/PhotonShowerShapeFudgeAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b7b9a8a4126f5b7a0d0b2a2e0abeaed307f77b2c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/Root/PhotonShowerShapeFudgeAlg.cxx @@ -0,0 +1,61 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <EgammaAnalysisAlgorithms/PhotonShowerShapeFudgeAlg.h> + +// +// method implementations +// + +namespace CP +{ + PhotonShowerShapeFudgeAlg :: + PhotonShowerShapeFudgeAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_showerShapeFudgeTool ("ElectronPhotonShowerShapeFudgeTool", this) + { + declareProperty ("showerShapeFudgeTool", m_showerShapeFudgeTool, "the smearing tool we apply"); + } + + + + StatusCode PhotonShowerShapeFudgeAlg :: + initialize () + { + ANA_CHECK (m_showerShapeFudgeTool.retrieve()); + m_systematicsList.addHandle (m_photonHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode PhotonShowerShapeFudgeAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::PhotonContainer *photons = nullptr; + ANA_CHECK (m_photonHandle.getCopy (photons, sys)); + for (xAOD::Photon *photon : *photons) + { + if (m_preselection.getBool (*photon)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *photon, m_showerShapeFudgeTool->applyCorrection (*photon)); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/EgammaAnalysisAlgorithmsTest.py b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/EgammaAnalysisAlgorithmsTest.py new file mode 100644 index 0000000000000000000000000000000000000000..eb8e4b901bcc38ab674d98db8b8ca17fb080f5df --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/EgammaAnalysisAlgorithmsTest.py @@ -0,0 +1,40 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +from AnaAlgorithm.AlgSequence import AlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm + +def makeSequence (dataType) : + algSeq = AlgSequence() + + # Create the algorithm's configuration. Note that we'll be able to add + # algorithm property settings here later on. + alg = createAlgorithm( 'CP::SysListLoaderAlg', 'SysLoaderAlg' ) + alg.sigmaRecommended = 1 + algSeq += alg + + # Include, and then set up the pileup analysis sequence: + from AsgAnalysisAlgorithms.PileupAnalysisSequence import \ + makePileupAnalysisSequence + pileupSequence = makePileupAnalysisSequence( dataType ) + pileupSequence.configure( inputName = 'EventInfo', outputName = 'EventInfo_%SYS%' ) + algSeq += pileupSequence + + # Include, and then set up the electron analysis sequence: + from EgammaAnalysisAlgorithms.ElectronAnalysisSequence import \ + makeElectronAnalysisSequence + electronSequence = makeElectronAnalysisSequence( dataType, 'LooseLHElectron.GradientLoose', postfix = 'loose', + recomputeLikelihood=True, enableCutflow=True, enableKinematicHistograms=True ) + electronSequence.configure( inputName = 'Electrons', + outputName = 'AnalysisElectrons_%SYS%' ) + algSeq += electronSequence + + # Include, and then set up the photon analysis sequence: + from EgammaAnalysisAlgorithms.PhotonAnalysisSequence import \ + makePhotonAnalysisSequence + photonSequence = makePhotonAnalysisSequence( dataType, 'Tight.FixedCutTight', postfix = 'tight', + recomputeIsEM=True, enableCutflow=True, enableKinematicHistograms=True ) + photonSequence.configure( inputName = 'Photons', + outputName = 'AnalysisPhotons_%SYS%' ) + algSeq += photonSequence + + return algSeq diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/ElectronAnalysisSequence.py b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/ElectronAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..a831079c6f4a83ec155f6a7d64c11b5aab21e87e --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/ElectronAnalysisSequence.py @@ -0,0 +1,284 @@ +# Copyright (C) 2002-2019 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 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 = ROOT.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 diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/PhotonAnalysisSequence.py b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/PhotonAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..85583acf4453d5607083075e7b1e48e0a615daba --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/PhotonAnalysisSequence.py @@ -0,0 +1,219 @@ +# 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 diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/__init__.py b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5ccb446532599c01cc3844e5b1b18db06f721002 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/python/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +__version__ = '1.0.0' diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/share/EgammaAnalysisAlgorithmsTest_eljob.py b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/share/EgammaAnalysisAlgorithmsTest_eljob.py new file mode 100755 index 0000000000000000000000000000000000000000..bbf680455ce301c37cc9a1900daa50095b940a88 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/share/EgammaAnalysisAlgorithmsTest_eljob.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# Read the submission directory as a command line argument. You can +# extend the list of arguments with your private ones later on. +import optparse +parser = optparse.OptionParser() +parser.add_option( '-d', '--data-type', dest = 'data_type', + action = 'store', type = 'string', default = 'data', + help = 'Type of data to run over. Valid options are data, mc, afii' ) +parser.add_option( '-s', '--submission-dir', dest = 'submission_dir', + action = 'store', type = 'string', default = 'submitDir', + help = 'Submission directory for EventLoop' ) +parser.add_option( '-u', '--unit-test', dest='unit_test', + action = 'store_true', default = False, + help = 'Run the job in "unit test mode"' ) +( options, args ) = parser.parse_args() + +# Set up (Py)ROOT. +import ROOT +ROOT.xAOD.Init().ignore() + +# ideally we'd run over all of them, but we don't have a mechanism to +# configure per-sample right now + +dataType = options.data_type + +if dataType not in ["data", "mc", "afii"] : + raise ValueError ("invalid data type: " + dataType) + +# Set up the sample handler object. See comments from the C++ macro +# for the details about these lines. +import os +sh = ROOT.SH.SampleHandler() +sh.setMetaString( 'nc_tree', 'CollectionTree' ) +sample = ROOT.SH.SampleLocal (dataType) +if dataType == "data" : + sample.add (os.getenv ('ASG_TEST_FILE_DATA')) + pass +if dataType == "mc" : + sample.add (os.getenv ('ASG_TEST_FILE_MC')) + pass +if dataType == "afii" : + sample.add (os.getenv ('ASG_TEST_FILE_MC_AFII')) + pass +sh.add (sample) +sh.printContent() + +# Create an EventLoop job. +job = ROOT.EL.Job() +job.sampleHandler( sh ) +job.options().setDouble( ROOT.EL.Job.optMaxEvents, 500 ) + +from EgammaAnalysisAlgorithms.EgammaAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging +for alg in algSeq : + job.algsAdd( alg ) + pass + +# Find the right output directory: +submitDir = options.submission_dir +if options.unit_test: + import os + import tempfile + submitDir = tempfile.mkdtemp( prefix = 'egammaTest_'+dataType+'_', dir = os.getcwd() ) + os.rmdir( submitDir ) + pass + +# Run the job using the direct driver. +driver = ROOT.EL.DirectDriver() +driver.submit( job, submitDir ) diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/share/EgammaAnalysisAlgorithmsTest_jobOptions.py b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/share/EgammaAnalysisAlgorithmsTest_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..f8b7e433b4d611c234ecd511a73266c034321549 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/share/EgammaAnalysisAlgorithmsTest_jobOptions.py @@ -0,0 +1,44 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +# User options, which can be set from command line after a "-" character +# athena EgammaAlgorithmsTest_jobOptions.py - --myOption ... +from AthenaCommon.AthArgumentParser import AthArgumentParser +athArgsParser = AthArgumentParser() +athArgsParser.add_argument("--data-type", action = "store", dest = "data_type", + default = "data", + help = "Type of input to run over. Valid options are 'data', 'mc', 'afii'") +athArgs = athArgsParser.parse_args() + +dataType = athArgs.data_type +if not dataType in ["data", "mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +print("Running on data type: " + dataType) + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +# Set up the reading of the input file: +import AthenaRootComps.ReadAthenaxAODHybrid +theApp.EvtMax = 500 +testFile = os.getenv ( inputfile[dataType] ) +svcMgr.EventSelector.InputCollections = [testFile] + +from EgammaAnalysisAlgorithms.EgammaAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging + +# Add all algorithms from the sequence to the job. +athAlgSeq += algSeq + +# Set up a histogram output file for the job: +ServiceMgr += CfgMgr.THistSvc() +ServiceMgr.THistSvc.Output += [ + "ANALYSIS DATAFILE='EgammaAnalysisAlgorithmsTest." + dataType + ".hist.root' OPT='RECREATE'" + ] + +# Reduce the printout from Athena: +include( "AthAnalysisBaseComps/SuppressLogging.py" ) diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/src/components/EgammaAnalysisAlgorithms_entries.cxx b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/src/components/EgammaAnalysisAlgorithms_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d4ed8c1679c72c2f347d148ce09da4d9c9483072 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/src/components/EgammaAnalysisAlgorithms_entries.cxx @@ -0,0 +1,29 @@ +// AsgExampleTools_entries.cxx + +#include <GaudiKernel/DeclareFactoryEntries.h> + +#include <EgammaAnalysisAlgorithms/EgammaCalibrationAndSmearingAlg.h> +#include <EgammaAnalysisAlgorithms/EgammaIsGoodOQSelectionTool.h> +#include <EgammaAnalysisAlgorithms/EgammaIsolationCorrectionAlg.h> +#include <EgammaAnalysisAlgorithms/EgammaIsolationSelectionAlg.h> +#include <EgammaAnalysisAlgorithms/ElectronEfficiencyCorrectionAlg.h> +#include <EgammaAnalysisAlgorithms/PhotonEfficiencyCorrectionAlg.h> +#include <EgammaAnalysisAlgorithms/PhotonShowerShapeFudgeAlg.h> + +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, EgammaCalibrationAndSmearingAlg) +DECLARE_NAMESPACE_TOOL_FACTORY (CP, EgammaIsGoodOQSelectionTool) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, EgammaIsolationCorrectionAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, EgammaIsolationSelectionAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, ElectronEfficiencyCorrectionAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, PhotonEfficiencyCorrectionAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, PhotonShowerShapeFudgeAlg) + +DECLARE_FACTORY_ENTRIES(EgammaAnalysisAlgorithms) { + DECLARE_NAMESPACE_ALGORITHM (CP, EgammaCalibrationAndSmearingAlg) + DECLARE_NAMESPACE_TOOL (CP, EgammaIsGoodOQSelectionTool) + DECLARE_NAMESPACE_ALGORITHM (CP, EgammaIsolationCorrectionAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, EgammaIsolationSelectionAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, ElectronEfficiencyCorrectionAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, PhotonEfficiencyCorrectionAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, PhotonShowerShapeFudgeAlg) +} diff --git a/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/src/components/EgammaAnalysisAlgorithms_load.cxx b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/src/components/EgammaAnalysisAlgorithms_load.cxx new file mode 100644 index 0000000000000000000000000000000000000000..fe3d2b768fca0948d9adf76951bedfd880d2ee68 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/EgammaAnalysisAlgorithms/src/components/EgammaAnalysisAlgorithms_load.cxx @@ -0,0 +1,3 @@ +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(EgammaAnalysisAlgorithms) diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/CMakeLists.txt b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..fce4b747c7714639128fabc463373253b38e06fc --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/CMakeLists.txt @@ -0,0 +1,61 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# The name of the package: +atlas_subdir( FTagAnalysisAlgorithms ) + +atlas_depends_on_subdirs( + PUBLIC + Event/xAOD/xAODJet + PhysicsAnalysis/Algorithms/SelectionHelpers + PhysicsAnalysis/Algorithms/SystematicsHandles + PhysicsAnalysis/D3PDTools/AnaAlgorithm + PhysicsAnalysis/Interfaces/FTagAnalysisInterfaces ) + +atlas_add_library( FTagAnalysisAlgorithmsLib + FTagAnalysisAlgorithms/*.h FTagAnalysisAlgorithms/*.icc Root/*.cxx + PUBLIC_HEADERS FTagAnalysisAlgorithms + LINK_LIBRARIES xAODJet SelectionHelpersLib SystematicsHandlesLib + AnaAlgorithmLib FTagAnalysisInterfacesLib ) + +atlas_add_dictionary( FTagAnalysisAlgorithmsDict + FTagAnalysisAlgorithms/FTagAnalysisAlgorithmsDict.h + FTagAnalysisAlgorithms/selection.xml + LINK_LIBRARIES FTagAnalysisAlgorithmsLib ) + +if( NOT XAOD_STANDALONE ) + atlas_add_component( FTagAnalysisAlgorithms + src/*.h src/*.cxx src/components/*.cxx + LINK_LIBRARIES GaudiKernel FTagAnalysisAlgorithmsLib ) +endif() + +atlas_install_python_modules( python/*.py ) +atlas_install_joboptions( share/*_jobOptions.py ) +atlas_install_scripts( share/*_eljob.py ) + +if( XAOD_STANDALONE ) + atlas_add_test( testJobData + SCRIPT FTagAnalysisAlgorithmsTest_eljob.py --data-type data --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSim + SCRIPT FTagAnalysisAlgorithmsTest_eljob.py --data-type mc --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSim + SCRIPT FTagAnalysisAlgorithmsTest_eljob.py --data-type afii --unit-test + PROPERTIES TIMEOUT 600 ) +elseif( NOT "${CMAKE_PROJECT_NAME}" STREQUAL "AthDerivation" ) + atlas_add_test( testJobData + SCRIPT athena.py + FTagAnalysisAlgorithms/FTagAnalysisAlgorithmsTest_jobOptions.py - --data-type data + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSim + SCRIPT athena.py + FTagAnalysisAlgorithms/FTagAnalysisAlgorithmsTest_jobOptions.py - --data-type mc + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSim + SCRIPT athena.py + FTagAnalysisAlgorithms/FTagAnalysisAlgorithmsTest_jobOptions.py - --data-type afii + PROPERTIES TIMEOUT 600 ) +endif() diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithms/BTaggingEfficiencyAlg.h b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithms/BTaggingEfficiencyAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..d19d19630f2ee6f2e9a2848f856bcb671f3c1985 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithms/BTaggingEfficiencyAlg.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef F_TAG_ANALYSIS_ALGORITHMS__B_TAGGING_EFFICIENCY_ALG_H +#define F_TAG_ANALYSIS_ALGORITHMS__B_TAGGING_EFFICIENCY_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <FTagAnalysisInterfaces/IBTaggingEfficiencyTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysDecorationHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <SystematicsHandles/SysReadHandle.h> +#include <xAODJet/JetContainer.h> +#include <memory> + +namespace CP +{ + /// \brief an algorithm for calling \ref IBTaggingEfficiencyTool + + class BTaggingEfficiencyAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + BTaggingEfficiencyAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IBTaggingEfficiencyTool> m_efficiencyTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysCopyHandle<xAOD::JetContainer> m_jetHandle { + this, "jets", "Jets", "the jet collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + + /// \brief the decoration for the b-tagging scale factor + private: + SysDecorationHandle<float> m_scaleFactorDecoration { + this, "scaleFactorDecoration", "", "the decoration for the b-tagging efficiency scale factor"}; + + /// \brief the decoration for the b-tagging selection + private: + SelectionReadHandle m_selectionHandle { + this, "selectionDecoration", "", "the decoration for the asg selection"}; + + /// \brief only run the inefficency for all jets + private: + bool m_onlyInefficiency {false}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithmsDict.h b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithmsDict.h new file mode 100644 index 0000000000000000000000000000000000000000..dd476fc0233a6b4f8d9152aef636a20b22ef4d23 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithmsDict.h @@ -0,0 +1,13 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef F_TAG_ANALYSIS_ALGORITHMS__F_TAG_ANALYSIS_ALGORITHMS_DICT_H +#define F_TAG_ANALYSIS_ALGORITHMS__F_TAG_ANALYSIS_ALGORITHMS_DICT_H + +#include <FTagAnalysisAlgorithms/BTaggingEfficiencyAlg.h> + +#endif diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithms/selection.xml b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithms/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..ebaebc249669d3cb1748e62ae3a5d348181eaa47 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/FTagAnalysisAlgorithms/selection.xml @@ -0,0 +1,5 @@ +<lcgdict> + + <class name="CP::BTaggingEfficiencyAlg" /> + +</lcgdict> diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/Root/BTaggingEfficiencyAlg.cxx b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/Root/BTaggingEfficiencyAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0e901cbe8a437e068889e2ff3a52601f6bbb2245 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/Root/BTaggingEfficiencyAlg.cxx @@ -0,0 +1,101 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <FTagAnalysisAlgorithms/BTaggingEfficiencyAlg.h> + +// +// method implementations +// + +namespace CP +{ + BTaggingEfficiencyAlg :: + BTaggingEfficiencyAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_efficiencyTool ("BTaggingEfficiencyTool", this) + { + declareProperty ("efficiencyTool", m_efficiencyTool, "the calibration and smearing tool we apply"); + declareProperty ("onlyInefficiency", m_onlyInefficiency, "whether only to calculate inefficiencies"); + } + + + + StatusCode BTaggingEfficiencyAlg :: + initialize () + { + if (m_onlyInefficiency && m_selectionHandle) + { + ANA_MSG_ERROR ("can't specify both onlyInefficiency and selectionDecoration"); + return StatusCode::FAILURE; + } + + if (m_scaleFactorDecoration.empty()) + { + ANA_MSG_ERROR ("no scale factor decoration name set"); + return StatusCode::FAILURE; + } + + ANA_CHECK (m_efficiencyTool.retrieve()); + m_systematicsList.addHandle (m_jetHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_efficiencyTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_selectionHandle.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + + return StatusCode::SUCCESS; + } + + + + StatusCode BTaggingEfficiencyAlg :: + execute () + { + ANA_CHECK (m_scaleFactorDecoration.preExecute (m_systematicsList)); + + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_efficiencyTool->applySystematicVariation (sys)); + xAOD::JetContainer *jets = nullptr; + ANA_CHECK (m_jetHandle.getCopy (jets, sys)); + for (xAOD::Jet *jet : *jets) + { + if (m_preselection.getBool (*jet)) + { + float sf = 0; + + // The efficiency tool can calculate both efficiencies and + // inefficiencies. This setup can calculate either, or + // both; in the case of the later a selection decoration is + // used to decide whether to calculate efficiencies or + // inefficiencies. + // + // Note that if you want to exclude jets from processing, + // this selection accessor/decoration has nothing to do with + // it. You do the pre-selection via a view container like + // for all the other CP algorithms. + if (!m_onlyInefficiency && m_selectionHandle.getBool (*jet)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *jet, m_efficiencyTool->getScaleFactor (*jet, sf)); + } else + { + ANA_CHECK_CORRECTION (m_outOfValidity, *jet, m_efficiencyTool->getInefficiencyScaleFactor (*jet, sf)); + } + m_scaleFactorDecoration.set (*jet, sf, sys); + } else { + m_scaleFactorDecoration.set (*jet, invalidScaleFactor(), sys); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisAlgorithmsTest.py b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisAlgorithmsTest.py new file mode 100644 index 0000000000000000000000000000000000000000..7e0c9e5bb4e118d9b4f92d246e4d0c1169113c3e --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisAlgorithmsTest.py @@ -0,0 +1,29 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +from AnaAlgorithm.AlgSequence import AlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm + +def makeSequence (dataType, jetContainer="AntiKt4EMPFlowJets") : + + 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 + jetSequence = makeJetAnalysisSequence( dataType, jetContainer, + enableCutflow=True, enableKinematicHistograms=True ) + from FTagAnalysisAlgorithms.FTagAnalysisSequence import makeFTagAnalysisSequence + makeFTagAnalysisSequence( jetSequence, dataType, jetContainer, noEfficiency = True, legacyRecommendations = True, + enableCutflow=True ) + jetSequence.configure( inputName = jetContainer, outputName = 'AnalysisJets_%SYS%' ) + + # Add the sequence to the job: + algSeq += jetSequence + + return algSeq diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisSequence.py b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..505ac45816cf086f226afd79c22edf8bd2b358c0 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/FTagAnalysisSequence.py @@ -0,0 +1,112 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +# AnaAlgorithm import(s): +from AnaAlgorithm.DualUseConfig import createAlgorithm, addPrivateTool + +def makeFTagAnalysisSequence( seq, dataType, jetCollection, + btagWP = "FixedCutBEff_77", + btagger = "MV2c10", + postfix = "", + preselection=None, + kinematicSelection = False, + noEfficiency = False, + legacyRecommendations = False, + enableCutflow = False ): + """Create a ftag analysis algorithm sequence + + for now the sequence is passed in, I'm unsure if I can concatenate + two sequences at the moment, or if that blows things up horribly + + Keyword arguments: + dataType -- The data type to run on ("data", "mc" or "afii") + jetCollection -- Jet container to run on + btagWP -- Flavour tagging working point + btagger -- Flavour tagger + kinematicSelection -- Wether to run kinematic selection + noEfficiency -- Wether to run efficiencies calculation + legacyRecommendations -- Use legacy recommendations without shallow copied containers + enableCutflow -- Whether or not to dump the cutflow + """ + + if dataType not in ["data", "mc", "afii"] : + raise ValueError ("invalid data type: " + dataType) + + if legacyRecommendations: + # Remove b-tagging calibration from the container name + btIndex = jetCollection.find('_BTagging') + if btIndex != -1: + jetCollection = jetCollection[:btIndex] + + bTagCalibFile = "xAODBTaggingEfficiency/13TeV/2017-21-13TeV-MC16-CDI-2019-07-30_v1.root" + else: + bTagCalibFile = "xAODBTaggingEfficiency/13TeV/2019-21-13TeV-MC16-CDI-2019-10-07_v1.root" + + # # Create the analysis algorithm sequence object: + # seq = AnaAlgSequence( "FTagAnalysisSequence" ) + + if kinematicSelection: + # Set up the ftag kinematic selection algorithm(s): + alg = createAlgorithm( 'CP::AsgSelectionAlg', 'FTagKinSelectionAlg'+postfix ) + addPrivateTool( alg, 'selectionTool', 'CP::AsgPtEtaSelectionTool' ) + alg.selectionTool.minPt = 20e3 + alg.selectionTool.maxEta = 2.5 + alg.selectionDecoration = 'ftag_kin_select' + seq.append( alg, inputPropName = 'particles', + outputPropName = 'particlesOut' ) + + # Set up an algorithm that makes a view container using the selections + # performed previously: + alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg', + 'FTagKinViewFromSelectionAlg'+postfix ) + alg.selection = [ 'ftag_kin_select' ] + seq.append( alg, inputPropName = 'input', outputPropName = 'output', + stageName = 'selection' ) + + # Set up the ftag selection algorithm(s): + alg = createAlgorithm( 'CP::AsgSelectionAlg', 'FTagSelectionAlg' + btagger + btagWP + postfix ) + addPrivateTool( alg, 'selectionTool', 'BTaggingSelectionTool' ) + alg.selectionTool.TaggerName = btagger + alg.selectionTool.OperatingPoint = btagWP + alg.selectionTool.JetAuthor = jetCollection + alg.selectionTool.FlvTagCutDefinitionsFileName = bTagCalibFile + if preselection is not None: + alg.preselection = preselection + alg.selectionDecoration = 'ftag_select_' + btagger + '_' + btagWP + ',as_char' + seq.append( alg, inputPropName = 'particles', + outputPropName = 'particlesOut', + stageName = 'selection' ) + + if not noEfficiency and dataType != 'data': + # Set up the efficiency calculation algorithm: + alg = createAlgorithm( 'CP::BTaggingEfficiencyAlg', + 'FTagEfficiencyScaleFactorAlg' + btagger + btagWP + postfix ) + addPrivateTool( alg, 'efficiencyTool', + 'BTaggingEfficiencyTool' ) + alg.efficiencyTool.TaggerName = btagger + alg.efficiencyTool.OperatingPoint = btagWP + alg.efficiencyTool.JetAuthor = jetCollection + alg.efficiencyTool.ScaleFactorFileName = bTagCalibFile + alg.efficiencyTool.SystematicsStrategy = "Envelope" + alg.scaleFactorDecoration = 'ftag_effSF_' + btagger + '_' + btagWP + '_%SYS%' + alg.scaleFactorDecorationRegex = '(^FT_EFF_.*)' + alg.selectionDecoration = 'ftag_select_' + btagger + '_' + btagWP + ',as_char' + alg.outOfValidity = 2 + alg.outOfValidityDeco = 'no_ftag_' + btagger + '_' + btagWP + if preselection is not None: + alg.preselection = preselection + seq.append( alg, inputPropName = 'jets', + affectingSystematics = '(^FT_EFF_.*)', + stageName = 'efficiency' ) + pass + + # Set up an algorithm used to create f-tag selection cutflow: + if enableCutflow: + alg = createAlgorithm( 'CP::ObjectCutFlowHistAlg', 'FTagCutFlowDumperAlg' + btagger + btagWP + postfix ) + alg.histPattern = 'ftag_cflow_' + btagger + '_' + btagWP + '_%SYS%' + alg.selection = ['ftag_select_' + btagger + '_' + btagWP + ',as_char'] + alg.selectionNCuts = [1] # really we have 4 cuts, but we use char + seq.append( alg, inputPropName = 'input', + stageName = 'selection' ) + + # Return the sequence: + return seq diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/__init__.py b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5ccb446532599c01cc3844e5b1b18db06f721002 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/python/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +__version__ = '1.0.0' diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/share/FTagAnalysisAlgorithmsTest_eljob.py b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/share/FTagAnalysisAlgorithmsTest_eljob.py new file mode 100755 index 0000000000000000000000000000000000000000..44a9e6a3d26cdb1bdce0684174e80b171480ddac --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/share/FTagAnalysisAlgorithmsTest_eljob.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# Read the submission directory as a command line argument. You can +# extend the list of arguments with your private ones later on. +import optparse +parser = optparse.OptionParser() +parser.add_option( '-d', '--data-type', dest = 'data_type', + action = 'store', type = 'string', default = 'data', + help = 'Type of data to run over. Valid options are data, mc, afii' ) +parser.add_option( '-s', '--submission-dir', dest = 'submission_dir', + action = 'store', type = 'string', default = 'submitDir', + help = 'Submission directory for EventLoop' ) +parser.add_option( '-u', '--unit-test', dest='unit_test', + action = 'store_true', default = False, + help = 'Run the job in "unit test mode"' ) +( options, args ) = parser.parse_args() + +# Set up (Py)ROOT. +import ROOT +ROOT.xAOD.Init().ignore() + +# this forces the jet algorithms dictionary to be loaded before +# anything else, which works around some strange dictionary issues I +# don't understand. +ROOT.CP.JetCalibrationAlg ("dummy", None) + +# ideally we'd run over all of them, but we don't have a mechanism to +# configure per-sample right now + +dataType = options.data_type + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +if dataType not in ["data", "mc", "afii"] : + raise ValueError ("invalid data type: " + dataType) + +# Set up the sample handler object. See comments from the C++ macro +# for the details about these lines. +import os +sh = ROOT.SH.SampleHandler() +sh.setMetaString( 'nc_tree', 'CollectionTree' ) +sample = ROOT.SH.SampleLocal (dataType) +sample.add (os.getenv (inputfile[dataType])) +sh.add (sample) +sh.printContent() + +# Create an EventLoop job. +job = ROOT.EL.Job() +job.sampleHandler( sh ) +job.options().setDouble( ROOT.EL.Job.optMaxEvents, 500 ) + +from FTagAnalysisAlgorithms.FTagAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging +for alg in algSeq: + job.algsAdd( alg ) + pass + +# Find the right output directory: +submitDir = options.submission_dir +if options.unit_test: + import os + import tempfile + submitDir = tempfile.mkdtemp( prefix = 'jetTest_'+dataType+'_', dir = os.getcwd() ) + os.rmdir( submitDir ) + pass + +# Run the job using the direct driver. +driver = ROOT.EL.DirectDriver() +driver.submit( job, submitDir ) diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/share/FTagAnalysisAlgorithmsTest_jobOptions.py b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/share/FTagAnalysisAlgorithmsTest_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..91d0e0056a66e05ec5a52715da308929552e0d31 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/share/FTagAnalysisAlgorithmsTest_jobOptions.py @@ -0,0 +1,44 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +# User options, which can be set from command line after a "-" character +# athena EgammaAlgorithmsTest_jobOptions.py - --myOption ... +from AthenaCommon.AthArgumentParser import AthArgumentParser +athArgsParser = AthArgumentParser() +athArgsParser.add_argument("--data-type", action = "store", dest = "data_type", + default = "data", + help = "Type of input to run over. Valid options are 'data', 'mc', 'afii'") +athArgs = athArgsParser.parse_args() + +dataType = athArgs.data_type +if not dataType in ["data", "mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +print("Running on data type: " + dataType) + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +# Set up the reading of the input file: +import AthenaRootComps.ReadAthenaxAODHybrid +theApp.EvtMax = 500 +testFile = os.getenv ( inputfile[dataType] ) +svcMgr.EventSelector.InputCollections = [testFile] + +from FTagAnalysisAlgorithms.FTagAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging + +# Add all algorithms from the sequence to the job. +athAlgSeq += algSeq + +# Set up a histogram output file for the job: +ServiceMgr += CfgMgr.THistSvc() +ServiceMgr.THistSvc.Output += [ + "ANALYSIS DATAFILE='JetAnalysisAlgorithmsTest." + dataType + ".hist.root' OPT='RECREATE'" + ] + +# Reduce the printout from Athena: +include( "AthAnalysisBaseComps/SuppressLogging.py" ) diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/src/components/FTagAnalysisAlgorithms_entries.cxx b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/src/components/FTagAnalysisAlgorithms_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..05df68d48072e4f484febf42f5d33811d2051381 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/src/components/FTagAnalysisAlgorithms_entries.cxx @@ -0,0 +1,11 @@ +// AsgExampleTools_entries.cxx + +#include <GaudiKernel/DeclareFactoryEntries.h> + +#include <FTagAnalysisAlgorithms/BTaggingEfficiencyAlg.h> + +DECLARE_ALGORITHM_FACTORY (CP::BTaggingEfficiencyAlg) + +DECLARE_FACTORY_ENTRIES(FTagAnalysisAlgorithms) { + DECLARE_ALGORITHM (CP::BTaggingEfficiencyAlg) +} diff --git a/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/src/components/FTagAnalysisAlgorithms_load.cxx b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/src/components/FTagAnalysisAlgorithms_load.cxx new file mode 100644 index 0000000000000000000000000000000000000000..7542cfe5a54de55a238454183dfac20fa8e6af9c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/FTagAnalysisAlgorithms/src/components/FTagAnalysisAlgorithms_load.cxx @@ -0,0 +1,5 @@ +// AsgExampleTools_load.cxx + +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(FTagAnalysisAlgorithms) diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/CMakeLists.txt b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..44c39deb7c52c37b440dd9c9dd84cf7cf6955052 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/CMakeLists.txt @@ -0,0 +1,88 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# The name of the package: +atlas_subdir( JetAnalysisAlgorithms ) + +atlas_depends_on_subdirs( + PUBLIC + Event/xAOD/xAODJet + PhysicsAnalysis/Algorithms/SelectionHelpers + PhysicsAnalysis/Algorithms/SystematicsHandles + PhysicsAnalysis/D3PDTools/AnaAlgorithm + Reconstruction/Jet/JetCalibTools + Reconstruction/Jet/JetCPInterfaces + Reconstruction/Jet/JetInterface + Reconstruction/Jet/JetJvtEfficiency + Reconstruction/Jet/JetResolution + Reconstruction/MET/METUtilities ) + +atlas_add_library( JetAnalysisAlgorithmsLib + JetAnalysisAlgorithms/*.h JetAnalysisAlgorithms/*.icc Root/*.cxx + PUBLIC_HEADERS JetAnalysisAlgorithms + LINK_LIBRARIES xAODJet SelectionHelpersLib SystematicsHandlesLib + AnaAlgorithmLib JetCalibToolsLib JetInterface JetResolutionLib + JetCPInterfaces JetJvtEfficiencyLib JetAnalysisInterfacesLib METUtilitiesLib ) + +atlas_add_dictionary( JetAnalysisAlgorithmsDict + JetAnalysisAlgorithms/JetAnalysisAlgorithmsDict.h + JetAnalysisAlgorithms/selection.xml + LINK_LIBRARIES JetAnalysisAlgorithmsLib ) + +if( NOT XAOD_STANDALONE ) + atlas_add_component( JetAnalysisAlgorithms + src/*.h src/*.cxx src/components/*.cxx + LINK_LIBRARIES GaudiKernel JetAnalysisAlgorithmsLib ) +endif() + +atlas_install_python_modules( python/*.py ) +atlas_install_joboptions( share/*_jobOptions.py ) +atlas_install_scripts( share/*_eljob.py ) + +if( XAOD_STANDALONE ) + atlas_add_test( testJobDataEMTopo + SCRIPT JetAnalysisAlgorithmsTest_EMTopo_eljob.py --data-type data --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobDataPFlow + SCRIPT JetAnalysisAlgorithmsTest_PFlow_eljob.py --data-type data --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSimEMTopo + SCRIPT JetAnalysisAlgorithmsTest_EMTopo_eljob.py --data-type mc --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSimPFlow + SCRIPT JetAnalysisAlgorithmsTest_PFlow_eljob.py --data-type mc --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSimEMTopo + SCRIPT JetAnalysisAlgorithmsTest_EMTopo_eljob.py --data-type afii --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSimPFlow + SCRIPT JetAnalysisAlgorithmsTest_PFlow_eljob.py --data-type afii --unit-test + PROPERTIES TIMEOUT 600 ) +else() + atlas_add_test( testJobDataEMTopo + SCRIPT athena.py + JetAnalysisAlgorithms/JetAnalysisAlgorithmsTest_EMTopo_jobOptions.py - --data-type data + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobDataPFlow + SCRIPT athena.py + JetAnalysisAlgorithms/JetAnalysisAlgorithmsTest_PFlow_jobOptions.py - --data-type data + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSimEMTopo + SCRIPT athena.py + JetAnalysisAlgorithms/JetAnalysisAlgorithmsTest_EMTopo_jobOptions.py - --data-type mc + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSimPFlow + SCRIPT athena.py + JetAnalysisAlgorithms/JetAnalysisAlgorithmsTest_PFlow_jobOptions.py - --data-type mc + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSimEMTopo + SCRIPT athena.py + JetAnalysisAlgorithms/JetAnalysisAlgorithmsTest_EMTopo_jobOptions.py - --data-type afii + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSimPFlow + SCRIPT athena.py + JetAnalysisAlgorithms/JetAnalysisAlgorithmsTest_PFlow_jobOptions.py - --data-type afii + PROPERTIES TIMEOUT 600 ) +endif() diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithmsDict.h b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithmsDict.h new file mode 100644 index 0000000000000000000000000000000000000000..3f2128c28272d43e761db7c4fb7aeee482afcea6 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithmsDict.h @@ -0,0 +1,20 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef JET_ANALYSIS_ALGORITHMS__JET_ANALYSIS_ALGORITHMS_DICT_H +#define JET_ANALYSIS_ALGORITHMS__JET_ANALYSIS_ALGORITHMS_DICT_H + +#include <JetAnalysisAlgorithms/JetCalibrationAlg.h> +#include <JetAnalysisAlgorithms/JetGhostMuonAssociationAlg.h> +#include <JetAnalysisAlgorithms/JetModifierAlg.h> +#include <JetAnalysisAlgorithms/JetSelectionAlg.h> +#include <JetAnalysisAlgorithms/JetSmearingAlg.h> +#include <JetAnalysisAlgorithms/JetUncertaintiesAlg.h> +#include <JetAnalysisAlgorithms/JvtEfficiencyAlg.h> +#include <JetAnalysisAlgorithms/JvtUpdateAlg.h> + +#endif diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetCalibrationAlg.h b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetCalibrationAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..61a745b581ca356d5ddba1d5cff8cc38e5de5a5a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetCalibrationAlg.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef JET_ANALYSIS_ALGORITHMS__JET_CALIBRATION_ALG_H +#define JET_ANALYSIS_ALGORITHMS__JET_CALIBRATION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <JetCalibTools/IJetCalibrationTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IJetCalibrationTool + + class JetCalibrationAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + JetCalibrationAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the calibration tool + private: + ToolHandle<IJetCalibrationTool> m_calibrationTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysCopyHandle<xAOD::JetContainer> m_jetHandle { + this, "jets", "AntiKt4EMTopoJets", "the jet collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetGhostMuonAssociationAlg.h b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetGhostMuonAssociationAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..66951ced52797c91cb2d83a64fd81dfeb807b47f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetGhostMuonAssociationAlg.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +#ifndef JET_ANALYSIS_ALGORITHMS__JET_GHOST_MUON_ASSOCIATION_ALG_H +#define JET_ANALYSIS_ALGORITHMS__JET_GHOST_MUON_ASSOCIATION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODJet/JetContainer.h> + +namespace CP +{ + /// \brief an algorithm for adding ghost muons to jets + + class JetGhostMuonAssociationAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + JetGhostMuonAssociationAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysCopyHandle<xAOD::JetContainer> m_jetHandle { + this, "jets", "AntiKt4EMTopoJets", "the jet collection to run on"}; + }; +} + +#endif // JET_ANALYSIS_ALGORITHMS__JET_GHOST_MUON_ASSOCIATION_ALG_H diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetModifierAlg.h b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetModifierAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..548e29202b20e43bcf490fe4f78265e15720ad75 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetModifierAlg.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef JET_ANALYSIS_ALGORITHMS__JET_MODIFIER_ALG_H +#define JET_ANALYSIS_ALGORITHMS__JET_MODIFIER_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <JetInterface/IJetModifier.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IJetModifierTool + + class JetModifierAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + JetModifierAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the modifier tool + private: + ToolHandle<IJetModifier> m_modifierTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysCopyHandle<xAOD::JetContainer> m_jetHandle { + this, "jets", "AntiKt4EMTopoJets", "the jet collection to run on"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetSelectionAlg.h b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetSelectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..14e727242a5c770df989c32222ebc705d9029ff1 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetSelectionAlg.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef JET_ANALYSIS_ALGORITHMS__JET_SELECTION_ALG_H +#define JET_ANALYSIS_ALGORITHMS__JET_SELECTION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <JetInterface/IJetSelector.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODJet/JetContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IJetSelector + + class JetSelectionAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + JetSelectionAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the selection tool + private: + ToolHandle<IJetSelector> m_selectionTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysCopyHandle<xAOD::JetContainer> m_jetHandle { + this, "jets", "AntiKt4EMTopoJets", "the jet collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the decoration for the jet selection + private: + std::string m_selectionDecoration {"clean_jet"}; + + /// \brief the accessor for \ref m_selectionDecoration + private: + std::unique_ptr<ISelectionAccessor> m_selectionAccessor; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetSmearingAlg.h b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetSmearingAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..ef56cf1848191122ce48b1dcc1e1baa3753690d5 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetSmearingAlg.h @@ -0,0 +1,63 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef JET_ANALYSIS_ALGORITHMS__JET_SMEARING_ALG_H +#define JET_ANALYSIS_ALGORITHMS__JET_SMEARING_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <JetResolution/IJERSmearingTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODJet/JetContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IJERSmearingTool + + class JetSmearingAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + JetSmearingAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IJERSmearingTool> m_smearingTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysCopyHandle<xAOD::JetContainer> m_jetHandle { + this, "jets", "AntiKt4EMTopoJets", "the jet collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetUncertaintiesAlg.h b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetUncertaintiesAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..70efa430e4a30bc401e42ed4ef42e8eb1b50fa58 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JetUncertaintiesAlg.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef JET_ANALYSIS_ALGORITHMS__JET_UNCERTAINTIES_ALG_H +#define JET_ANALYSIS_ALGORITHMS__JET_UNCERTAINTIES_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <JetCPInterfaces/ICPJetUncertaintiesTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref ICPJetUncertaintiesTool + + class JetUncertaintiesAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + JetUncertaintiesAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the uncertainties tool + private: + ToolHandle<ICPJetUncertaintiesTool> m_uncertaintiesTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysCopyHandle<xAOD::JetContainer> m_jetHandle { + this, "jets", "AntiKt4EMTopoJets", "the jet collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JvtEfficiencyAlg.h b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JvtEfficiencyAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..e4850b108274b8e8c8410c59079b1478e794b707 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JvtEfficiencyAlg.h @@ -0,0 +1,98 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef JET_ANALYSIS_ALGORITHMS__JVT_EFFICIENCY_ALG_H +#define JET_ANALYSIS_ALGORITHMS__JVT_EFFICIENCY_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <JetAnalysisInterfaces/IJetJvtEfficiency.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysDecorationHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODJet/JetContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IJEREfficiencyTool + + class JvtEfficiencyAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + JvtEfficiencyAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the efficiency tool + private: + ToolHandle<CP::IJetJvtEfficiency> m_efficiencyTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysCopyHandle<xAOD::JetContainer> m_jetHandle { + this, "jets", "AntiKt4EMTopoJets", "the jet collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the truth jet collection to use + private: + std::string m_truthJetsName; + + /// \brief differenciate between JVT and fJVT + private: + bool m_dofJVT = false; + + /// \brief the decoration for the fJVT selection + private: + std::string m_fJVTStatus; + + /// \brief the accessor for \ref m_fJVTStatus + private: + std::unique_ptr<ISelectionAccessor> m_fJVTStatusAccessor; + + /// \brief the decoration for the JVT selection + private: + std::string m_selection; + + /// \brief the accessor for \ref m_selection + private: + std::unique_ptr<ISelectionAccessor> m_selectionAccessor; + + /// \brief the decoration for the JVT scale factor + private: + SysDecorationHandle<float> m_scaleFactorDecoration { + this, "scaleFactorDecoration", "", "the decoration for the JVT efficiency scale factor"}; + + /// \brief whether to skip efficiency calculation if the selection failed + private: + bool m_skipBadEfficiency = false; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JvtUpdateAlg.h b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JvtUpdateAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..bc3b8c1c8fd4936259fe342c50a1763e71644528 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/JvtUpdateAlg.h @@ -0,0 +1,66 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef JET_ANALYSIS_ALGORITHMS__JVT_UPDATE_ALG_H +#define JET_ANALYSIS_ALGORITHMS__JVT_UPDATE_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <JetInterface/IJetUpdateJvt.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODJet/JetContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IJetUpdateJvt + + class JvtUpdateAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + JvtUpdateAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the update tool + private: + ToolHandle<IJetUpdateJvt> m_jvtTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the jet collection we run on + private: + SysCopyHandle<xAOD::JetContainer> m_jetHandle { + this, "jets", "AntiKt4EMTopoJets", "the jet collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the name of the decoration we create + private: + std::string m_decorationName {"Jvt"}; + + /// \brief the decoration accessor we use + private: + std::unique_ptr<SG::AuxElement::Accessor<float> > m_decorationAccessor; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/selection.xml b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..a851d1f967b420f8c737f111984a2d02834e751c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/JetAnalysisAlgorithms/selection.xml @@ -0,0 +1,12 @@ +<lcgdict> + + <class name="CP::JetCalibrationAlg" /> + <class name="CP::JetGhostMuonAssociationAlg" /> + <class name="CP::JetModifierAlg" /> + <class name="CP::JetSelectionAlg" /> + <class name="CP::JetSmearingAlg" /> + <class name="CP::JetUncertaintiesAlg" /> + <class name="CP::JvtEfficiencyAlg" /> + <class name="CP::JvtUpdateAlg" /> + +</lcgdict> diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetCalibrationAlg.cxx b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetCalibrationAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3f820c72a55a216a44e3f77cf45ce9cf7631d353 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetCalibrationAlg.cxx @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <JetAnalysisAlgorithms/JetCalibrationAlg.h> + +// +// method implementations +// + +namespace CP +{ + JetCalibrationAlg :: + JetCalibrationAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_calibrationTool ("JetCalibrationTool", this) + { + declareProperty ("calibrationTool", m_calibrationTool, "the calibration tool we apply"); + } + + + + StatusCode JetCalibrationAlg :: + initialize () + { + ANA_CHECK (m_calibrationTool.retrieve()); + m_systematicsList.addHandle (m_jetHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode JetCalibrationAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::JetContainer *jets = nullptr; + ANA_CHECK (m_jetHandle.getCopy (jets, sys)); + for (xAOD::Jet *jet : *jets) + { + if (m_preselection.getBool (*jet)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *jet, m_calibrationTool->applyCorrection (*jet)); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetGhostMuonAssociationAlg.cxx b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetGhostMuonAssociationAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..278eac5c369a0ce868e484a6b68ceb0a37823fb8 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetGhostMuonAssociationAlg.cxx @@ -0,0 +1,53 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + +// +// includes +// + +#include <JetAnalysisAlgorithms/JetGhostMuonAssociationAlg.h> +#include <METUtilities/METHelpers.h> +#include <xAODMuon/MuonContainer.h> + +// +// method implementations +// + +namespace CP +{ + JetGhostMuonAssociationAlg :: + JetGhostMuonAssociationAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + } + + + StatusCode JetGhostMuonAssociationAlg :: + initialize () + { + m_systematicsList.addHandle (m_jetHandle); + ANA_CHECK (m_systematicsList.initialize()); + return StatusCode::SUCCESS; + } + + + StatusCode JetGhostMuonAssociationAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::JetContainer *jets = nullptr; + ANA_CHECK (m_jetHandle.getCopy (jets, sys)); + + // associate the ghost muons to the jets (needed by MET muon-jet OR later) + const xAOD::MuonContainer* muons = nullptr; + ATH_CHECK( evtStore()->retrieve(muons, "Muons") ); + met::addGhostMuonsToJets(*muons, *jets); + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetModifierAlg.cxx b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetModifierAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9ebd150c9db8794bb8d5d8130e23e32fb5c2e596 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetModifierAlg.cxx @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <JetAnalysisAlgorithms/JetModifierAlg.h> + +// +// method implementations +// + +namespace CP +{ + JetModifierAlg :: + JetModifierAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_modifierTool ("JetForwardJvtTool", this) + { + declareProperty ("modifierTool", m_modifierTool, "the modifier tool we apply"); + } + + + + StatusCode JetModifierAlg :: + initialize () + { + ANA_CHECK (m_modifierTool.retrieve()); + m_systematicsList.addHandle (m_jetHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode JetModifierAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::JetContainer *jets = nullptr; + ANA_CHECK (m_jetHandle.getCopy (jets, sys)); + if (m_modifierTool->modify (*jets) != 0) + { + ANA_MSG_ERROR ("Failed to call \"m_modifierTool->modify (*jets)\""); + return StatusCode::FAILURE; + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetSelectionAlg.cxx b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetSelectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..575adc9b7d29baa6467cc0bb5690de358094bad0 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetSelectionAlg.cxx @@ -0,0 +1,71 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <JetAnalysisAlgorithms/JetSelectionAlg.h> + +#include <SelectionHelpers/SelectionHelpers.h> + +// +// method implementations +// + +namespace CP +{ + JetSelectionAlg :: + JetSelectionAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_selectionTool ("", this) + { + declareProperty ("selectionTool", m_selectionTool, "the selection tool we apply"); + declareProperty ("selectionDecoration", m_selectionDecoration, "the decoration for the jet selection"); + } + + + + StatusCode JetSelectionAlg :: + initialize () + { + ANA_CHECK (m_selectionTool.retrieve()); + m_systematicsList.addHandle (m_jetHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + + if (m_selectionDecoration.empty()) + { + ANA_MSG_ERROR ("no selection decoration name set"); + return StatusCode::FAILURE; + } + ANA_CHECK (makeSelectionAccessor (m_selectionDecoration, m_selectionAccessor)); + + return StatusCode::SUCCESS; + } + + + + StatusCode JetSelectionAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::JetContainer *jets = nullptr; + ANA_CHECK (m_jetHandle.getCopy (jets, sys)); + for (xAOD::Jet *jet : *jets) + { + if (m_preselection.getBool (*jet)) + { + m_selectionAccessor->setBool + (*jet, m_selectionTool->keep(*jet)); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetSmearingAlg.cxx b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetSmearingAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..55438e290a57f925ac07b9b2c8814eb6c95bdc63 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetSmearingAlg.cxx @@ -0,0 +1,62 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <JetAnalysisAlgorithms/JetSmearingAlg.h> + +// +// method implementations +// + +namespace CP +{ + JetSmearingAlg :: + JetSmearingAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_smearingTool ("JERSmearingTool", this) + { + declareProperty ("smearingTool", m_smearingTool, "the smearing tool we apply"); + } + + + + StatusCode JetSmearingAlg :: + initialize () + { + ANA_CHECK (m_smearingTool.retrieve()); + m_systematicsList.addHandle (m_jetHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_smearingTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode JetSmearingAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_smearingTool->applySystematicVariation (sys)); + xAOD::JetContainer *jets = nullptr; + ANA_CHECK (m_jetHandle.getCopy (jets, sys)); + for (xAOD::Jet *jet : *jets) + { + if (m_preselection.getBool (*jet)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *jet, m_smearingTool->applyCorrection (*jet)); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetUncertaintiesAlg.cxx b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetUncertaintiesAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ed1f72889d6956a90ea0cda6f58ef1da5c518fff --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JetUncertaintiesAlg.cxx @@ -0,0 +1,62 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <JetAnalysisAlgorithms/JetUncertaintiesAlg.h> + +// +// method implementations +// + +namespace CP +{ + JetUncertaintiesAlg :: + JetUncertaintiesAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_uncertaintiesTool ("JetUncertaintiesTool", this) + { + declareProperty ("uncertaintiesTool", m_uncertaintiesTool, "the uncertainties tool we apply"); + } + + + + StatusCode JetUncertaintiesAlg :: + initialize () + { + ANA_CHECK (m_uncertaintiesTool.retrieve()); + m_systematicsList.addHandle (m_jetHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_uncertaintiesTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode JetUncertaintiesAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_uncertaintiesTool->applySystematicVariation (sys)); + xAOD::JetContainer *jets = nullptr; + ANA_CHECK (m_jetHandle.getCopy (jets, sys)); + for (xAOD::Jet *jet : *jets) + { + if (m_preselection.getBool (*jet)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *jet, m_uncertaintiesTool->applyCorrection (*jet)); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JvtEfficiencyAlg.cxx b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JvtEfficiencyAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..765a6f635149c3fc7262926af512e207c100cb69 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JvtEfficiencyAlg.cxx @@ -0,0 +1,114 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <JetAnalysisAlgorithms/JvtEfficiencyAlg.h> + +#include <SelectionHelpers/SelectionHelpers.h> + +// +// method implementations +// + +namespace CP +{ + JvtEfficiencyAlg :: + JvtEfficiencyAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_efficiencyTool ("", this) + , m_truthJetsName("AntiKt4TruthJets") + { + declareProperty ("efficiencyTool", m_efficiencyTool, "the efficiency tool we apply"); + declareProperty ("dofJVT", m_dofJVT, "differenciate between JVT and fJVT"); + declareProperty ("fJVTStatus", m_fJVTStatus, "the decoration for the fJVT status"); + declareProperty ("selection", m_selection, "the decoration for the JVT selection"); + declareProperty ("skipBadEfficiency", m_skipBadEfficiency, "whether to skip efficiency calculation if the selection failed"); + declareProperty ("truthJetCollection", m_truthJetsName, "the truth jet collection to use for truth tagging"); + } + + + + StatusCode JvtEfficiencyAlg :: + initialize () + { + if (m_dofJVT && m_fJVTStatus.empty()) + { + ANA_MSG_ERROR ("fJVTStatus decoration needs to be configured when running fJVT"); + return StatusCode::FAILURE; + } + + ANA_CHECK (m_efficiencyTool.retrieve()); + m_systematicsList.addHandle (m_jetHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_efficiencyTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + + if (m_dofJVT && !m_fJVTStatus.empty()) + ANA_CHECK (makeSelectionAccessor (m_fJVTStatus, m_fJVTStatusAccessor)); + + if (!m_selection.empty()) + ANA_CHECK (makeSelectionAccessor (m_selection, m_selectionAccessor)); + + return StatusCode::SUCCESS; + } + + + + StatusCode JvtEfficiencyAlg :: + execute () + { + ANA_CHECK (m_scaleFactorDecoration.preExecute (m_systematicsList)); + + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_efficiencyTool->applySystematicVariation (sys)); + xAOD::JetContainer *jets = nullptr; + ANA_CHECK (m_jetHandle.getCopy (jets, sys)); + + const xAOD::JetContainer *truthjets = nullptr; + if(!m_truthJetsName.empty()) { + ANA_CHECK(evtStore()->retrieve(truthjets,m_truthJetsName)); + ANA_CHECK(m_efficiencyTool->tagTruth(jets,truthjets)); + } + + for (xAOD::Jet *jet : *jets) + { + if (m_preselection.getBool (*jet)) + { + bool goodJet = true; + if (m_selectionAccessor || m_skipBadEfficiency) + { + goodJet = m_dofJVT ? m_fJVTStatusAccessor->getBool (*jet) : m_efficiencyTool->passesJvtCut (*jet); + if (m_selectionAccessor) + m_selectionAccessor->setBool (*jet, goodJet); + } + if (m_scaleFactorDecoration) + { + float sf = 1; + if (goodJet) { + ANA_CHECK_CORRECTION (m_outOfValidity, *jet, m_efficiencyTool->getEfficiencyScaleFactor (*jet, sf)); + } else if (!m_skipBadEfficiency) { + ANA_CHECK_CORRECTION (m_outOfValidity, *jet, m_efficiencyTool->getInefficiencyScaleFactor (*jet, sf)); + } + m_scaleFactorDecoration.set (*jet, sf, sys); + } + } else { + if (m_selectionAccessor) + m_selectionAccessor->setBool (*jet, false); + + if (m_scaleFactorDecoration) + m_scaleFactorDecoration.set (*jet, invalidScaleFactor(), sys); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JvtUpdateAlg.cxx b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JvtUpdateAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..15df9bf8c98a34454cbf952b3e7d99e8b75bb094 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/Root/JvtUpdateAlg.cxx @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <JetAnalysisAlgorithms/JvtUpdateAlg.h> + +// +// method implementations +// + +namespace CP +{ + JvtUpdateAlg :: + JvtUpdateAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_jvtTool ("", this) + { + declareProperty ("jvtTool", m_jvtTool, "the jvt tool we apply"); + declareProperty ("decorationName", m_decorationName, "the decoration name to use"); + } + + + + StatusCode JvtUpdateAlg :: + initialize () + { + if (m_decorationName.empty()) + { + ANA_MSG_ERROR ("decoration name set to empty string, not allowed"); + return StatusCode::FAILURE; + } + m_decorationAccessor = std::make_unique + <SG::AuxElement::Accessor<float> > (m_decorationName); + + ANA_CHECK (m_jvtTool.retrieve()); + m_systematicsList.addHandle (m_jetHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode JvtUpdateAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::JetContainer *jets = nullptr; + ANA_CHECK (m_jetHandle.getCopy (jets, sys)); + for (xAOD::Jet *jet : *jets) + { + if (m_preselection.getBool (*jet)) + { + // manually update jvt decoration using the tool + const float jvt = m_jvtTool->updateJvt (*jet); + (*m_decorationAccessor) (*jet) = jvt; + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisAlgorithmsTest.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisAlgorithmsTest.py new file mode 100644 index 0000000000000000000000000000000000000000..6d04dd9bd5da853a4c566f00de62dca09a75343b --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisAlgorithmsTest.py @@ -0,0 +1,71 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +from AnaAlgorithm.AlgSequence import AlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm + +def makeSequence (dataType, jetContainer="AntiKt4EMPFlowJets") : + + # config + + + 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 pileup analysis sequence: + from AsgAnalysisAlgorithms.PileupAnalysisSequence import \ + makePileupAnalysisSequence + pileupSequence = makePileupAnalysisSequence( dataType ) + pileupSequence.configure( inputName = 'EventInfo', outputName = 'EventInfo_%SYS%' ) + print( pileupSequence ) # For debugging + + # Include, and then set up the jet analysis algorithm sequence: + from JetAnalysisAlgorithms.JetAnalysisSequence import makeJetAnalysisSequence + jetSequence = makeJetAnalysisSequence( dataType, jetContainer, enableCutflow=True, enableKinematicHistograms=True ) + jetSequence.configure( inputName = jetContainer, outputName = 'AnalysisJetsBase_%SYS%' ) + print( jetSequence ) # For debugging + + # Include, and then set up the jet analysis algorithm sequence: + from JetAnalysisAlgorithms.JetJvtAnalysisSequence import makeJetJvtAnalysisSequence + jvtSequence = makeJetJvtAnalysisSequence( dataType, jetContainer, enableCutflow=True ) + jvtSequence.configure( inputName = { 'eventInfo' : 'EventInfo_%SYS%', + 'jets' : 'AnalysisJetsBase_%SYS%' }, + outputName = { 'jets' : 'AnalysisJets_%SYS%' }, + affectingSystematics = { 'jets' : jetSequence.affectingSystematics() } ) + print( jvtSequence ) # For debugging + + # Add the sequences to the job: + algSeq += pileupSequence + algSeq += jetSequence + algSeq += jvtSequence + + # Set up an ntuple to check the job with: + treeMaker = createAlgorithm( 'CP::TreeMakerAlg', 'TreeMaker' ) + treeMaker.TreeName = 'jets' + algSeq += treeMaker + ntupleMaker = createAlgorithm( 'CP::AsgxAODNTupleMakerAlg', 'NTupleMaker' ) + ntupleMaker.TreeName = 'jets' + ntupleMaker.Branches = [ + 'EventInfo.runNumber -> runNumber', + 'EventInfo.eventNumber -> eventNumber', + 'AnalysisJets_%SYS%.pt -> jet_%SYS%_pt', + ] + if dataType != 'data': + ntupleMaker.Branches += [ + # 'EventInfo.jvt_effSF_%SYS% -> jvtSF_%SYS%', + # 'EventInfo.fjvt_effSF_%SYS% -> fjvtSF_%SYS%', + 'AnalysisJets_%SYS%.jvt_effSF_NOSYS -> jet_%SYS%_jvtEfficiency', + # 'AnalysisJets_%SYS%.fjvt_effSF_NOSYS -> jet_%SYS%_fjvtEfficiency', + ] + ntupleMaker.systematicsRegex = '(^$)|(^JET_.*)' + algSeq += ntupleMaker + treeFiller = createAlgorithm( 'CP::TreeFillerAlg', 'TreeFiller' ) + treeFiller.TreeName = 'jets' + algSeq += treeFiller + + return algSeq diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisSequence.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..5dae4f300888839fc01a6e0268a3b097dfb5ceca --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetAnalysisSequence.py @@ -0,0 +1,399 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +from __future__ import print_function + +# AnaAlgorithm import(s): +from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm, addPrivateTool +import re + +# These algorithms set up the jet recommendations as-of 04/02/2019. +# Jet calibration recommendations +# https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/ApplyJetCalibrationR21 +# Jet uncertainties recommendations +# Small-R +# https://twiki.cern.ch/twiki/bin/view/AtlasProtected/JetUncertaintiesRel21Summer2018SmallR +# Large-R +# https://twiki.cern.ch/twiki/bin/viewauth/AtlasProtected/JetUncertaintiesRel21Moriond2018LargeR +# JVT recommendations +# https://twiki.cern.ch/twiki/bin/view/AtlasProtected/JVTCalibrationRel21 + +# Keep the different possible sets of systematics here. +# All possible large-R jet systematics +largeRSysts = "|".join([ + "(^JET_Rtrk_.*)", + "(^JET_TAM_.*)", + "(^JET_MassRes_.*)", + "(^JET_Comb_.*_mass.*)"]) +smallRSysts = "|".join([ + "(^JET_BJES_Response$)", + "(^JET_EtaIntercalibration_.*)", + "(^JET_Flavor_.*)", + "(^JET_Gjet_.*)", + "(^JET_JER_.*)", + "(^JET_MJB_.*)", + "(^JET_Pileup_.*)", + "(^JET_PunchThrough_.*)", + "(^JET_RelativeNonClosure_.*)", + "(^JET_SingleParticle_HighPt$)", + "(^JET_Zjet_.*)", + "(^JET_EffectiveNP_.*)", + "(^JET_GroupedNP_.*)"]) +jvtSysts = "|".join([ + "(^JET_JvtEfficiency$)"]) +fjvtSysts = "|".join([ + "(^JET_fJvtEfficiency$)"]) + +def makeJetAnalysisSequence( dataType, jetCollection, postfix = '', + deepCopyOutput = False, + shallowViewOutput = True, + runGhostMuonAssociation = True, + enableCutflow = False, + enableKinematicHistograms = False, + **kwargs): + """Create a jet analysis algorithm sequence + The jet collection is interpreted and selects the correct function to call, + makeSmallRJetAnalysisSequence, makeRScanJetAnalysisSequence or + makeLargeRJetAnalysisSequence + + Keyword arguments + dataType -- The data type to run on ("data", "mc" or "afii") + jetCollection -- The jet container to run on. + postfix -- String to be added to the end of all public names. + deepCopyOutput -- Whether or not to deep copy the output + shallowViewOutput -- Whether or not to output a shallow view as the output + enableCutflow -- Whether or not to dump the cutflow + enableKinematicHistograms -- Whether or not to dump the kinematic histograms + Other keyword arguments are forwarded to the other functions. + """ + if dataType not in ["data", "mc", "afii"]: + raise ValueError ("invalid data type: " + dataType ) + + # Setup the postfix + if postfix != '': + postfix = "_" + postfix + + # Make sure selection options make sense + if deepCopyOutput and shallowViewOutput: + raise ValueError ("deepCopyOutput and shallowViewOutput can't both be true!") + + # Remove b-tagging calibration from the container name + btIndex = jetCollection.find('_BTagging') + if btIndex != -1: + jetCollection = jetCollection[:btIndex] + + # interpret the jet collection + collection_pattern = re.compile( + r"AntiKt(\d+)(EMTopo|EMPFlow|LCTopo|TrackCaloCluster)(TrimmedPtFrac5SmallR20)?Jets") + match = collection_pattern.match(jetCollection) + if not match: + raise ValueError( + "Jet collection {0} does not match expected pattern!".format(jetCollection) ) + radius = int(match.group(1) ) + if radius not in [2, 4, 6, 10]: + raise ValueError("Jet collection has an unsupported radius '{0}'!".format(radius) ) + jetInput = match.group(2) + + # Create the analysis algorithm sequence object. + seq = AnaAlgSequence( "JetAnalysisSequence"+postfix ) + # Relink original jets in case of b-tagging calibration + if btIndex != -1: + alg = createAlgorithm( 'CP::AsgOriginalObjectLinkAlg', + 'JetOriginalObjectLinkAlg'+postfix ) + alg.baseContainerName = jetCollection + seq.append( alg, inputPropName = 'particles', outputPropName = 'particlesOut', stageName = 'calibration' ) + + # Set up the jet ghost muon association algorithm: + if runGhostMuonAssociation: + alg = createAlgorithm( 'CP::JetGhostMuonAssociationAlg', + 'JetGhostMuonAssociationAlg'+postfix ) + seq.append( alg, inputPropName = 'jets', outputPropName = 'jetsOut', stageName = 'calibration' ) + + # record all the selections each subfunction makes + cutlist = [] + cutlength = [] + + if radius == 4: + makeSmallRJetAnalysisSequence(seq, cutlist, cutlength, + dataType, jetCollection, jetInput=jetInput, postfix=postfix, **kwargs) + elif radius in [2, 6]: + makeRScanJetAnalysisSequence(seq, cutlist, cutlength, + dataType, jetCollection, jetInput=jetInput, radius=radius, + postfix=postfix, **kwargs) + else: + trim = match.group(3) + if trim == "": + raise ValueError("Untrimmed large-R jets are not supported!") + makeLargeRJetAnalysisSequence(seq, cutlist, cutlength, + dataType, jetCollection, jetInput=jetInput, postfix=postfix, **kwargs) + + # Set up an algorithm used to create jet selection cutflow: + if enableCutflow: + alg = createAlgorithm( 'CP::ObjectCutFlowHistAlg', 'JetCutFlowDumperAlg'+postfix ) + alg.histPattern = 'jet_cflow_%SYS%'+postfix + alg.selection = cutlist + alg.selectionNCuts = cutlength + seq.append( alg, inputPropName = 'input', stageName = 'selection' ) + + # Set up an algorithm dumping the kinematic properties of the jets: + if enableKinematicHistograms: + alg = createAlgorithm( 'CP::KinematicHistAlg', 'JetKinematicDumperAlg'+postfix ) + alg.preselection = "&&".join (cutlist) + alg.histPattern = 'jet_%VAR%_%SYS%'+postfix + seq.append( alg, inputPropName = 'input', stageName = 'selection' ) + + if shallowViewOutput: + # Set up an algorithm that makes a view container using the selections + # performed previously: + alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg', 'JetViewFromSelectionAlg'+postfix ) + alg.selection = cutlist + seq.append( alg, inputPropName = 'input', outputPropName = 'output', + stageName = 'selection' ) + + # Set up a final deep copy making algorithm if requested: + if deepCopyOutput: + alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg', 'JetDeepCopyMaker'+postfix ) + alg.deepCopy = True + seq.append( alg, inputPropName = 'input', outputPropName = 'output', + stageName = 'selection' ) + + return seq + +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 + +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!") + +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) diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetJvtAnalysisSequence.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetJvtAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..8ebee22a2ab30f3bd48b25d641f3792a9ca7dcc7 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/JetJvtAnalysisSequence.py @@ -0,0 +1,89 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +# AnaAlgorithm import(s): +from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm + +def makeJetJvtAnalysisSequence( dataType, jetCollection, + preselection = '', + disableFJvt = False, + globalSF = True, + runSelection = True, + enableCutflow = False ): + """Create a jet JVT analysis algorithm sequence + + Keyword arguments: + dataType -- The data type to run on ("data", "mc" or "afii") + jetCollection -- The jet container to run on + disableFJvt -- Whether to disable forward JVT calculations + globalSF -- Whether to calculate per event scale factors + runSelection -- Whether to run selection + enableCutflow -- Whether or not to dump the cutflow + """ + + if dataType not in ["data", "mc", "afii"] : + raise ValueError ("invalid data type: " + dataType) + + if runSelection and not globalSF : + raise ValueError ("per-event scale factors needs to be computed when doing a JVT selection") + + # Create the analysis algorithm sequence object: + seq = AnaAlgSequence( "JetJVTAnalysisSequence" ) + + # Define a list of cuts to apply later on and the + # number of bits in the corresponding TAccept + cutlist = [] + cutlength = [] + + # Set up the per-event jet efficiency scale factor calculation algorithm + if dataType != 'data' and globalSF: + from JetAnalysisSequence import jvtSysts, fjvtSysts + + alg = createAlgorithm( 'CP::AsgEventScaleFactorAlg', 'JvtEventScaleFactorAlg' ) + alg.preselection = preselection + '&&no_jvt' if preselection else 'no_jvt' + alg.scaleFactorInputDecoration = 'jvt_effSF_%SYS%' + alg.scaleFactorInputDecorationRegex = jvtSysts + alg.scaleFactorOutputDecoration = 'jvt_effSF_%SYS%' + + seq.append( alg, + affectingSystematics = jvtSysts, + inputPropName = { 'jets' : 'particles', + 'eventInfo' : 'eventInfo' } ) + + if not disableFJvt: + alg = createAlgorithm( 'CP::AsgEventScaleFactorAlg', 'ForwardJvtEventScaleFactorAlg' ) + alg.preselection = preselection + '&&no_fjvt' if preselection else 'no_fjvt' + alg.scaleFactorInputDecoration = 'fjvt_effSF_%SYS%' + alg.scaleFactorInputDecorationRegex = fjvtSysts + alg.scaleFactorOutputDecoration = 'fjvt_effSF_%SYS%' + + seq.append( alg, + affectingSystematics = fjvtSysts, + inputPropName = { 'jets' : 'particles', + 'eventInfo' : 'eventInfo' } ) + + if runSelection: + cutlist.append('jvt_selection') + cutlength.append(1) + + if not disableFJvt: + cutlist.append('fjvt_selection') + cutlength.append(1) + + # Set up an algorithm used to create jet JVT selection cutflow: + if enableCutflow: + alg = createAlgorithm( 'CP::ObjectCutFlowHistAlg', 'JetJvtCutFlowDumperAlg' ) + alg.histPattern = 'jet_cflow_jvt_%SYS%' + alg.selection = cutlist + alg.selectionNCuts = cutlength + seq.append( alg, inputPropName = { 'jets' : 'input' }) + + # Set up an algorithm that makes a view container using the selections + # performed previously: + alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg', 'JetJvtViewFromSelectionAlg' ) + alg.selection = cutlist + seq.append( alg, inputPropName = { 'jets' : 'input' }, + outputPropName = { 'jets' : 'output' } ) + + # Return the sequence: + return seq diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/__init__.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5ccb446532599c01cc3844e5b1b18db06f721002 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/python/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +__version__ = '1.0.0' diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_EMTopo_eljob.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_EMTopo_eljob.py new file mode 100755 index 0000000000000000000000000000000000000000..c114d0ad7608511074292f704493e289441e7d74 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_EMTopo_eljob.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# Read the submission directory as a command line argument. You can +# extend the list of arguments with your private ones later on. +import optparse +parser = optparse.OptionParser() +parser.add_option( '-d', '--data-type', dest = 'data_type', + action = 'store', type = 'string', default = 'data', + help = 'Type of data to run over. Valid options are data, mc, afii' ) +parser.add_option( '-s', '--submission-dir', dest = 'submission_dir', + action = 'store', type = 'string', default = 'submitDir', + help = 'Submission directory for EventLoop' ) +parser.add_option( '-u', '--unit-test', dest='unit_test', + action = 'store_true', default = False, + help = 'Run the job in "unit test mode"' ) +( options, args ) = parser.parse_args() + +# Set up (Py)ROOT. +import ROOT +ROOT.xAOD.Init().ignore() + +# this forces the jet algorithms dictionary to be loaded before +# anything else, which works around some strange dictionary issues I +# don't understand. +ROOT.CP.JetCalibrationAlg ("dummy", None) + +# ideally we'd run over all of them, but we don't have a mechanism to +# configure per-sample right now + +dataType = options.data_type + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +jetContainer = "AntiKt4EMTopoJets" + +if dataType not in ["data", "mc", "afii"] : + raise ValueError ("invalid data type: " + dataType) + +# Set up the sample handler object. See comments from the C++ macro +# for the details about these lines. +import os +sh = ROOT.SH.SampleHandler() +sh.setMetaString( 'nc_tree', 'CollectionTree' ) +sample = ROOT.SH.SampleLocal (dataType) +sample.add (os.getenv (inputfile[dataType])) +sh.add (sample) +sh.printContent() + +# Create an EventLoop job. +job = ROOT.EL.Job() +job.sampleHandler( sh ) +job.options().setDouble( ROOT.EL.Job.optMaxEvents, 500 ) + +from JetAnalysisAlgorithms.JetAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType, jetContainer) +print algSeq # For debugging +for alg in algSeq: + job.algsAdd( alg ) + pass + +# Set up an output file for the job: +job.outputAdd( ROOT.EL.OutputStream( 'ANALYSIS' ) ) + +# Find the right output directory: +submitDir = options.submission_dir +if options.unit_test: + import os + import tempfile + submitDir = tempfile.mkdtemp( prefix = 'jetTest_'+dataType+'_EMTopo_', dir = os.getcwd() ) + os.rmdir( submitDir ) + pass + +# Run the job using the direct driver. +driver = ROOT.EL.DirectDriver() +driver.submit( job, submitDir ) diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_EMTopo_jobOptions.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_EMTopo_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..7b5afce3ae68197992610bcc596a53cbedfb92b9 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_EMTopo_jobOptions.py @@ -0,0 +1,46 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +# User options, which can be set from command line after a "-" character +# athena EgammaAlgorithmsTest_jobOptions.py - --myOption ... +from AthenaCommon.AthArgumentParser import AthArgumentParser +athArgsParser = AthArgumentParser() +athArgsParser.add_argument("--data-type", action = "store", dest = "data_type", + default = "data", + help = "Type of input to run over. Valid options are 'data', 'mc', 'afii'") +athArgs = athArgsParser.parse_args() + +dataType = athArgs.data_type +if not dataType in ["data", "mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +print("Running on data type: " + dataType) + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +jetContainer = "AntiKt4EMTopoJets" + +# Set up the reading of the input file: +import AthenaRootComps.ReadAthenaxAODHybrid +theApp.EvtMax = 500 +testFile = os.getenv ( inputfile[dataType] ) +svcMgr.EventSelector.InputCollections = [testFile] + +from JetAnalysisAlgorithms.JetAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType, jetContainer) +print algSeq # For debugging + +# Add all algorithms from the sequence to the job. +athAlgSeq += algSeq + +# Set up a histogram output file for the job: +ServiceMgr += CfgMgr.THistSvc() +ServiceMgr.THistSvc.Output += [ + "ANALYSIS DATAFILE='JetAnalysisAlgorithmsTestEMTopo." + dataType + ".hist.root' OPT='RECREATE'" + ] + +# Reduce the printout from Athena: +include( "AthAnalysisBaseComps/SuppressLogging.py" ) diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_PFlow_eljob.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_PFlow_eljob.py new file mode 100755 index 0000000000000000000000000000000000000000..97f94a5bcd89ff802e544dc8954dec1d5a43e434 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_PFlow_eljob.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# Read the submission directory as a command line argument. You can +# extend the list of arguments with your private ones later on. +import optparse +parser = optparse.OptionParser() +parser.add_option( '-d', '--data-type', dest = 'data_type', + action = 'store', type = 'string', default = 'data', + help = 'Type of data to run over. Valid options are data, mc, afii' ) +parser.add_option( '-s', '--submission-dir', dest = 'submission_dir', + action = 'store', type = 'string', default = 'submitDir', + help = 'Submission directory for EventLoop' ) +parser.add_option( '-u', '--unit-test', dest='unit_test', + action = 'store_true', default = False, + help = 'Run the job in "unit test mode"' ) +( options, args ) = parser.parse_args() + +# Set up (Py)ROOT. +import ROOT +ROOT.xAOD.Init().ignore() + +# this forces the jet algorithms dictionary to be loaded before +# anything else, which works around some strange dictionary issues I +# don't understand. +ROOT.CP.JetCalibrationAlg ("dummy", None) + +# ideally we'd run over all of them, but we don't have a mechanism to +# configure per-sample right now + +dataType = options.data_type + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +jetContainer = "AntiKt4EMTopoJets" + +if dataType not in ["data", "mc", "afii"] : + raise ValueError ("invalid data type: " + dataType) + +# Set up the sample handler object. See comments from the C++ macro +# for the details about these lines. +import os +sh = ROOT.SH.SampleHandler() +sh.setMetaString( 'nc_tree', 'CollectionTree' ) +sample = ROOT.SH.SampleLocal (dataType) +sample.add (os.getenv (inputfile[dataType])) +sh.add (sample) +sh.printContent() + +# Create an EventLoop job. +job = ROOT.EL.Job() +job.sampleHandler( sh ) +job.options().setDouble( ROOT.EL.Job.optMaxEvents, 500 ) + +from JetAnalysisAlgorithms.JetAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType, jetContainer) +print algSeq # For debugging +for alg in algSeq: + job.algsAdd( alg ) + pass + +# Set up an output file for the job: +job.outputAdd( ROOT.EL.OutputStream( 'ANALYSIS' ) ) + +# Find the right output directory: +submitDir = options.submission_dir +if options.unit_test: + import os + import tempfile + submitDir = tempfile.mkdtemp( prefix = 'jetTest_'+dataType+'_PFlow_', dir = os.getcwd() ) + os.rmdir( submitDir ) + pass + +# Run the job using the direct driver. +driver = ROOT.EL.DirectDriver() +driver.submit( job, submitDir ) diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_PFlow_jobOptions.py b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_PFlow_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..69d7df65f6ff762245f20ef7c3903562eca105ca --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/share/JetAnalysisAlgorithmsTest_PFlow_jobOptions.py @@ -0,0 +1,46 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +# User options, which can be set from command line after a "-" character +# athena EgammaAlgorithmsTest_jobOptions.py - --myOption ... +from AthenaCommon.AthArgumentParser import AthArgumentParser +athArgsParser = AthArgumentParser() +athArgsParser.add_argument("--data-type", action = "store", dest = "data_type", + default = "data", + help = "Type of input to run over. Valid options are 'data', 'mc', 'afii'") +athArgs = athArgsParser.parse_args() + +dataType = athArgs.data_type +if not dataType in ["data", "mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +print("Running on data type: " + dataType) + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +jetContainer = "AntiKt4EMTopoJets" + +# Set up the reading of the input file: +import AthenaRootComps.ReadAthenaxAODHybrid +theApp.EvtMax = 500 +testFile = os.getenv ( inputfile[dataType] ) +svcMgr.EventSelector.InputCollections = [testFile] + +from JetAnalysisAlgorithms.JetAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType, jetContainer) +print algSeq # For debugging + +# Add all algorithms from the sequence to the job. +athAlgSeq += algSeq + +# Set up a histogram output file for the job: +ServiceMgr += CfgMgr.THistSvc() +ServiceMgr.THistSvc.Output += [ + "ANALYSIS DATAFILE='JetAnalysisAlgorithmsTestPFlow." + dataType + ".hist.root' OPT='RECREATE'" + ] + +# Reduce the printout from Athena: +include( "AthAnalysisBaseComps/SuppressLogging.py" ) diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/src/components/JetAnalysisAlgorithms_entries.cxx b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/src/components/JetAnalysisAlgorithms_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..757495457d3f4a77d15d045efb528c2840434c29 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/src/components/JetAnalysisAlgorithms_entries.cxx @@ -0,0 +1,32 @@ +// AsgExampleTools_entries.cxx + +#include <GaudiKernel/DeclareFactoryEntries.h> + +#include <JetAnalysisAlgorithms/JetCalibrationAlg.h> +#include <JetAnalysisAlgorithms/JetGhostMuonAssociationAlg.h> +#include <JetAnalysisAlgorithms/JetModifierAlg.h> +#include <JetAnalysisAlgorithms/JetSelectionAlg.h> +#include <JetAnalysisAlgorithms/JetSmearingAlg.h> +#include <JetAnalysisAlgorithms/JetUncertaintiesAlg.h> +#include <JetAnalysisAlgorithms/JvtEfficiencyAlg.h> +#include <JetAnalysisAlgorithms/JvtUpdateAlg.h> + +DECLARE_ALGORITHM_FACTORY (CP::JetCalibrationAlg) +DECLARE_ALGORITHM_FACTORY (CP::JetGhostMuonAssociationAlg) +DECLARE_ALGORITHM_FACTORY (CP::JetModifierAlg) +DECLARE_ALGORITHM_FACTORY (CP::JetSelectionAlg) +DECLARE_ALGORITHM_FACTORY (CP::JetSmearingAlg) +DECLARE_ALGORITHM_FACTORY (CP::JetUncertaintiesAlg) +DECLARE_ALGORITHM_FACTORY (CP::JvtEfficiencyAlg) +DECLARE_ALGORITHM_FACTORY (CP::JvtUpdateAlg) + +DECLARE_FACTORY_ENTRIES(JetAnalysisAlgorithms) { + DECLARE_ALGORITHM (CP::JetCalibrationAlg) + DECLARE_ALGORITHM (CP::JetGhostMuonAssociationAlg) + DECLARE_ALGORITHM (CP::JetModifierAlg) + DECLARE_ALGORITHM (CP::JetSelectionAlg) + DECLARE_ALGORITHM (CP::JetSmearingAlg) + DECLARE_ALGORITHM (CP::JetUncertaintiesAlg) + DECLARE_ALGORITHM (CP::JvtEfficiencyAlg) + DECLARE_ALGORITHM (CP::JvtUpdateAlg) +} diff --git a/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/src/components/JetAnalysisAlgorithms_load.cxx b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/src/components/JetAnalysisAlgorithms_load.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e0d9aaf857bd6459352e06b881f084107585ac85 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/JetAnalysisAlgorithms/src/components/JetAnalysisAlgorithms_load.cxx @@ -0,0 +1,5 @@ +// AsgExampleTools_load.cxx + +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(JetAnalysisAlgorithms) diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/CMakeLists.txt b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..8705936bbbe40b9a13e33611ae1c9c68a8bf841b --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/CMakeLists.txt @@ -0,0 +1,66 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# The name of the package: +atlas_subdir( MetAnalysisAlgorithms ) + +# The package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Event/xAOD/xAODMissingET + PhysicsAnalysis/Algorithms/SystematicsHandles + PhysicsAnalysis/D3PDTools/AnaAlgorithm + PhysicsAnalysis/Interfaces/METInterface + Reconstruction/MET/METInterface + Reconstruction/MET/METUtilities + PRIVATE ) + +atlas_add_library( MetAnalysisAlgorithmsLib + MetAnalysisAlgorithms/*.h MetAnalysisAlgorithms/*.icc Root/*.cxx + PUBLIC_HEADERS MetAnalysisAlgorithms + LINK_LIBRARIES xAODMissingET + SystematicsHandlesLib AnaAlgorithmLib METInterface + SelectionHelpersLib METUtilitiesLib + PRIVATE_LINK_LIBRARIES ) + +atlas_add_dictionary( MetAnalysisAlgorithmsDict + MetAnalysisAlgorithms/MetAnalysisAlgorithmsDict.h + MetAnalysisAlgorithms/selection.xml + LINK_LIBRARIES MetAnalysisAlgorithmsLib ) + +if( NOT XAOD_STANDALONE ) + atlas_add_component( MetAnalysisAlgorithms + src/*.h src/*.cxx src/components/*.cxx + LINK_LIBRARIES GaudiKernel MetAnalysisAlgorithmsLib ) +endif() + +atlas_install_python_modules( python/*.py ) +atlas_install_joboptions( share/*_jobOptions.py ) +atlas_install_scripts( share/*_eljob.py ) + +if( XAOD_STANDALONE ) + atlas_add_test( testJobData + SCRIPT MetAnalysisAlgorithmsTest_eljob.py --data-type data --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSim + SCRIPT MetAnalysisAlgorithmsTest_eljob.py --data-type mc --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSim + SCRIPT MetAnalysisAlgorithmsTest_eljob.py --data-type afii --unit-test + PROPERTIES TIMEOUT 600 ) +elseif( NOT "${CMAKE_PROJECT_NAME}" STREQUAL "AthDerivation" ) + atlas_add_test( testJobData + SCRIPT athena.py + MetAnalysisAlgorithms/MetAnalysisAlgorithmsTest_jobOptions.py - --data-type data + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSim + SCRIPT athena.py + MetAnalysisAlgorithms/MetAnalysisAlgorithmsTest_jobOptions.py - --data-type mc + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSim + SCRIPT athena.py + MetAnalysisAlgorithms/MetAnalysisAlgorithmsTest_jobOptions.py - --data-type afii + PROPERTIES TIMEOUT 600 ) +endif() diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithmsDict.h b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithmsDict.h new file mode 100644 index 0000000000000000000000000000000000000000..751f56e8171afc57f916267267c5cc3ffb60dc2f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithmsDict.h @@ -0,0 +1,16 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef MET_ANALYSIS_ALGORITHMS__MET_ANALYSIS_ALGORITHMS_DICT_H +#define MET_ANALYSIS_ALGORITHMS__MET_ANALYSIS_ALGORITHMS_DICT_H + +#include <MetAnalysisAlgorithms/MetBuilderAlg.h> +#include <MetAnalysisAlgorithms/MetMakerAlg.h> +#include <MetAnalysisAlgorithms/MetSignificanceAlg.h> +#include <MetAnalysisAlgorithms/MetSystematicsAlg.h> + +#endif diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetBuilderAlg.h b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetBuilderAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..fb9aaec2853ae602e5d5e54f1a7cb6121ebdc11c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetBuilderAlg.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef MET_ANALYSIS_ALGORITHMS__MET_BUILDER_ALG_H +#define MET_ANALYSIS_ALGORITHMS__MET_BUILDER_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <METInterface/IMETMaker.h> +#include <xAODMissingET/MissingETContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IMetCalibrationAndSmearingTool + + class MetBuilderAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + MetBuilderAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the met collection we run on + private: + SysCopyHandle<xAOD::MissingETContainer> m_metHandle { + this, "met", "MissingET_%SYS%", "the met collection we run on"}; + + /// \brief the key for the final met term + private: + std::string m_finalKey {"Final"}; + + /// \brief the key for the soft term + private: + std::string m_softTerm {"PVSoftTrk"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetMakerAlg.h b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetMakerAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..da7cab77319412a73a3100b56b4b5b4f7a43882d --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetMakerAlg.h @@ -0,0 +1,134 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef MET_ANALYSIS_ALGORITHMS__MET_MAKER_ALG_H +#define MET_ANALYSIS_ALGORITHMS__MET_MAKER_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <SystematicsHandles/SysReadHandle.h> +#include <SystematicsHandles/SysWriteHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <METInterface/IMETMaker.h> + +#include <xAODBase/IParticleContainer.h> +#include <xAODMissingET/MissingETContainer.h> +#include <xAODMissingET/MissingETAuxContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IMETMaker + /// + /// This algorithm is fairly complex for a common CP algorithm. The + /// main issue here is that the MET tools store temporary + /// information on the xAOD objects that gets reset on each + /// systematic, so a lot of actions have to happen in one go. + /// Despite that complexity it still can't be run on its own, you + /// always have to call \ref MetBuilderAlg afterwards to build the + /// final MET. + + class MetMakerAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + MetMakerAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IMETMaker> m_makerTool; + + /// \brief the name of the core MissingETContainer + private: + std::string m_metCoreName; + + /// \brief the name of the MissingETAssociationMap + private: + std::string m_metAssociationName; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the electron container to use + private: + SysReadHandle<xAOD::IParticleContainer> m_electronsHandle { + this, "electrons", "", "the electron container to use" }; + + /// \brief the key for \ref m_electronsHandle + private: + std::string m_electronsKey {"RefEle"}; + + /// \brief the photon container to use + private: + SysReadHandle<xAOD::IParticleContainer> m_photonsHandle { + this, "photons", "", "the photon container to use" }; + + /// \brief the key for \ref m_photonsHandle + private: + std::string m_photonsKey {"RefGamma"}; + + /// \brief the muon container to use + private: + SysReadHandle<xAOD::IParticleContainer> m_muonsHandle { + this, "muons", "", "the muon container to use" }; + + /// \brief the key for \ref m_muonsHandle + private: + std::string m_muonsKey {"Muons"}; + + /// \brief the electron container to use + private: + SysReadHandle<xAOD::IParticleContainer> m_tausHandle { + this, "taus", "", "the tau container to use" }; + + /// \brief the key for \ref m_tausHandle + private: + std::string m_tausKey {"RefTau"}; + + /// \brief the input jet collection we run on + private: + SysReadHandle<xAOD::JetContainer> m_jetsHandle { + this, "jets", "", "the jet collection we use"}; + + private: + SysReadHandle<xAOD::IParticleContainer> m_invisHandle { + this, "invisible", "", "Any particles to treat as invisible."}; + + /// \brief the key for \ref m_jetsHandle + private: + std::string m_jetsKey {"RefJet"}; + + /// \brief the soft term key + private: + std::string m_softTermKey {"PVSoftTrk"}; + + /// \brief whether to use track-met instead of jet-met + private: + bool m_doTrackMet {false}; + + /// \brief whether to do jet JVT + private: + bool m_doJetJVT {true}; + + /// \brief the met collection we run on + private: + SysWriteHandle<xAOD::MissingETContainer,xAOD::MissingETAuxContainer> m_metHandle { + this, "met", "MissingET_%SYS%", "the met collection we produce"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetSignificanceAlg.h b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetSignificanceAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..f2dd8fcc93af2f1f0f639721512c20aa88951309 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetSignificanceAlg.h @@ -0,0 +1,74 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef MET_ANALYSIS_ALGORITHMS__MET_SIGNIFICANCE_ALG_H +#define MET_ANALYSIS_ALGORITHMS__MET_SIGNIFICANCE_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <SystematicsHandles/SysWriteHandle.h> +#include <METInterface/IMETSignificance.h> +#include <xAODMissingET/MissingETContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IMETSignificanceTool + + class MetSignificanceAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + MetSignificanceAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IMETSignificance> m_significanceTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the met collection we run on + private: + SysCopyHandle<xAOD::MissingETContainer> m_metHandle { + this, "met", "MissingET_%SYS%", "the met collection we run on"}; + + /// \brief the key for the final met term + private: + std::string m_totalMETName {"Final"}; + + /// \brief the key for the jets term + private: + std::string m_jetTermName {"RefJet"}; + + /// \brief the key for the soft term + private: + std::string m_softTermName {"PVSoftTrk"}; + + /// \brief the decoration for the significance + private: + std::string m_significanceDecoration {"significance"}; + + /// \brief the accessor for \ref m_selectionDecoration + private: + std::unique_ptr<const SG::AuxElement::Accessor<float> > m_significanceAccessor; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetSystematicsAlg.h b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetSystematicsAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..cba1d161ef4467072008872141b653956d32489b --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/MetSystematicsAlg.h @@ -0,0 +1,57 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef MET_ANALYSIS_ALGORITHMS__MET_SYSTEMATICS_ALG_H +#define MET_ANALYSIS_ALGORITHMS__MET_SYSTEMATICS_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <METInterface/IMETSystematicsTool.h> +#include <xAODMissingET/MissingETContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IMetCalibrationAndSmearingTool + + class MetSystematicsAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + MetSystematicsAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IMETSystematicsTool> m_systematicsTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the met collection we run on + private: + SysCopyHandle<xAOD::MissingETContainer> m_metHandle { + this, "met", "MissingET_%SYS%", "the met collection we run on"}; + + /// \brief the key for the soft term + private: + std::string m_softTerm {"PVSoftTrk"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/selection.xml b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..c83c888c5044aabdc2ad83858b67ec1222229d77 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/MetAnalysisAlgorithms/selection.xml @@ -0,0 +1,8 @@ +<lcgdict> + + <class name="CP::MetBuilderAlg" /> + <class name="CP::MetMakerAlg" /> + <class name="CP::MetSignificanceAlg" /> + <class name="CP::MetSystematicsAlg" /> + +</lcgdict> diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetBuilderAlg.cxx b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetBuilderAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..4a0f1c7c5a10de194f1beb8649e9112522b0b885 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetBuilderAlg.cxx @@ -0,0 +1,63 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <MetAnalysisAlgorithms/MetBuilderAlg.h> + +#include <METUtilities/METHelpers.h> +#include <xAODMissingET/MissingETAuxContainer.h> + +// +// method implementations +// + +namespace CP +{ + MetBuilderAlg :: + MetBuilderAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + { + declareProperty ("finalKey", m_finalKey, "the key for the final met term"); + declareProperty ("softTerm", m_softTerm, "the key for the soft term"); + } + + + + StatusCode MetBuilderAlg :: + initialize () + { + m_systematicsList.addHandle (m_metHandle); + ANA_CHECK (m_systematicsList.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode MetBuilderAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::MissingETContainer *met {}; + ANA_CHECK (m_metHandle.getCopy (met, sys)); + + xAOD::MissingET *softTerm = (*met)[m_softTerm]; + if (softTerm == nullptr) + { + ANA_MSG_ERROR ("could not find MET soft-term: " << m_softTerm); + return StatusCode::FAILURE; + } + ATH_CHECK (met::buildMETSum (m_finalKey, met, softTerm->source())); + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetMakerAlg.cxx b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetMakerAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6a4a76279d69e025523424b746adde48afcdb1ff --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetMakerAlg.cxx @@ -0,0 +1,125 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <MetAnalysisAlgorithms/MetMakerAlg.h> + +#include <xAODMissingET/MissingETAuxContainer.h> + +// +// method implementations +// + +namespace CP +{ + MetMakerAlg :: + MetMakerAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_makerTool ("METMaker", this) + { + declareProperty ("makerTool", m_makerTool, "the METMaker tool we apply"); + declareProperty ("metCore", m_metCoreName, "the name of the core MissingETContainer"); + declareProperty ("metAssociation", m_metAssociationName, "the name of the core MissingETContainer"); + declareProperty ("electronsKey", m_electronsKey, "the key for the electrons"); + declareProperty ("photonsKey", m_photonsKey, "the key for the photons"); + declareProperty ("muonsKey", m_muonsKey, "the key for the muons"); + declareProperty ("tausKey", m_tausKey, "the key for the taus"); + declareProperty ("jetsKey", m_jetsKey, "the key for jets"); + declareProperty ("softTermKey", m_softTermKey, "the soft term key"); + declareProperty ("doTrackMet", m_doTrackMet, "whether to use track-met instead of jet-met"); + declareProperty ("doJetJVT", m_doJetJVT, "whether to do jet JVT"); + } + + + + StatusCode MetMakerAlg :: + initialize () + { + ANA_CHECK (m_makerTool.retrieve()); + for (auto* handle : {&m_electronsHandle, &m_photonsHandle, + &m_muonsHandle, &m_tausHandle, &m_invisHandle}) { + if (*handle) { + m_systematicsList.addHandle (*handle); + } + } + m_systematicsList.addHandle (m_jetsHandle); + m_systematicsList.addHandle (m_metHandle); + ANA_CHECK (m_systematicsList.initialize()); + + return StatusCode::SUCCESS; + } + + + + StatusCode MetMakerAlg :: + execute () + { + const xAOD::MissingETContainer* metcore {nullptr}; + ANA_CHECK (evtStore()->retrieve(metcore, m_metCoreName)); + + const xAOD::MissingETAssociationMap* metMap {nullptr}; + ANA_CHECK (evtStore()->retrieve(metMap, m_metAssociationName)); + + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + auto met = std::make_unique<xAOD::MissingETContainer> (); + auto aux = std::make_unique<xAOD::MissingETAuxContainer> (); + met->setStore (aux.get()); + + metMap->resetObjSelectionFlags(); + + if (m_invisHandle) { + const xAOD::IParticleContainer* invisible = nullptr; + ATH_CHECK( m_invisHandle.retrieve(invisible, sys) ); + ATH_CHECK( m_makerTool->markInvisible(invisible, metMap, met.get() ) ); + } + + // Lambda helping with calculating the MET terms coming from the leptons + // (and photons). + auto processParticles = + [&] (SysReadHandle<xAOD::IParticleContainer>& handle, + xAOD::Type::ObjectType type, + const std::string& term) -> StatusCode { + if (!handle) { + return StatusCode::SUCCESS; + } + const xAOD::IParticleContainer* particles = nullptr; + ANA_CHECK (handle.retrieve (particles, sys)); + ANA_CHECK (m_makerTool->rebuildMET (term, type, met.get(), + particles, metMap)); + return StatusCode::SUCCESS; + }; + + // Calculate the terms coming from the user's selected objects. + ANA_CHECK (processParticles (m_electronsHandle, xAOD::Type::Electron, + m_electronsKey)); + ANA_CHECK (processParticles (m_photonsHandle, xAOD::Type::Photon, + m_photonsKey)); + ANA_CHECK (processParticles (m_tausHandle, xAOD::Type::Tau, m_tausKey)); + ANA_CHECK (processParticles (m_muonsHandle, xAOD::Type::Muon, + m_muonsKey)); + + const xAOD::JetContainer *jets {nullptr}; + ANA_CHECK (m_jetsHandle.retrieve (jets, sys)); + + if (m_doTrackMet) + { + ANA_CHECK (m_makerTool->rebuildTrackMET (m_jetsKey, m_softTermKey, met.get(), jets, metcore, metMap, m_doJetJVT)); + } else + { + ANA_CHECK (m_makerTool->rebuildJetMET (m_jetsKey, m_softTermKey, met.get(), jets, metcore, metMap, m_doJetJVT)); + } + + ANA_CHECK (m_metHandle.record (std::move (met), std::move (aux), sys)); + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetSignificanceAlg.cxx b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetSignificanceAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e2a7c72855e96eb177669e0dff2c2acaf5702bde --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetSignificanceAlg.cxx @@ -0,0 +1,75 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <MetAnalysisAlgorithms/MetSignificanceAlg.h> + +#include <xAODMissingET/MissingETAuxContainer.h> +#include "xAODEventInfo/EventInfo.h" + +// +// method implementations +// +namespace CP +{ + MetSignificanceAlg :: + MetSignificanceAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_significanceTool ("METMaker", this) + { + declareProperty ("significanceTool", m_significanceTool, "the significance tool we apply"); + declareProperty ("significanceDecoration", m_significanceDecoration, "the decoration to use for the significance"); + declareProperty ("totalMETName", m_totalMETName, "the key for the final met term"); + declareProperty ("jetTermName", m_jetTermName, "the key for the jets term"); + declareProperty ("softTermName", m_softTermName, "the key for the soft term"); + } + + + + StatusCode MetSignificanceAlg :: + initialize () + { + if (m_significanceDecoration.empty()) + { + ANA_MSG_ERROR ("no significance decoration name set"); + return StatusCode::FAILURE; + } + m_significanceAccessor = std::make_unique<SG::AuxElement::Accessor<float> > (m_significanceDecoration); + + ANA_CHECK (m_significanceTool.retrieve()); + m_systematicsList.addHandle (m_metHandle); + ANA_CHECK (m_systematicsList.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode MetSignificanceAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + // I'm not sure why this can't be const, but the interface + // requires a non-const object + xAOD::MissingETContainer *met {}; + ANA_CHECK (m_metHandle.getCopy (met, sys)); + + const xAOD::EventInfo* evtInfo = 0; + ANA_CHECK( evtStore()->retrieve( evtInfo, "EventInfo" ) ); + + ANA_CHECK (m_significanceTool->varianceMET (met, evtInfo->averageInteractionsPerCrossing(), m_jetTermName, m_softTermName, m_totalMETName)); + const float significance = m_significanceTool->GetSignificance(); + (*m_significanceAccessor) (*(*met)[m_totalMETName]) = significance; + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetSystematicsAlg.cxx b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetSystematicsAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1e255b6581d66bc07cda3bfc34b1b94bc59cff90 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/Root/MetSystematicsAlg.cxx @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <MetAnalysisAlgorithms/MetSystematicsAlg.h> + +#include <xAODMissingET/MissingETAuxContainer.h> + +// +// method implementations +// + +namespace CP +{ + MetSystematicsAlg :: + MetSystematicsAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_systematicsTool ("met::METSystematicsTool", this) + { + declareProperty ("systematicsTool", m_systematicsTool, "the systematics tool we apply"); + declareProperty ("softTerm", m_softTerm, "the key for the soft term"); + } + + + + StatusCode MetSystematicsAlg :: + initialize () + { + ANA_CHECK (m_systematicsTool.retrieve()); + m_systematicsList.addHandle (m_metHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_systematicsTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode MetSystematicsAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_systematicsTool->applySystematicVariation (sys)); + + xAOD::MissingETContainer *met {}; + ANA_CHECK (m_metHandle.getCopy (met, sys)); + + xAOD::MissingET *softTerm = (*met)[m_softTerm]; + if (softTerm == nullptr) + { + ANA_MSG_ERROR ("failed to find MET soft-term \"" << m_softTerm << "\""); + return StatusCode::FAILURE; + } + + // This returns a `CorrectionCode`, so in principle this could + // return an `OutOfValidity` result, but I have no idea what + // that would mean or how to handle it, so I'm implicitly + // converting it into a `FAILURE` instead. + ANA_CHECK (m_systematicsTool->applyCorrection (*softTerm)); + + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/python/MetAnalysisAlgorithmsTest.py b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/python/MetAnalysisAlgorithmsTest.py new file mode 100644 index 0000000000000000000000000000000000000000..3086cdaabaf0c198098f53212494051e8c4c7a8a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/python/MetAnalysisAlgorithmsTest.py @@ -0,0 +1,75 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +from AnaAlgorithm.AlgSequence import AlgSequence +from AnaAlgorithm.DualUseConfig import addPrivateTool, createAlgorithm + +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 diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/python/MetAnalysisSequence.py b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/python/MetAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..a20926c5c835ec62b6471c6ea8c1027b3ebcd6b2 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/python/MetAnalysisSequence.py @@ -0,0 +1,95 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +# AnaAlgorithm import(s): +from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm, addPrivateTool + +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 diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/python/__init__.py b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5ccb446532599c01cc3844e5b1b18db06f721002 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/python/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +__version__ = '1.0.0' diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/share/MetAnalysisAlgorithmsTest_eljob.py b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/share/MetAnalysisAlgorithmsTest_eljob.py new file mode 100755 index 0000000000000000000000000000000000000000..bdcc1d76fda56b9cd117006de3d1082dbc82a771 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/share/MetAnalysisAlgorithmsTest_eljob.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# Read the submission directory as a command line argument. You can +# extend the list of arguments with your private ones later on. +import optparse +parser = optparse.OptionParser() +parser.add_option( '-d', '--data-type', dest = 'data_type', + action = 'store', type = 'string', default = 'data', + help = 'Type of data to run over. Valid options are data, mc, afii' ) +parser.add_option( '-s', '--submission-dir', dest = 'submission_dir', + action = 'store', type = 'string', default = 'submitDir', + help = 'Submission directory for EventLoop' ) +parser.add_option( '-u', '--unit-test', dest='unit_test', + action = 'store_true', default = False, + help = 'Run the job in "unit test mode"' ) + +( options, args ) = parser.parse_args() + +# Set up (Py)ROOT. +import ROOT +ROOT.xAOD.Init().ignore() + +# ideally we'd run over all of them, but we don't have a mechanism to +# configure per-sample right now + +dataType = options.data_type + +if dataType not in ["data", "mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +# Set up the sample handler object. See comments from the C++ macro +# for the details about these lines. +import os +sh = ROOT.SH.SampleHandler() +sh.setMetaString( 'nc_tree', 'CollectionTree' ) +sample = ROOT.SH.SampleLocal (dataType) +if dataType == "data" : + sample.add (os.getenv ('ASG_TEST_FILE_DATA')) + pass +if dataType == "mc" : + sample.add (os.getenv ('ASG_TEST_FILE_MC')) + pass +if dataType == "afii" : + sample.add (os.getenv ('ASG_TEST_FILE_MC_AFII')) + pass +sh.add (sample) +sh.printContent() + +# Create an EventLoop job. +job = ROOT.EL.Job() +job.sampleHandler( sh ) +job.options().setDouble( ROOT.EL.Job.optMaxEvents, 500 ) + +job.outputAdd( ROOT.EL.OutputStream( 'ANALYSIS' ) ) + +from MetAnalysisAlgorithms.MetAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging +for alg in algSeq: + job.algsAdd( alg ) + pass + +# Find the right output directory: +submitDir = options.submission_dir +if options.unit_test: + import os + import tempfile + submitDir = tempfile.mkdtemp( prefix = 'metTest_'+dataType+'_', dir = os.getcwd() ) + os.rmdir( submitDir ) + pass + +# Run the job using the direct driver. +driver = ROOT.EL.DirectDriver() +driver.submit( job, submitDir ) diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/share/MetAnalysisAlgorithmsTest_jobOptions.py b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/share/MetAnalysisAlgorithmsTest_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..b78287fabb906189f45f9a9bbae951fcf0a36ad2 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/share/MetAnalysisAlgorithmsTest_jobOptions.py @@ -0,0 +1,44 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +# User options, which can be set from command line after a "-" character +# athena EgammaAlgorithmsTest_jobOptions.py - --myOption ... +from AthenaCommon.AthArgumentParser import AthArgumentParser +athArgsParser = AthArgumentParser() +athArgsParser.add_argument("--data-type", action = "store", dest = "data_type", + default = "data", + help = "Type of input to run over. Valid options are 'data', 'mc', 'afii'") +athArgs = athArgsParser.parse_args() + +dataType = athArgs.data_type +if not dataType in ["data", "mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +print("Running on data type: " + dataType) + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +# Set up the reading of the input file: +import AthenaRootComps.ReadAthenaxAODHybrid +theApp.EvtMax = 500 +testFile = os.getenv ( inputfile[dataType] ) +svcMgr.EventSelector.InputCollections = [testFile] + +from MetAnalysisAlgorithms.MetAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging + +# Add all algorithms from the sequence to the job. +athAlgSeq += algSeq + +# Set up a histogram output file for the job: +ServiceMgr += CfgMgr.THistSvc() +ServiceMgr.THistSvc.Output += [ + "ANALYSIS DATAFILE='MetAnalysisAlgorithmsTest." + dataType + ".hist.root' OPT='RECREATE'" + ] + +# Reduce the printout from Athena: +include( "AthAnalysisBaseComps/SuppressLogging.py" ) diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/src/components/MetAnalysisAlgorithms_entries.cxx b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/src/components/MetAnalysisAlgorithms_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..0c6538358cc1095944ab4edeb8285e84e0c49d4f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/src/components/MetAnalysisAlgorithms_entries.cxx @@ -0,0 +1,20 @@ +// AsgExampleTools_entries.cxx + +#include <GaudiKernel/DeclareFactoryEntries.h> + +#include <MetAnalysisAlgorithms/MetBuilderAlg.h> +#include <MetAnalysisAlgorithms/MetMakerAlg.h> +#include <MetAnalysisAlgorithms/MetSignificanceAlg.h> +#include <MetAnalysisAlgorithms/MetSystematicsAlg.h> + +DECLARE_ALGORITHM_FACTORY (CP::MetBuilderAlg) +DECLARE_ALGORITHM_FACTORY (CP::MetMakerAlg) +DECLARE_ALGORITHM_FACTORY (CP::MetSignificanceAlg) +DECLARE_ALGORITHM_FACTORY (CP::MetSystematicsAlg) + +DECLARE_FACTORY_ENTRIES(MetAnalysisAlgorithms) { + DECLARE_ALGORITHM (CP::MetBuilderAlg) + DECLARE_ALGORITHM (CP::MetMakerAlg) + DECLARE_ALGORITHM (CP::MetSignificanceAlg) + DECLARE_ALGORITHM (CP::MetSystematicsAlg) +} diff --git a/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/src/components/MetAnalysisAlgorithms_load.cxx b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/src/components/MetAnalysisAlgorithms_load.cxx new file mode 100644 index 0000000000000000000000000000000000000000..9bcc930733e1332169b3504f4a0ac213ae81221c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MetAnalysisAlgorithms/src/components/MetAnalysisAlgorithms_load.cxx @@ -0,0 +1,5 @@ +// AsgExampleTools_load.cxx + +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(MetAnalysisAlgorithms) diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/CMakeLists.txt b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a43af6b8437e1c40611133a73b0d9a0c5fe0f585 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/CMakeLists.txt @@ -0,0 +1,68 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# The name of the package: +atlas_subdir( MuonAnalysisAlgorithms ) + +# The package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Event/xAOD/xAODEventInfo + Event/xAOD/xAODMuon + PhysicsAnalysis/Algorithms/SelectionHelpers + PhysicsAnalysis/Algorithms/SystematicsHandles + PhysicsAnalysis/AnalysisCommon/IsolationSelection + PhysicsAnalysis/D3PDTools/AnaAlgorithm + PhysicsAnalysis/Interfaces/MuonAnalysisInterfaces + PRIVATE + PhysicsAnalysis/D3PDTools/RootCoreUtils ) + +atlas_add_library( MuonAnalysisAlgorithmsLib + MuonAnalysisAlgorithms/*.h MuonAnalysisAlgorithms/*.icc Root/*.cxx + PUBLIC_HEADERS MuonAnalysisAlgorithms + LINK_LIBRARIES xAODEventInfo xAODMuon SelectionHelpersLib + SystematicsHandlesLib MuonAnalysisInterfacesLib IsolationSelectionLib + AnaAlgorithmLib + PRIVATE_LINK_LIBRARIES RootCoreUtils ) + +atlas_add_dictionary( MuonAnalysisAlgorithmsDict + MuonAnalysisAlgorithms/MuonAnalysisAlgorithmsDict.h + MuonAnalysisAlgorithms/selection.xml + LINK_LIBRARIES MuonAnalysisAlgorithmsLib ) + +if( NOT XAOD_STANDALONE ) + atlas_add_component( MuonAnalysisAlgorithms + src/*.h src/*.cxx src/components/*.cxx + LINK_LIBRARIES GaudiKernel MuonAnalysisAlgorithmsLib ) +endif() + +atlas_install_python_modules( python/*.py ) +atlas_install_joboptions( share/*_jobOptions.py ) +atlas_install_scripts( share/*_eljob.py ) + +if( XAOD_STANDALONE ) + atlas_add_test( testJobData + SCRIPT MuonAnalysisAlgorithmsTest_eljob.py --data-type data --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSim + SCRIPT MuonAnalysisAlgorithmsTest_eljob.py --data-type mc --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSim + SCRIPT MuonAnalysisAlgorithmsTest_eljob.py --data-type afii --unit-test + PROPERTIES TIMEOUT 600 ) +else() + atlas_add_test( testJobData + SCRIPT athena.py + MuonAnalysisAlgorithms/MuonAnalysisAlgorithmsTest_jobOptions.py --evtMax=500 - --data-type data + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSim + SCRIPT athena.py + MuonAnalysisAlgorithms/MuonAnalysisAlgorithmsTest_jobOptions.py --evtMax=500 - --data-type mc + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSim + SCRIPT athena.py + MuonAnalysisAlgorithms/MuonAnalysisAlgorithmsTest_jobOptions.py --evtMax=500 - --data-type afii + PROPERTIES TIMEOUT 600 ) +endif() diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithmsDict.h b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithmsDict.h new file mode 100644 index 0000000000000000000000000000000000000000..7f54f49de8ad94a10d33a5a94599b32b294f77fc --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithmsDict.h @@ -0,0 +1,17 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef MUON_ANALYSIS_ALGORITHMS__MUON_ANALYSIS_ALGORITHMS_DICT_H +#define MUON_ANALYSIS_ALGORITHMS__MUON_ANALYSIS_ALGORITHMS_DICT_H + +#include <MuonAnalysisAlgorithms/MuonCalibrationAndSmearingAlg.h> +#include <MuonAnalysisAlgorithms/MuonEfficiencyScaleFactorAlg.h> +#include <MuonAnalysisAlgorithms/MuonIsolationAlg.h> +#include <MuonAnalysisAlgorithms/MuonSelectionAlg.h> +#include <MuonAnalysisAlgorithms/MuonTriggerEfficiencyScaleFactorAlg.h> + +#endif diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonCalibrationAndSmearingAlg.h b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonCalibrationAndSmearingAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..36daa86cc57a73e44e060b3f5fd6d59b95ea5fdf --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonCalibrationAndSmearingAlg.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef MUON_ANALYSIS_ALGORITHMS__MUON_CALIBRATION_AND_SMEARING_ALG_H +#define MUON_ANALYSIS_ALGORITHMS__MUON_CALIBRATION_AND_SMEARING_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <MuonAnalysisInterfaces/IMuonCalibrationAndSmearingTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODMuon/MuonContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IMuonCalibrationAndSmearingTool + + class MuonCalibrationAndSmearingAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + MuonCalibrationAndSmearingAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IMuonCalibrationAndSmearingTool> m_calibrationAndSmearingTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the muon collection we run on + private: + SysCopyHandle<xAOD::MuonContainer> m_muonHandle { + this, "muons", "Muons", "the muon collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonEfficiencyScaleFactorAlg.h b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonEfficiencyScaleFactorAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..cec9c4ad817b0d23399871da6ee19889327d3355 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonEfficiencyScaleFactorAlg.h @@ -0,0 +1,86 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef MUON_ANALYSIS_ALGORITHMS__MUON_EFFICIENCY_SCALE_FACTOR_ALG_H +#define MUON_ANALYSIS_ALGORITHMS__MUON_EFFICIENCY_SCALE_FACTOR_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <MuonAnalysisInterfaces/IMuonEfficiencyScaleFactors.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysDecorationHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <SystematicsHandles/SysReadHandle.h> +#include <xAODEventInfo/EventInfo.h> +#include <xAODMuon/MuonContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IMuonEfficiencyScaleFactorTool + + class MuonEfficiencyScaleFactorAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + MuonEfficiencyScaleFactorAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IMuonEfficiencyScaleFactors> m_efficiencyScaleFactorTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the muon collection we run on + private: + SysCopyHandle<xAOD::MuonContainer> m_muonHandle { + this, "muons", "Muons", "the muon collection to run on"}; + + /// \brief the EventInfo collection we use + private: + SysReadHandle<xAOD::EventInfo> m_eventInfoHandle { + this, "eventInfo", "EventInfo", "the EventInfo we use"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + + /// \brief the decoration for the muon scale factor + private: + SysDecorationHandle<float> m_scaleFactorDecoration { + this, "scaleFactorDecoration", "", "the decoration for the muon efficiency scale factor"}; + + /// \brief the decoration for the muon mc efficiency + private: + SysDecorationHandle<float> m_mcEfficiencyDecoration { + this, "mcEfficiencyDecoration", "", "the decoration for the muon MC efficiency"}; + + /// \brief the decoration for the muon data efficiency + private: + SysDecorationHandle<float> m_dataEfficiencyDecoration { + this, "dataEfficiencyDecoration", "", "the decoration for the muon data efficiency"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonIsolationAlg.h b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonIsolationAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..3f8b83f301f2d85b32067698be7c7250a6d6d8e8 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonIsolationAlg.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef MUON_ANALYSIS_ALGORITHMS__MUON_ISOLATION_ALG_H +#define MUON_ANALYSIS_ALGORITHMS__MUON_ISOLATION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <IsolationSelection/IIsolationSelectionTool.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODMuon/MuonContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IMuonSelectionTool + + class MuonIsolationAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + MuonIsolationAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IIsolationSelectionTool> m_isolationTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the muon collection we run on + private: + SysCopyHandle<xAOD::MuonContainer> m_muonHandle { + this, "muons", "Muons", "the muon collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the decoration for the muon isolation + private: + std::string m_isolationDecoration; + + /// \brief the accessor for \ref m_isolationDecoration + private: + std::unique_ptr<ISelectionAccessor> m_isolationAccessor; + + /// \brief the bits to set for an object failing the preselection + private: + SelectionType m_setOnFail; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonSelectionAlg.h b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonSelectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..7537d0ce572af66642f7309355f6627db3519dd6 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonSelectionAlg.h @@ -0,0 +1,78 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + +#ifndef MUON_ANALYSIS_ALGORITHMS__MUON_SELECTION_ALG_H +#define MUON_ANALYSIS_ALGORITHMS__MUON_SELECTION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <MuonAnalysisInterfaces/IMuonSelectionTool.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODMuon/MuonContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IMuonSelectionTool + + class MuonSelectionAlgV2 final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + MuonSelectionAlgV2 (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the selection tool + private: + ToolHandle<IMuonSelectionTool> m_selectionTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the particle continer we run on + private: + SysCopyHandle<xAOD::MuonContainer> m_muonsHandle { + this, "muons", "Muons", "the muons collection to run on"}; + + /// \brief the decoration for the quality selection + private: + std::string m_selectionDecoration; + + /// \brief the accessor for \ref m_selectionDecoration + private: + std::unique_ptr<ISelectionAccessor> m_selectionAccessor; + + /// \brief the decoration for the bad muon veto + private: + std::string m_badMuonVetoDecoration; + + /// \brief the accessor for \ref m_selectionDecoration + private: + std::unique_ptr<ISelectionAccessor> m_badMuonVetoAccessor; + + /// \brief the bits to set for an object failing the preselection + private: + SelectionType m_setOnFail; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonTriggerEfficiencyScaleFactorAlg.h b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonTriggerEfficiencyScaleFactorAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..934ba8d5859b2c6bbda0339fddba1979e13eb5cf --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/MuonTriggerEfficiencyScaleFactorAlg.h @@ -0,0 +1,98 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +#ifndef MUON_ANALYSIS_ALGORITHMS__MUON_TRIGGER_EFFICIENCY_SCALE_FACTOR_ALG_H +#define MUON_ANALYSIS_ALGORITHMS__MUON_TRIGGER_EFFICIENCY_SCALE_FACTOR_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <MuonAnalysisInterfaces/IMuonTriggerScaleFactors.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysDecorationHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <SystematicsHandles/SysReadHandle.h> +#include <xAODEventInfo/EventInfo.h> +#include <xAODMuon/MuonContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IMuonTriggerScaleFactors + + class MuonTriggerEfficiencyScaleFactorAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + MuonTriggerEfficiencyScaleFactorAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<IMuonTriggerScaleFactors> m_efficiencyScaleFactorTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the muon collection we run on + private: + SysCopyHandle<xAOD::MuonContainer> m_muonHandle { + this, "muons", "Muons", "the muon collection to run on"}; + + /// \brief the EventInfo collection we use + private: + SysReadHandle<xAOD::EventInfo> m_eventInfoHandle { + this, "eventInfo", "EventInfo", "the EventInfo we use"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + + /// \brief trigger to run efficiency for + private: + std::string m_trigger; + + /// \brief minimum run number this trigger is valid for + private: + uint32_t m_minRunNumber; + + /// \brief maximum run number this trigger is valid for + private: + uint32_t m_maxRunNumber; + + /// \brief the decoration for the muon scale factor + private: + SysDecorationHandle<float> m_scaleFactorDecoration { + this, "scaleFactorDecoration", "", "the decoration for the muon efficiency scale factor"}; + + /// \brief the decoration for the muon mc efficiency + private: + SysDecorationHandle<float> m_mcEfficiencyDecoration { + this, "mcEfficiencyDecoration", "", "the decoration for the muon MC efficiency"}; + + /// \brief the decoration for the muon data efficiency + private: + SysDecorationHandle<float> m_dataEfficiencyDecoration { + this, "dataEfficiencyDecoration", "", "the decoration for the muon data efficiency"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/selection.xml b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..f86b52b89753924208abb153adbc2eadbeb83558 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/MuonAnalysisAlgorithms/selection.xml @@ -0,0 +1,9 @@ +<lcgdict> + + <class name="CP::MuonCalibrationAndSmearingAlg" /> + <class name="CP::MuonEfficiencyScaleFactorAlg" /> + <class name="CP::MuonIsolationAlg" /> + <class name="CP::MuonSelectionAlgV2" /> + <class name="CP::MuonTriggerEfficiencyScaleFactorAlg" /> + +</lcgdict> diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonCalibrationAndSmearingAlg.cxx b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonCalibrationAndSmearingAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..055a56b507eb6790e1561f7abf26e3b8304fcc19 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonCalibrationAndSmearingAlg.cxx @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <MuonAnalysisAlgorithms/MuonCalibrationAndSmearingAlg.h> + +#include <RootCoreUtils/Assert.h> + +// +// method implementations +// + +namespace CP +{ + MuonCalibrationAndSmearingAlg :: + MuonCalibrationAndSmearingAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_calibrationAndSmearingTool ("CP::MuonCalibrationAndSmearingTool", this) + { + declareProperty ("calibrationAndSmearingTool", m_calibrationAndSmearingTool, "the calibration and smearing tool we apply"); + } + + + + StatusCode MuonCalibrationAndSmearingAlg :: + initialize () + { + ANA_CHECK (m_calibrationAndSmearingTool.retrieve()); + m_systematicsList.addHandle (m_muonHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_calibrationAndSmearingTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode MuonCalibrationAndSmearingAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_calibrationAndSmearingTool->applySystematicVariation (sys)); + xAOD::MuonContainer *muons = nullptr; + ANA_CHECK (m_muonHandle.getCopy (muons, sys)); + for (xAOD::Muon *muon : *muons) + { + if (m_preselection.getBool (*muon)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *muon, m_calibrationAndSmearingTool->applyCorrection (*muon)); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonEfficiencyScaleFactorAlg.cxx b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonEfficiencyScaleFactorAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8a2decda46a764853a45635f9a5e34ed84cc4f93 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonEfficiencyScaleFactorAlg.cxx @@ -0,0 +1,113 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <MuonAnalysisAlgorithms/MuonEfficiencyScaleFactorAlg.h> + +#include <RootCoreUtils/Assert.h> + +// +// method implementations +// + +namespace CP +{ + MuonEfficiencyScaleFactorAlg :: + MuonEfficiencyScaleFactorAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_efficiencyScaleFactorTool ("CP::MuonEfficiencyScaleFactors", this) + { + declareProperty ("efficiencyScaleFactorTool", m_efficiencyScaleFactorTool, "the calibration and smearing tool we apply"); + } + + + + StatusCode MuonEfficiencyScaleFactorAlg :: + initialize () + { + if (m_scaleFactorDecoration.empty() && m_mcEfficiencyDecoration.empty() && m_dataEfficiencyDecoration.empty()) + { + ANA_MSG_ERROR ("no scale factor or efficiency decoration name set"); + return StatusCode::FAILURE; + } + + ANA_CHECK (m_efficiencyScaleFactorTool.retrieve()); + m_systematicsList.addHandle (m_muonHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_efficiencyScaleFactorTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + + return StatusCode::SUCCESS; + } + + + + StatusCode MuonEfficiencyScaleFactorAlg :: + execute () + { + if (m_scaleFactorDecoration) { + ANA_CHECK (m_scaleFactorDecoration.preExecute (m_systematicsList)); + } + if (m_mcEfficiencyDecoration) { + ANA_CHECK (m_mcEfficiencyDecoration.preExecute (m_systematicsList)); + } + if (m_dataEfficiencyDecoration) { + ANA_CHECK (m_dataEfficiencyDecoration.preExecute (m_systematicsList)); + } + + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_efficiencyScaleFactorTool->applySystematicVariation (sys)); + xAOD::MuonContainer *muons = nullptr; + ANA_CHECK (m_muonHandle.getCopy (muons, sys)); + const xAOD::EventInfo *eventInfo = nullptr; + ANA_CHECK (m_eventInfoHandle.retrieve (eventInfo, sys)); + for (xAOD::Muon *muon : *muons) + { + if (m_preselection.getBool (*muon)) + { + if (m_scaleFactorDecoration) { + float sf = 0; + ANA_CHECK_CORRECTION (m_outOfValidity, *muon, m_efficiencyScaleFactorTool->getEfficiencyScaleFactor (*muon, sf, eventInfo)); + m_scaleFactorDecoration.set (*muon, sf, sys); + } + + if (m_mcEfficiencyDecoration) { + float eff = 0; + ANA_CHECK_CORRECTION (m_outOfValidity, *muon, m_efficiencyScaleFactorTool->getMCEfficiency (*muon, eff, eventInfo)); + m_mcEfficiencyDecoration.set (*muon, eff, sys); + } + + if (m_dataEfficiencyDecoration) { + float eff = 0; + ANA_CHECK_CORRECTION (m_outOfValidity, *muon, m_efficiencyScaleFactorTool->getDataEfficiency (*muon, eff, eventInfo)); + m_dataEfficiencyDecoration.set (*muon, eff, sys); + } + } else + { + if (m_scaleFactorDecoration) { + m_scaleFactorDecoration.set (*muon, invalidScaleFactor(), sys); + } + + if (m_mcEfficiencyDecoration) { + m_mcEfficiencyDecoration.set (*muon, invalidEfficiency(), sys); + } + + if (m_dataEfficiencyDecoration) { + m_dataEfficiencyDecoration.set (*muon, invalidEfficiency(), sys); + } + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonIsolationAlg.cxx b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonIsolationAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..cc4481ec6b09373543563a8945888bf094334cd5 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonIsolationAlg.cxx @@ -0,0 +1,80 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <MuonAnalysisAlgorithms/MuonIsolationAlg.h> + +#include <RootCoreUtils/Assert.h> + +// +// method implementations +// + +namespace CP +{ + MuonIsolationAlg :: + MuonIsolationAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_isolationTool ("CP::IsolationSelectionTool", this) + { + declareProperty ("isolationTool", m_isolationTool, "the isolation tool we apply"); + declareProperty ("isolationDecoration", m_isolationDecoration, "the decoration for the muon isolation"); + } + + + + StatusCode MuonIsolationAlg :: + initialize () + { + if (m_isolationDecoration.empty()) + { + ANA_MSG_ERROR ("no isolation decoration name set"); + return StatusCode::FAILURE; + } + ANA_CHECK (makeSelectionAccessor (m_isolationDecoration, m_isolationAccessor)); + + ANA_CHECK (m_isolationTool.retrieve()); + m_systematicsList.addHandle (m_muonHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + + Root::TAccept blankAccept = m_isolationTool->getObjTAccept(); + // Just in case this isn't initially set up as a failure clear it this one + // time. This only calls reset on the bitset + blankAccept.clear(); + m_setOnFail = selectionFromAccept(blankAccept); + + return StatusCode::SUCCESS; + } + + + + StatusCode MuonIsolationAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::MuonContainer *muons = nullptr; + ANA_CHECK (m_muonHandle.getCopy (muons, sys)); + for (xAOD::Muon *muon : *muons) + { + if (m_preselection.getBool (*muon)) + { + m_isolationAccessor->setBits + (*muon, selectionFromAccept (m_isolationTool->accept (*muon))); + } else { + m_isolationAccessor->setBits (*muon, m_setOnFail); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonSelectionAlg.cxx b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonSelectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a586bbcbb8c4df56121832e5e6bc18655d90a136 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonSelectionAlg.cxx @@ -0,0 +1,96 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + +// +// includes +// + +#include <MuonAnalysisAlgorithms/MuonSelectionAlg.h> +#include <PATCore/IAsgSelectionTool.h> + +// +// method implementations +// + +namespace CP +{ + MuonSelectionAlgV2 :: + MuonSelectionAlgV2 (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_selectionTool ("", this) + { + declareProperty ("selectionTool", m_selectionTool, "the selection tool we apply"); + declareProperty ("selectionDecoration", m_selectionDecoration, "the decoration for the quality selection"); + declareProperty ("badMuonVetoDecoration", m_badMuonVetoDecoration, "the decoration for the bad muon veto"); + } + + + + StatusCode MuonSelectionAlgV2 :: + initialize () + { + if (m_selectionDecoration.empty()) + { + ANA_MSG_ERROR ("no selection decoration name set"); + return StatusCode::FAILURE; + } + ANA_CHECK (makeSelectionAccessor (m_selectionDecoration, m_selectionAccessor)); + ANA_CHECK (m_selectionTool.retrieve()); + + if (!m_badMuonVetoDecoration.empty()) + { + ANA_CHECK (makeSelectionAccessor (m_badMuonVetoDecoration, m_badMuonVetoAccessor)); + ANA_CHECK (m_selectionTool.retrieve()); + } + + m_systematicsList.addHandle (m_muonsHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + + auto *selectionTool = dynamic_cast<IAsgSelectionTool *>(&*m_selectionTool); + Root::TAccept blankAccept = selectionTool->getTAccept(); + // Just in case this isn't initially set up as a failure clear it this one + // time. This only calls reset on the bitset + blankAccept.clear(); + m_setOnFail = selectionFromAccept(blankAccept); + + return StatusCode::SUCCESS; + } + + + + StatusCode MuonSelectionAlgV2 :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode + { + xAOD::MuonContainer *muons = nullptr; + ANA_CHECK (m_muonsHandle.getCopy (muons, sys)); + for (xAOD::Muon *muon : *muons) + { + if (m_preselection.getBool (*muon)) + { + m_selectionAccessor->setBits + (*muon, selectionFromAccept (m_selectionTool->accept (*muon))); + + if (m_badMuonVetoAccessor != nullptr) + { + m_badMuonVetoAccessor->setBool (*muon, m_selectionTool->isBadMuon (*muon)); + } + } else { + m_selectionAccessor->setBits (*muon, m_setOnFail); + + if (m_badMuonVetoAccessor != nullptr) + { + m_badMuonVetoAccessor->setBool (*muon, false); + } + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonTriggerEfficiencyScaleFactorAlg.cxx b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonTriggerEfficiencyScaleFactorAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a5795bf12295fdb41b23474d0f15c2bda1349de4 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/Root/MuonTriggerEfficiencyScaleFactorAlg.cxx @@ -0,0 +1,127 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + + +// +// includes +// + +#include <MuonAnalysisAlgorithms/MuonTriggerEfficiencyScaleFactorAlg.h> + +#include <AthContainers/ConstDataVector.h> +#include <RootCoreUtils/Assert.h> + +// +// method implementations +// + +namespace CP +{ + MuonTriggerEfficiencyScaleFactorAlg :: + MuonTriggerEfficiencyScaleFactorAlg (const std::string& name, ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_efficiencyScaleFactorTool ("CP::MuonTriggerScaleFactors", this) + { + declareProperty ("efficiencyScaleFactorTool", m_efficiencyScaleFactorTool, "the trigger efficiency scale factor tool we apply"); + declareProperty ("trigger", m_trigger, "trigger or trigger leg to calculate efficiency for"); + declareProperty ("minRunNumber", m_minRunNumber = 0, "trigger or trigger leg to calculate efficiency for"); + declareProperty ("maxRunNumber", m_maxRunNumber = 999999, "trigger or trigger leg to calculate efficiency for"); + } + + + + StatusCode MuonTriggerEfficiencyScaleFactorAlg :: + initialize () + { + if (m_trigger.empty()) + { + ANA_MSG_ERROR ("trigger name needs to be set"); + return StatusCode::FAILURE; + } + + if (m_scaleFactorDecoration.empty() && m_mcEfficiencyDecoration.empty() && m_dataEfficiencyDecoration.empty()) + { + ANA_MSG_ERROR ("no scale factor or efficiency decoration name set"); + return StatusCode::FAILURE; + } + + ANA_CHECK (m_efficiencyScaleFactorTool.retrieve()); + m_systematicsList.addHandle (m_muonHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_efficiencyScaleFactorTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + + return StatusCode::SUCCESS; + } + + + + StatusCode MuonTriggerEfficiencyScaleFactorAlg :: + execute () + { + if (m_scaleFactorDecoration) { + ANA_CHECK (m_scaleFactorDecoration.preExecute (m_systematicsList)); + } + if (m_mcEfficiencyDecoration) { + ANA_CHECK (m_mcEfficiencyDecoration.preExecute (m_systematicsList)); + } + if (m_dataEfficiencyDecoration) { + ANA_CHECK (m_dataEfficiencyDecoration.preExecute (m_systematicsList)); + } + + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_efficiencyScaleFactorTool->applySystematicVariation (sys)); + xAOD::MuonContainer *muons = nullptr; + ANA_CHECK (m_muonHandle.getCopy (muons, sys)); + const xAOD::EventInfo *eventInfo = nullptr; + ANA_CHECK (m_eventInfoHandle.retrieve (eventInfo, sys)); + + unsigned int randomRunNumber = eventInfo->auxdecor<unsigned int>("RandomRunNumber"); + bool validEvent = m_minRunNumber <= randomRunNumber && m_maxRunNumber >= randomRunNumber; + + for (xAOD::Muon *muon : *muons) + { + if (validEvent && m_preselection.getBool (*muon)) + { + if (m_scaleFactorDecoration) { + double sf = 0; + ConstDataVector<xAOD::MuonContainer> singleMuonContainer(SG::VIEW_ELEMENTS); + singleMuonContainer.push_back(muon); + ANA_CHECK_CORRECTION (m_outOfValidity, *muon, m_efficiencyScaleFactorTool->getTriggerScaleFactor (*singleMuonContainer.asDataVector(), sf, m_trigger)); + m_scaleFactorDecoration.set (*muon, sf, sys); + } + + if (m_mcEfficiencyDecoration) { + double eff = 0; + ANA_CHECK_CORRECTION (m_outOfValidity, *muon, m_efficiencyScaleFactorTool->getTriggerEfficiency (*muon, eff, m_trigger, false)); + m_mcEfficiencyDecoration.set (*muon, eff, sys); + } + + if (m_dataEfficiencyDecoration) { + double eff = 0; + ANA_CHECK_CORRECTION (m_outOfValidity, *muon, m_efficiencyScaleFactorTool->getTriggerEfficiency (*muon, eff, m_trigger, true)); + m_dataEfficiencyDecoration.set (*muon, eff, sys); + } + } else { + if (m_scaleFactorDecoration) { + m_scaleFactorDecoration.set (*muon, invalidScaleFactor(), sys); + } + + if (m_mcEfficiencyDecoration) { + m_mcEfficiencyDecoration.set (*muon, invalidEfficiency(), sys); + } + + if (m_dataEfficiencyDecoration) { + m_dataEfficiencyDecoration.set (*muon, invalidEfficiency(), sys); + } + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/MuonAnalysisAlgorithmsTest.py b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/MuonAnalysisAlgorithmsTest.py new file mode 100644 index 0000000000000000000000000000000000000000..eee5a797da60513626a7c26d3dc54b41761abacb --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/MuonAnalysisAlgorithmsTest.py @@ -0,0 +1,70 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +from AnaAlgorithm.AlgSequence import AlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm + +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 pileup analysis sequence: + from AsgAnalysisAlgorithms.PileupAnalysisSequence import \ + makePileupAnalysisSequence + pileupSequence = makePileupAnalysisSequence( dataType ) + pileupSequence.configure( inputName = 'EventInfo', outputName = 'EventInfo_%SYS%' ) + + # Add the pileup sequence to the job: + algSeq += pileupSequence + + # Include, and then set up the muon analysis algorithm sequence: + from MuonAnalysisAlgorithms.MuonAnalysisSequence import makeMuonAnalysisSequence + muonSequenceMedium = makeMuonAnalysisSequence( dataType, deepCopyOutput = True, shallowViewOutput = False, + workingPoint = 'Medium.Iso', postfix = 'medium', + enableCutflow=True, enableKinematicHistograms=True ) + muonSequenceMedium.configure( inputName = 'Muons', + outputName = 'AnalysisMuonsMedium_%SYS%' ) + + # Add the sequence to the job: + algSeq += muonSequenceMedium + + muonSequenceTight = makeMuonAnalysisSequence( dataType, deepCopyOutput = True, shallowViewOutput = False, + workingPoint = 'Tight.Iso', postfix = 'tight', + enableCutflow=True, enableKinematicHistograms=True ) + muonSequenceTight.removeStage ("calibration") + muonSequenceTight.configure( inputName = 'AnalysisMuonsMedium_%SYS%', + outputName = 'AnalysisMuons_%SYS%', + affectingSystematics = muonSequenceMedium.affectingSystematics()) + + # Add the sequence to the job: + algSeq += muonSequenceTight + + # Add an ntuple dumper algorithm: + treeMaker = createAlgorithm( 'CP::TreeMakerAlg', 'TreeMaker' ) + treeMaker.TreeName = 'muons' + algSeq += treeMaker + ntupleMaker = createAlgorithm( 'CP::AsgxAODNTupleMakerAlg', 'NTupleMakerEventInfo' ) + ntupleMaker.TreeName = 'muons' + ntupleMaker.Branches = [ 'EventInfo.runNumber -> runNumber', + 'EventInfo.eventNumber -> eventNumber', ] + ntupleMaker.systematicsRegex = '(^$)' + algSeq += ntupleMaker + ntupleMaker = createAlgorithm( 'CP::AsgxAODNTupleMakerAlg', 'NTupleMakerMuons' ) + ntupleMaker.TreeName = 'muons' + ntupleMaker.Branches = [ 'AnalysisMuons_NOSYS.eta -> mu_eta', + 'AnalysisMuons_NOSYS.phi -> mu_phi', + 'AnalysisMuons_%SYS%.pt -> mu_%SYS%_pt', ] + ntupleMaker.systematicsRegex = '(^MUON_.*)' + algSeq += ntupleMaker + treeFiller = createAlgorithm( 'CP::TreeFillerAlg', 'TreeFiller' ) + treeFiller.TreeName = 'muons' + algSeq += treeFiller + + return algSeq diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/MuonAnalysisSequence.py b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/MuonAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..2d3b893b8b27878c7c752f107ddd04914a4d036d --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/MuonAnalysisSequence.py @@ -0,0 +1,224 @@ +# 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, + 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 diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/__init__.py b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5ccb446532599c01cc3844e5b1b18db06f721002 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/python/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +__version__ = '1.0.0' diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/share/MuonAnalysisAlgorithmsTest_eljob.py b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/share/MuonAnalysisAlgorithmsTest_eljob.py new file mode 100755 index 0000000000000000000000000000000000000000..70d19f314de8a487a024e8600523f713172360e7 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/share/MuonAnalysisAlgorithmsTest_eljob.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# Read the submission directory as a command line argument. You can +# extend the list of arguments with your private ones later on. +import optparse +parser = optparse.OptionParser() +parser.add_option( '-d', '--data-type', dest = 'data_type', + action = 'store', type = 'string', default = 'data', + help = 'Type of data to run over. Valid options are data, mc, afii' ) +parser.add_option( '-s', '--submission-dir', dest = 'submission_dir', + action = 'store', type = 'string', default = 'submitDir', + help = 'Submission directory for EventLoop' ) +parser.add_option( '-u', '--unit-test', dest='unit_test', + action = 'store_true', default = False, + help = 'Run the job in "unit test mode"' ) +( options, args ) = parser.parse_args() + +# Set up (Py)ROOT. +import ROOT +ROOT.xAOD.Init().ignore() + +# ideally we'd run over all of them, but we don't have a mechanism to +# configure per-sample right now + +dataType = options.data_type + +if dataType not in ["data", "mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +# Set up the sample handler object. See comments from the C++ macro +# for the details about these lines. +import os +sh = ROOT.SH.SampleHandler() +sh.setMetaString( 'nc_tree', 'CollectionTree' ) +sample = ROOT.SH.SampleLocal (dataType) +if dataType == "data" : + sample.add (os.getenv ('ASG_TEST_FILE_DATA')) + pass +if dataType == "mc" : + sample.add (os.getenv ('ASG_TEST_FILE_MC')) + pass +if dataType == "afii" : + sample.add (os.getenv ('ASG_TEST_FILE_MC_AFII')) + pass +sh.add (sample) +sh.printContent() + +# Create an EventLoop job. +job = ROOT.EL.Job() +job.sampleHandler( sh ) +job.options().setDouble( ROOT.EL.Job.optMaxEvents, 500 ) + + +from MuonAnalysisAlgorithms.MuonAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging +for alg in algSeq: + job.algsAdd( alg ) + pass + +# Make sure that both the ntuple and the xAOD dumper have a stream to write to. +job.outputAdd( ROOT.EL.OutputStream( 'ANALYSIS' ) ) + +# Find the right output directory: +submitDir = options.submission_dir +if options.unit_test: + import os + import tempfile + submitDir = tempfile.mkdtemp( prefix = 'muonTest_'+dataType+'_', dir = os.getcwd() ) + os.rmdir( submitDir ) + pass + +# Run the job using the direct driver. +driver = ROOT.EL.DirectDriver() +driver.submit( job, submitDir ) diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/share/MuonAnalysisAlgorithmsTest_jobOptions.py b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/share/MuonAnalysisAlgorithmsTest_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..3b627b920c1e263f34279c65bfffc9c767d61681 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/share/MuonAnalysisAlgorithmsTest_jobOptions.py @@ -0,0 +1,66 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack, Will Buttinger + +#User options, which can be set from command line after a "-" character +#athena MuonAnalysisAlgorithmsTest_jobOptions.py - --myOption ... +from AthenaCommon.AthArgumentParser import AthArgumentParser +athArgsParser = AthArgumentParser() +athArgsParser.add_argument("--data-type",action="store",dest="data_type", + default="data", + help="Type of data to run over. Valid options are data, mc, afii") +athArgsParser.add_argument("--write-xaod",action="store",dest="write_xaod", + default=False, + help="Specify if you want xaod writing to happen (which means slower access mode for now)") +athArgs = athArgsParser.parse_args() + + +if athArgs.write_xaod: + #currently we must use POOLAccess mode when writing an xAOD + jps.AthenaCommonFlags.AccessMode = "POOLAccess" +else: + #ClassAccess is much faster than POOLAccess + jps.AthenaCommonFlags.AccessMode = "ClassAccess" + +dataType = athArgs.data_type + +# Set up a histogram/tree output file for the job: +jps.AthenaCommonFlags.HistOutputs = ["ANALYSIS:MuonAnalysisAlgorithmsTest." + dataType + ".hist.root"] +svcMgr.THistSvc.MaxFileSize=-1 #make job run faster by disabling file size check + +#set a default file and number of events to process +#can override with standard athena command line options (--evtMax and --filesInput) +jps.AthenaCommonFlags.EvtMax = 500 + +if dataType=="data": + testFile = os.getenv ('ASG_TEST_FILE_DATA') +elif dataType=="mc": + testFile = os.getenv ('ASG_TEST_FILE_MC') +elif dataType=="afii": + testFile = os.getenv ('ASG_TEST_FILE_MC_AFII') + +jps.AthenaCommonFlags.FilesInput = [testFile] + + + +from MuonAnalysisAlgorithms.MuonAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging + +# Add all algorithms from the sequence to the job. +athAlgSeq += algSeq + +# Write a mini-xAOD if requested: +if athArgs.write_xaod: + from OutputStreamAthenaPool.MultipleStreamManager import MSMgr + minixAOD = MSMgr.NewPoolRootStream( 'AAOD_MUON', + FileName = 'MuonAnalysisAlgorithmsTest.AAOD_MUON.pool.root' ) + minixAOD.AddItem( + [ 'xAOD::EventInfo#EventInfo', + 'xAOD::EventAuxInfo#EventInfoAux.-', + 'xAOD::MuonContainer#AnalysisMuons_NOSYS', + 'xAOD::AuxContainerBase#AnalysisMuons_NOSYSAux.eta.phi.pt' ] ) + + +# Reduce the printout from Athena: +include( "AthAnalysisBaseComps/SuppressLogging.py" ) diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/src/components/MuonAnalysisAlgorithms_entries.cxx b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/src/components/MuonAnalysisAlgorithms_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..6bc2608c046013817c6377f0ab1c700c1d26e2b6 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/src/components/MuonAnalysisAlgorithms_entries.cxx @@ -0,0 +1,23 @@ +// AsgExampleTools_entries.cxx + +#include <GaudiKernel/DeclareFactoryEntries.h> + +#include <MuonAnalysisAlgorithms/MuonCalibrationAndSmearingAlg.h> +#include <MuonAnalysisAlgorithms/MuonIsolationAlg.h> +#include <MuonAnalysisAlgorithms/MuonEfficiencyScaleFactorAlg.h> +#include <MuonAnalysisAlgorithms/MuonSelectionAlg.h> +#include <MuonAnalysisAlgorithms/MuonTriggerEfficiencyScaleFactorAlg.h> + +DECLARE_ALGORITHM_FACTORY (CP::MuonCalibrationAndSmearingAlg) +DECLARE_ALGORITHM_FACTORY (CP::MuonIsolationAlg) +DECLARE_ALGORITHM_FACTORY (CP::MuonEfficiencyScaleFactorAlg) +DECLARE_ALGORITHM_FACTORY (CP::MuonSelectionAlgV2) +DECLARE_ALGORITHM_FACTORY (CP::MuonTriggerEfficiencyScaleFactorAlg) + +DECLARE_FACTORY_ENTRIES(MuonAnalysisAlgorithms) { + DECLARE_ALGORITHM (CP::MuonCalibrationAndSmearingAlg) + DECLARE_ALGORITHM (CP::MuonIsolationAlg) + DECLARE_ALGORITHM (CP::MuonEfficiencyScaleFactorAlg) + DECLARE_ALGORITHM (CP::MuonSelectionAlgV2) + DECLARE_ALGORITHM (CP::MuonTriggerEfficiencyScaleFactorAlg) +} diff --git a/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/src/components/MuonAnalysisAlgorithms_load.cxx b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/src/components/MuonAnalysisAlgorithms_load.cxx new file mode 100644 index 0000000000000000000000000000000000000000..309e5caa4afeb84c25c870d33e02edd174549f8f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/MuonAnalysisAlgorithms/src/components/MuonAnalysisAlgorithms_load.cxx @@ -0,0 +1,5 @@ +// AsgExampleTools_load.cxx + +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(MuonAnalysisAlgorithms) diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/CMakeLists.txt b/PhysicsAnalysis/Algorithms/SelectionHelpers/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..2b7655fb9e8cffb998a5b7966f175fa7eb8b9981 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +atlas_subdir( SelectionHelpers ) + +atlas_depends_on_subdirs( + PUBLIC + Control/AthContainers + Control/AthToolSupport/AsgTools + Event/xAOD/xAODBase + PhysicsAnalysis/D3PDTools/AnaAlgorithm + PRIVATE + Control/AthToolSupport/AsgTesting + Event/xAOD/xAODJet + PhysicsAnalysis/AnalysisCommon/PATCore + PhysicsAnalysis/AnalysisCommon/PATInterfaces ) + +atlas_add_library( SelectionHelpersLib + SelectionHelpers/*.h SelectionHelpers/*.icc Root/*.cxx + PUBLIC_HEADERS SelectionHelpers + LINK_LIBRARIES AthContainers AsgTools xAODBase AnaAlgorithmLib + PRIVATE_LINK_LIBRARIES PATCoreLib PATInterfaces ) + +atlas_add_dictionary( SelectionHelpersDict + SelectionHelpers/SelectionHelpersDict.h + SelectionHelpers/selection.xml + LINK_LIBRARIES SelectionHelpersLib ) + +find_package( GTest ) + +atlas_add_test( gt_ISelectionAccessor + SOURCES test/gt_ISelectionAccessor.cxx + INCLUDE_DIRS ${GTEST_INCLUDE_DIRS} + LINK_LIBRARIES ${GTEST_LIBRARIES} AsgTestingLib SelectionHelpersLib xAODJet ) diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/ISelectionAccessor.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/ISelectionAccessor.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d3c2ecb7743795111968eef1b2b09428a45d6407 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/ISelectionAccessor.cxx @@ -0,0 +1,140 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SelectionHelpers/ISelectionAccessor.h> + +#include <AsgTools/StatusCode.h> +#include <SelectionHelpers/SelectionAccessorBits.h> +#include <SelectionHelpers/SelectionAccessorChar.h> +#include <SelectionHelpers/SelectionAccessorInvert.h> +#include <SelectionHelpers/SelectionAccessorList.h> +#include <SelectionHelpers/SelectionAccessorNull.h> +#include <SelectionHelpers/SelectionExprParser.h> +#include <exception> +#include <unordered_map> + +// +// method implementations +// + +namespace CP +{ + namespace + { + std::vector<std::string> + splitString (const std::string& input, const std::string& separator) + { + std::vector<std::string> result; + std::string::size_type start = 0, split = 0; + while ((split = input.find (separator, start)) != std::string::npos) + { + result.emplace_back (input.substr (start, split - start)); + start = split + separator.size(); + } + result.emplace_back (input.substr (start)); + return result; + } + + } + + StatusCode + makeSelectionAccessor(const std::string& expr, + std::unique_ptr<ISelectionAccessor>& accessor, + bool defaultToChar) + { + using namespace msgSelectionHelpers; + + if (expr.empty()) + { + accessor = std::make_unique<SelectionAccessorNull> (true); + return StatusCode::SUCCESS; + } + + try { + SelectionExprParser parser(expr, defaultToChar); + ANA_CHECK(parser.build(accessor)); + } catch (const std::exception& e) { + ANA_MSG_FATAL("Failure to parse expression: '" << expr << "': " << e.what()); + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; + } + + + StatusCode + makeSelectionAccessorVar (const std::string& name, + std::unique_ptr<ISelectionAccessor>& accessor, + bool defaultToChar) + { + using namespace msgSelectionHelpers; + + std::string var; + bool asChar = false; + bool asBits = false; + bool invert = false; + + for (const std::string& option : splitString (name, ",")) + { + if (var.empty()) + { + // this is a bit of a hack, it will pick up the first + // component as the decoration name + var = option; + } else if (option == "as_char") + { + // using ",as_char" as a postfix to indicate char decorations + // (and ",as_bits" as a postfix to indicate bitset + // decorations). I chose that suffix as it should make it + // easier to read in configuration files and allows for future + // extensions if needed. + asChar = true; + } else if (option == "as_bits") + { + asBits = true; + } else if (option == "invert") + { + invert = true; + } else + { + ANA_MSG_ERROR ("invalid option " << option << "for selection decoration"); + return StatusCode::FAILURE; + } + } + + if (asChar && asBits) + { + ANA_MSG_ERROR ("can't specify both 'as_bits' and 'as_char' for the same selection decoration, pick one!!!"); + return StatusCode::FAILURE; + } + + if (!asChar && !asBits) + { + if (defaultToChar) + asChar = true; + else + asBits = true; + } + + if (asChar) + accessor = std::make_unique<SelectionAccessorChar> (var); + else + accessor = std::make_unique<SelectionAccessorBits> (var); + + if (invert) + { + accessor = std::make_unique<SelectionAccessorInvert> + (std::move (accessor)); + } + + return StatusCode::SUCCESS; + } +} diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/OutOfValidityEventHelper.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/OutOfValidityEventHelper.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5eaa8d02501ee2db70daf6547c73d242fb604201 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/OutOfValidityEventHelper.cxx @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SelectionHelpers/OutOfValidityEventHelper.h> + +#include <AsgTools/MessageCheck.h> +#include <AsgTools/StatusCode.h> +#include <PATInterfaces/CorrectionCode.h> + +// +// method implementations +// + +namespace CP +{ + ::StatusCode OutOfValidityEventHelper :: + initialize () + { + m_isInitialized = true; + return StatusCode::SUCCESS; + } + + + ::StatusCode OutOfValidityEventHelper :: + check (const CP::CorrectionCode& code, + const char *context) const + { + assert (m_isInitialized); + + switch (code) + { + case CP::CorrectionCode::Ok: + return StatusCode::SUCCESS; + case CP::CorrectionCode::Error: + return StatusCode::FAILURE; + case CP::CorrectionCode::OutOfValidityRange: + switch (OutOfValidityAction (m_action)) + { + case OutOfValidityAction::ABORT: + ANA_MSG_ERROR ("encountered OutOfValidity: " << context); + return StatusCode::FAILURE; + case OutOfValidityAction::WARNING: + ANA_MSG_WARNING ("encountered OutOfValidity: " << context); + return StatusCode::SUCCESS; + case OutOfValidityAction::SILENT: + return StatusCode::SUCCESS; + } + } + ANA_MSG_ERROR (__FILE__ << ":" << __LINE__ << ": invalid enum value encountered " << code << " " << int (m_action)); + return StatusCode::FAILURE; + } + + + + MsgStream& OutOfValidityEventHelper :: + msg (MSG::Level lvl) const + { + assert (m_msg != nullptr); + *m_msg << lvl; + return *m_msg; + } +} diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/OutOfValidityHelper.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/OutOfValidityHelper.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3069eb56eb09b4f6699369da3b29ef55f6a0de98 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/OutOfValidityHelper.cxx @@ -0,0 +1,78 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SelectionHelpers/OutOfValidityHelper.h> + +#include <AsgTools/MessageCheck.h> +#include <AsgTools/StatusCode.h> +#include <PATInterfaces/CorrectionCode.h> + +// +// method implementations +// + +namespace CP +{ + ::StatusCode OutOfValidityHelper :: + initialize () + { + if (!m_decorationName.empty()) + { + ANA_CHECK (makeSelectionAccessor (m_decorationName, m_accessor)); + } + + m_isInitialized = true; + return StatusCode::SUCCESS; + } + + + ::StatusCode OutOfValidityHelper :: + check (xAOD::IParticle& particle, + const CP::CorrectionCode& code, + const char *context) const + { + assert (m_isInitialized); + + switch (code) + { + case CP::CorrectionCode::Ok: + if (m_accessor) m_accessor->setBool (particle, true); + return StatusCode::SUCCESS; + case CP::CorrectionCode::Error: + return StatusCode::FAILURE; + case CP::CorrectionCode::OutOfValidityRange: + if (m_accessor) m_accessor->setBool (particle, false); + switch (OutOfValidityAction (m_action)) + { + case OutOfValidityAction::ABORT: + ANA_MSG_ERROR ("encountered OutOfValidity: " << context); + return StatusCode::FAILURE; + case OutOfValidityAction::WARNING: + ANA_MSG_WARNING ("encountered OutOfValidity: " << context); + return StatusCode::SUCCESS; + case OutOfValidityAction::SILENT: + return StatusCode::SUCCESS; + } + } + ANA_MSG_ERROR (__FILE__ << ":" << __LINE__ << ": invalid enum value encountered " << code << " " << int (m_action)); + return StatusCode::FAILURE; + } + + + + MsgStream& OutOfValidityHelper :: + msg (MSG::Level lvl) const + { + assert (m_msg != nullptr); + *m_msg << lvl; + return *m_msg; + } +} diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorBits.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorBits.cxx new file mode 100644 index 0000000000000000000000000000000000000000..56edd0aafa4c5c20fdf254e4fc09cfa5758abe9a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorBits.cxx @@ -0,0 +1,69 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SelectionHelpers/SelectionAccessorBits.h> + +// +// method implementations +// + +namespace CP +{ + SelectionAccessorBits :: + SelectionAccessorBits (const std::string& name) + : m_accessor (name), m_constAccessor (name), m_label(name) + {} + + + + SelectionType SelectionAccessorBits :: + getBits (const SG::AuxElement& element) const + { + return m_constAccessor (element); + } + + + + void SelectionAccessorBits :: + setBits (SG::AuxElement& element, + SelectionType selection) const + { + m_accessor (element) = selection; + } + + + + bool SelectionAccessorBits :: + getBool (const SG::AuxElement& element) const + { + return m_constAccessor (element) == selectionAccept(); + } + + + + void SelectionAccessorBits :: + setBool (SG::AuxElement& element, + bool selection) const + { + if (selection) + m_accessor (element) = selectionAccept(); + else + m_accessor (element) = selectionAccept() ^ 0x1; + } + + + + std::string SelectionAccessorBits :: + label () const + { + return m_label; + } +} diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorChar.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorChar.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c6a45b09a5199736eaebbac920b999cb2301aab1 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorChar.cxx @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SelectionHelpers/SelectionAccessorChar.h> + +// +// method implementations +// + +namespace CP +{ + SelectionAccessorChar :: + SelectionAccessorChar (const std::string& name) + : m_accessor (name), m_constAccessor (name), m_label(name) + {} + + + + SelectionType SelectionAccessorChar :: + getBits (const SG::AuxElement& element) const + { + if (m_constAccessor (element)) + return selectionAccept(); + else + return 0; + } + + + + void SelectionAccessorChar :: + setBits (SG::AuxElement& element, + SelectionType selection) const + { + if (selection == selectionAccept()) + m_accessor (element) = 1; + else + m_accessor (element) = 0; + } + + + + bool SelectionAccessorChar :: + getBool (const SG::AuxElement& element) const + { + return m_constAccessor (element); + } + + + + void SelectionAccessorChar :: + setBool (SG::AuxElement& element, + bool selection) const + { + m_accessor (element) = selection; + } + + + + std::string SelectionAccessorChar :: + label () const + { + return m_label; + } +} diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorExprBase.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorExprBase.cxx new file mode 100644 index 0000000000000000000000000000000000000000..441396cf53c85aea2a2ec807c50de7ada269622b --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorExprBase.cxx @@ -0,0 +1,28 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "SelectionHelpers/SelectionAccessorExprBase.h" + +namespace CP { + +SelectionType SelectionAccessorExprBase::getBits( + const SG::AuxElement& element) const { + return getBool(element) ? selectionAccept() : selectionReject(); +} + +void SelectionAccessorExprBase::setBool(SG::AuxElement& /*element*/, + bool /*value*/) const { + throw std::runtime_error( + "setting not supported for CP::SelectionAccessorExprBase"); +} + +void SelectionAccessorExprBase::setBits(SG::AuxElement& /*element*/, + SelectionType /*selection*/) const { + throw std::runtime_error( + "setting not supported for CP::SelectionAccessorExprBase"); +} + +} // namespace CP + + diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorExprNot.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorExprNot.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2829f4f6612470c8fcd3e1daf606677659f537b6 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorExprNot.cxx @@ -0,0 +1,21 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "SelectionHelpers/SelectionAccessorExprNot.h" + +namespace CP { + +SelectionAccessorExprNot::SelectionAccessorExprNot( + std::unique_ptr<ISelectionAccessor> child) + : m_child(std::move(child)) {} + +bool SelectionAccessorExprNot::getBool(const SG::AuxElement& element) const { + return !m_child->getBool(element); +} + +std::string SelectionAccessorExprNot::label() const { + return "!" + m_child->label(); +} + +} // namespace CP diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorExprOr.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorExprOr.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b91abe4978f0673b53cef221bf213dfe708341b5 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorExprOr.cxx @@ -0,0 +1,23 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "SelectionHelpers/SelectionAccessorExprOr.h" + +namespace CP { + +SelectionAccessorExprOr::SelectionAccessorExprOr( + std::unique_ptr<ISelectionAccessor> left, + std::unique_ptr<ISelectionAccessor> right) + : m_left(std::move(left)), m_right(std::move(right)) {} + +bool SelectionAccessorExprOr::getBool(const SG::AuxElement& element) const { + return m_left->getBool(element) || m_right->getBool(element); +} + +std::string SelectionAccessorExprOr::label() const { + return "( " + m_left->label() + " || " + m_right->label() + " )"; +} + +} // namespace CP + diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorInvert.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorInvert.cxx new file mode 100644 index 0000000000000000000000000000000000000000..071088bbfd3f6bb693473a5bf32a39fce4c00797 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorInvert.cxx @@ -0,0 +1,69 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SelectionHelpers/SelectionAccessorInvert.h> + +// +// method implementations +// + +namespace CP +{ + SelectionAccessorInvert :: + SelectionAccessorInvert (std::unique_ptr<ISelectionAccessor> val_base) + : m_base (std::move (val_base)) + {} + + + + SelectionType SelectionAccessorInvert :: + getBits (const SG::AuxElement& element) const + { + if (m_base->getBool (element) == false) + return selectionAccept(); + else + return 0; + } + + + + void SelectionAccessorInvert :: + setBits (SG::AuxElement& element, + SelectionType selection) const + { + m_base->setBool (element, selection != selectionAccept()); + } + + + + bool SelectionAccessorInvert :: + getBool (const SG::AuxElement& element) const + { + return m_base->getBool (element) == false; + } + + + + void SelectionAccessorInvert :: + setBool (SG::AuxElement& element, + bool selection) const + { + m_base->setBool (element, !selection); + } + + + + std::string SelectionAccessorInvert :: + label () const + { + return "not " + m_base->label(); + } +} diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorList.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorList.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3cca05d9ec56bf8ead00b6d8f97ec1b7a8dfa277 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorList.cxx @@ -0,0 +1,106 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SelectionHelpers/SelectionAccessorList.h> + +// +// method implementations +// + +namespace CP +{ + SelectionAccessorList :: + SelectionAccessorList (std::vector<std::unique_ptr<ISelectionAccessor> > val_list) + : m_list (std::move (val_list)) + { + for (const std::unique_ptr<ISelectionAccessor> &acc : m_list) + { + if (!m_label.empty()) + m_label.append(" && "); + + m_label.append(acc->label()); + } + + m_label = "( " + m_label + " )"; + } + + + + SelectionType SelectionAccessorList :: + getBits (const SG::AuxElement& element) const + { + // total number of bits in SelectionType + constexpr size_t SelectionTotalBits = 8 * sizeof (SelectionType); + + // if we have more cuts than bits, just return true/false + if (m_list.size() > SelectionTotalBits) + { + if (getBool (element)) + return selectionAccept(); + else + return 0; + } + + SelectionType result = selectionAccept(); + for (std::size_t iter = 0; iter != m_list.size(); ++ iter) + { + if (m_list[iter]->getBool (element) == false) + { + result = result & ~(SelectionType (1) << iter); + } + } + return result; + } + + + + void SelectionAccessorList :: + setBits (SG::AuxElement& /*element*/, + SelectionType /*selection*/) const + { + // technically we could support setting by setting all the + // components, but I can't think of a situation in which that + // would be a good idea + throw std::runtime_error ("setting not supported for CP::SelectionAccessorList"); + } + + + + bool SelectionAccessorList :: + getBool (const SG::AuxElement& element) const + { + for (auto& accessor : m_list) + { + if (!accessor->getBool (element)) + return false; + } + return true; + } + + + + void SelectionAccessorList :: + setBool (SG::AuxElement& /*element*/, + bool /*selection*/) const + { + // technically we could support setting by setting all the + // components, but I can't think of a situation in which that + // would be a good idea + throw std::runtime_error ("setting not supported for CP::SelectionAccessorList"); + } + + + std::string SelectionAccessorList :: + label () const + { + return m_label; + } +} diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorNull.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorNull.cxx new file mode 100644 index 0000000000000000000000000000000000000000..642d474b0ff94bbf9878643680d8591fdc882dc1 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionAccessorNull.cxx @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SelectionHelpers/SelectionAccessorNull.h> + +// +// method implementations +// + +namespace CP +{ + SelectionAccessorNull :: + SelectionAccessorNull (bool value) : m_value(value) + {} + + + + SelectionType SelectionAccessorNull :: + getBits (const SG::AuxElement& /*element*/) const + { + return m_value ? selectionAccept() : selectionReject(); + } + + + + void SelectionAccessorNull :: + setBits (SG::AuxElement& /*element*/, + SelectionType /*selection*/) const + { + // ok, let's not do anything here, making this an easy way to + // ignore selection decorations an algorithm calculates. however, + // the implication is that you can simply forget to set the + // decoration property and not get an error + } + + + + bool SelectionAccessorNull :: + getBool (const SG::AuxElement& /*element*/) const + { + return m_value; + } + + + + void SelectionAccessorNull :: + setBool (SG::AuxElement& /*element*/, + bool /*selection*/) const + { + // ok, let's not do anything here, making this an easy way to + // ignore selection decorations an algorithm calculates. however, + // the implication is that you can simply forget to set the + // decoration property and not get an error + } + + + std::string SelectionAccessorNull :: + label () const + { + return m_value ? "true" : "false"; + } +} diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionExprParser.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionExprParser.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c15925fae605b70880c247e1c3d124fd8ef040d2 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionExprParser.cxx @@ -0,0 +1,171 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#include "SelectionHelpers/SelectionExprParser.h" +#include "SelectionHelpers/SelectionAccessorExprNot.h" +#include "SelectionHelpers/SelectionAccessorExprOr.h" +#include "SelectionHelpers/SelectionAccessorList.h" +#include "SelectionHelpers/SelectionAccessorNull.h" + +#include <iostream> +#include <regex> +#include <string> + +using CP::DetailSelectionExprParser::Lexer; + +namespace CP { +using namespace msgSelectionHelpers; + +namespace DetailSelectionExprParser { +bool Separator::operator()(std::string::const_iterator& next, + const std::string::const_iterator& end, + std::string& tok) const { + if (next == end) { + return false; + } + + static const std::regex base_regex( + "^( ?((?:[^|&()! ]+)|(?:&&)|(?:!)|(?:\\()|(?:\\))|(?:\\|\\|))).*"); + std::smatch m; + + if (std::regex_match(next, end, m, base_regex)) { + tok = m[2].str(); + next += m[1].length(); + } else { + std::smatch m2; + static const std::regex space_re{"^ +$"}; + if (std::regex_match(next, end, m, space_re)) { + // only spaces left, we're done + return false; + } + throw std::runtime_error("Cannot tokenize: '" + std::string(next, end) + + "'"); + } + return true; +} + +Lexer::Lexer(const std::string& s) : m_string(s), m_tokenizer(s, {}) { + m_iterator = m_tokenizer.begin(); +} + +auto Lexer::nextSymbol() -> Symbol { + if (m_iterator == m_tokenizer.end()) { + return Symbol{END, ""}; + } + std::string t = *m_iterator; + Type type; + if (t == "&&") + type = AND; + else if (t == "||") + type = OR; + else if (t == "(") + type = LEFT; + else if (t == ")") + type = RIGHT; + else if (t == "!") + type = NOT; + else if (t == "true") + type = TRUE_LITERAL; + else if (t == "false") + type = FALSE_LITERAL; + else { + // check if variable is valid + const std::regex base_regex("^([^|()&! ]*)$"); + std::smatch base_match; + + if (!std::regex_match(t, base_match, base_regex)) { + throw std::runtime_error("illegal variable encountered"); + } else { + type = VAR; + } + } + + ++m_iterator; + return Symbol{type, t}; +} + +} // namespace DetailSelectionExprParser + +SelectionExprParser::SelectionExprParser(Lexer lexer, bool defaultToChar) + : m_lexer(std::move(lexer)), m_defaultToChar(defaultToChar) {} + +StatusCode SelectionExprParser::build( + std::unique_ptr<ISelectionAccessor>& accessor) { + std::unique_ptr<ISelectionAccessor> root{nullptr}; + ANA_CHECK(expression(root)); + + if (m_symbol.type != Lexer::END) { + throw std::runtime_error( + "Not all symbols in expression were consumed. Check your expression."); + } + + accessor = std::move(root); + return StatusCode::SUCCESS; +} + +StatusCode SelectionExprParser::expression( + std::unique_ptr<ISelectionAccessor>& root) { + ANA_CHECK(term(root)); + while (m_symbol.type == Lexer::OR) { + std::unique_ptr<ISelectionAccessor> left = std::move(root); + ANA_CHECK(term(root)); + std::unique_ptr<ISelectionAccessor> right = std::move(root); + root = std::make_unique<SelectionAccessorExprOr>(std::move(left), + std::move(right)); + } + return StatusCode::SUCCESS; +} + +StatusCode SelectionExprParser::term( + std::unique_ptr<ISelectionAccessor>& root) { + ANA_CHECK(factor(root)); + std::vector<std::unique_ptr<ISelectionAccessor>> factors; + factors.push_back(std::move(root)); + + while (m_symbol.type == Lexer::AND) { + ANA_CHECK(factor(root)); + factors.push_back(std::move(root)); + } + + if (factors.size() == 1) { + root = std::move(factors[0]); + } else { + root = std::make_unique<SelectionAccessorList>(std::move(factors)); + } + return StatusCode::SUCCESS; +} + +StatusCode SelectionExprParser::factor( + std::unique_ptr<ISelectionAccessor>& root) { + m_symbol = m_lexer.nextSymbol(); + if (m_symbol.type == Lexer::TRUE_LITERAL) { + root = std::make_unique<SelectionAccessorNull>(true); + m_symbol = m_lexer.nextSymbol(); + } else if (m_symbol.type == Lexer::FALSE_LITERAL) { + root = std::make_unique<SelectionAccessorNull>(false); + m_symbol = m_lexer.nextSymbol(); + } else if (m_symbol.type == Lexer::NOT) { + ANA_CHECK(factor(root)); + std::unique_ptr<ISelectionAccessor> notEx = + std::make_unique<SelectionAccessorExprNot>(std::move(root)); + root = std::move(notEx); + } else if (m_symbol.type == Lexer::LEFT) { + ANA_CHECK(expression(root)); + if (m_symbol.type != Lexer::RIGHT) { + throw std::runtime_error( + "Missing closing bracket, check your expression."); + } + m_symbol = m_lexer.nextSymbol(); + + } else if (m_symbol.type == Lexer::VAR) { + ANA_CHECK(makeSelectionAccessorVar(m_symbol.value, root, m_defaultToChar)); + m_symbol = m_lexer.nextSymbol(); + } else { + throw std::runtime_error("Malformed expression."); + } + + return StatusCode::SUCCESS; +} + +} // namespace CP diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionHelpers.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionHelpers.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bba7731d9650759ad487e063eaa22b53564dd17b --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionHelpers.cxx @@ -0,0 +1,40 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SelectionHelpers/SelectionHelpers.h> + +#include <PATCore/TAccept.h> + +// +// method implementations +// + +namespace CP +{ + SelectionType selectionFromBool (bool accept) + { + if (accept) + return selectionAccept(); + else + return selectionReject(); + } + + + + SelectionType selectionFromAccept (const Root::TAccept& accept) + { + return ~SelectionType (accept.getCutResultInvertedBitSet().to_ulong()); + } + + + + ANA_MSG_SOURCE (msgSelectionHelpers, "selectionHelpers") +} diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionReadHandle.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionReadHandle.cxx new file mode 100644 index 0000000000000000000000000000000000000000..80a95355b81966379d46615809db102d2ab4b282 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/Root/SelectionReadHandle.cxx @@ -0,0 +1,64 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SelectionHelpers/SelectionReadHandle.h> + +#include <AsgTools/MessageCheck.h> +#include <AsgTools/StatusCode.h> + +// +// method implementations +// + +namespace CP +{ + MsgStream& SelectionReadHandle :: + msg () const + { + assert (m_msg != nullptr); + return *m_msg; + } + + + + MsgStream& SelectionReadHandle :: + msg (MSG::Level lvl) const + { + assert (m_msg != nullptr); + *m_msg << lvl; + return *m_msg; + } + + + + bool SelectionReadHandle :: + empty () const noexcept + { + return m_selection.empty(); + } + + + + SelectionReadHandle :: + operator bool () const noexcept + { + return !m_selection.empty(); + } + + + + StatusCode SelectionReadHandle :: + initialize () + { + ANA_CHECK (makeSelectionAccessor (m_selection, m_accessor)); + return StatusCode::SUCCESS; + } +} diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/ISelectionAccessor.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/ISelectionAccessor.h new file mode 100644 index 0000000000000000000000000000000000000000..a41e66be72f021702a3813f757198e23bea16abd --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/ISelectionAccessor.h @@ -0,0 +1,100 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SELECTION_HELPERS__I_SELECTION_ACCESSOR_H +#define SELECTION_HELPERS__I_SELECTION_ACCESSOR_H + +#include <AthContainers/AuxElement.h> +#include <SelectionHelpers/SelectionHelpers.h> +#include <memory> + +class StatusCode; + +namespace CP +{ + /// \brief a specialized accessor to read/write a selection + /// decoration from/to an xAOD object + /// + /// We have (at least) two conventions on how selection decorations + /// can look like, the one from the CP algorithms/TAccept and the + /// other from the derivation framework/overlap removal tool. This + /// accessor is a base class with specific implementations for + /// different conventions. + /// + /// The actual interface has separate accessor functions for + /// accessing as bitsets or as booleans. In part that is to avoid a + /// lot of unnecessary back and forth conversions, but mostly it is + /// to give us some more flexibility if we need to extend this in + /// the future. + + class ISelectionAccessor + { + // no slicing + ISelectionAccessor& operator = (const ISelectionAccessor&) = delete; + + /// \brief standard (virtual) destructor + public: + virtual ~ISelectionAccessor () noexcept = default; + + /// \brief get the selection decoration + public: + virtual SelectionType + getBits (const SG::AuxElement& element) const = 0; + + /// \brief set the selection decoration + public: + virtual void setBits (SG::AuxElement& element, + SelectionType selection) const = 0; + + /// \brief get the selection decoration + public: + virtual bool getBool (const SG::AuxElement& element) const = 0; + + /// \brief set the selection decoration + public: + virtual void setBool (SG::AuxElement& element, + bool selection) const = 0; + + /// \brief get the label of the accessor + public: + virtual std::string label () const = 0; + }; + + + /// \brief make the \ref ISelectionAccessor for the given name + /// + /// This will invoke @c SelectionExprParser to build a @c ISelectionAccessor + /// that corresponds to a given expression. + /// @note Passing in a simple selection name will createa plain selection accessor that + /// only reads that single name. + /// @note Passing in an expression which only contains names and && will produce an + /// instance of @c SelectionAccessorList, which has special semantics and allows + /// retrievel of AND'ed accessors via a bit sequence. + /// @note Allowed operators are &&, || and !, grouping with () is possible. + /// + /// @param [in] expr The expression to parse. + /// @param [out] accessor The created accessor will be owned by this unique pointer. + /// @param [in] defaultToChar Whether to treat decorations as char by default + StatusCode + makeSelectionAccessor (const std::string& expr, + std::unique_ptr<ISelectionAccessor>& accessor, + bool defaultToChar = false); + + /// @brief Produces a simple @c ISelectionAccessor accessing the given decoration + /// @note Through annotations like ",as_char" or ",as_bits" at the end of a name, + /// different decoding strategies can be selected. These need to match the + /// decoration type. + /// @param [in] name The name of the decoration to create an accessor for. + /// @param [out] accessor The created accessor will be owned by this unique pointer. + /// @param [in] defaultToChar Whether to treat decorations as char by default + StatusCode + makeSelectionAccessorVar (const std::string& name, + std::unique_ptr<ISelectionAccessor>& accessor, + bool defaultToChar = false); +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/OutOfValidityEventHelper.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/OutOfValidityEventHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..4fcc1f49c8fc29fadeba584edfe4edb9ef19f7ac --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/OutOfValidityEventHelper.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SELECTION_HELPERS__OUT_OF_VALIDITY_EVENT_HELPER_H +#define SELECTION_HELPERS__OUT_OF_VALIDITY_EVENT_HELPER_H + +#include <AsgTools/MsgStream.h> +#include <AthContainers/AuxElement.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <xAODBase/IParticle.h> +#include <memory> + +class StatusCode; + +namespace CP +{ + class CorrectionCode; + + + + /// \brief a helper to translate a \ref CP::CorrectionCode into a + /// \ref ::StatusCode + /// + /// The prolem is OutOfValidityRange which does not have an + /// equivalent in StatusCode and which does not have a unique, + /// correct handling in all situations. This helper allows to + /// configure a variety of behaviors via properties. + + class OutOfValidityEventHelper final + { + /// \brief standard constructor + public: + template<typename T> + OutOfValidityEventHelper (T *owner, const std::string& propertyName = "outOfValidity", + const std::string& propertyDescription = "how to handle out of validity results"); + + + /// \brief standard initialize + public: + ::StatusCode initialize (); + + /// \brief check the correction code and do the proper thing + public: + ::StatusCode check (const CP::CorrectionCode& code, + const char *context) const; + + + /// \brief the action to take + private: + unsigned m_action {unsigned (OutOfValidityAction::ABORT)}; + + /// \brief the message stream we use + private: + MsgStream *m_msg {nullptr}; + + /// \brief whether we have been initialized + /// + /// This is only used in debug mode to indicate a programming + /// fault. Otherwise it is too easy for users to forget to + /// initialize this object. + private: + bool m_isInitialized = false; + + /// \brief helper for message macros + private: + MsgStream& msg( const MSG::Level lvl ) const; + }; + + + + template<typename T> OutOfValidityEventHelper :: + OutOfValidityEventHelper (T *owner, const std::string& propertyName, + const std::string& propertyDescription) + : m_msg (&owner->msg()) + { + owner->declareProperty (propertyName, m_action, + propertyDescription); + } +} + +/// \brief a helper check macro to work with \ref OutOfValidityEventHelper +#define ANA_CHECK_CORRECTION_EVENT(helper,expr) \ + { if ((helper).check ((expr), #expr).isFailure()) \ + return StatusCode::FAILURE; } + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/OutOfValidityHelper.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/OutOfValidityHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..97787061e61164fa61c67e6f54e9b92712b00645 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/OutOfValidityHelper.h @@ -0,0 +1,138 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SELECTION_HELPERS__OUT_OF_VALIDITY_HELPER_H +#define SELECTION_HELPERS__OUT_OF_VALIDITY_HELPER_H + +#include <AsgTools/MsgStream.h> +#include <AthContainers/AuxElement.h> +#include <SelectionHelpers/ISelectionAccessor.h> +#include <xAODBase/IParticle.h> +#include <memory> + +class StatusCode; + +namespace CP +{ + class CorrectionCode; + + + /// \brief the action to perform on encountering an + /// OutOfValidityRange in \ref OutOfValidityHelper + /// + /// This is in addition to possibly setting a selection decoration + /// (if that has been configured. + /// + /// This is not a member enum of \ref OutOfValidityHelper to void + /// problems with member enums in dictionary generation, etc. + + enum class OutOfValidityAction + { + /// \brief print an error message and return a failure status code + /// (triggering an abort) + /// + /// This is currently the default, as it forces users to think + /// about what they want to do with OutOfValidityRange results. + /// That is fairly safe, as most tools don't actually report + /// OutOfValidityRange and we don't want to add a lot of + /// meaningless selection decorations to each object. + ABORT, + + /// \brief print a warning message and return a success status + /// code. + /// + /// This should only be used if OutOfValidity is a *rare* event, + /// or otherwise it will completely clobber the log file. + WARNING, + + /// \brief don't print anything and return success + /// + /// This should (normally) be combined with a selection decoration + /// that records OutOfValidity results, allowing to retrieve that + /// information subsequently. + SILENT + }; + + + + /// \brief a helper to translate a \ref CP::CorrectionCode into a + /// \ref ::StatusCode + /// + /// The prolem is OutOfValidityRange which does not have an + /// equivalent in StatusCode and which does not have a unique, + /// correct handling in all situations. This helper allows to + /// configure a variety of behaviors via properties. + + class OutOfValidityHelper final + { + /// \brief standard constructor + public: + template<typename T> + OutOfValidityHelper (T *owner, const std::string& propertyName = "outOfValidity", + const std::string& propertyDescription = "how to handle out of validity results"); + + + /// \brief standard initialize + public: + ::StatusCode initialize (); + + /// \brief check the correction code and do the proper thing + public: + ::StatusCode check (xAOD::IParticle& particle, + const CP::CorrectionCode& code, + const char *context) const; + + + /// \brief the action to take + private: + unsigned m_action {unsigned (OutOfValidityAction::ABORT)}; + + /// \brief the message stream we use + private: + MsgStream *m_msg {nullptr}; + + /// \brief the accessor if we apply one + private: + std::unique_ptr<ISelectionAccessor> m_accessor; + + /// \brief the decoration name we use (if we have one) + private: + std::string m_decorationName; + + /// \brief whether we have been initialized + /// + /// This is only used in debug mode to indicate a programming + /// fault. Otherwise it is too easy for users to forget to + /// initialize this object. + private: + bool m_isInitialized = false; + + /// \brief helper for message macros + private: + MsgStream& msg( const MSG::Level lvl ) const; + }; + + + + template<typename T> OutOfValidityHelper :: + OutOfValidityHelper (T *owner, const std::string& propertyName, + const std::string& propertyDescription) + : m_msg (&owner->msg()) + { + owner->declareProperty (propertyName, m_action, + propertyDescription); + owner->declareProperty (propertyName + "Deco", m_decorationName, + "decoration to set alongside action described by " + propertyName); + } +} + +/// \brief a helper check macro to work with \ref OutOfValidityHelper +#define ANA_CHECK_CORRECTION(helper,object,expr) \ + { if ((helper).check ((object), (expr), #expr).isFailure()) \ + return StatusCode::FAILURE; } + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorBits.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorBits.h new file mode 100644 index 0000000000000000000000000000000000000000..5c5d1df875225a8a4864c9fdf98e04d961d96d3d --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorBits.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SELECTION_HELPERS__SELECTION_ACCESSOR_BITS_H +#define SELECTION_HELPERS__SELECTION_ACCESSOR_BITS_H + +#include <SelectionHelpers/ISelectionAccessor.h> + +namespace CP +{ + /// \brief the \ref SelectionAccesor for standard CP algorithm + /// selection decorations encoded as bits + + class SelectionAccessorBits final : public ISelectionAccessor + { + // + // public interface + // + + public: + SelectionAccessorBits (const std::string& name); + + public: + virtual SelectionType + getBits (const SG::AuxElement& element) const override; + + public: + virtual void setBits (SG::AuxElement& element, + SelectionType selection) const override; + + public: + virtual bool + getBool (const SG::AuxElement& element) const override; + + public: + virtual void setBool (SG::AuxElement& element, + bool selection) const override; + + public: + virtual std::string label () const override; + + + // + // private interface + // + + /// \brief the underlying accessor + private: + SG::AuxElement::Accessor<SelectionType> m_accessor; + + /// \brief the underlying accessor + private: + SG::AuxElement::ConstAccessor<SelectionType> m_constAccessor; + + /// \brief the label of the accessor + private: + std::string m_label; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorChar.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorChar.h new file mode 100644 index 0000000000000000000000000000000000000000..8d9fe03c329b4c6224df8acdf93527213ea56945 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorChar.h @@ -0,0 +1,65 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SELECTION_HELPERS__SELECTION_ACCESSOR_OR_H +#define SELECTION_HELPERS__SELECTION_ACCESSOR_OR_H + +#include <SelectionHelpers/ISelectionAccessor.h> + +namespace CP +{ + /// \brief the \ref SelectionAccesor for OR tool selection + /// decorations + + class SelectionAccessorChar final : public ISelectionAccessor + { + // + // public interface + // + + public: + SelectionAccessorChar (const std::string& name); + + public: + virtual SelectionType + getBits (const SG::AuxElement& element) const override; + + public: + virtual void setBits (SG::AuxElement& element, + SelectionType selection) const override; + + public: + virtual bool + getBool (const SG::AuxElement& element) const override; + + public: + virtual void setBool (SG::AuxElement& element, + bool selection) const override; + + public: + virtual std::string label () const override; + + + // + // private interface + // + + /// \brief th underlying accessor + private: + SG::AuxElement::Accessor<char> m_accessor; + + /// \brief th underlying accessor + private: + SG::AuxElement::ConstAccessor<char> m_constAccessor; + + /// \brief the label of the accessor + private: + std::string m_label; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorExprBase.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorExprBase.h new file mode 100644 index 0000000000000000000000000000000000000000..46cfcc31f479fc077bda44c0cf1dcf6470be0b13 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorExprBase.h @@ -0,0 +1,29 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SELECTION_HELPERS__SELECTION_ACCESSOR_EXPR_BASE_H +#define SELECTION_HELPERS__SELECTION_ACCESSOR_EXPR_BASE_H + +#include "SelectionHelpers/ISelectionAccessor.h" + +namespace CP { + +/// @brief Serves as the base for a few logical expression classes. +class SelectionAccessorExprBase : public ISelectionAccessor { + // leave getBool pure virtual + // leave label pure virtual + + public: + virtual SelectionType getBits(const SG::AuxElement &element) const override; + + virtual void setBool(SG::AuxElement & /*element*/, + bool /*value*/) const override; + + virtual void setBits(SG::AuxElement & /*element*/, + SelectionType /*selection*/) const override; +}; + +} // namespace CP + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorExprNot.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorExprNot.h new file mode 100644 index 0000000000000000000000000000000000000000..b7464e16c6af53cddb6624daf119b101c0343884 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorExprNot.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SELECTION_HELPERS__SELECTION_ACCESSOR_EXPR_AND_H +#define SELECTION_HELPERS__SELECTION_ACCESSOR_EXPR_AND_H + +#include "SelectionHelpers/SelectionAccessorExprBase.h" + +#include <memory> + +namespace CP { + +/// @brief SelectionAccessor which implements a logical NOT +class SelectionAccessorExprNot : public SelectionAccessorExprBase { + public: + /// @param child The selection accessor that is to be negated + SelectionAccessorExprNot(std::unique_ptr<ISelectionAccessor> child); + + /// @param element AuxElement to evaluate the selection on + /// @return Result of the negated result of @c child + virtual bool getBool(const SG::AuxElement &element) const override; + + /// @return Returns a readable and parseable representation + virtual std::string label() const override; + + private: + std::unique_ptr<ISelectionAccessor> m_child; +}; + + +} // namespace CP + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorExprOr.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorExprOr.h new file mode 100644 index 0000000000000000000000000000000000000000..072ff29819f0fa40330ced18a483065f0d6a16cb --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorExprOr.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SELECTION_HELPERS__SELECTION_ACCESSOR_EXPR_OR_H +#define SELECTION_HELPERS__SELECTION_ACCESSOR_EXPR_OR_H + +#include "SelectionHelpers/SelectionAccessorExprBase.h" + +#include <memory> + +namespace CP { + +/// @brief Implements a SelectionAccessor that performs a binary logical OR +class SelectionAccessorExprOr : public SelectionAccessorExprBase { + public: + /// @param left Left argument to the OR expression + /// @param Right Right argument to the OR expression + SelectionAccessorExprOr(std::unique_ptr<ISelectionAccessor> left, + std::unique_ptr<ISelectionAccessor> right); + + /// @param element AuxElement to evaluate the selection on + /// @return The result of the expression `left OR right` + virtual bool getBool(const SG::AuxElement &element) const override; + + /// @return Returns a readable and parseable representation + virtual std::string label() const override; + + private: + std::unique_ptr<ISelectionAccessor> m_left; + std::unique_ptr<ISelectionAccessor> m_right; +}; + +} // namespace CP + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorInvert.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorInvert.h new file mode 100644 index 0000000000000000000000000000000000000000..abb9c2a09aaf5dce476f58379ce8ff82e34e3874 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorInvert.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SELECTION_HELPERS__SELECTION_ACCESSOR_INVERT_H +#define SELECTION_HELPERS__SELECTION_ACCESSOR_INVERT_H + +#include <SelectionHelpers/ISelectionAccessor.h> + +#include <memory> + +namespace CP +{ + /// \brief the \ref SelectionAccesor for inverting a selection + /// decoration + + class SelectionAccessorInvert final : public ISelectionAccessor + { + // + // public interface + // + + public: + SelectionAccessorInvert (std::unique_ptr<ISelectionAccessor> val_base); + + public: + virtual SelectionType + getBits (const SG::AuxElement& element) const override; + + public: + virtual void setBits (SG::AuxElement& element, + SelectionType selection) const override; + + public: + virtual bool + getBool (const SG::AuxElement& element) const override; + + public: + virtual void setBool (SG::AuxElement& element, + bool selection) const override; + + public: + virtual std::string label () const override; + + + // + // private interface + // + + /// \brief the base selection accessors I invert + private: + std::unique_ptr<ISelectionAccessor> m_base; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorList.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorList.h new file mode 100644 index 0000000000000000000000000000000000000000..900fa820136a9b1dd61ce32a6dfc2c39e0b11fda --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorList.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SELECTION_HELPERS__SELECTION_ACCESSOR_LIST_H +#define SELECTION_HELPERS__SELECTION_ACCESSOR_LIST_H + +#include <SelectionHelpers/ISelectionAccessor.h> + +#include <memory> +#include <vector> + +namespace CP +{ + /// \brief the \ref SelectionAccesor for list of selection + /// decorations + + class SelectionAccessorList final : public ISelectionAccessor + { + // + // public interface + // + + public: + SelectionAccessorList (std::vector<std::unique_ptr<ISelectionAccessor> > val_list); + + public: + virtual SelectionType + getBits (const SG::AuxElement& element) const override; + + public: + virtual void setBits (SG::AuxElement& element, + SelectionType selection) const override; + + public: + virtual bool + getBool (const SG::AuxElement& element) const override; + + public: + virtual void setBool (SG::AuxElement& element, + bool selection) const override; + + public: + virtual std::string label () const override; + + + // + // private interface + // + + /// \brief the list of selection accessors I rely on + private: + std::vector<std::unique_ptr<ISelectionAccessor> > m_list; + + /// \brief the label of the accessor + private: + std::string m_label; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorNull.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorNull.h new file mode 100644 index 0000000000000000000000000000000000000000..08fbe74e243aec05f535e5575ea4361155dfc2da --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionAccessorNull.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SELECTION_HELPERS__SELECTION_ACCESSOR_NULL_H +#define SELECTION_HELPERS__SELECTION_ACCESSOR_NULL_H + +#include <SelectionHelpers/ISelectionAccessor.h> + +namespace CP +{ + /// \brief a \ref SelectionAccesor that can be used instead of a + /// nullptr + /// + /// This makes it easier to set up code that just uses an \ref + /// ISelectionAccessor to preselect its objects, and doesn't want a + /// special code path for the case of no preselections. + + class SelectionAccessorNull final : public ISelectionAccessor + { + // + // public interface + // + + public: + SelectionAccessorNull (bool value = true); + + public: + virtual SelectionType + getBits (const SG::AuxElement& element) const override; + + public: + virtual void setBits (SG::AuxElement& element, + SelectionType selection) const override; + + public: + virtual bool + getBool (const SG::AuxElement& element) const override; + + public: + virtual void setBool (SG::AuxElement& element, + bool selection) const override; + + public: + virtual std::string label () const override; + + + // + // private interface + // + private: + bool m_value; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionExprParser.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionExprParser.h new file mode 100644 index 0000000000000000000000000000000000000000..cd58408031a8dd7f8b00d1e686f607babeba7171 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionExprParser.h @@ -0,0 +1,112 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef SELECTION_HELPERS__SELECTION_EXPR_PARSER_H +#define SELECTION_HELPERS__SELECTION_EXPR_PARSER_H + +#include <boost/tokenizer.hpp> +#include <functional> +#include <memory> +#include <string> + +#include "SelectionHelpers/ISelectionAccessor.h" +#include "SelectionHelpers/SelectionHelpers.h" + +namespace CP { + +// Private detail namespace. This is not strictly private to enable testing +namespace DetailSelectionExprParser { + +/// Separator to be used in a @c boost::tokenizer +class Separator { + public: + /// @brief Extracts the subsequent token from the input string iterator + bool operator()(std::string::const_iterator &next, + const std::string::const_iterator &end, + std::string &tok) const; + + /// @brief Optional state reset method, does nothing. + void reset() {} +}; + +// Typedef over boost's tokenizer using the above Separator +typedef boost::tokenizer<Separator> Tokenizer; + +/// Lexer which turns a token stream into a stream of unambigous symbols to be +/// used by a parser +class Lexer { + public: + /// @brief Constructor from a strig + Lexer(const std::string &s); + + /// Disable copying of this class + Lexer(const Lexer &) = delete; + /// Default move-constructor behaviour + Lexer(Lexer &&) = default; + + /// Enum over the possible symbols that can be extracted from the token + /// stream. + enum Type { + AND = 0, + OR, + LEFT, + RIGHT, + NOT, + TRUE_LITERAL, + FALSE_LITERAL, + VAR, + END + }; + + /// Struct grouping together the type and original string representation + /// of a symbol. + struct Symbol { + Type type; + std::string value; + }; + + /// Generate a new symbol from the token sequence + Symbol nextSymbol(); + + private: + std::string m_string; + Tokenizer m_tokenizer; + Tokenizer::iterator m_iterator; +}; +} // namespace DetailSelectionExprParser + +/// Public interface for the expression parsing facility. +class SelectionExprParser { + public: + /// Constructor for the parser which accepts a @c Lecer + /// @param lexer The lexer to use for parsing + /// @note @c Lexer can be auto-constructed from a string, so you can pass one directly. + /// @param defaultToChar Assume "as_char" as default encoding + SelectionExprParser(DetailSelectionExprParser::Lexer lexer, + bool defaultToChar = false); + + /// Triggers the actual parsing of the expression + /// @param [out] accessor Unique pointer the resulting accessor will be written to. + /// @return StatusCode noting whether the operation succeeded. + StatusCode build(std::unique_ptr<ISelectionAccessor> &accessor); + + private: + // Construct a binary OR + StatusCode expression(std::unique_ptr<ISelectionAccessor> &root); + // Construct an AND, attempts to group all ANDs it can see into a list + StatusCode term(std::unique_ptr<ISelectionAccessor> &root); + // Handle other constructs, potentially more ORs or ANDs. + StatusCode factor(std::unique_ptr<ISelectionAccessor> &root); + + // The lexer to generate symbols from. + DetailSelectionExprParser::Lexer m_lexer; + // The last extracted symbol + DetailSelectionExprParser::Lexer::Symbol m_symbol; + // Stores constructor parameter to be used in calls to makeSelectionAccessorVar. + bool m_defaultToChar; +}; + +} // namespace CP + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionHelpers.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionHelpers.h new file mode 100644 index 0000000000000000000000000000000000000000..c75f7ba99eed885ac220b2f78327ab0d5895f7d1 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionHelpers.h @@ -0,0 +1,61 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SELECTION_HELPERS__SELECTION_HELPERS_H +#define SELECTION_HELPERS__SELECTION_HELPERS_H + +#include <AsgTools/MessageCheck.h> +#include <cstdint> + +namespace Root +{ + class TAccept; +} + +namespace CP +{ + /// \brief the type for selection decorations that are meant to hold + /// a \ref Root::TAccept + /// + /// This is matched to the number of bits in a TAccept, since that + /// holds 32 bits, so do we. + typedef uint32_t SelectionType; + + + /// \brief the selection decoration to apply for objects that are + /// selected + /// + /// This is to be used when making a selection decoration for a + /// single cut and no TAccept object is at hand, as well as to check + /// whether a particular selection passed. + inline constexpr SelectionType selectionAccept () { + return ~SelectionType (0);} + + + /// \brief the selection decoration to apply for objects that are + /// rejected + /// + /// This is to be used when making a selection decoration for a + /// single cut and no TAccept object is at hand. + inline constexpr SelectionType selectionReject () { + return ~SelectionType (1);} + + + /// \brief the selection decoration made from the given boolean + /// (true = accept) + SelectionType selectionFromBool (bool accept); + + + /// \brief the selection decoration made from the given TAccept + /// object + SelectionType selectionFromAccept (const Root::TAccept& accept); + + + ANA_MSG_HEADER (msgSelectionHelpers) +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionHelpersDict.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionHelpersDict.h new file mode 100644 index 0000000000000000000000000000000000000000..ea6e06901e907dae9f03d3d5579b864998959931 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionHelpersDict.h @@ -0,0 +1,14 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SELECTION_HELPERS__SELECTION_HELPERS_DICT_H +#define SELECTION_HELPERS__SELECTION_HELPERS_DICT_H + +#include "SelectionHelpers/ISelectionAccessor.h" +#include "SelectionHelpers/OutOfValidityHelper.h" + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionReadHandle.h b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionReadHandle.h new file mode 100644 index 0000000000000000000000000000000000000000..3ad43fc265e24799bf12a9c7a56857db42b51dc1 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionReadHandle.h @@ -0,0 +1,92 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SELECTION_HELPERS_SELECTION_READ_HANDLE_H +#define SELECTION_HELPERS_SELECTION_READ_HANDLE_H + +#include <AthContainers/AuxElement.h> +#include <AsgTools/MsgStream.h> +#include <memory> + +class StatusCode; + +namespace CP +{ + class ISelectionAccessor; + + /// \brief a data handle for reading selection properties from + /// objects + /// + /// Essentially this is just a wrapper around \ref + /// ISelectionAccessor to make it easier to use in an algorithm. + /// Since we are now using this a lot, it seems like a good idea to + /// streamline this as much as possible. + + class SelectionReadHandle final + { + // + // public interface + // + + /// \brief standard constructor + public: + template<typename T2> + SelectionReadHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription); + + + /// \brief whether we have a name configured + public: + bool empty () const noexcept; + + /// \brief !empty() + public: + explicit operator bool () const noexcept; + + + /// \brief initialize the accessor + public: + StatusCode initialize (); + + + /// \brief get the selection as a bool + public: + bool getBool (const SG::AuxElement& element) const; + + + + // + // private interface + // + + /// \brief the selection we use + private: + std::string m_selection; + + /// \brief the accessor we use + private: + std::unique_ptr<ISelectionAccessor> m_accessor; + + + /// \brief the message stream we use + private: + MsgStream *m_msg {nullptr}; + + /// \brief helper for message macros + private: + MsgStream& msg( ) const; + + /// \brief helper for message macros + private: + MsgStream& msg( const MSG::Level lvl ) const; + }; +} + +#include "SelectionReadHandle.icc" + +#endif diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionReadHandle.icc b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionReadHandle.icc new file mode 100644 index 0000000000000000000000000000000000000000..e6d084e78168c6898dc7ff61c15d27b1e1b7b11d --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/SelectionReadHandle.icc @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SelectionHelpers/ISelectionAccessor.h> + +// +// method implementations +// + +namespace CP +{ + template<typename T2> SelectionReadHandle :: + SelectionReadHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription) + : m_selection (propertyValue) + , m_msg (&owner->msg()) + { + owner->declareProperty (propertyName, m_selection, propertyDescription); + } + + + + inline bool SelectionReadHandle :: + getBool (const SG::AuxElement& element) const + { + assert (m_accessor); + return m_accessor->getBool (element); + } +} diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/selection.xml b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..9f977b4433e0f347dd67f96c5dd8e6a6706ab5b9 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/SelectionHelpers/selection.xml @@ -0,0 +1,6 @@ +<lcgdict> + + <class name="CP::ISelectionAccessor" /> + <class name="CP::OutOfValidityAction" /> + +</lcgdict> diff --git a/PhysicsAnalysis/Algorithms/SelectionHelpers/test/gt_ISelectionAccessor.cxx b/PhysicsAnalysis/Algorithms/SelectionHelpers/test/gt_ISelectionAccessor.cxx new file mode 100644 index 0000000000000000000000000000000000000000..58b44391d3888f147cfae218c8ef6f5590f0e7b1 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SelectionHelpers/test/gt_ISelectionAccessor.cxx @@ -0,0 +1,541 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <SelectionHelpers/ISelectionAccessor.h> +#include <SelectionHelpers/SelectionAccessorChar.h> +#include <SelectionHelpers/SelectionAccessorBits.h> +#include <SelectionHelpers/SelectionAccessorList.h> +#include <SelectionHelpers/SelectionAccessorNull.h> +#include <AsgTools/MessageCheck.h> +#include <AsgTesting/UnitTest.h> +#include <xAODJet/Jet.h> +#include <gtest/gtest.h> +#include "SelectionHelpers/SelectionExprParser.h" + +// +// unit test +// + +namespace CP +{ + TEST (ISelectionAccessorTest, all_tests) + { + auto jet = std::make_unique<xAOD::Jet> (); + jet->makePrivateStore(); + + // check a basic char accessor + std::unique_ptr<ISelectionAccessor> accA; + ASSERT_SUCCESS (makeSelectionAccessor ("a,as_char", accA)); + auto* selA = dynamic_cast<SelectionAccessorChar*>(accA.get()); + // check that this is actually nothing but a simple char accessor + EXPECT_NE(selA, nullptr); + accA->setBool (*jet, false); + EXPECT_EQ (jet->auxdata<char> ("a"), 0); + accA->setBool (*jet, true); + EXPECT_EQ (jet->auxdata<char> ("a"), 1); + accA->setBits (*jet, selectionReject()); + EXPECT_EQ (jet->auxdata<char> ("a"), 0); + accA->setBits (*jet, selectionAccept()); + EXPECT_EQ (jet->auxdata<char> ("a"), 1); + + // check an implicit char accessor + std::unique_ptr<ISelectionAccessor> accB; + ASSERT_SUCCESS (makeSelectionAccessor ("b", accB, true)); + accB->setBool (*jet, false); + EXPECT_EQ (jet->auxdata<char> ("b"), 0); + accB->setBool (*jet, true); + EXPECT_EQ (jet->auxdata<char> ("b"), 1); + + // check a basic bits accessor + std::unique_ptr<ISelectionAccessor> accC; + ASSERT_SUCCESS (makeSelectionAccessor ("c,as_bits", accC)); + // check that this is actually nothing but a simple bits accessor + auto* selC = dynamic_cast<SelectionAccessorBits*>(accC.get()); + EXPECT_NE(selC, nullptr); + accC->setBool (*jet, false); + EXPECT_EQ (jet->auxdata<SelectionType> ("c"), selectionReject()); + accC->setBool (*jet, true); + EXPECT_EQ (jet->auxdata<SelectionType> ("c"), selectionAccept()); + accC->setBits (*jet, selectionReject()); + EXPECT_EQ (jet->auxdata<SelectionType> ("c"), selectionReject()); + accC->setBits (*jet, selectionAccept()); + EXPECT_EQ (jet->auxdata<SelectionType> ("c"), selectionAccept()); + + // check an implicit bits accessor + std::unique_ptr<ISelectionAccessor> accD; + ASSERT_SUCCESS (makeSelectionAccessor ("d", accD, false)); + accD->setBool (*jet, false); + EXPECT_EQ (jet->auxdata<SelectionType> ("d"), selectionReject()); + accD->setBool (*jet, true); + EXPECT_EQ (jet->auxdata<SelectionType> ("d"), selectionAccept()); + + // check an and of two accessors + std::unique_ptr<ISelectionAccessor> accAnd; + ASSERT_SUCCESS (makeSelectionAccessor ("a,as_char&&b,as_char", accAnd)); + accA->setBool (*jet, true); + accB->setBool (*jet, true); + EXPECT_TRUE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)0); + accA->setBool (*jet, false); + accB->setBool (*jet, true); + EXPECT_FALSE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)1); + accA->setBool (*jet, true); + accB->setBool (*jet, false); + EXPECT_FALSE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)2); + accA->setBool (*jet, false); + accB->setBool (*jet, false); + EXPECT_FALSE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)3); + + // check AND of three accessors + ASSERT_SUCCESS (makeSelectionAccessor ("a,as_char&&b,as_char&&c,as_bits", accAnd)); + auto* selAnd = dynamic_cast<SelectionAccessorList*>(accAnd.get()); + EXPECT_NE(selAnd, nullptr); + + accA->setBool (*jet, true); + accB->setBool (*jet, true); + accC->setBool (*jet, true); + EXPECT_TRUE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)0); + + accA->setBool (*jet, false); + accB->setBool (*jet, true); + accC->setBool (*jet, true); + EXPECT_FALSE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)1); + + accA->setBool (*jet, true); + accB->setBool (*jet, false); + accC->setBool (*jet, true); + EXPECT_FALSE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)2); + + accA->setBool (*jet, false); + accB->setBool (*jet, false); + accC->setBool (*jet, true); + EXPECT_FALSE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)3); + + accA->setBool (*jet, true); + accB->setBool (*jet, true); + accC->setBool (*jet, false); + EXPECT_FALSE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)4); + + accA->setBool (*jet, false); + accB->setBool (*jet, true); + accC->setBool (*jet, false); + EXPECT_FALSE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)5); + + accA->setBool (*jet, true); + accB->setBool (*jet, false); + accC->setBool (*jet, false); + EXPECT_FALSE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)6); + + accA->setBool (*jet, false); + accB->setBool (*jet, false); + accC->setBool (*jet, false); + EXPECT_FALSE (accAnd->getBool (*jet)); + EXPECT_EQ (accAnd->getBits (*jet), ~(SelectionType)7); + + // check an OR of two accessors + std::unique_ptr<ISelectionAccessor> accOr; + ASSERT_SUCCESS (makeSelectionAccessor ("a,as_char||b,as_char", accOr)); + accA->setBool (*jet, false); + accB->setBool (*jet, true); + EXPECT_TRUE (accOr->getBool (*jet)); + EXPECT_EQ (accOr->getBits (*jet), selectionAccept()); + accA->setBool (*jet, true); + accB->setBool (*jet, false); + EXPECT_TRUE (accOr->getBool (*jet)); + EXPECT_EQ (accOr->getBits (*jet), selectionAccept()); + accA->setBool (*jet, false); + accB->setBool (*jet, false); + EXPECT_FALSE (accOr->getBool (*jet)); + EXPECT_EQ (accOr->getBits (*jet), selectionReject()); + + std::unique_ptr<ISelectionAccessor> accEx; + ASSERT_SUCCESS (makeSelectionAccessor ("a,as_char||(b,as_char && c,as_bits)", accEx)); + accA->setBool (*jet, true); + accB->setBool (*jet, true); + accC->setBool (*jet, true); + EXPECT_TRUE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionAccept()); + accA->setBool (*jet, false); + accB->setBool (*jet, true); + accC->setBool (*jet, true); + EXPECT_TRUE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionAccept()); + accA->setBool (*jet, false); + accB->setBool (*jet, false); + accC->setBool (*jet, true); + EXPECT_FALSE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionReject()); + accA->setBool (*jet, false); + accB->setBool (*jet, true); + accC->setBool (*jet, false); + EXPECT_FALSE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionReject()); + accA->setBool (*jet, false); + accB->setBool (*jet, false); + accC->setBool (*jet, false); + EXPECT_FALSE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionReject()); + accA->setBool (*jet, true); + accB->setBool (*jet, false); + accC->setBool (*jet, false); + EXPECT_TRUE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionAccept()); + + ASSERT_SUCCESS (makeSelectionAccessor ("a,as_char||(b,as_char && !c,as_bits)", accEx)); + accA->setBool (*jet, true); + accB->setBool (*jet, true); + accC->setBool (*jet, false); + EXPECT_TRUE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionAccept()); + accA->setBool (*jet, false); + accB->setBool (*jet, true); + accC->setBool (*jet, false); + EXPECT_TRUE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionAccept()); + accA->setBool (*jet, false); + accB->setBool (*jet, false); + accC->setBool (*jet, false); + EXPECT_FALSE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionReject()); + accA->setBool (*jet, false); + accB->setBool (*jet, true); + accC->setBool (*jet, true); + EXPECT_FALSE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionReject()); + accA->setBool (*jet, false); + accB->setBool (*jet, false); + accC->setBool (*jet, true); + EXPECT_FALSE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionReject()); + accA->setBool (*jet, true); + accB->setBool (*jet, false); + accC->setBool (*jet, true); + EXPECT_TRUE (accEx->getBool (*jet)); + EXPECT_EQ (accEx->getBits (*jet), selectionAccept()); + + + // test that an empty string produces a SelectionAccessorNull(true) + std::unique_ptr<ISelectionAccessor> accEmpty; + ASSERT_SUCCESS (makeSelectionAccessor ("", accEmpty)); + auto accNull = dynamic_cast<SelectionAccessorNull*>(accEmpty.get()); + EXPECT_NE (accNull, nullptr); // is in fact a null accessor + // can either be true or false, let's test that it is true + EXPECT_TRUE (accEmpty->getBool (*jet)); + + } + + TEST (SelectionExprParser, tokenizer) { + using tok = DetailSelectionExprParser::Tokenizer; + + std::string s = "A && B"; + tok tokens(s, {}); + auto it = tokens.begin(); + EXPECT_EQ(*(it++), "A"); + EXPECT_EQ(*(it++), "&&"); + EXPECT_EQ(*(it++), "B"); + + s = "A&&B"; + tokens = tok{s, {}}; + it = tokens.begin(); + EXPECT_EQ(*(it++), "A"); + EXPECT_EQ(*(it++), "&&"); + EXPECT_EQ(*(it++), "B"); + + s = "( alpha || gamma) &beta "; + tokens = tok{s, {}}; + it = tokens.begin(); + EXPECT_EQ(*(it++), "("); + EXPECT_EQ(*(it++), "alpha"); + EXPECT_EQ(*(it++), "||"); + EXPECT_EQ(*(it++), "gamma"); + EXPECT_EQ(*it, ")"); + EXPECT_THROW(it++, std::runtime_error); + + s = "a|b"; + tokens = tok{s, {}}; + it = tokens.begin(); + EXPECT_EQ(*it, "a"); + EXPECT_THROW(it++, std::runtime_error); + + s = "( alpha || gamma) &&beta "; + tokens = tok{s, {}}; + it = tokens.begin(); + EXPECT_EQ(*(it++), "("); + EXPECT_EQ(*(it++), "alpha"); + EXPECT_EQ(*(it++), "||"); + EXPECT_EQ(*(it++), "gamma"); + EXPECT_EQ(*(it++), ")"); + EXPECT_EQ(*(it++), "&&"); // & not a token: considered part of variable + EXPECT_EQ(*(it++), "beta"); + + } + + TEST (SelectionExprParser, lexer) { + using lexer = DetailSelectionExprParser::Lexer; + using type = lexer::Type; + + lexer::Symbol s; + { + lexer lex("A&&B"); + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "A"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::AND); + EXPECT_EQ(s.value, "&&"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "B"); + } + + { + std::string str = "alpha,as_bits && beta,as_char"; + lexer lex{str}; + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "alpha,as_bits"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::AND); + EXPECT_EQ(s.value, "&&"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "beta,as_char"); + } + + + { + std::string str = "alpha,as_bits&&beta,as_char"; + lexer lex{str}; + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "alpha,as_bits"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::AND); + EXPECT_EQ(s.value, "&&"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "beta,as_char"); + } + + { + std::string str = "alpha,as_bits || beta,as_char"; + lexer lex{str}; + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "alpha,as_bits"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::OR); + EXPECT_EQ(s.value, "||"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "beta,as_char"); + } + + + { + std::string str = "alpha,as_bits||beta,as_char"; + lexer lex{str}; + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "alpha,as_bits"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::OR); + EXPECT_EQ(s.value, "||"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "beta,as_char"); + } + + { + std::string str = "alpha,as_bits||(beta,as_char &&!gamma,as_bits)"; + lexer lex{str}; + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "alpha,as_bits"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::OR); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::LEFT); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "beta,as_char"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::AND); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::NOT); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::VAR); + EXPECT_EQ(s.value, "gamma,as_bits"); + + s = lex.nextSymbol(); + EXPECT_EQ(s.type, type::RIGHT); + } + } + + TEST (SelectionExprParser, parser) { + auto parse = [](std::string s) -> std::string { + SelectionExprParser p(s, true); + std::unique_ptr<ISelectionAccessor> acc; + if(!p.build(acc).isSuccess()) { + ADD_FAILURE() << "unable to parse expression"; + } + return acc->label(); + }; + + std::string s; + // this asserts the tree structure + s = parse("A&&(C||!B)"); + EXPECT_EQ(s, "( A && ( C || !B ) )"); + // and this asserts the label output can be parse again, + // leading to the exact same expression + EXPECT_EQ(parse(s), s); + + s = parse("A&&(C||!(B&&true))"); + EXPECT_EQ(s, "( A && ( C || !( B && true ) ) )"); + EXPECT_EQ(parse(s), s); + + s = parse("alpha && ( beta || ! gamma )"); + EXPECT_EQ(s, "( alpha && ( beta || !gamma ) )"); + EXPECT_EQ(parse(s), s); + + s = parse(" alpha&&beta || !gamma "); + EXPECT_EQ(s, "( ( alpha && beta ) || !gamma )"); + EXPECT_EQ(parse(s), s); + + s = parse(" (alpha&&beta) || !gamma "); + EXPECT_EQ(s, "( ( alpha && beta ) || !gamma )"); + EXPECT_EQ(parse(s), s); + + s = parse(" A && B && C && D"); + EXPECT_EQ(s, "( A && B && C && D )"); + EXPECT_EQ(parse(s), s); + + + EXPECT_THROW(parse("alpha &&"), std::runtime_error); + EXPECT_THROW(parse("&&"), std::runtime_error); + EXPECT_THROW(parse("&& alpha"), std::runtime_error); + EXPECT_THROW(parse("alpha ||"), std::runtime_error); + EXPECT_THROW(parse("||"), std::runtime_error); + EXPECT_THROW(parse("|| alpha"), std::runtime_error); + EXPECT_THROW(parse("(alpha && beta || gamma"), std::runtime_error); + EXPECT_THROW(parse("alpha && beta) || gamma"), std::runtime_error); + EXPECT_THROW(parse("!"), std::runtime_error); + EXPECT_THROW(parse("alpha !"), std::runtime_error); + EXPECT_THROW(parse("()"), std::runtime_error); + EXPECT_THROW(parse(")"), std::runtime_error); + EXPECT_THROW(parse("("), std::runtime_error); + } + + TEST (SelectionExprParser, evaluate) { + auto mkex = [](const std::string& s) { + SelectionExprParser p(s, true); + std::unique_ptr<ISelectionAccessor> acc; + if(!p.build(acc).isSuccess()) { + ADD_FAILURE() << "unable to parse expression"; + } + return acc; + }; + + auto jet_ptr = std::make_unique<xAOD::Jet> (); + auto& jet = *jet_ptr; + jet.makePrivateStore(); + + xAOD::Jet::Decorator<char> alpha("alpha"); + xAOD::Jet::Decorator<char> beta("beta"); + xAOD::Jet::Decorator<char> gamma("gamma"); + + { + + std::string s = "alpha && ( beta || ! gamma )"; + auto ex = mkex(s); + + alpha(jet) = true; + beta(jet) = true; + gamma(jet) = true; + EXPECT_EQ(ex->getBool(jet), true); + + alpha(jet) = false; + EXPECT_EQ(ex->getBool(jet), 0); + + alpha(jet) = true; + beta(jet) = false; + EXPECT_EQ(ex->getBool(jet), 0); + + gamma(jet) = false; + EXPECT_EQ(ex->getBool(jet), 1); + } + { + std::string s = "true||(alpha && ( beta || ! gamma ))"; + auto ex = mkex(s); + + EXPECT_TRUE(ex->getBool(jet)); + + alpha(jet) = false; + EXPECT_TRUE(ex->getBool(jet)); + + alpha(jet) = true; + beta(jet) = false; + EXPECT_TRUE(ex->getBool(jet)); + + gamma(jet) = false; + EXPECT_TRUE(ex->getBool(jet)); + } + { + auto ex = mkex("true"); + EXPECT_TRUE(ex->getBool(jet)); + + ex = mkex("false"); + EXPECT_FALSE(ex->getBool(jet)); + + ex = mkex("true && false"); + EXPECT_FALSE(ex->getBool(jet)); + + ex = mkex("true || false"); + EXPECT_TRUE(ex->getBool(jet)); + + ex = mkex("true && !false"); + EXPECT_TRUE(ex->getBool(jet)); + + ex = mkex("!true && !false"); + EXPECT_FALSE(ex->getBool(jet)); + + } + } +} + +ATLAS_GOOGLE_TEST_MAIN diff --git a/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/CMakeLists.txt b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ff41deca6757173eaef0d86abb266ac79bf563c7 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/CMakeLists.txt @@ -0,0 +1,36 @@ + +# Set the name of the package: +atlas_subdir( StandaloneAnalysisAlgorithms ) + +# Check that this is a standalone release: +if( NOT XAOD_STANDALONE ) + message( WARNING "This package is only meant for standalone releases" ) + return() +endif() + +# Set the package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Control/xAODRootAccess + PhysicsAnalysis/Algorithms/SystematicsHandles + PhysicsAnalysis/D3PDTools/AnaAlgorithm + PRIVATE + Control/AthContainers + PhysicsAnalysis/D3PDTools/EventLoop ) + +# External(s): +find_package( ROOT COMPONENTS Core RIO ) + +# Set up the main library: +atlas_add_library( StandaloneAnalysisAlgorithmsLib + StandaloneAnalysisAlgorithms/*.h Root/*.cxx + PUBLIC_HEADERS StandaloneAnalysisAlgorithms + LINK_LIBRARIES xAODRootAccess SystematicsHandlesLib AnaAlgorithmLib + PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainers EventLoop ) + +# Set up a dictionary: +atlas_add_dictionary( StandaloneAnalysisAlgorithmsDict + StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithmsDict.h + StandaloneAnalysisAlgorithms/selection.xml + LINK_LIBRARIES StandaloneAnalysisAlgorithmsLib ) diff --git a/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/README.md b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/README.md new file mode 100644 index 0000000000000000000000000000000000000000..866f31f8a482324a01bce80cd494f802d011f508 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/README.md @@ -0,0 +1,9 @@ +# Standalone Analysis Algorithms + +This package collects code/algorithms that are only relevant for standalone +analysis releases. So they wouldn't need to be compiled in Athena based +releases. + +Current algorithm(s) in the package: + - [CP::xAODWriterAlg](StandaloneAnalysisAlgorithms/xAODWriterAlg.h): + Algorithm for writing mini-xAOD files as the output of analysis jobs. diff --git a/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/Root/xAODWriterAlg.cxx b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/Root/xAODWriterAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ae74459e41638f063e9c2e3ea68df98102e37c91 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/Root/xAODWriterAlg.cxx @@ -0,0 +1,202 @@ +// +// Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +// + +// System include(s): +#include <regex> + +// ROOT include(s): +#include <TClass.h> +#include <TFile.h> + +// Core include(s): +#include "AthContainers/normalizedTypeinfoName.h" +#include "EventLoop/Worker.h" +#include "SystematicsHandles/Helpers.h" + +// Local include(s): +#include "StandaloneAnalysisAlgorithms/xAODWriterAlg.h" + +namespace CP { + + xAODWriterAlg::xAODWriterAlg( const std::string& name, ISvcLocator* svcLoc ) + : EL::AnaAlgorithm( name, svcLoc ) { + + // Declare the algorithm's properties. + declareProperty( "OutputStreamName", m_outputStreamName = "ANALYSIS", + "Stream name of the output file to use" ); + declareProperty( "ItemList", m_itemList, + "Objects to write to the output file" ); + declareProperty( "BasketSize", m_basketSize = 32000, + "(Starter) Basket size for the created branches" ); + declareProperty( "SplitLevel", m_splitLevel = 0, + "Split level for the created branches" ); + } + + StatusCode xAODWriterAlg::initialize() { + + // Make sure that the xAOD::TEvent object managed by EventLoop is the + // "active" one. + evtStore()->event()->setActive(); + + // Set up the systematics list. + ATH_CHECK( m_systematicsList.initialize() ); + + // Access the file of the output stream. + TFile* ofile = wk()->getOutputFile( m_outputStreamName ); + if( ! ofile ) { + ATH_MSG_FATAL( "Couldn't access output file for stream \"" + << m_outputStreamName << "\"" ); + return StatusCode::FAILURE; + } + + // Write to this output file. + ANA_CHECK( m_event.writeTo( ofile ) ); + + // Reset the internal flag(s). + m_itemListInitialized = false; + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode xAODWriterAlg::execute() { + + // If this is the first event, figure out which objects can actually be + // written out. + if( ! m_itemListInitialized ) { + ANA_CHECK( setup() ); + m_itemListInitialized = true; + } + + // Write all objects to the output file. + xAOD::TEvent* event = evtStore()->event(); + for( const Item& item : m_writtenItemList ) { + + // Get the object. See the description in @c xAOD::TEvent::retrieve + // (the const version) for an explanation of this implementation. + static const bool SILENT = true; + static const bool METADATA = false; + const void* obj = event->getOutputObject( item.name, *( item.type ), + METADATA ); + if( ! obj ) { + obj = event->getInputObject( item.name, *( item.type ), SILENT, + METADATA ); + } else { + event->getInputObject( item.name, *( item.type ), SILENT, + METADATA ); + } + + // Check that we succeeded. + if( ! obj ) { + ATH_MSG_FATAL( "Couldn't retrieve object \"" << item.name << "\"" ); + return StatusCode::FAILURE; + } + + // Record it to the output for the current event. + ANA_CHECK( m_event.record( const_cast< void* >( obj ), item.typeName, + item.name, m_basketSize, m_splitLevel ) ); + } + + // Write the event. + if( m_event.fill() <= 0 ) { + ATH_MSG_FATAL( "There was an error writing out the event" ); + return StatusCode::FAILURE; + } + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode xAODWriterAlg::finalize() { + + // Access the file of the output stream. + TFile* ofile = wk()->getOutputFile( m_outputStreamName ); + if( ! ofile ) { + ATH_MSG_FATAL( "Couldn't access output file for stream \"" + << m_outputStreamName << "\"" ); + return StatusCode::FAILURE; + } + + // Finish writing to this output file. + ANA_CHECK( m_event.finishWritingTo( ofile ) ); + + // Return gracefully. + return StatusCode::SUCCESS; + } + + StatusCode xAODWriterAlg::setup() { + + // Loop over all of the declared items. + for( const std::string& stringItem : m_itemList ) { + + // Interpret the item string. + static const std::regex itemRegex( "([^#]+)#([^\\.]+\\.?)(.*)" ); + std::smatch itemMatch; + if( ! std::regex_match( stringItem, itemMatch, itemRegex ) ) { + ATH_MSG_FATAL( "Item \"" << stringItem + << "\" is not of the form: \"Type#Name\"" ); + return StatusCode::FAILURE; + } + ATH_MSG_VERBOSE( "Found item: " << itemMatch[ 1 ] << "#" + << itemMatch[ 2 ] << itemMatch[ 3 ] ); + + // Consider all systematics. Not usin CP::SysListHandle::foreach, to + // be able to exit the for-loop early if necessary. + auto sysVector = m_systematicsList.systematicsVector(); + for( const auto& sys : sysVector ) { + + // Event store key for the object under consideration. + const std::string key = makeSystematicsName( itemMatch[ 2 ], sys ); + + // Whether or not the object will be available, as long as + // variable selection rules were set up for it, let xAOD::TEvent + // know about them. + if( itemMatch[ 3 ] != "" ) { + ATH_MSG_DEBUG( "Calling setAuxItemList( \"" << key << "\"" + << ", \"" << itemMatch[ 3 ] + << "\" )" ); + m_event.setAuxItemList( key, itemMatch[ 3 ] ); + } + + // Construct an Item object. + Item item; + item.name = key; + TClass* cl = TClass::GetClass( itemMatch[ 1 ].str().c_str() ); + if( ! cl ) { + ATH_MSG_FATAL( "Type \"" << itemMatch[ 1 ] << "\" not found" ); + return StatusCode::FAILURE; + } + item.type = cl->GetTypeInfo(); + if( ! item.type ) { + ATH_MSG_FATAL( "No compiled dictionary found for \"" + << itemMatch[ 1 ] << "\"" ); + return StatusCode::FAILURE; + } + item.typeName = SG::normalizedTypeinfoName( *( item.type ) ); + + // Check if the item is available. + static const bool SILENT = true; + static const bool METADATA = false; + xAOD::TEvent* event = evtStore()->event(); + if( event->getOutputObject( item.name, *( item.type ), METADATA ) || + event->getInputObject( item.name, *( item.type ), SILENT, + METADATA ) ) { + m_writtenItemList.push_back( item ); + ATH_MSG_DEBUG( "Scheduling \"" << itemMatch[ 1 ] << "#" + << key << "\" for writing" ); + } + + // If there was no %SYS% pattern in the object name, stop the loop + // over the systematics now. + if( key == itemMatch[ 2 ] ) { + break; + } + } + } + + // Return gracefully. + return StatusCode::SUCCESS; + } + +} // namespace CP diff --git a/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithmsDict.h b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithmsDict.h new file mode 100644 index 0000000000000000000000000000000000000000..0fad3aeb3153c93849a857e5b81b259b4834b551 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithmsDict.h @@ -0,0 +1,11 @@ +// Dear emacs, this is -*- c++ -*- +// +// Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +// +#ifndef STANDALONEANALYSISALGORITHMS_STANDALONEANALYSISALGORITHMSDICT_H +#define STANDALONEANALYSISALGORITHMS_STANDALONEANALYSISALGORITHMSDICT_H + +// Local include(s): +#include "StandaloneAnalysisAlgorithms/xAODWriterAlg.h" + +#endif // STANDALONEANALYSISALGORITHMS_STANDALONEANALYSISALGORITHMSDICT_H diff --git a/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithms/selection.xml b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithms/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..073de929384c57dfbffdf09ba40ca49693669739 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithms/selection.xml @@ -0,0 +1,7 @@ +<!-- Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration --> +<lcgdict> + + <!-- Algorithm(s): --> + <class name="CP::xAODWriterAlg" /> + +</lcgdict> diff --git a/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithms/xAODWriterAlg.h b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithms/xAODWriterAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..2be743298f94f86255598a2990a0a657027395c9 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/StandaloneAnalysisAlgorithms/StandaloneAnalysisAlgorithms/xAODWriterAlg.h @@ -0,0 +1,92 @@ +// Dear emacs, this is -*- c++ -*- +// +// Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +// +#ifndef STANDALONEANALYSISALGORITHMS_XAODWRITERALG_H +#define STANDALONEANALYSISALGORITHMS_XAODWRITERALG_H + +// System include(s): +#include <string> +#include <vector> +#include <typeinfo> + +// Core include(s): +#include "AnaAlgorithm/AnaAlgorithm.h" +#include "SystematicsHandles/SysListHandle.h" +#include "xAODRootAccess/TEvent.h" + +namespace CP { + + /// Algorithm writing an xAOD output file + /// + /// This algorithm is meant to be used to write mini-xAOD output files from + /// analysis jobs. Similar to how such a file could be written using an + /// Athena job. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + class xAODWriterAlg final : public EL::AnaAlgorithm { + + public: + /// Algorithm constructor + xAODWriterAlg( const std::string& name, ISvcLocator* svcLoc ); + + /// @name Function(s) inherited from @c EL::AnaAlgorithm + /// @{ + + /// Function initialising the algorithm + StatusCode initialize() override; + + /// Function executing the algorithm + StatusCode execute() override; + + /// Function finalising the algorithm + StatusCode finalize() override; + + /// @} + + private: + /// Function setting up the algorithm while processing the first event + StatusCode setup(); + + /// @name Algorithm properties + /// @{ + + /// Name of the output stream to write to + std::string m_outputStreamName; + /// Item list to write to the output file + std::vector< std::string > m_itemList; + + /// (Starter) Basket size for the created branches + int m_basketSize; + /// Split level for the created branches + int m_splitLevel; + + /// @} + + /// Helper struct + struct Item { + /// Name of the written object + std::string name; + /// Type of the written object + const std::type_info* type; + /// Type name of the written object + std::string typeName; + }; // struct Item + + /// Object to write the output file with + xAOD::TEvent m_event; + + /// Internal flag + bool m_itemListInitialized = false; + /// Item list being written after the first event + std::vector< Item > m_writtenItemList; + + /// The systematic list to consider during execution + SysListHandle m_systematicsList{ this }; + + }; // class xAODWriterAlg + +} // namespace CP + +#endif // STANDALONEANALYSISALGORITHMS_XAODWRITERALG_H diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/CMakeLists.txt b/PhysicsAnalysis/Algorithms/SystematicsHandles/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6fa55968831c29fa603107f3f8d099f5268dcbb2 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/CMakeLists.txt @@ -0,0 +1,58 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +atlas_subdir( SystematicsHandles ) + +atlas_depends_on_subdirs( + PUBLIC + Control/AthContainers + Control/AthToolSupport/AsgTools + PhysicsAnalysis/AnalysisCommon/PATInterfaces + PhysicsAnalysis/D3PDTools/AnaAlgorithm + Event/xAOD/xAODBase + Event/xAOD/xAODCore + Event/xAOD/xAODEventInfo + PRIVATE + Control/xAODRootAccess + Event/xAOD/xAODJet + Event/xAOD/xAODMuon + Event/xAOD/xAODEgamma + Event/xAOD/xAODTau + PhysicsAnalysis/D3PDTools/RootCoreUtils ) + +atlas_add_library( SystematicsHandlesLib + SystematicsHandles/*.h SystematicsHandles/*.icc Root/*.cxx + PUBLIC_HEADERS SystematicsHandles + LINK_LIBRARIES AsgTools PATInterfaces AnaAlgorithmLib xAODBase xAODCore AthContainers xAODEventInfo + PRIVATE_LINK_LIBRARIES RootCoreUtils + xAODJet xAODMuon xAODEgamma xAODTau ) + +atlas_add_test( cc_SysReadHandle + SOURCES test/cc_SysReadHandle.cxx + LINK_LIBRARIES AsgTools AnaAlgorithmLib SystematicsHandlesLib ) + +atlas_add_test( cc_SysCopyHandle + SOURCES test/cc_SysCopyHandle.cxx + LINK_LIBRARIES AsgTools AnaAlgorithmLib xAODEventInfo xAODJet + SystematicsHandlesLib ) + +if( XAOD_STANDALONE ) + atlas_add_test( ut_CopyHelpers + SOURCES test/ut_CopyHelpers.cxx + LINK_LIBRARIES xAODRootAccess AsgTools xAODBase xAODJet + SystematicsHandlesLib ) +endif() + +atlas_add_test( cc_SysWriteHandle + SOURCES test/cc_SysWriteHandle.cxx + LINK_LIBRARIES AsgTools AnaAlgorithmLib SystematicsHandlesLib ) + +atlas_add_test( cc_SysListHandle + SOURCES test/cc_SysListHandle.cxx + LINK_LIBRARIES AsgTools AnaAlgorithmLib SystematicsHandlesLib ) + +atlas_add_test( cc_SysDecorationHandle + SOURCES test/cc_SysDecorationHandle.cxx + LINK_LIBRARIES AsgTools AnaAlgorithmLib SystematicsHandlesLib ) diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/CopyHelpers.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/CopyHelpers.cxx new file mode 100644 index 0000000000000000000000000000000000000000..91520513e1911f1dd759e4395db96152d872314b --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/CopyHelpers.cxx @@ -0,0 +1,69 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/CopyHelpers.h> + +#include <xAODEgamma/PhotonContainer.h> +#include <xAODEgamma/ElectronContainer.h> +#include <xAODJet/JetContainer.h> +#include <xAODMuon/MuonContainer.h> +#include <xAODTau/TauJetContainer.h> +#include <xAODTracking/TrackParticleContainer.h> + +// +// method implementations +// + +namespace CP +{ + namespace detail + { + StatusCode ShallowCopy<xAOD::IParticleContainer> :: + getCopy (MsgStream& msgStream, StoreType& store, + xAOD::IParticleContainer*& object, + const xAOD::IParticleContainer *inputObject, + const std::string& outputName, const std::string& auxName) + { + // this is probably not the best way to do this, but doing this + // the proper way will require an xAOD expert to do it. + + // Set up a lambda for providing a msg(...) function. + const auto msg = [&] (MSG::Level lvl) -> MsgStream& {msgStream << lvl; return msgStream;}; + + // using a macro is a bit awkward, but doing this as a template + // is not practical either +#define COPY(TYPE) \ + do { \ + const TYPE *in = dynamic_cast< const TYPE* >( inputObject ); \ + if( in ) { \ + TYPE *out = nullptr; \ + ANA_CHECK( ShallowCopy<TYPE>::getCopy( msgStream, store, out, in, \ + outputName, auxName ) ); \ + object = out; \ + return StatusCode::SUCCESS; \ + } \ + } while( false ) + + COPY( xAOD::JetContainer ); + COPY( xAOD::MuonContainer ); + COPY( xAOD::ElectronContainer ); + COPY( xAOD::PhotonContainer ); + COPY( xAOD::TauJetContainer ); + COPY(xAOD::TrackParticleContainer); + +#undef COPY + + ANA_MSG_ERROR ("could not determine type to create shallow copy " << outputName); + ANA_MSG_ERROR ("please extend CopyHelpers.cxx with the appropriate type"); + return StatusCode::FAILURE; + } + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/Helpers.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/Helpers.cxx new file mode 100644 index 0000000000000000000000000000000000000000..64e25257586b14a32fc6bec187390f036848b8e4 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/Helpers.cxx @@ -0,0 +1,56 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/Helpers.h> + +#include <RootCoreUtils/StringUtil.h> +#include <PATInterfaces/SystematicSet.h> +#include <regex> + +// +// method implementations +// + +namespace CP +{ + std::string nominalSystematicsName () + { + return "NOSYS"; + } + + + + std::string makeSystematicsName (const std::string& name, + const CP::SystematicSet& sys) + { + std::string sysName = sys.name(); + if (sysName.empty()) + sysName = nominalSystematicsName(); + return RCU::substitute (name, "%SYS%", sysName); + } + + + + std::string makeSystematicsName (const std::string& name, + const std::string& affecting, + const CP::SystematicSet& sys) + { + CP::SystematicSet mysys; + std::regex expr (affecting); + + for (auto& var : sys) + { + if (regex_match (var.basename(), expr)) + mysys.insert (var); + } + return makeSystematicsName (name, mysys); + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/ISysHandleBase.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/ISysHandleBase.cxx new file mode 100644 index 0000000000000000000000000000000000000000..67a269319eb27130b7f62c7ae61536b6f9d23d41 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/ISysHandleBase.cxx @@ -0,0 +1,20 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/ISysHandleBase.h> + +// +// method implementations +// + +namespace CP +{ +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysFilterReporter.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysFilterReporter.cxx new file mode 100644 index 0000000000000000000000000000000000000000..602f2d290aec669302f8c550177e70792f5267ce --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysFilterReporter.cxx @@ -0,0 +1,67 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/SysFilterReporter.h> + +#include <SystematicsHandles/SysFilterReporterCombiner.h> +#include <SystematicsHandles/SysFilterReporterParams.h> +#include <AsgMessaging/MessageCheck.h> + +// +// method implementations +// + +namespace CP +{ + SysFilterReporter :: + SysFilterReporter (SysFilterReporterCombiner& val_combiner, + const SystematicSet& val_sys) + : AsgMessagingForward (&val_combiner) + , m_combiner (val_combiner) + , m_sys (val_sys) + , m_passed (val_combiner.m_passedDefault) + { + ANA_CHECK_THROW (val_combiner.m_params.m_eventInfoHandle.getCopy (m_eventInfo, m_sys)); + } + + + + SysFilterReporter :: + ~SysFilterReporter () noexcept + { + ANA_MSG_DEBUG ("setting systematics-filter-passed flag to " << m_passed << " for " << m_sys.name()); + if (m_passed) + m_combiner.m_passedOne = true; + else + m_combiner.m_passedAll = false; + // decorate event info + m_combiner.m_params.m_eventDecisionOutputDecoration.set (*m_eventInfo, m_passed, m_sys); + + // only recording nominal event selection for now + if (m_passed && m_sys.empty()) + m_combiner.m_params.m_passedNominal += 1; + +#ifndef XAOD_STANDALONE + // only recording nominal event selection for now + if (m_passed && m_sys.empty() && m_combiner.m_params.m_cutID != 0) + m_combiner.m_params.m_cutFlowSvc->addEvent (m_combiner.m_params.m_cutID); +#endif + } + + + + void SysFilterReporter :: + setPassed (bool val_passed) noexcept + { + ANA_MSG_DEBUG ("change systematics-filter-passed flag to " << m_passed << " for " << m_sys.name()); + m_passed = val_passed; + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysFilterReporterCombiner.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysFilterReporterCombiner.cxx new file mode 100644 index 0000000000000000000000000000000000000000..eff665d98c889e94531beb14a19757f318e36c58 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysFilterReporterCombiner.cxx @@ -0,0 +1,54 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/SysFilterReporterCombiner.h> + +#include <SystematicsHandles/SysFilterReporterParams.h> +#include <AsgMessaging/MessageCheck.h> +#include <exception> + +// +// method implementations +// + +namespace CP +{ + SysFilterReporterCombiner :: + SysFilterReporterCombiner (SysFilterReporterParams& val_params, + SysListHandle& systematicsList, + bool val_passedDefault) + : AsgMessagingForward (&val_params) + , m_params (val_params) + , m_passedDefault (val_passedDefault) + { + if (!m_params.m_isInitialized) + { + ANA_MSG_FATAL ("using uninitialized SysFilterReporterParams, throwing exception"); + throw std::logic_error ("using uninitialized SysFilterReporterParams"); + } + + ANA_CHECK_THROW (m_params.m_eventDecisionOutputDecoration.preExecute(systematicsList)); + } + + + + SysFilterReporterCombiner :: + ~SysFilterReporterCombiner () noexcept + { + ANA_MSG_DEBUG ("setting algorithm-filter-passed flag to " << m_passedOne); + m_params.m_setFilterPassed (m_passedOne); + m_params.m_total += 1; + if (m_passedOne) + m_params.m_passedOne += 1; + if (m_passedAll) + m_params.m_passedAll += 1; + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysFilterReporterParams.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysFilterReporterParams.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3daac19f9e8efa948e7f58b0559a05e7aaf4534a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysFilterReporterParams.cxx @@ -0,0 +1,71 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/SysFilterReporterParams.h> + +#include <AsgMessaging/MessageCheck.h> +#include <AsgMessaging/StatusCode.h> + +// +// method implementations +// + +namespace CP +{ + StatusCode SysFilterReporterParams :: + initialize () + { + if (m_isInitialized) + { + ANA_MSG_FATAL ("calling initialize twice on SysFilterReporterParams, aborting"); + return StatusCode::FAILURE; + } + + if (m_eventDecisionOutputDecoration.empty()) + { + ANA_MSG_ERROR ("no event filter decoration name set"); + return StatusCode::FAILURE; + } + +#ifndef XAOD_STANDALONE + if (!m_cutFlowSvc.empty()) + { + ANA_CHECK (m_cutFlowSvc.retrieve()); + m_cutID = m_cutFlowSvc->registerFilter (m_cutFlowSvc.parentName(), m_filterDescription + " (nominal only)"); + if (m_cutID == 0) + { + ANA_MSG_ERROR ("problem registering myself with cutflow-svc"); + return StatusCode::FAILURE; + } + } +#endif + + m_isInitialized = true; + return StatusCode::SUCCESS; + } + + + + StatusCode SysFilterReporterParams :: + finalize () + { + if (!m_isInitialized) + { + ANA_MSG_FATAL ("using unitialized SysFilterReporterParams, aborting"); + return StatusCode::FAILURE; + } + + ATH_MSG_INFO ("Events passing selection for at least one systematic: " << m_passedOne << " / " << m_total << " for " << m_filterDescription); + ATH_MSG_INFO ("Events passing selection for at nominal: " << m_passedNominal << " / " << m_total << " for " << m_filterDescription); + ATH_MSG_INFO ("Events passing selection for all systematics: " << m_passedAll << " / " << m_total << " for " << m_filterDescription); + return StatusCode::SUCCESS; + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysListHandle.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysListHandle.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ccd200164bc7c0d63bc160d19b8689f570932a72 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysListHandle.cxx @@ -0,0 +1,135 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/SysListHandle.h> + +#include <AsgTools/MessageCheck.h> +#include <AsgTools/StatusCode.h> +#include <PATInterfaces/SystematicSet.h> +#include <SystematicsHandles/ISysHandleBase.h> +#include <regex> + +#include <stdexcept> + +// +// method implementations +// + +namespace CP +{ + void SysListHandle :: + addHandle (ISysHandleBase& handle) + { + assert (!isInitialized()); + m_sysHandles.push_back (&handle); + } + + + + StatusCode SysListHandle :: + addAffectingSystematics (const CP::SystematicSet& affectingSystematics) + { + assert (!isInitialized()); + bool failures = false; + std::regex expr (m_affectingRegex); + for (const CP::SystematicVariation& sys : affectingSystematics) + { + if (!regex_match (sys.basename(), expr)) + { + ANA_MSG_ERROR ("algorithm reports affecting systematic " << sys << " which doesn't match user supplied pattern " << m_affectingRegex); + failures = true; + } + } + if (failures) + return StatusCode::FAILURE; + return StatusCode::SUCCESS; + } + + + + ::StatusCode SysListHandle :: + initialize () + { + m_evtStore = m_evtStoreGetter(); + m_isInitialized = true; + return StatusCode::SUCCESS; + } + + + + std::unordered_set<CP::SystematicSet> SysListHandle :: + systematicsVector () + { + assert (isInitialized()); + + if (m_fullAffecting.empty()) + { + std::string affecting = m_affectingRegex; + for (ISysHandleBase *handle : m_sysHandles) + { + std::string subAffecting = handle->getInputAffecting (); + if (!subAffecting.empty()) + { + if (!affecting.empty()) + affecting += "|"; + affecting += subAffecting; + } + } + if (affecting.empty()) + affecting = "^$"; + m_fullAffecting = std::move (affecting); + } + + const SysListType *systematicsList = nullptr; + ANA_CHECK_THROW (m_evtStore->retrieve (systematicsList, m_systematicsListName)); + + std::unordered_set<CP::SystematicSet> mysysList; + for (const auto& sys : *systematicsList) + { + auto iter = m_affectingCache.find (sys); + if (iter != m_affectingCache.end()) + { + mysysList.insert (iter->second); + } else + { + CP::SystematicSet mysys; + std::regex affecting (m_fullAffecting); + + for (const CP::SystematicVariation& subsys : sys) + { + if (regex_match (subsys.basename(),affecting)) + mysys.insert (subsys); + } + m_affectingCache.insert (std::make_pair (sys, mysys)); + mysysList.insert (mysys); + } + } + return mysysList; + } + + + + StatusCode SysListHandle :: + foreach (const std::function<StatusCode(const CP::SystematicSet&)>& func) + { + assert (isInitialized()); + + for (const CP::SystematicSet& sys : systematicsVector()) + { + if (func (sys).isFailure()) + { + ANA_MSG_ERROR ("failed to evaluate algorithm for systematic " << sys.name()); + return StatusCode::FAILURE; + } + } + return StatusCode::SUCCESS; + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysListType.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysListType.cxx new file mode 100644 index 0000000000000000000000000000000000000000..c352f7aff01b453f98f6f12b628bf67d3b3ea633 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/Root/SysListType.cxx @@ -0,0 +1,27 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/SysListType.h> + +#include <string> + +// +// method implementations +// + +namespace CP +{ + const std::string& sysListDefaultName () + { + static const std::string result = "systematics"; + return result; + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/CopyHelpers.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/CopyHelpers.h new file mode 100644 index 0000000000000000000000000000000000000000..c2eb45959410e9c270828132d1dc2da2ae38582f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/CopyHelpers.h @@ -0,0 +1,315 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SYSTEMATICS_HANDLES__COPY_HELPERS_H +#define SYSTEMATICS_HANDLES__COPY_HELPERS_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/MessageCheck.h> +#include <AsgTools/StatusCode.h> +#include <xAODBase/IParticleContainer.h> +#include <xAODBase/IParticleHelpers.h> +#include <xAODCore/ShallowCopy.h> + +#include <memory> + +namespace CP +{ + namespace detail + { + /// \brief check what kind of object/container the argument is + template <typename T> + struct ContainerType + { + template <class, class> class checker; + + template <typename C> + static std::true_type test_iparticle(checker<C, decltype((*(const xAOD::IParticle**)nullptr) = ((C*)nullptr)->at(0))> *); + + template <typename C> + static std::false_type test_iparticle(...); + + template <typename C> + static std::true_type test_container(checker<C, decltype((*(const SG::AuxVectorBase**)nullptr) = ((C*)nullptr))>*); + + template <typename C> + static std::false_type test_container(...); + + /// Value evaluating to: + /// - 1 for xAOD::IParticleContainer types; + /// - 2 for other DataVector types; + /// - 3 for non-vector types. + static const int value = ( std::is_same< std::true_type, decltype( test_iparticle< T >( nullptr ) ) >::value ? + 1 : ( std::is_same< std::true_type, decltype( test_container< T >( nullptr ) ) >::value ? + 2 : 3 ) ); + }; + + /// \brief a helper class to create shallow copies and register + /// them in the event store + /// + /// The main purpose of this class is to make it (fairly) + /// straightforward to do partial specializations for base classes + /// which need special handling to register their objects with the + /// correct type. + template<typename T, int type = ContainerType<T>::value> + struct ShallowCopy + { + static_assert ((type==1)||(type==2)||(type==3), + "Type can not be shallow copied"); + }; + + template<typename T> + struct ShallowCopy<T,1> + { + /// \brief the type of the event store we use + public: + typedef std::decay<decltype(*((EL::AnaAlgorithm*)0)->evtStore())>::type + StoreType; + + static StatusCode + getCopy (MsgStream& msgStream, StoreType& store, + T*& object, const T *inputObject, + const std::string& outputName, const std::string& auxName) + { + // Define the msg(...) function as a lambda. + const auto msg = [&] (MSG::Level lvl) -> MsgStream& {msgStream << lvl; + return msgStream;}; + + // Make sure that we get a valid pointer. + assert (inputObject != nullptr); + + // Handle the case when the input object is a view container. + if( ! inputObject->getConstStore() ) { + + // Decide how to handle the container. + if( inputObject->size() ) { + // Get the pointer to the "owning container" from the first + // element. + const T* originContainer = + dynamic_cast< const T* >( ( *inputObject )[ 0 ]->container() ); + // Make sure that every element in the view container has the same + // parent. + for( size_t i = 1; i < inputObject->size(); ++i ) { + if( ( *inputObject )[ i ]->container() != originContainer ) { + ANA_MSG_ERROR( "Not all elements of the received view " + "container come from the same container!" ); + return StatusCode::FAILURE; + } + } + // Postfix for the shallow-copy container of the origin container. + static const char* ORIGIN_POSTFIX = "_ShallowCopyOrigin"; + // Make a shallow copy of the origin container. + auto originCopy = xAOD::shallowCopyContainer( *originContainer ); + if( ( ! originCopy.first ) || ( ! originCopy.second ) ) { + ANA_MSG_ERROR( "Failed to shallow copy the origin of a view " + << "container, meant for: " << outputName ); + return StatusCode::FAILURE; + } + // ...and record it. + ANA_CHECK( store.record( originCopy.first, + outputName + ORIGIN_POSTFIX ) ); + ANA_CHECK( store.record( originCopy.second, + outputName + ORIGIN_POSTFIX + "Aux." ) ); + // Make a view copy on top of it. + auto viewCopy = std::make_unique< T >( SG::VIEW_ELEMENTS ); + auto viewCopyPtr = viewCopy.get(); + for( const auto* element : *inputObject ) { + viewCopy->push_back( originCopy.first->at( element->index() ) ); + } + // Set the origin links on it. Note that + // xAOD::setOriginalObjectLink's "container version" doesn't work + // with view containers, we have to call this function one-by-one + // on the elements. + for( size_t i = 0; i < inputObject->size(); ++i ) { + if( ! xAOD::setOriginalObjectLink( *( ( *inputObject )[ i ] ), + *( ( *viewCopy )[ i ] ) ) ) { + return StatusCode::FAILURE; + } + } + // Finally, record the view container with the requested name. + ANA_CHECK( store.record( viewCopy.release(), outputName ) ); + // The copy is done. + object = viewCopyPtr; + return StatusCode::SUCCESS; + } else { + // If the container was empty, then let's just make a new empty + // container, and that's that... + auto viewCopy = std::make_unique< T >( SG::VIEW_ELEMENTS ); + auto viewCopyPtr = viewCopy.get(); + ANA_CHECK( store.record( viewCopy.release(), outputName ) ); + // The copy is done. + object = viewCopyPtr; + return StatusCode::SUCCESS; + } + + } else { + + // We can just copy the container as is. + auto copy = xAOD::shallowCopyContainer( *inputObject ); + if (!copy.first || !copy.second) + { + ANA_MSG_ERROR ("failed to shallow copy object: " << outputName); + ANA_MSG_ERROR ("likely shallow copying a view container"); + return StatusCode::FAILURE; + } + + if (!xAOD::setOriginalObjectLink (*inputObject, *copy.first)) { + return StatusCode::FAILURE; + } + + ANA_CHECK (store.record (copy.second, auxName)); + ANA_CHECK (store.record (copy.first, outputName)); + object = copy.first; + return StatusCode::SUCCESS; + } + } + }; + + template<typename T> + struct ShallowCopy<T,2> + { + /// \brief the type of the event store we use + public: + typedef std::decay<decltype(*((EL::AnaAlgorithm*)0)->evtStore())>::type + StoreType; + + static StatusCode + getCopy (MsgStream& msgStream, StoreType& store, + T*& object, const T *inputObject, + const std::string& outputName, const std::string& auxName) + { + // Define the msg(...) function as a lambda. + const auto msg = [&] (MSG::Level lvl) -> MsgStream& {msgStream << lvl; + return msgStream;}; + + // Make sure that we get a valid pointer. + assert (inputObject != nullptr); + + // Handle the case when the input object is a view container. + if( ! inputObject->getConstStore() ) { + + // Decide how to handle the container. + if( inputObject->size() ) { + // Get the pointer to the "owning container" from the first + // element. + const T* originContainer = + dynamic_cast< const T* >( ( *inputObject )[ 0 ]->container() ); + // Make sure that every element in the view container has the same + // parent. + for( size_t i = 1; i < inputObject->size(); ++i ) { + if( ( *inputObject )[ i ]->container() != originContainer ) { + ANA_MSG_ERROR( "Not all elements of the received view " + "container come from the same container!" ); + return StatusCode::FAILURE; + } + } + // Postfix for the shallow-copy container of the origin container. + static const char* ORIGIN_POSTFIX = "_ShallowCopyOrigin"; + // Make a shallow copy of the origin container. + auto originCopy = xAOD::shallowCopyContainer( *originContainer ); + if( ( ! originCopy.first ) || ( ! originCopy.second ) ) { + ANA_MSG_ERROR( "Failed to shallow copy the origin of a view " + << "container, meant for: " << outputName ); + return StatusCode::FAILURE; + } + // ...and record it. + ANA_CHECK( store.record( originCopy.first, + outputName + ORIGIN_POSTFIX ) ); + ANA_CHECK( store.record( originCopy.second, + outputName + ORIGIN_POSTFIX + + "Aux." ) ); + // Make a view copy on top of it. + auto viewCopy = std::make_unique< T >( SG::VIEW_ELEMENTS ); + auto viewCopyPtr = viewCopy.get(); + for( const auto* element : *inputObject ) { + viewCopy->push_back( originCopy.first->at( element->index() ) ); + } + // Finally, record the view container with the requested name. + ANA_CHECK( store.record( viewCopy.release(), outputName ) ); + // The copy is done. + object = viewCopyPtr; + return StatusCode::SUCCESS; + } else { + // If the container was empty, then let's just make a new empty + // container, and that's that... + auto viewCopy = std::make_unique< T >( SG::VIEW_ELEMENTS ); + auto viewCopyPtr = viewCopy.get(); + ANA_CHECK( store.record( viewCopy.release(), outputName ) ); + // The copy is done. + object = viewCopyPtr; + return StatusCode::SUCCESS; + } + + } else { + + // We can just copy the container as is. + auto copy = xAOD::shallowCopyContainer( *inputObject ); + if (!copy.first || !copy.second) + { + ANA_MSG_ERROR ("failed to shallow copy object: " << outputName); + ANA_MSG_ERROR ("likely shallow copying a view container"); + return StatusCode::FAILURE; + } + + ANA_CHECK (store.record (copy.second, auxName)); + ANA_CHECK (store.record (copy.first, outputName)); + object = copy.first; + return StatusCode::SUCCESS; + } + } + }; + + template<typename T> + struct ShallowCopy<T,3> + { + /// \brief the type of the event store we use + public: + typedef std::decay<decltype(*((EL::AnaAlgorithm*)0)->evtStore())>::type + StoreType; + + static StatusCode + getCopy (MsgStream& msgStream, StoreType& store, + T*& object, const T *inputObject, + const std::string& outputName, const std::string& auxName) + { + // Define the msg(...) function as a lambda. + const auto msg = [&] (MSG::Level lvl) -> MsgStream& {msgStream << lvl; + return msgStream;}; + + // We can just copy the object as is. + auto copy = xAOD::shallowCopyObject( *inputObject ); + if (!copy.first || !copy.second) + { + ANA_MSG_ERROR ("failed to shallow copy object: " << outputName); + ANA_MSG_ERROR ("likely shallow copying a view container"); + return StatusCode::FAILURE; + } + + ANA_CHECK (store.record (copy.second, auxName)); + ANA_CHECK (store.record (copy.first, outputName)); + object = copy.first; + return StatusCode::SUCCESS; + } + }; + + template<> + struct ShallowCopy<xAOD::IParticleContainer> + { + /// \brief the type of the event store we use + public: + typedef std::decay<decltype(*((EL::AnaAlgorithm*)0)->evtStore())>::type StoreType; + + static StatusCode + getCopy (MsgStream& msgStream, StoreType& store, + xAOD::IParticleContainer*& object, + const xAOD::IParticleContainer *inputObject, + const std::string& outputName, const std::string& auxName); + }; + } +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/Helpers.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/Helpers.h new file mode 100644 index 0000000000000000000000000000000000000000..702564bf452c0c16bf56e43eb36aaed2f0998b5f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/Helpers.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SYSTEMATICS_HANDLES__HELPERS_H +#define SYSTEMATICS_HANDLES__HELPERS_H + +#include <string> + +namespace CP +{ + class SystematicSet; + + /// \brief nominal systematics name + std::string nominalSystematicsName (); + + + /// \brief make the name for the given systematics + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + std::string makeSystematicsName (const std::string& name, + const CP::SystematicSet& sys); + + + /// \brief make the name for the given systematics, filtered for + /// the given affecting pattern + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory II + std::string makeSystematicsName (const std::string& name, + const std::string& affecting, + const CP::SystematicSet& sys); +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/ISysHandleBase.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/ISysHandleBase.h new file mode 100644 index 0000000000000000000000000000000000000000..8aeb9efaa51d833324d62f1a623ab97075acf90e --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/ISysHandleBase.h @@ -0,0 +1,40 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SYSTEMATICS_HANDLES__I_SYS_HANDLE_BASE_H +#define SYSTEMATICS_HANDLES__I_SYS_HANDLE_BASE_H + +#include <string> + +namespace CP +{ + /// \brief a basic interface for all systematics handles + /// + /// This is used by \ref SysListHandle to communicate with the + /// individual data handles. + + class ISysHandleBase + { + /// \brief standard (virtual) destructor + public: + virtual ~ISysHandleBase () noexcept = default; + + /// \brief get the regular expression for the affecting + /// systematics if this is an input handle + /// + /// This returns the empty string if this is either not an input + /// handle, or if the input handle is not affected by systematics. + /// + /// This should only be called inside execute(), not initialize(), + /// to allow upgrades to reading the affecting systematics from + /// the event store. + public: + virtual std::string getInputAffecting () const = 0; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysCopyHandle.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysCopyHandle.h new file mode 100644 index 0000000000000000000000000000000000000000..7f7e5f62705e922410d366cb6ead68fe31ecf60b --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysCopyHandle.h @@ -0,0 +1,110 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SYSTEMATICS_HANDLES__SYS_COPY_HANDLE_H +#define SYSTEMATICS_HANDLES__SYS_COPY_HANDLE_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/AsgMessagingForward.h> +#include <PATInterfaces/SystematicSet.h> +#include <SystematicsHandles/ISysHandleBase.h> +#include <string> +#include <tuple> +#include <unordered_map> + +class StatusCode; + +namespace CP +{ + class SystematicSet; + + /// \brief a data handle for copying systematics varied input data + + template<typename T> class SysCopyHandle final + : public ISysHandleBase, public asg::AsgMessagingForward + { + // + // public interface + // + + /// \brief standard constructor + public: + template<typename T2> + SysCopyHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription); + + + /// \brief whether we have a name configured + public: + bool empty () const noexcept; + + /// \brief !empty() + public: + explicit operator bool () const noexcept; + + + /// \brief retrieve the object for the given name + public: + ::StatusCode getCopy (T*& object, + const CP::SystematicSet& sys) const; + + + + // + // inherited interface + // + + public: + virtual std::string getInputAffecting () const override; + + + + // + // private interface + // + + /// \brief the input name we use + private: + std::string m_inputName; + + /// \brief the regular expression for affecting systematics + private: + std::string m_affectingRegex {".*"}; + + /// \brief the output name we use + private: + std::string m_outputName; + + /// \brief the cache of names we use + private: + mutable std::unordered_map<CP::SystematicSet,std::tuple<std::string,std::string,std::string> > m_nameCache; + + + /// \brief the type of the event store we use + private: + typedef std::decay<decltype(*((EL::AnaAlgorithm*)0)->evtStore())>::type StoreType; + + /// \brief the event store we use + private: + mutable StoreType *m_evtStore = nullptr; + + /// \brief the function to retrieve the event store + /// + /// This is an std::function to allow the parent to be either a + /// tool or an algorithm. Though we are not really supporting + /// tools as parents when using \ref SysListHandle, so in + /// principle this could be replaced with a pointer to the + /// algorithm instead. + private: + std::function<StoreType*()> m_evtStoreGetter; + }; +} + +#include "SysCopyHandle.icc" + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysCopyHandle.icc b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysCopyHandle.icc new file mode 100644 index 0000000000000000000000000000000000000000..e41dd1c55ca1af023168ac5525cfddab231d3101 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysCopyHandle.icc @@ -0,0 +1,95 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <AsgTools/MessageCheck.h> +#include <SystematicsHandles/CopyHelpers.h> +#include <SystematicsHandles/Helpers.h> + +// +// method implementations +// + +namespace CP +{ + template<typename T> template<typename T2> SysCopyHandle<T> :: + SysCopyHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription) + : AsgMessagingForward (owner), m_inputName (propertyValue) + , m_evtStoreGetter ([owner] () {return &*owner->evtStore();}) + { + owner->declareProperty (propertyName, m_inputName, propertyDescription); + owner->declareProperty (propertyName + "Regex", m_affectingRegex, "affecting systematics for " + propertyDescription); + owner->declareProperty (propertyName + "Out", m_outputName, "name to which to copy " + propertyName); + } + + + + template<typename T> bool SysCopyHandle<T> :: + empty () const noexcept + { + return m_inputName.empty(); + } + + + + template<typename T> SysCopyHandle<T> :: + operator bool () const noexcept + { + return !m_inputName.empty(); + } + + + + template<typename T> ::StatusCode SysCopyHandle<T> :: + getCopy (T*& object, const CP::SystematicSet& sys) const + { + auto cache = m_nameCache.find (sys); + if (cache == m_nameCache.end()) + { + std::string inputName = makeSystematicsName (m_inputName, m_affectingRegex, sys); + std::string outputName = makeSystematicsName (m_outputName, sys); + ANA_MSG_DEBUG ("SysCopyHandle: " << inputName << " -> " << outputName << " (" << sys.name() << ")"); + m_nameCache.insert (std::make_pair (sys, std::make_tuple (inputName, outputName, outputName+"Aux."))); + cache = m_nameCache.find (sys); + assert (cache != m_nameCache.end()); + if (!m_evtStore) + m_evtStore = m_evtStoreGetter(); + } + assert (m_evtStore); + if (std::get<1>(cache->second).empty()) + { + // if no output name is configured, act like an update handle + return m_evtStore->retrieve (object, std::get<0>(cache->second)); + } else + { + // if an output name is configured, retrieve the input object as + // a const object, (shallow) copy it, record the copy and return + // it. + + const T *inputObject = nullptr; + if (m_evtStore->retrieve (inputObject, std::get<0>(cache->second)).isFailure()) + return StatusCode::FAILURE; + + return detail::ShallowCopy<T>::getCopy + (msg(), *m_evtStore, object, inputObject, + std::get<1>(cache->second), std::get<2>(cache->second)); + } + } + + + + template<typename T> std::string SysCopyHandle<T> :: + getInputAffecting () const + { + return m_affectingRegex; + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysDecorationHandle.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysDecorationHandle.h new file mode 100644 index 0000000000000000000000000000000000000000..5c736c3aaf41a9b2b2f690b12a0d018aede58a77 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysDecorationHandle.h @@ -0,0 +1,134 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SYSTEMATICS_HANDLES__SYS_DECORATION_HANDLE_H +#define SYSTEMATICS_HANDLES__SYS_DECORATION_HANDLE_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/AsgMessagingForward.h> +#include <AthContainers/AuxElement.h> +#include <PATInterfaces/SystematicSet.h> +#include <SystematicsHandles/ISysHandleBase.h> +#include <SystematicsHandles/SysListHandle.h> +#include <string> +#include <type_traits> +#include <unordered_map> + +class StatusCode; + +namespace CP +{ + class SystematicSet; + + /// \brief the decoration value to use if there is no valid scale + /// factor decoration + constexpr float invalidScaleFactor () {return -1;} + + /// \brief the decoration value to use if there is no valid + /// efficiency decoration + constexpr float invalidEfficiency () {return -1;} + + + /// \brief a data handle for reading systematics varied input data + + template<typename T> class SysDecorationHandle final + : public ISysHandleBase, public asg::AsgMessagingForward + { + // + // public interface + // + + /// \brief standard constructor + public: + template<typename T2> + SysDecorationHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription); + + + /// \brief register a set of used systematics for in the current + /// execut call (usually obtained from \ref CP::SystListHandle) + public: + StatusCode preExecute (SysListHandle &systematics); + + + /// \brief whether \ref preExecute has been called successfully at least once + public: + bool isPrepared () const noexcept; + + + /// \brief whether we have a name configured + public: + bool empty () const noexcept; + + /// \brief !empty() + public: + explicit operator bool () const noexcept; + + + /// \brief get the name we retrieve from the event store + public: + const std::string& getName (const CP::SystematicSet& sys) const; + + + /// \brief retrieve the object decoration for the given systematic + public: + const T& get (const SG::AuxElement& object, + const CP::SystematicSet& sys) const; + + /// \brief check if the object decoration is available + public: + bool isAvailable (const SG::AuxElement& object, + const CP::SystematicSet& sys) const; + + + /// \brief set the object decoration for the given systematic + public: + void set (SG::AuxElement& object, const T& value, + const CP::SystematicSet& sys) const; + + + + // + // inherited interface + // + + public: + virtual std::string getInputAffecting () const override; + + + + // + // private interface + // + + /// \brief the value of \ref isPrepared + private: + bool m_isPrepared{false}; + + /// \brief the input name we use + private: + std::string m_inputName; + + /// \brief the regular expression for affecting systematics + private: + std::string m_affectingRegex {".*"}; + + /// \brief the cache of names we use + private: + mutable std::unordered_map<CP::SystematicSet,std::tuple<std::string,SG::AuxElement::ConstAccessor<T>,SG::AuxElement::Accessor<T> > > m_dataCache; + + /// \brief get the data for the given systematics + private: + const std::tuple<std::string,SG::AuxElement::ConstAccessor<T>,SG::AuxElement::Accessor<T> >& + getData (const CP::SystematicSet& sys) const; + }; +} + +#include "SysDecorationHandle.icc" + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysDecorationHandle.icc b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysDecorationHandle.icc new file mode 100644 index 0000000000000000000000000000000000000000..13a59deed6ecdfac643b907c3b40cab0634437d8 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysDecorationHandle.icc @@ -0,0 +1,152 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <AsgTools/MessageCheck.h> +#include <AsgTools/StatusCode.h> +#include <SystematicsHandles/Helpers.h> + +#include <regex> + +// +// method implementations +// + +namespace CP +{ + template<typename T> template<typename T2> SysDecorationHandle<T> :: + SysDecorationHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription) + : AsgMessagingForward (owner), m_inputName (propertyValue) + { + owner->declareProperty (propertyName, m_inputName, propertyDescription); + owner->declareProperty (propertyName + "Regex", m_affectingRegex, "affecting systematics for " + propertyDescription); + } + + + + template<typename T> ::StatusCode SysDecorationHandle<T> :: + preExecute (SysListHandle &systematics) + { + if (isPrepared()) + { + return StatusCode::SUCCESS; + } + + ANA_CHECK (systematics.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode + { + getData (sys); + return StatusCode::SUCCESS; + })); + + m_isPrepared = true; + + return StatusCode::SUCCESS; + } + + + + template<typename T> inline bool SysDecorationHandle<T> :: + isPrepared () const noexcept + { + return m_isPrepared; + } + + + + template<typename T> bool SysDecorationHandle<T> :: + empty () const noexcept + { + return m_inputName.empty(); + } + + + + template<typename T> SysDecorationHandle<T> :: + operator bool () const noexcept + { + return !m_inputName.empty(); + } + + + + template<typename T> const std::string& SysDecorationHandle<T> :: + getName (const CP::SystematicSet& sys) const + { + assert (isPrepared()); + + const auto& data = getData (sys); + return std::get<0> (data); + } + + + + template<typename T> const T& SysDecorationHandle<T> :: + get (const SG::AuxElement& object, + const CP::SystematicSet& sys) const + { + assert (isPrepared()); + + const auto& data = getData (sys); + return std::get<1> (data) (object); + } + + + + template<typename T> bool SysDecorationHandle<T> :: + isAvailable (const SG::AuxElement& object, + const CP::SystematicSet& sys) const + { + assert (isPrepared()); + + const auto& data = getData (sys); + return std::get<1> (data).isAvailable(object); + } + + + + template<typename T> void SysDecorationHandle<T> :: + set (SG::AuxElement& object, const T& value, + const CP::SystematicSet& sys) const + { + assert (isPrepared()); + + const auto& data = getData (sys); + std::get<2> (data) (object) = value; + } + + + + template<typename T> std::string SysDecorationHandle<T> :: + getInputAffecting () const + { + return m_affectingRegex; + } + + + + template<typename T> const std::tuple<std::string,SG::AuxElement::ConstAccessor<T>,SG::AuxElement::Accessor<T> >& + SysDecorationHandle<T> :: + getData (const CP::SystematicSet& sys) const + { + auto cache = m_dataCache.find (sys); + if (cache == m_dataCache.end()) + { + std::string newName = makeSystematicsName + (m_inputName, m_affectingRegex, sys); + ANA_MSG_DEBUG ("SysDecorationHandle: " << newName << " (" << sys.name() << ")"); + m_dataCache.insert (std::make_pair (sys, std::make_tuple (newName, newName, newName))); + cache = m_dataCache.find (sys); + assert (cache != m_dataCache.end()); + } + return cache->second; + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysFilterReporter.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysFilterReporter.h new file mode 100644 index 0000000000000000000000000000000000000000..57042a5feccd307a77b4dfdd250610cc2e34a9b1 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysFilterReporter.h @@ -0,0 +1,96 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef SYSTEMATICS_HANDLES__FILTER_REPORTER_H +#define SYSTEMATICS_HANDLES__FILTER_REPORTER_H + +#include <AsgMessaging/AsgMessagingForward.h> +#include <xAODEventInfo/EventInfo.h> + +namespace CP +{ + class SysFilterReporterCombiner; + class SystematicSet; + + /// \brief a systematics aware filter reporter + /// + /// In order to ensure that the filter decision will always be set + /// as part of `execute()`, this reporter class should be used like + /// this: + /// + /// ``` + /// StatusCode Foo::execute() + /// { + /// ... + /// static constexpr bool DEFAULT_DECISION = false; + /// SysFilterReporterCombiner filterCombiner + /// (m_filterParams, m_systematicsList, DEFAULT_DECISION); + /// + /// return m_systematicsList.foreach ([&](const CP::SystematicSet &sys) -> StatusCode { + /// SysFilterReporter filter (filterCombiner, sys); + /// ... + /// filter.setPassed (); + /// return StatusCode::SUCCESS; + /// }); + /// } + /// ``` + + class SysFilterReporter final : public asg::AsgMessagingForward + { + // + // public interface + // + + /// \brief standard constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory I + public: + SysFilterReporter (SysFilterReporterCombiner& val_combiner, + const SystematicSet& val_sys); + + + /// \brief standard destructor + /// \par Guarantee + /// no-fail + public: + ~SysFilterReporter () noexcept; + + + /// \brief report the filter decision + /// \par Guarantee + /// no-fail + public: + void setPassed (bool val_passed = true) noexcept; + + + + // + // private interface + // + + /// \brief the \ref SysFilterReporterParams object + private: + SysFilterReporterCombiner& m_combiner; + + /// \brief the \ref SystematicSet object we use + private: + const SystematicSet& m_sys; + + /// \brief the event info object we are decorating + private: + xAOD::EventInfo *m_eventInfo {nullptr}; + + /// \brief the value of passed we will set + private: + bool m_passed {false}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysFilterReporterCombiner.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysFilterReporterCombiner.h new file mode 100644 index 0000000000000000000000000000000000000000..481ee7be7ca85eedf90f3269e059946abf35d400 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysFilterReporterCombiner.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef SYSTEMATICS_HANDLES__FILTER_REPORTER_COMBINER_H +#define SYSTEMATICS_HANDLES__FILTER_REPORTER_COMBINER_H + +#include <AsgMessaging/AsgMessagingForward.h> + +class EventContext; + +namespace CP +{ + class SysFilterReporterParams; + class SysListHandle; + + + /// \brief a reporter class that combines the filter decisions for + /// all systematics + /// + /// Unlike the non-systematics aware version, when dealing with + /// systematics we need to combine all the individual filter + /// decisions into an overall filter decision for the algorithm, + /// i.e. if and only if the filter decision fails for all + /// systematics we should set filter to failed for the algorithm + /// itself, so that we avoid/skip processing of subsequent + /// algorithms. For details on usage see \ref SysFilterReporter. + + class SysFilterReporterCombiner final : public asg::AsgMessagingForward + { + // + // public interface + // + + /// \brief standard constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory I + public: + SysFilterReporterCombiner (SysFilterReporterParams& val_params, + SysListHandle& systematicsList, + bool val_passedDefault); + + + /// \brief standard destructor + /// \par Guarantee + /// no-fail + public: + ~SysFilterReporterCombiner () noexcept; + + + + // + // private interface + // + + // this class does most of the actual work and acts as accessor to + // our private data members, and needs our internals for that. + friend class SysFilterReporter; + + /// \brief the \ref SysFilterReporterParams object + private: + SysFilterReporterParams& m_params; + + /// \brief the default value of passed we use for each individual reporter + private: + bool m_passedDefault {false}; + + /// \brief whether we passed for at least one/all systematics + private: + bool m_passedOne {false}; + bool m_passedAll {true}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysFilterReporterParams.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysFilterReporterParams.h new file mode 100644 index 0000000000000000000000000000000000000000..f73c74500627915b1ed40e0114053503a95dfda5 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysFilterReporterParams.h @@ -0,0 +1,156 @@ +/* + Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef SYSTEMATICS_HANDLES__FILTER_REPORTER_PARAMS_H +#define SYSTEMATICS_HANDLES__FILTER_REPORTER_PARAMS_H + +#include <AsgMessaging/AsgMessagingForward.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysDecorationHandle.h> +#include <xAODEventInfo/EventInfo.h> +#include <functional> + +#ifndef XAOD_STANDALONE +#include <AthenaKernel/ICutFlowSvc.h> +#include <GaudiKernel/ServiceHandle.h> +#endif + +class StatusCode; + +namespace CP +{ + /// \brief the properties and persistent data for systematics aware + /// filter reporters + /// + /// This is a systematics-aware version of the \ref + /// EL::FilterReporter mechanism. This is somewhat more + /// complicated, since there is per-systematics filter decisions and + /// an overall event-level filter decision, for details see \ref + /// SysFilterReporter. + + class SysFilterReporterParams final : public asg::AsgMessagingForward + { + // + // public interface + // + + /// \brief standard constructor + /// \par Guarantee + /// strong + /// \par Failures + /// out of memory I + public: + template<typename T> + explicit SysFilterReporterParams (T *owner, std::string val_filterDescription); + + + /// \brief do anything we need to do in initialize + /// \par Guarantee + /// strong + /// \par Failures + /// configuration/initialization errors + public: + StatusCode initialize (); + + + /// \brief do anything we need to do in finalize + /// \par Guarantee + /// strong + /// \par Failures + /// finalization errors + public: + StatusCode finalize (); + + + + // + // private interface + // + + // this class does most of the actual work and acts as accessor to + // our private data members, and needs our internals for that. + friend class SysFilterReporterCombiner; + friend class SysFilterReporter; + + /// \brief the function to call setFilterPassed() on the algorithm + /// + /// This is using a `std::function` object, so as to avoid tying + /// this to a particular algorithm class. + private: + std::function<void(bool)> m_setFilterPassed; + + /// \brief the event info we run on + private: + SysCopyHandle<xAOD::EventInfo> m_eventInfoHandle; + + /// \brief the decoration for writing the event decision + private: + SysDecorationHandle<char> m_eventDecisionOutputDecoration; + + /// \brief counter for passed events + private: + unsigned m_passedOne {0}; + unsigned m_passedNominal {0}; + unsigned m_passedAll {0}; + + /// \brief counter for total events + private: + unsigned m_total {0}; + + /// \brief whether the handle was initialized + private: + bool m_isInitialized {false}; + + /// \brief description what this filter does + private: + std::string m_filterDescription; + + +#ifndef XAOD_STANDALONE + + /// \brief the \ref CutIdentifier for this filter algorithm + private: + CutIdentifier m_cutID; + + /// \brief the handle to the service holding tables of cut-flows + /// for filtering algs. + private: + ServiceHandle<ICutFlowSvc> m_cutFlowSvc; + +#endif + }; + + + + // + // inline/template methods + // + + template<typename T> SysFilterReporterParams :: + SysFilterReporterParams (T *owner, std::string val_filterDescription) + : AsgMessagingForward (owner) + , m_setFilterPassed ([owner] (bool val_setFilterPassed) {owner->setFilterPassed (val_setFilterPassed);}) + , m_eventInfoHandle (owner, "eventInfo", "EventInfo", "the event info object to run on") + , m_eventDecisionOutputDecoration (owner, "eventDecisionOutputDecoration", "", "the decoration for the event decision") + , m_filterDescription (std::move (val_filterDescription)) +#ifndef XAOD_STANDALONE + , m_cutFlowSvc ("CutFlowSvc/CutFlowSvc", owner->name()) +#endif + { + owner->declareProperty("FilterDescription", m_filterDescription, + "describe to the cutflowsvc what this filter does."); + +#ifndef XAOD_STANDALONE + owner->declareProperty("CutFlowSvc", m_cutFlowSvc, + "handle to the ICutFlowSvc instance this filtering algorithm" + " will use for building the flow of cuts."); +#endif + } +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysListHandle.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysListHandle.h new file mode 100644 index 0000000000000000000000000000000000000000..53ec9d7a325a7c329637ad0b715b528836274d7a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysListHandle.h @@ -0,0 +1,161 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SYSTEMATICS_HANDLES__SYS_LIST_HANDLE_H +#define SYSTEMATICS_HANDLES__SYS_LIST_HANDLE_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/AsgMessagingForward.h> +#include <PATInterfaces/SystematicSet.h> +#include <SystematicsHandles/SysListType.h> +#include <functional> +#include <string> +#include <vector> +#include <unordered_set> + +class StatusCode; + +namespace CP +{ + class ISysHandleBase; + class SystematicSet; + + /// \brief a class managing the property to configure the list of + /// systematics to process + + class SysListHandle : public asg::AsgMessagingForward + { + // + // public interface + // + + /// \brief standard constructor + public: + template<typename T> + SysListHandle (T *owner, const std::string& propertyName = "systematics", + const std::string& propertyDescription = "list of systematics to evaluate"); + + + /// \brief register an input handle we are using + /// + /// This is currently a no-op, but it could be useful for a + /// variety of future directions we could take the systematics + /// handling. + /// + /// \pre !isInitialized() + public: + void addHandle (ISysHandleBase& handle); + + + /// \brief register a set of affecting variables for the current + /// algorithm (usually obtained from an \ref CP::ISystematicsTool) + /// + /// This is currently a no-op, but it could be useful for a + /// variety of future directions we could take the systematics + /// handling (or at least as a cross check of those). + /// + /// \pre !isInitialized() + public: + StatusCode addAffectingSystematics + (const CP::SystematicSet& affectingSystematics); + + + /// \brief intialize this property + /// + /// This should be called exactly once during initialize of the + /// owning algorithm. + public: + ::StatusCode initialize (); + + + /// \brief whether \ref initialize has been called successfully + public: + bool isInitialized () const noexcept; + + + /// \brief the list of systematics to loop over + public: + std::unordered_set<CP::SystematicSet> systematicsVector (); + + + /// \brief run the function for each systematic + /// + /// This allows to perform some amount of behind-the-scenes + /// optimizations in the future, which hopefully not creating too + /// many issues in the present. + /// + /// Technically this would be slightly more performant as a + /// template, but this is likely not to be an issue, and can still + /// be changed if it ever becomes an issue. + /// + /// Ideally this would be const, but the current version is not + /// thread-safe, so I'd rather not add a const qualifier to it. + /// + /// \par Guarantee + /// basic + /// \par Failures + /// function failures + /// \pre isInitialized() + public: + StatusCode foreach + (const std::function<StatusCode(const CP::SystematicSet&)>& func); + + + + // + // private interface + // + + /// \brief the name under which the systematics list is stored in + /// the event store + private: + std::string m_systematicsListName {"systematics"}; + + /// \brief the regular expression for affecting systematics + private: + std::string m_affectingRegex {"^$"}; + + /// \brief the full affecting systematics including the inputs + private: + std::string m_fullAffecting; + + /// \brief the cache of affecting filtered systematics + private: + std::unordered_map<CP::SystematicSet,CP::SystematicSet> m_affectingCache; + + /// \brief the list of systematics handles we have + private: + std::vector<ISysHandleBase*> m_sysHandles; + + /// \brief the value of \ref isInitialized + private: + bool m_isInitialized = false; + + + /// \brief the type of the event store we use + private: + typedef std::decay<decltype(*((EL::AnaAlgorithm*)0)->evtStore())>::type StoreType; + + /// \brief the event store we use + private: + mutable StoreType *m_evtStore = nullptr; + + /// \brief the function to retrieve the event store + /// + /// This is an std::function to allow the parent to be either a + /// tool or an algorithm. Though we are not really supporting + /// tools as parents when using \ref SysListHandle, so in + /// principle this could be replaced with a pointer to the + /// algorithm instead. + private: + std::function<StoreType*()> m_evtStoreGetter; + }; +} + +#include "SysListHandle.icc" + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysListHandle.icc b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysListHandle.icc new file mode 100644 index 0000000000000000000000000000000000000000..753fc7c9905ec37c860f4d76a4d78c0ba14a5fdf --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysListHandle.icc @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <cassert> + +// +// method implementations +// + +namespace CP +{ + template<typename T> SysListHandle :: + SysListHandle (T *owner, const std::string& propertyName, + const std::string& propertyDescription) + : AsgMessagingForward (owner) + , m_evtStoreGetter ([owner] () {return &*owner->evtStore();}) + { + owner->declareProperty (propertyName, m_systematicsListName, + propertyDescription); + owner->declareProperty (propertyName + "Regex", m_affectingRegex, "affecting systematics for " + propertyDescription); + } + + + + inline bool SysListHandle :: + isInitialized () const noexcept + { + return m_isInitialized; + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysListType.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysListType.h new file mode 100644 index 0000000000000000000000000000000000000000..57f7c8705b4d418d15af1509610130fd27aef766 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysListType.h @@ -0,0 +1,37 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SYSTEMATICS_HANDLES__SYS_LIST_TYPE_H +#define SYSTEMATICS_HANDLES__SYS_LIST_TYPE_H + +#include <string> +#include <vector> +#include <AsgTools/CLASS_DEF.h> + +namespace CP +{ + class SystematicSet; +} + +CLASS_DEF( std::vector<CP::SystematicSet> , 79952367 , 1 ) + +namespace CP +{ + /// \brief the type for the systematics list in the event store + /// + /// For now this is just a vector of SystematicSet, but I made a + /// typedef for this as I am not sure this will necessarily be + /// performant in all situations. This way at least I will get + /// compilation errors if I change it. + typedef std::vector<CP::SystematicSet> SysListType; + + /// \brief the default name for putting the systematics list into + /// the event store + const std::string& sysListDefaultName (); +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandle.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandle.h new file mode 100644 index 0000000000000000000000000000000000000000..ae7c304c77fea2f4a96e6b83e282b833a198a1e1 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandle.h @@ -0,0 +1,111 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SYSTEMATICS_HANDLES__SYS_READ_HANDLE_H +#define SYSTEMATICS_HANDLES__SYS_READ_HANDLE_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/AsgMessagingForward.h> +#include <PATInterfaces/SystematicSet.h> +#include <SystematicsHandles/ISysHandleBase.h> +#include <string> +#include <type_traits> +#include <unordered_map> + +class StatusCode; + +namespace CP +{ + class SystematicSet; + + /// \brief a data handle for reading systematics varied input data + + template<typename T> class SysReadHandle final + : public ISysHandleBase, public asg::AsgMessagingForward + { + // + // public interface + // + + /// \brief standard constructor + public: + template<typename T2> + SysReadHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription); + + + /// \brief whether we have a name configured + public: + bool empty () const noexcept; + + /// \brief !empty() + public: + explicit operator bool () const noexcept; + + + /// \brief get the name we retrieve from the event store + public: + const std::string& getName (const CP::SystematicSet& sys) const; + + + /// \brief retrieve the object for the given name + public: + ::StatusCode retrieve (const T*& object, + const CP::SystematicSet& sys) const; + + + + // + // inherited interface + // + + public: + virtual std::string getInputAffecting () const override; + + + + // + // private interface + // + + /// \brief the input name we use + private: + std::string m_inputName; + + /// \brief the regular expression for affecting systematics + private: + std::string m_affectingRegex {".*"}; + + /// \brief the cache of names we use + private: + mutable std::unordered_map<CP::SystematicSet,std::string> m_inputNameCache; + + + /// \brief the type of the event store we use + private: + typedef std::decay<decltype(*((EL::AnaAlgorithm*)0)->evtStore())>::type StoreType; + + /// \brief the event store we use + private: + mutable StoreType *m_evtStore = nullptr; + + /// \brief the function to retrieve the event store + /// + /// This is an std::function to allow the parent to be either a + /// tool or an algorithm. Though we are not really supporting + /// tools as parents when using \ref SysListHandle, so in + /// principle this could be replaced with a pointer to the + /// algorithm instead. + private: + std::function<StoreType*()> m_evtStoreGetter; + }; +} + +#include "SysReadHandle.icc" + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandle.icc b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandle.icc new file mode 100644 index 0000000000000000000000000000000000000000..690580cc971379baad805984ccf345cc1a4970e9 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandle.icc @@ -0,0 +1,88 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <AsgTools/MessageCheck.h> +#include <AsgTools/StatusCode.h> +#include <SystematicsHandles/Helpers.h> + +// +// method implementations +// + +namespace CP +{ + template<typename T> template<typename T2> SysReadHandle<T> :: + SysReadHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription) + : AsgMessagingForward (owner), m_inputName (propertyValue) + , m_evtStoreGetter ([owner] () {return &*owner->evtStore();}) + { + owner->declareProperty (propertyName, m_inputName, propertyDescription); + owner->declareProperty (propertyName + "Regex", m_affectingRegex, "affecting systematics for " + propertyDescription); + } + + + + template<typename T> bool SysReadHandle<T> :: + empty () const noexcept + { + return m_inputName.empty(); + } + + + + template<typename T> SysReadHandle<T> :: + operator bool () const noexcept + { + return !m_inputName.empty(); + } + + + + template<typename T> const std::string& SysReadHandle<T> :: + getName (const CP::SystematicSet& sys) const + { + auto cache = m_inputNameCache.find (sys); + if (cache == m_inputNameCache.end()) + { + std::string newName = makeSystematicsName + (m_inputName, m_affectingRegex, sys); + ANA_MSG_DEBUG ("SysReadHandle: " << newName << " (" << sys.name() << ")"); + m_inputNameCache.insert (std::make_pair (sys, newName)); + cache = m_inputNameCache.find (sys); + assert (cache != m_inputNameCache.end()); + + // retrieving this here, just so it exists + if (!m_evtStore) + m_evtStore = m_evtStoreGetter(); + } + return cache->second; + } + + + + template<typename T> ::StatusCode SysReadHandle<T> :: + retrieve (const T*& object, const CP::SystematicSet& sys) const + { + const std::string& name = getName (sys); + assert (m_evtStore); + return m_evtStore->retrieve (object, name); + } + + + + template<typename T> std::string SysReadHandle<T> :: + getInputAffecting () const + { + return m_affectingRegex; + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandleArray.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandleArray.h new file mode 100644 index 0000000000000000000000000000000000000000..614541e0cf96dd3da47b3a790266be34487c7985 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandleArray.h @@ -0,0 +1,123 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SYSTEMATICS_HANDLES__SYS_READ_HANDLE_ARRAY_H +#define SYSTEMATICS_HANDLES__SYS_READ_HANDLE_ARRAY_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/AsgMessagingForward.h> +#include <PATInterfaces/SystematicSet.h> +#include <SystematicsHandles/ISysHandleBase.h> +#include <boost/functional/hash.hpp> +#include <string> +#include <type_traits> +#include <unordered_map> + +class StatusCode; + +namespace CP +{ + class SystematicSet; + + /// \brief a data handle for reading systematics varied input data + + template<typename T> class SysReadHandleArray final + : public ISysHandleBase, public asg::AsgMessagingForward + { + // + // public interface + // + + /// \brief standard constructor + public: + template<typename T2> + SysReadHandleArray (T2 *owner, const std::string& propertyName, + const std::string& propertyDescription); + + + /// \brief initialize this data handle + public: + StatusCode initialize (); + + + /// \brief the number of read objects configured + public: + std::size_t size () const noexcept; + + + /// \brief get the name we retrieve from the event store + public: + const std::string& getName (const CP::SystematicSet& sys, + std::size_t index) const; + + + /// \brief retrieve the object for the given name + public: + ::StatusCode retrieve (const T*& object, + const CP::SystematicSet& sys, + std::size_t index) const; + + + + // + // inherited interface + // + + public: + virtual std::string getInputAffecting () const override; + + + + // + // private interface + // + + /// \brief the name of the property we configured + private: + std::string m_propertyName; + + /// \brief whether we have been initialized + private: + bool m_isInitialized {false}; + + + /// \brief the input name we use + private: + std::vector<std::string> m_inputName; + + /// \brief the regular expression for affecting systematics + private: + std::vector<std::string> m_affectingRegex; + + /// \brief the cache of names we use + private: + mutable std::unordered_map<std::pair<CP::SystematicSet,std::size_t>,std::string,boost::hash<std::pair<CP::SystematicSet,std::size_t>>> m_inputNameCache; + + + /// \brief the type of the event store we use + private: + typedef std::decay<decltype(*((EL::AnaAlgorithm*)0)->evtStore())>::type StoreType; + + /// \brief the event store we use + private: + mutable StoreType *m_evtStore = nullptr; + + /// \brief the function to retrieve the event store + /// + /// This is an std::function to allow the parent to be either a + /// tool or an algorithm. Though we are not really supporting + /// tools as parents when using \ref SysListHandle, so in + /// principle this could be replaced with a pointer to the + /// algorithm instead. + private: + std::function<StoreType*()> m_evtStoreGetter; + }; +} + +#include "SysReadHandleArray.icc" + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandleArray.icc b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandleArray.icc new file mode 100644 index 0000000000000000000000000000000000000000..89cbde7909719e76e745ac27a27947b89d8d36fd --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysReadHandleArray.icc @@ -0,0 +1,113 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <AsgTools/MessageCheck.h> +#include <AsgTools/StatusCode.h> +#include <SystematicsHandles/Helpers.h> + +// +// method implementations +// + +namespace CP +{ + template<typename T> template<typename T2> SysReadHandleArray<T> :: + SysReadHandleArray (T2 *owner, const std::string& propertyName, + const std::string& propertyDescription) + : AsgMessagingForward (owner) + , m_propertyName (propertyName) + , m_evtStoreGetter ([owner] () {return &*owner->evtStore();}) + { + owner->declareProperty (propertyName, m_inputName, propertyDescription); + owner->declareProperty (propertyName + "Regex", m_affectingRegex, "affecting systematics for " + propertyDescription); + } + + + + template<typename T> StatusCode SysReadHandleArray<T> :: + initialize () + { + assert (m_isInitialized == false); + if (m_inputName.size() != m_affectingRegex.size()) + { + ANA_MSG_ERROR ("array sizes for property " << m_propertyName << " and " << m_propertyName << "Regex do not match"); + return StatusCode::FAILURE; + } + m_isInitialized = true; + return StatusCode::SUCCESS; + } + + + + template<typename T> std::size_t SysReadHandleArray<T> :: + size () const noexcept + { + assert (m_isInitialized); + return m_inputName.size(); + } + + + + template<typename T> const std::string& SysReadHandleArray<T> :: + getName (const CP::SystematicSet& sys, + std::size_t index) const + { + assert (m_isInitialized); + assert (index < size()); + auto cache = m_inputNameCache.find (std::make_pair (sys, index)); + if (cache == m_inputNameCache.end()) + { + std::string newName = makeSystematicsName + (m_inputName[index], m_affectingRegex[index], sys); + ANA_MSG_DEBUG ("SysReadHandleArray: " << newName << " (" << sys.name() << ")"); + m_inputNameCache.insert (std::make_pair (std::make_pair (sys, index), newName)); + cache = m_inputNameCache.find (std::make_pair (sys, index)); + assert (cache != m_inputNameCache.end()); + + // retrieving this here, just so it exists + if (!m_evtStore) + m_evtStore = m_evtStoreGetter(); + } + return cache->second; + } + + + + template<typename T> ::StatusCode SysReadHandleArray<T> :: + retrieve (const T*& object, const CP::SystematicSet& sys, + std::size_t index) const + { + assert (m_isInitialized); + assert (index < size()); + const std::string& name = getName (sys, index); + assert (m_evtStore); + return m_evtStore->retrieve (object, name); + } + + + + template<typename T> std::string SysReadHandleArray<T> :: + getInputAffecting () const + { + assert (m_isInitialized); + std::string result; + for (const std::string& regex : m_affectingRegex) + { + if (!regex.empty()) + { + if (!result.empty()) + result += "|"; + result += regex; + } + } + return result; + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysWriteHandle.h b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysWriteHandle.h new file mode 100644 index 0000000000000000000000000000000000000000..81d7a20202b29a3f51388592f83c0efd301e94df --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysWriteHandle.h @@ -0,0 +1,164 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef SYSTEMATICS_HANDLES__SYS_WRITE_HANDLE_H +#define SYSTEMATICS_HANDLES__SYS_WRITE_HANDLE_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/AsgMessagingForward.h> +#include <PATInterfaces/SystematicSet.h> +#include <SystematicsHandles/ISysHandleBase.h> +#include <memory> +#include <string> +#include <unordered_map> + +class StatusCode; + +namespace CP +{ + class SystematicSet; + + /// \brief a data handle for writing systematics varied input data + + template<typename T,typename Aux = void> class SysWriteHandle final + : public ISysHandleBase, public asg::AsgMessagingForward + { + // + // public interface + // + + /// \brief standard constructor + public: + template<typename T2> + SysWriteHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription); + + + /// \brief retrieve the object for the given name + public: + ::StatusCode record (std::unique_ptr<T> object, + std::unique_ptr<Aux> aux, + const CP::SystematicSet& sys) const; + + + + // + // inherited interface + // + + public: + virtual std::string getInputAffecting () const override; + + + + // + // private interface + // + + /// \brief the output name we use + private: + std::string m_outputName; + + /// \brief the cache of names we use + private: + mutable std::unordered_map<CP::SystematicSet,std::string> m_outputNameCache; + + + /// \brief the type of the event store we use + private: + typedef std::decay<decltype(*((EL::AnaAlgorithm*)0)->evtStore())>::type StoreType; + + /// \brief the event store we use + private: + mutable StoreType *m_evtStore = nullptr; + + /// \brief the function to retrieve the event store + /// + /// This is an std::function to allow the parent to be either a + /// tool or an algorithm. Though we are not really supporting + /// tools as parents when using \ref SysListHandle, so in + /// principle this could be replaced with a pointer to the + /// algorithm instead. + private: + std::function<StoreType*()> m_evtStoreGetter; + }; + + + + template<typename T> class SysWriteHandle<T,void> final + : public ISysHandleBase, public asg::AsgMessagingForward + { + // + // public interface + // + + /// \brief standard constructor + public: + template<typename T2> + SysWriteHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription); + + + /// \brief get the name we record to the event store + public: + const std::string& getName (const CP::SystematicSet& sys) const; + + + /// \brief record the object for the given systematic + public: + ::StatusCode record (std::unique_ptr<T> object, + const CP::SystematicSet& sys) const; + + + + // + // inherited interface + // + + public: + virtual std::string getInputAffecting () const override; + + + + // + // private interface + // + + /// \brief the output name we use + private: + std::string m_outputName; + + /// \brief the cache of names we use + private: + mutable std::unordered_map<CP::SystematicSet,std::string> m_outputNameCache; + + + /// \brief the type of the event store we use + private: + typedef std::decay<decltype(*((EL::AnaAlgorithm*)0)->evtStore())>::type StoreType; + + /// \brief the event store we use + private: + mutable StoreType *m_evtStore = nullptr; + + /// \brief the function to retrieve the event store + /// + /// This is an std::function to allow the parent to be either a + /// tool or an algorithm. Though we are not really supporting + /// tools as parents when using \ref SysListHandle, so in + /// principle this could be replaced with a pointer to the + /// algorithm instead. + private: + std::function<StoreType*()> m_evtStoreGetter; + }; +} + +#include "SysWriteHandle.icc" + +#endif diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysWriteHandle.icc b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysWriteHandle.icc new file mode 100644 index 0000000000000000000000000000000000000000..74ba4964619dbf002cbfda78d76cc5ce04f47a74 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/SystematicsHandles/SysWriteHandle.icc @@ -0,0 +1,114 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <AsgTools/MessageCheck.h> +#include <SystematicsHandles/Helpers.h> + +// +// method implementations +// + +namespace CP +{ + template<typename T,typename Aux> template<typename T2> SysWriteHandle<T,Aux> :: + SysWriteHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription) + : AsgMessagingForward (owner), m_outputName (propertyValue) + , m_evtStoreGetter ([owner] () {return &*owner->evtStore();}) + { + owner->declareProperty (propertyName, m_outputName, propertyDescription); + } + + + + template<typename T,typename Aux> ::StatusCode SysWriteHandle<T,Aux> :: + record (std::unique_ptr<T> object, std::unique_ptr<Aux> aux, + const CP::SystematicSet& sys) const + { + auto cache = m_outputNameCache.find (sys); + if (cache == m_outputNameCache.end()) + { + std::string newName = makeSystematicsName (m_outputName, sys); + ANA_MSG_DEBUG ("SysWriteHandle: " << newName << " (" << sys.name() << ")"); + m_outputNameCache.insert (std::make_pair (sys, newName)); + cache = m_outputNameCache.find (sys); + assert (cache != m_outputNameCache.end()); + if (!m_evtStore) + m_evtStore = m_evtStoreGetter(); + } + assert (m_evtStore); + if (m_evtStore->record (aux.release(), cache->second + "Aux.").isFailure()) + return StatusCode::FAILURE; + if (m_evtStore->record (object.release(), cache->second).isFailure()) + return StatusCode::FAILURE; + return StatusCode::SUCCESS; + } + + + + template<typename T,typename Aux> std::string SysWriteHandle<T,Aux> :: + getInputAffecting () const + { + return ""; + } + + + + template<typename T> template<typename T2> SysWriteHandle<T,void> :: + SysWriteHandle (T2 *owner, const std::string& propertyName, + const std::string& propertyValue, + const std::string& propertyDescription) + : AsgMessagingForward (owner), m_outputName (propertyValue) + , m_evtStoreGetter ([owner] () {return &*owner->evtStore();}) + { + owner->declareProperty (propertyName, m_outputName, propertyDescription); + } + + + + template<typename T> const std::string& SysWriteHandle<T,void> :: + getName (const CP::SystematicSet& sys) const + { + auto cache = m_outputNameCache.find (sys); + if (cache == m_outputNameCache.end()) + { + std::string newName = makeSystematicsName (m_outputName, sys); + ANA_MSG_DEBUG ("SysWriteHandle: " << newName << " (" << sys.name() << ")"); + m_outputNameCache.insert (std::make_pair (sys, newName)); + cache = m_outputNameCache.find (sys); + assert (cache != m_outputNameCache.end()); + + // retrieving this here, just so that it exists + if (!m_evtStore) + m_evtStore = m_evtStoreGetter(); + } + return cache->second; + } + + + + template<typename T> ::StatusCode SysWriteHandle<T,void> :: + record (std::unique_ptr<T> object, const CP::SystematicSet& sys) const + { + const std::string& name = getName (sys); + assert (m_evtStore); + return m_evtStore->record (object.release(), name); + } + + + + template<typename T> std::string SysWriteHandle<T,void> :: + getInputAffecting () const + { + return ""; + } +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysCopyHandle.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysCopyHandle.cxx new file mode 100644 index 0000000000000000000000000000000000000000..31ed464c6c0bd058fd4010d8f2eb1ec9a587a7ed --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysCopyHandle.cxx @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/SysCopyHandle.h> +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/AsgTool.h> +#include <xAODEventInfo/EventInfo.h> +#include <xAODJet/JetContainer.h> + +// +// test code +// + +// this tries to instantiate the various handles +void test () +{ + CP::SystematicSet *sys = nullptr; + xAOD::EventInfo *object1 = nullptr; + xAOD::JetContainer *object2 = nullptr; + + EL::AnaAlgorithm *alg = nullptr; + CP::SysCopyHandle<xAOD::EventInfo> algHandle (alg, "test", "test", "test"); + algHandle.getCopy (object1, *sys); + + asg::AsgTool *tool = nullptr; + CP::SysCopyHandle<xAOD::JetContainer> toolHandle (tool, "test", "test", "test"); + toolHandle.getCopy (object2, *sys); +} + +int main () +{ + return 0; +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysDecorationHandle.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysDecorationHandle.cxx new file mode 100644 index 0000000000000000000000000000000000000000..08a1b12617bc55ff1a49502ab9064eb2b0bbea93 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysDecorationHandle.cxx @@ -0,0 +1,39 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/SysDecorationHandle.h> +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/AsgTool.h> + +// +// test code +// + +// this tries to instantiate the various handles +void test () +{ + CP::SystematicSet *sys = nullptr; + const SG::AuxElement *constObject = nullptr; + SG::AuxElement *object = nullptr; + + EL::AnaAlgorithm *alg = nullptr; + CP::SysDecorationHandle<float> algHandle (alg, "test", "test", "test"); + float value = algHandle.get (*constObject, *sys); + algHandle.set (*object, value, *sys); + + asg::AsgTool *tool = nullptr; + CP::SysDecorationHandle<float> toolHandle (tool, "test", "test", "test"); +} + +int main () +{ + return 0; +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysListHandle.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysListHandle.cxx new file mode 100644 index 0000000000000000000000000000000000000000..dbcb0acc7d003ee158b12a61e6565b83155036f8 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysListHandle.cxx @@ -0,0 +1,41 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/AsgTool.h> +#include <SystematicsHandles/SysListHandle.h> +#include <SystematicsHandles/SysReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> + +// +// test code +// + +// this tries to instantiate the various templates +void test () +{ + EL::AnaAlgorithm *alg = nullptr; + CP::SysListHandle algProperty (alg); + CP::SysReadHandle<float> algHandle (alg, "test", "test", "test"); + algProperty.addHandle (algHandle); + + // we probably don't want to use SysListHandle with tools, but + // we may as well allow it for now. + asg::AsgTool *tool = nullptr; + CP::SysListHandle toolProperty (tool); + CP::SysReadHandle<float> toolHandle (tool, "test", "test", "test"); + toolProperty.addHandle (toolHandle); +} + +int main () +{ + return 0; +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysReadHandle.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysReadHandle.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8edea9045817d150d1283becb52968136119017c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysReadHandle.cxx @@ -0,0 +1,38 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/SysReadHandle.h> +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/AsgTool.h> + +// +// test code +// + +// this tries to instantiate the various handles +void test () +{ + CP::SystematicSet *sys = nullptr; + const float *object = nullptr; + + EL::AnaAlgorithm *alg = nullptr; + CP::SysReadHandle<float> algHandle (alg, "test", "test", "test"); + algHandle.retrieve (object, *sys); + + asg::AsgTool *tool = nullptr; + CP::SysReadHandle<float> toolHandle (tool, "test", "test", "test"); + toolHandle.retrieve (object, *sys); +} + +int main () +{ + return 0; +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysWriteHandle.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysWriteHandle.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d3454c857f7f57c975103cab07fb20be1e6f0856 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/cc_SysWriteHandle.cxx @@ -0,0 +1,37 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +// +// includes +// + +#include <SystematicsHandles/SysWriteHandle.h> +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgTools/AsgTool.h> + +// +// test code +// + +// this tries to instantiate the various handles +void test () +{ + CP::SystematicSet *sys = nullptr; + + EL::AnaAlgorithm *alg = nullptr; + CP::SysWriteHandle<float> algHandle (alg, "test", "test", "test"); + algHandle.record (std::unique_ptr<float> (), *sys); + + asg::AsgTool *tool = nullptr; + CP::SysWriteHandle<float,double> toolHandle (tool, "test", "test", "test"); + toolHandle.record (std::unique_ptr<float> (), std::unique_ptr<double> (), *sys); +} + +int main () +{ + return 0; +} diff --git a/PhysicsAnalysis/Algorithms/SystematicsHandles/test/ut_CopyHelpers.cxx b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/ut_CopyHelpers.cxx new file mode 100644 index 0000000000000000000000000000000000000000..284efb0108095bb2731cbf369f43e537db8b942f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/SystematicsHandles/test/ut_CopyHelpers.cxx @@ -0,0 +1,117 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +// System include(s): +#include <cstdlib> +#include <cmath> +#include <memory> + +// Infrastructure include(s): +#include "xAODRootAccess/TEvent.h" +#include "xAODRootAccess/TStore.h" +#include "xAODRootAccess/Init.h" +#include "AsgTools/MsgStream.h" +#include "AsgTools/MessageCheck.h" +#include "AsgTools/SgTEvent.h" + +// EDM include(s): +#include "xAODBase/IParticleHelpers.h" +#include "xAODJet/JetContainer.h" +#include "xAODJet/JetAuxContainer.h" + +// Local include(s): +#include "SystematicsHandles/CopyHelpers.h" + +/// Function generating a random number in a specific range +double randomInRange( double min, double max ) { + return static_cast< double >( rand() ) / RAND_MAX * ( max - min ) + min; +} + +int main() { + + // Set up the usage of the ANA_CHECK(...) macro. + using namespace asg::msgUserCode; + ANA_CHECK_SET_TYPE( int ); + + // Set up the environment. + ANA_CHECK( xAOD::Init() ); + + // Create the transient store objects. + xAOD::TEvent event; + xAOD::TStore store; + asg::SgTEvent sgEvent( &event, &store ); + + // Create a message stream, to be used later on in the code. + MsgStream msgStream( "ut_CopyHelpers" ); + + // Create a primary container, fill it with some random content, and + // record it into the transient store. + auto originalJets = std::make_unique< xAOD::JetContainer >(); + auto originalAux = std::make_unique< xAOD::JetAuxContainer >(); + originalJets->setStore( originalAux.get() ); + + for( int i = 0; i < 10; ++i ) { + xAOD::Jet* jet = new xAOD::Jet(); + originalJets->push_back( jet ); + jet->setJetP4( xAOD::JetFourMom_t( randomInRange( 10000.0, 50000.0 ), // Pt + randomInRange( -2.5, 2.5 ), // Eta + randomInRange( -M_PI, M_PI ), // Phi + randomInRange( 0.0, 500.0 ) ) ); // M + } + + const xAOD::JetContainer* originalJetsPtr = originalJets.get(); + ANA_CHECK( store.record( std::move( originalJets ), "OriginalJets" ) ); + ANA_CHECK( store.record( std::move( originalAux ), "OriginalJetsAux." ) ); + + // Make it easier to use CP::detail::ShallowCopy. + using CP::detail::ShallowCopy; + + // Make a copy of this simple container. + xAOD::JetContainer* copiedJets = nullptr; + ANA_CHECK( ShallowCopy< xAOD::JetContainer >::getCopy( msgStream, + sgEvent, + copiedJets, + originalJetsPtr, + "CopiedJets", + "CopiedJetsAux." ) ); + + // Make sure that the copied objects point to the originals. + ANA_CHECK( copiedJets->size() == originalJetsPtr->size() ); + for( size_t i = 0; i < copiedJets->size(); ++i ) { + ANA_CHECK( xAOD::getOriginalObject( *( copiedJets->at( i ) ) ) == + originalJetsPtr->at( i ) ); + } + msgStream << MSG::INFO << "Simple copy succeeded" << endmsg; + + // Make a view copy of the copied container, which selects only every second + // object from it. + auto viewCopy = std::make_unique< xAOD::JetContainer >( SG::VIEW_ELEMENTS ); + for( size_t i = 0; i < copiedJets->size(); i = i + 2 ) { + viewCopy->push_back( copiedJets->at( i ) ); + } + + const xAOD::JetContainer* viewCopyPtr = viewCopy.get(); + ANA_CHECK( store.record( std::move( viewCopy ), "ViewOfCopiedJets" ) ); + + // Now make a shallow copy of this view copy. + xAOD::JetContainer* copiedViewJets = nullptr; + ANA_CHECK( ShallowCopy< xAOD::JetContainer >::getCopy( msgStream, + sgEvent, + copiedViewJets, + viewCopyPtr, + "CopyOfViewJets", + "CopyOfViewJetsAux." ) ); + + // Check the copy. The logic here is a bit complicated, since the original + // objects of the copies of the view container are still the objects in the + // original container. And not the objects in the view container. + ANA_CHECK( copiedViewJets->size() == viewCopyPtr->size() ); + for( size_t i = 0; i < viewCopyPtr->size(); ++i ) { + ANA_CHECK( xAOD::getOriginalObject( *( copiedViewJets->at( i ) ) ) == + originalJetsPtr->at( copiedViewJets->at( i )->index() ) ); + } + msgStream << MSG::INFO << "Copy of view vector succeeded" << endmsg; + + return 0; +} diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/CMakeLists.txt b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..0b5989cb8c8d8078ba2ce48b44b4ae45217babf4 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/CMakeLists.txt @@ -0,0 +1,64 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# The name of the package: +atlas_subdir( TauAnalysisAlgorithms ) + +# The package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + Event/xAOD/xAODTau + PhysicsAnalysis/Algorithms/SelectionHelpers + PhysicsAnalysis/Algorithms/SystematicsHandles + PhysicsAnalysis/D3PDTools/AnaAlgorithm + PhysicsAnalysis/TauID/TauAnalysisTools ) + +atlas_add_library( TauAnalysisAlgorithmsLib + TauAnalysisAlgorithms/*.h TauAnalysisAlgorithms/*.icc Root/*.cxx + PUBLIC_HEADERS TauAnalysisAlgorithms + LINK_LIBRARIES xAODTau SelectionHelpersLib + SystematicsHandlesLib + AnaAlgorithmLib TauAnalysisToolsLib ) + +atlas_add_dictionary( TauAnalysisAlgorithmsDict + TauAnalysisAlgorithms/TauAnalysisAlgorithmsDict.h + TauAnalysisAlgorithms/selection.xml + LINK_LIBRARIES TauAnalysisAlgorithmsLib ) + +if( NOT XAOD_STANDALONE ) + atlas_add_component( TauAnalysisAlgorithms + src/*.h src/*.cxx src/components/*.cxx + LINK_LIBRARIES GaudiKernel TauAnalysisAlgorithmsLib ) +endif() + +atlas_install_python_modules( python/*.py ) +atlas_install_joboptions( share/*_jobOptions.py ) +atlas_install_scripts( share/*_eljob.py ) +atlas_install_data( data/*.conf ) + +if( XAOD_STANDALONE ) + atlas_add_test( testJobData + SCRIPT TauAnalysisAlgorithmsTest_eljob.py --data-type data --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSim + SCRIPT TauAnalysisAlgorithmsTest_eljob.py --data-type mc --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSim + SCRIPT TauAnalysisAlgorithmsTest_eljob.py --data-type afii --unit-test + PROPERTIES TIMEOUT 600 ) +else() + atlas_add_test( testJobData + SCRIPT athena.py + TauAnalysisAlgorithms/TauAnalysisAlgorithmsTest_jobOptions.py - --data-type data + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFullSim + SCRIPT athena.py + TauAnalysisAlgorithms/TauAnalysisAlgorithmsTest_jobOptions.py - --data-type mc + PROPERTIES TIMEOUT 600 ) + atlas_add_test( testJobFastSim + SCRIPT athena.py + TauAnalysisAlgorithms/TauAnalysisAlgorithmsTest_jobOptions.py - --data-type afii + PROPERTIES TIMEOUT 600 ) +endif() diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/DiTauEfficiencyCorrectionsAlg.cxx b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/DiTauEfficiencyCorrectionsAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..140ad67c91e0ee4f2b84ba165b858d1a2bd97392 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/DiTauEfficiencyCorrectionsAlg.cxx @@ -0,0 +1,73 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <TauAnalysisAlgorithms/DiTauEfficiencyCorrectionsAlg.h> + +// +// method implementations +// + +namespace CP +{ + DiTauEfficiencyCorrectionsAlg :: + DiTauEfficiencyCorrectionsAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_efficiencyCorrectionsTool ("TauAnalysisTools::DiTauEfficiencyCorrectionsTool", this) + { + declareProperty ("efficiencyCorrectionsTool", m_efficiencyCorrectionsTool, "the calibration and smearing tool we apply"); + declareProperty ("scaleFactorDecoration", m_scaleFactorDecoration, "the decoration for the tau scale factor"); + } + + + + StatusCode DiTauEfficiencyCorrectionsAlg :: + initialize () + { + if (m_scaleFactorDecoration.empty()) + { + 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_efficiencyCorrectionsTool.retrieve()); + m_systematicsList.addHandle (m_tauHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_efficiencyCorrectionsTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode DiTauEfficiencyCorrectionsAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_efficiencyCorrectionsTool->applySystematicVariation (sys)); + xAOD::DiTauJetContainer *taus = nullptr; + ANA_CHECK (m_tauHandle.getCopy (taus, sys)); + for (xAOD::DiTauJet *tau : *taus) + { + if (m_preselection.getBool (*tau)) + { + double sf = 0; + ANA_CHECK_CORRECTION (m_outOfValidity, *tau, m_efficiencyCorrectionsTool->getEfficiencyScaleFactor (*tau, sf)); + (*m_scaleFactorAccessor) (*tau) = sf; + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/DiTauSmearingAlg.cxx b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/DiTauSmearingAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e3a367ead8796488160470d8a15cbe64756c43c8 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/DiTauSmearingAlg.cxx @@ -0,0 +1,63 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <TauAnalysisAlgorithms/DiTauSmearingAlg.h> + +// +// method implementations +// + +namespace CP +{ + DiTauSmearingAlg :: + DiTauSmearingAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_smearingTool ("TauAnalysisTools::DiTauSmearingTool", this) + { + declareProperty ("smearingTool", m_smearingTool, "the calibration and smearing tool we apply"); + } + + + + StatusCode DiTauSmearingAlg :: + initialize () + { + ANA_CHECK (m_smearingTool.retrieve()); + m_systematicsList.addHandle (m_tauHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_smearingTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode DiTauSmearingAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_smearingTool->applySystematicVariation (sys)); + xAOD::DiTauJetContainer *taus = nullptr; + ANA_CHECK (m_tauHandle.getCopy (taus, sys)); + for (xAOD::DiTauJet *tau : *taus) + { + if (m_preselection.getBool (*tau)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *tau, m_smearingTool->applyCorrection (*tau)); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/DiTauTruthMatchingAlg.cxx b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/DiTauTruthMatchingAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..685c0e87581f89ef3203d2b924d3ca8ee13152cc --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/DiTauTruthMatchingAlg.cxx @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <TauAnalysisAlgorithms/DiTauTruthMatchingAlg.h> + +// +// method implementations +// + +namespace CP +{ + DiTauTruthMatchingAlg :: + DiTauTruthMatchingAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_matchingTool ("TauAnalysisTools::DiTauTruthMatchingTool", this) + { + declareProperty ("matchingTool", m_matchingTool, "the matching tool we apply"); + } + + + + StatusCode DiTauTruthMatchingAlg :: + initialize () + { + ANA_CHECK (m_matchingTool.retrieve()); + m_systematicsList.addHandle (m_tauHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode DiTauTruthMatchingAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::DiTauJetContainer *taus = nullptr; + ANA_CHECK (m_tauHandle.getCopy (taus, sys)); + for (xAOD::DiTauJet *tau : *taus) + { + if (m_preselection.getBool (*tau)) + { + m_matchingTool->applyTruthMatch (*tau); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/TauEfficiencyCorrectionsAlg.cxx b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/TauEfficiencyCorrectionsAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bc7ed9a74c667f84a9c147032af1f11bd77a407e --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/TauEfficiencyCorrectionsAlg.cxx @@ -0,0 +1,75 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <TauAnalysisAlgorithms/TauEfficiencyCorrectionsAlg.h> + +// +// method implementations +// + +namespace CP +{ + TauEfficiencyCorrectionsAlg :: + TauEfficiencyCorrectionsAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_efficiencyCorrectionsTool ("TauAnalysisTools::TauEfficiencyCorrectionsTool", this) + { + declareProperty ("efficiencyCorrectionsTool", m_efficiencyCorrectionsTool, "the calibration and smearing tool we apply"); + } + + + + StatusCode TauEfficiencyCorrectionsAlg :: + initialize () + { + if (m_scaleFactorDecoration.empty()) + { + ANA_MSG_ERROR ("no scale factor decoration name set"); + return StatusCode::FAILURE; + } + + ANA_CHECK (m_efficiencyCorrectionsTool.retrieve()); + m_systematicsList.addHandle (m_tauHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_efficiencyCorrectionsTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode TauEfficiencyCorrectionsAlg :: + execute () + { + ANA_CHECK (m_scaleFactorDecoration.preExecute (m_systematicsList)); + + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_efficiencyCorrectionsTool->applySystematicVariation (sys)); + xAOD::TauJetContainer *taus = nullptr; + ANA_CHECK (m_tauHandle.getCopy (taus, sys)); + for (xAOD::TauJet *tau : *taus) + { + if (m_preselection.getBool (*tau)) + { + double sf = 0; + ANA_CHECK_CORRECTION (m_outOfValidity, *tau, m_efficiencyCorrectionsTool->getEfficiencyScaleFactor (*tau, sf)); + m_scaleFactorDecoration.set (*tau, sf, sys); + } else { + m_scaleFactorDecoration.set (*tau, invalidScaleFactor(), sys); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/TauSmearingAlg.cxx b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/TauSmearingAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..f7b65a29ee8735390f5a133539c0fabcfb650e00 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/TauSmearingAlg.cxx @@ -0,0 +1,63 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <TauAnalysisAlgorithms/TauSmearingAlg.h> + +// +// method implementations +// + +namespace CP +{ + TauSmearingAlg :: + TauSmearingAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_smearingTool ("TauAnalysisTools::TauSmearingTool", this) + { + declareProperty ("smearingTool", m_smearingTool, "the calibration and smearing tool we apply"); + } + + + + StatusCode TauSmearingAlg :: + initialize () + { + ANA_CHECK (m_smearingTool.retrieve()); + m_systematicsList.addHandle (m_tauHandle); + ANA_CHECK (m_systematicsList.addAffectingSystematics (m_smearingTool->affectingSystematics())); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + ANA_CHECK (m_outOfValidity.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode TauSmearingAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + ANA_CHECK (m_smearingTool->applySystematicVariation (sys)); + xAOD::TauJetContainer *taus = nullptr; + ANA_CHECK (m_tauHandle.getCopy (taus, sys)); + for (xAOD::TauJet *tau : *taus) + { + if (m_preselection.getBool (*tau)) + { + ANA_CHECK_CORRECTION (m_outOfValidity, *tau, m_smearingTool->applyCorrection (*tau)); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/TauTruthMatchingAlg.cxx b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/TauTruthMatchingAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..d679581d9d9049a8c62075e0d82296727c8e0abc --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/Root/TauTruthMatchingAlg.cxx @@ -0,0 +1,60 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +// +// includes +// + +#include <TauAnalysisAlgorithms/TauTruthMatchingAlg.h> + +// +// method implementations +// + +namespace CP +{ + TauTruthMatchingAlg :: + TauTruthMatchingAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_matchingTool ("TauAnalysisTools::TauTruthMatchingTool", this) + { + declareProperty ("matchingTool", m_matchingTool, "the matching tool we apply"); + } + + + + StatusCode TauTruthMatchingAlg :: + initialize () + { + ANA_CHECK (m_matchingTool.retrieve()); + m_systematicsList.addHandle (m_tauHandle); + ANA_CHECK (m_systematicsList.initialize()); + ANA_CHECK (m_preselection.initialize()); + return StatusCode::SUCCESS; + } + + + + StatusCode TauTruthMatchingAlg :: + execute () + { + return m_systematicsList.foreach ([&] (const CP::SystematicSet& sys) -> StatusCode { + xAOD::TauJetContainer *taus = nullptr; + ANA_CHECK (m_tauHandle.getCopy (taus, sys)); + for (xAOD::TauJet *tau : *taus) + { + if (m_preselection.getBool (*tau)) + { + m_matchingTool->applyTruthMatch (*tau); + } + } + return StatusCode::SUCCESS; + }); + } +} diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/DiTauEfficiencyCorrectionsAlg.h b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/DiTauEfficiencyCorrectionsAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..194af5403133fc1bef8ec19bea7923f213b1945f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/DiTauEfficiencyCorrectionsAlg.h @@ -0,0 +1,72 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef TAU_ANALYSIS_ALGORITHMS__DI_TAU_EFFICIENCY_CORRECTIONS_ALG_H +#define TAU_ANALYSIS_ALGORITHMS__DI_TAU_EFFICIENCY_CORRECTIONS_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <TauAnalysisTools/IDiTauEfficiencyCorrectionsTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <SystematicsHandles/SysReadHandle.h> +#include <xAODTau/DiTauJetContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IDiTauEfficiencyCorrectionsTool + + class DiTauEfficiencyCorrectionsAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + DiTauEfficiencyCorrectionsAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<TauAnalysisTools::IDiTauEfficiencyCorrectionsTool> m_efficiencyCorrectionsTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the tau collection we run on + private: + SysCopyHandle<xAOD::DiTauJetContainer> m_tauHandle { + this, "taus", "DiTauJets", "the tau collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + + /// \brief the decoration for the tau 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; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/DiTauSmearingAlg.h b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/DiTauSmearingAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..9610128e082e3e0e461294b5821fad2426efe043 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/DiTauSmearingAlg.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef TAU_ANALYSIS_ALGORITHMS__DI_TAU_CALIBRATION_AND_SMEARING_ALG_H +#define TAU_ANALYSIS_ALGORITHMS__DI_TAU_CALIBRATION_AND_SMEARING_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <TauAnalysisTools/IDiTauSmearingTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODTau/DiTauJetContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IDiTauSmearingTool + + class DiTauSmearingAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + DiTauSmearingAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<TauAnalysisTools::IDiTauSmearingTool> m_smearingTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the tau collection we run on + private: + SysCopyHandle<xAOD::DiTauJetContainer> m_tauHandle { + this, "taus", "DiTauJets", "the tau collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/DiTauTruthMatchingAlg.h b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/DiTauTruthMatchingAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..a93a3aaf61726eaf6a52e2d82079aaa9059107ae --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/DiTauTruthMatchingAlg.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef TAU_ANALYSIS_ALGORITHMS__DI_TAU_TRUTH_MATCHING_ALG_H +#define TAU_ANALYSIS_ALGORITHMS__DI_TAU_TRUTH_MATCHING_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <TauAnalysisTools/IDiTauTruthMatchingTool.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODTau/DiTauJetContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref IDiTauTruthMatchingTool + + class DiTauTruthMatchingAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + DiTauTruthMatchingAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the matching tool + private: + ToolHandle<TauAnalysisTools::IDiTauTruthMatchingTool> m_matchingTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the tau collection we run on + private: + SysCopyHandle<xAOD::DiTauJetContainer> m_tauHandle { + this, "taus", "DiTauJets", "the tau collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithmsDict.h b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithmsDict.h new file mode 100644 index 0000000000000000000000000000000000000000..146cf87c4538b12e98bc258f8d6ab18d6f30be02 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithmsDict.h @@ -0,0 +1,18 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef TAU_ANALYSIS_ALGORITHMS__TAU_ANALYSIS_ALGORITHMS_DICT_H +#define TAU_ANALYSIS_ALGORITHMS__TAU_ANALYSIS_ALGORITHMS_DICT_H + +#include <TauAnalysisAlgorithms/DiTauEfficiencyCorrectionsAlg.h> +#include <TauAnalysisAlgorithms/DiTauSmearingAlg.h> +#include <TauAnalysisAlgorithms/DiTauTruthMatchingAlg.h> +#include <TauAnalysisAlgorithms/TauEfficiencyCorrectionsAlg.h> +#include <TauAnalysisAlgorithms/TauSmearingAlg.h> +#include <TauAnalysisAlgorithms/TauTruthMatchingAlg.h> + +#endif diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauEfficiencyCorrectionsAlg.h b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauEfficiencyCorrectionsAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..321199c88c5b0cbfe57ac8fbe2f83ceaea174f83 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauEfficiencyCorrectionsAlg.h @@ -0,0 +1,70 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + +#ifndef TAU_ANALYSIS_ALGORITHMS__TAU_EFFICIENCY_CORRECTIONS_ALG_H +#define TAU_ANALYSIS_ALGORITHMS__TAU_EFFICIENCY_CORRECTIONS_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <TauAnalysisTools/ITauEfficiencyCorrectionsTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysDecorationHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <SystematicsHandles/SysReadHandle.h> +#include <xAODTau/TauJetContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref ITauEfficiencyCorrectionsTool + + class TauEfficiencyCorrectionsAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + TauEfficiencyCorrectionsAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<TauAnalysisTools::ITauEfficiencyCorrectionsTool> m_efficiencyCorrectionsTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the tau collection we run on + private: + SysCopyHandle<xAOD::TauJetContainer> m_tauHandle { + this, "taus", "TauJets", "the tau collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + + /// \brief the decoration for the tau scale factor + private: + SysDecorationHandle<float> m_scaleFactorDecoration { + this, "scaleFactorDecoration", "", "the decoration for the tau efficiency scale factor"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauSmearingAlg.h b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauSmearingAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..fa5f903e504949f9a2a60d7f92d0161ec8423649 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauSmearingAlg.h @@ -0,0 +1,64 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef TAU_ANALYSIS_ALGORITHMS__TAU_CALIBRATION_AND_SMEARING_ALG_H +#define TAU_ANALYSIS_ALGORITHMS__TAU_CALIBRATION_AND_SMEARING_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <TauAnalysisTools/ITauSmearingTool.h> +#include <SelectionHelpers/OutOfValidityHelper.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODTau/TauJetContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref ITauSmearingTool + + class TauSmearingAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + TauSmearingAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the smearing tool + private: + ToolHandle<TauAnalysisTools::ITauSmearingTool> m_smearingTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the tau collection we run on + private: + SysCopyHandle<xAOD::TauJetContainer> m_tauHandle { + this, "taus", "TauJets", "the tau collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + + /// \brief the helper for OutOfValidity results + private: + OutOfValidityHelper m_outOfValidity {this}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauTruthMatchingAlg.h b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauTruthMatchingAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..0bd2409052c34bd10dd8fcd40157123108aca6e2 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/TauTruthMatchingAlg.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Nils Krumnack + + + +#ifndef TAU_ANALYSIS_ALGORITHMS__TAU_TRUTH_MATCHING_ALG_H +#define TAU_ANALYSIS_ALGORITHMS__TAU_TRUTH_MATCHING_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <TauAnalysisTools/ITauTruthMatchingTool.h> +#include <SelectionHelpers/SelectionReadHandle.h> +#include <SystematicsHandles/SysCopyHandle.h> +#include <SystematicsHandles/SysListHandle.h> +#include <xAODTau/TauJetContainer.h> + +namespace CP +{ + /// \brief an algorithm for calling \ref ITauTruthMatchingTool + + class TauTruthMatchingAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + TauTruthMatchingAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + + /// \brief the matching tool + private: + ToolHandle<TauAnalysisTools::ITauTruthMatchingTool> m_matchingTool; + + /// \brief the systematics list we run + private: + SysListHandle m_systematicsList {this}; + + /// \brief the tau collection we run on + private: + SysCopyHandle<xAOD::TauJetContainer> m_tauHandle { + this, "taus", "TauJets", "the tau collection to run on"}; + + /// \brief the preselection we apply to our input + private: + SelectionReadHandle m_preselection { + this, "preselection", "", "the preselection to apply"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/selection.xml b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..a815f8e0a47edce1db6a49c6270e37aa573dfa5c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/TauAnalysisAlgorithms/selection.xml @@ -0,0 +1,10 @@ +<lcgdict> + + <class name="CP::DiTauEfficiencyCorrectionsAlg" /> + <class name="CP::DiTauSmearingAlg" /> + <class name="CP::DiTauTruthMatchingAlg" /> + <class name="CP::TauEfficiencyCorrectionsAlg" /> + <class name="CP::TauSmearingAlg" /> + <class name="CP::TauTruthMatchingAlg" /> + +</lcgdict> diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_baseline.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_baseline.conf new file mode 100644 index 0000000000000000000000000000000000000000..6fa54ab13cdc849e78564ae3e7621214296fa239 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_baseline.conf @@ -0,0 +1,9 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 + +# EOF diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_baseline_legacy.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_baseline_legacy.conf new file mode 100644 index 0000000000000000000000000000000000000000..bf5b84d0e25f8aeb5c4d1a5678d8f2d493d4b72c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_baseline_legacy.conf @@ -0,0 +1,10 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP EleOLR EleBDTWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 +EleOLR: True + +# EOF diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_loose.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_loose.conf new file mode 100644 index 0000000000000000000000000000000000000000..5c3c8e8d125deeeea2ead9fe63cf5914d3c9e52e --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_loose.conf @@ -0,0 +1,11 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP EleOLR EleBDTWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 +JetIDWP: JETIDRNNLOOSE +EleBDTWP: ELEIDBDTLOOSE + +# EOF diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_loose_legacy.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_loose_legacy.conf new file mode 100644 index 0000000000000000000000000000000000000000..5cd30ef26f94075d54dd63ad4e238ff860efb9d0 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_loose_legacy.conf @@ -0,0 +1,12 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP EleOLR EleBDTWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 +JetIDWP: JETIDBDTLOOSE +EleOLR: True +EleBDTWP: ELEIDBDTOLDLOOSE + +# EOF \ No newline at end of file diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_medium.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_medium.conf new file mode 100644 index 0000000000000000000000000000000000000000..db9c7e1eff77ed7a3a21c4bad8a40ffba4bc4f6b --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_medium.conf @@ -0,0 +1,11 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP EleOLR EleBDTWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 +JetIDWP: JETIDRNNMEDIUM +EleBDTWP: ELEIDBDTLOOSE + +# EOF diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_medium_legacy.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_medium_legacy.conf new file mode 100644 index 0000000000000000000000000000000000000000..73d26a97e56a9a1c92084d0b84dcf191f4f558c6 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_medium_legacy.conf @@ -0,0 +1,12 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP EleOLR EleBDTWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 +JetIDWP: JETIDBDTMEDIUM +EleOLR: True +EleBDTWP: ELEIDBDTOLDLOOSE + +# EOF diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_noid.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_noid.conf new file mode 100644 index 0000000000000000000000000000000000000000..8d12d46d42ada61fc596208eb60bedc1608ad48d --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_noid.conf @@ -0,0 +1,11 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP EleOLR EleBDTWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 +JetIDWP: JETIDNONE +EleBDTWP: ELEIDBDTLOOSE + +# EOF diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_noid_legacy.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_noid_legacy.conf new file mode 100644 index 0000000000000000000000000000000000000000..c58146ecc3074d2b16bb14808d35575db6b2ac19 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_noid_legacy.conf @@ -0,0 +1,12 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP EleOLR EleBDTWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 +JetIDWP: JETIDNONE +EleOLR: True +EleBDTWP: ELEIDBDTOLDLOOSE + +# EOF diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_tight.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_tight.conf new file mode 100644 index 0000000000000000000000000000000000000000..862691f0f17e2ca2a47ae0d1371796f6394dc77e --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_tight.conf @@ -0,0 +1,11 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP EleOLR EleBDTWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 +JetIDWP: JETIDRNNTIGHT +EleBDTWP: ELEIDBDTLOOSE + +# EOF diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_tight_legacy.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_tight_legacy.conf new file mode 100644 index 0000000000000000000000000000000000000000..c855481512ac2658ee2c07c76ff9d5c906f2ce45 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_tight_legacy.conf @@ -0,0 +1,12 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP EleOLR EleBDTWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 +JetIDWP: JETIDBDTTIGHT +EleOLR: True +EleBDTWP: ELEIDBDTOLDLOOSE + +# EOF \ No newline at end of file diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_veryloose.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_veryloose.conf new file mode 100644 index 0000000000000000000000000000000000000000..1f3c0fb379e71c6debc24fbb2c3fdcf06bb85abc --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_veryloose.conf @@ -0,0 +1,11 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP EleOLR EleBDTWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 +JetIDWP: JETIDRNNVERYLOOSE +EleBDTWP: ELEIDBDTLOOSE + +# EOF diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_veryloose_legacy.conf b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_veryloose_legacy.conf new file mode 100644 index 0000000000000000000000000000000000000000..5266e9f6875bbe765ff2b5621ac7cb83d6153191 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/data/tau_selection_veryloose_legacy.conf @@ -0,0 +1,12 @@ +# Cuts to perform, need to be specified below +SelectionCuts: PtMin AbsEtaRegion AbsCharge NTracks JetIDWP EleOLR EleBDTWP + +PtMin: 20 +AbsEtaRegion: 0; 1.37; 1.52; 2.5 +AbsCharge: 1 +NTracks: 1; 3 +JetIDWP: JETIDBDTVERYLOOSE +EleOLR: True +EleBDTWP: ELEIDBDTOLDLOOSE + +# EOF \ No newline at end of file diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/DiTauAnalysisSequence.py b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/DiTauAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..b95773d5252648f511046e7a1d674c6b1d24075b --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/DiTauAnalysisSequence.py @@ -0,0 +1,100 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +# AnaAlgorithm import(s): +from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm, addPrivateTool + +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 diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/TauAnalysisAlgorithmsTest.py b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/TauAnalysisAlgorithmsTest.py new file mode 100644 index 0000000000000000000000000000000000000000..7c496b06b12be9f4bdcd56a54d5985fa44af3c3f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/TauAnalysisAlgorithmsTest.py @@ -0,0 +1,35 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +from AnaAlgorithm.AlgSequence import AlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm + +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 tau analysis algorithm sequence: + from TauAnalysisAlgorithms.TauAnalysisSequence import makeTauAnalysisSequence + tauSequence = makeTauAnalysisSequence( dataType, 'Tight', postfix = 'tight', + enableCutflow=True, enableKinematicHistograms=True ) + tauSequence.configure( inputName = 'TauJets', outputName = 'AnalysisTauJets_%SYS%' ) + + # Add the sequence to the job: + algSeq += tauSequence + + # Include, and then set up the tau analysis algorithm sequence: + from TauAnalysisAlgorithms.DiTauAnalysisSequence import makeDiTauAnalysisSequence + diTauSequence = makeDiTauAnalysisSequence( dataType, 'Tight', postfix = 'tight' ) + diTauSequence.configure( inputName = 'DiTauJets', outputName = 'AnalysisDiTauJets_%SYS%' ) + + # Add the sequence to the job: + # disabling this, the standard test files don't have DiTauJets + # algSeq += diTauSequence + + return algSeq diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/TauAnalysisSequence.py b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/TauAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..c48a2fc3b96f012405440ffc50436e6a8a188216 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/TauAnalysisSequence.py @@ -0,0 +1,170 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +# AnaAlgorithm import(s): +from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm, addPrivateTool, \ + createPublicTool + +def makeTauAnalysisSequence( dataType, workingPoint, postfix = '', + legacyRecommendations = False, + deepCopyOutput = False, + shallowViewOutput = True, + rerunTruthMatching = True, + enableCutflow = False, + enableKinematicHistograms = False ): + """Create a tau analysis algorithm sequence + + Keyword arguments: + dataType -- The data type to run on ("data", "mc" or "afii") + legacyRecommendations -- use legacy tau BDT and electron veto recommendations + 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. + rerunTruthMatching -- Whether or not to rerun truth matching + 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) != 1 : + raise ValueError ('working point should be of format "quality", not ' + workingPoint) + + nameFormat = 'TauAnalysisAlgorithms/tau_selection_{}.conf' + if legacyRecommendations: + nameFormat = 'TauAnalysisAlgorithms/tau_selection_{}_legacy.conf' + + if splitWP[0] not in ['Tight', 'Medium', 'Loose', 'VeryLoose', 'NoID', 'Baseline'] : + raise ValueError ("invalid tau quality: \"" + splitWP[0] + + "\", allowed values are Tight, Medium, Loose, " + + "VeryLoose, NoID, Baseline") + inputfile = nameFormat.format(splitWP[0].lower()) + + # Create the analysis algorithm sequence object: + seq = AnaAlgSequence( "TauAnalysisSequence" + postfix ) + + # Variables keeping track of the selections being applied. + selectionDecorNames = [] + selectionDecorCount = [] + + # Setup the tau selection tool + selectionTool = createPublicTool( 'TauAnalysisTools::TauSelectionTool', + 'TauSelectionTool' + postfix) + selectionTool.ConfigPath = inputfile + seq.addPublicTool( selectionTool, stageName = 'selection' ) + + # Set up the tau truth matching algorithm: + if rerunTruthMatching and dataType != 'data': + alg = createAlgorithm( 'CP::TauTruthMatchingAlg', + 'TauTruthMatchingAlg' + postfix ) + addPrivateTool( alg, 'matchingTool', + 'TauAnalysisTools::TauTruthMatchingTool' ) + alg.matchingTool.WriteTruthTaus = 1 + seq.append( alg, inputPropName = 'taus', outputPropName = 'tausOut', + stageName = 'selection' ) + pass + + # Set up the tau 4-momentum smearing algorithm: + alg = createAlgorithm( 'CP::TauSmearingAlg', 'TauSmearingAlg' + postfix ) + addPrivateTool( alg, 'smearingTool', 'TauAnalysisTools::TauSmearingTool' ) + seq.append( alg, inputPropName = 'taus', outputPropName = 'tausOut', + affectingSystematics = '(^TAUS_TRUEHADTAU_SME_TES_.*)', + stageName = 'calibration' ) + + # Set up the algorithm selecting taus: + alg = createAlgorithm( 'CP::AsgSelectionAlg', 'TauSelectionAlg' + postfix ) + alg.selectionTool = '%s/%s' % \ + ( selectionTool.getType(), selectionTool.getName() ) + alg.selectionDecoration = 'selected_tau' + postfix + ',as_bits' + seq.append( alg, inputPropName = 'particles', + stageName = 'selection' ) + selectionDecorNames.append( alg.selectionDecoration ) + selectionDecorCount.append( 6 ) + + # Set up the algorithm calculating the efficiency scale factors for the + # taus: + if dataType != 'data': + alg = createAlgorithm( 'CP::TauEfficiencyCorrectionsAlg', + 'TauEfficiencyCorrectionsAlg' + postfix ) + addPrivateTool( alg, 'efficiencyCorrectionsTool', + 'TauAnalysisTools::TauEfficiencyCorrectionsTool' ) + alg.efficiencyCorrectionsTool.TauSelectionTool = '%s/%s' % \ + ( selectionTool.getType(), selectionTool.getName() ) + alg.scaleFactorDecoration = 'tau_effSF' + postfix + '_%SYS%' + alg.scaleFactorDecorationRegex = '(^TAUS_TRUEELECTRON_EFF_.*)' \ + + '|(^TAUS_TRUEHADTAU_EFF_RECO.*)' \ + + '|(^TAUS_TRUEHADTAU_EFF_RNNID.*)' \ + + '|(^TAUS_TRUEHADTAU_EFF_JETID.*)' \ + + '|(^TAUS_TRUEHADTAU_EFF_RECO.*)' \ + + '|(^TAUS_TRUEHADTAU_EFF_ELEOLR.*)' + alg.outOfValidity = 2 #silent + alg.outOfValidityDeco = 'bad_eff' + postfix + seq.append( alg, inputPropName = 'taus', + affectingSystematics = '(^TAUS_TRUEELECTRON_EFF_.*)' \ + + '|(^TAUS_TRUEHADTAU_EFF_RECO.*)' \ + + '|(^TAUS_TRUEHADTAU_EFF_RNNID.*)' \ + + '|(^TAUS_TRUEHADTAU_EFF_JETID.*)' \ + + '|(^TAUS_TRUEHADTAU_EFF_RECO.*)' \ + + '|(^TAUS_TRUEHADTAU_EFF_ELEOLR.*)', + stageName = 'efficiency' ) + + # Set up an algorithm used to create tau selection cutflow: + if enableCutflow: + alg = createAlgorithm( 'CP::ObjectCutFlowHistAlg', 'TauCutFlowDumperAlg' + postfix ) + alg.histPattern = 'tau_cflow_%SYS%' + alg.selection = selectionDecorNames[ : ] + alg.selectionNCuts = selectionDecorCount[ : ] + seq.append( alg, inputPropName = 'input', stageName = 'selection' ) + + # Set up an algorithm used for decorating baseline tau selection: + alg = createAlgorithm( 'CP::AsgSelectionAlg', + 'TauSelectionSummary' + 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 that makes a view container using the selections + # performed previously: + if shallowViewOutput: + alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg', + 'TauViewFromSelectionAlg' + postfix ) + alg.selection = selectionDecorNames[ : ] + seq.append( alg, inputPropName = 'input', outputPropName = 'output', + stageName = 'selection' ) + + # Set up an algorithm dumping the kinematic properties of the taus: + if enableKinematicHistograms: + alg = createAlgorithm( 'CP::KinematicHistAlg', 'TauKinematicDumperAlg' + postfix ) + alg.preselection = '&&'.join (selectionDecorNames) + alg.histPattern = 'tau_%VAR%_%SYS%' + seq.append( alg, inputPropName = 'input', stageName = 'selection' ) + + # Set up a final deep copy making algorithm if requested: + if deepCopyOutput: + alg = createAlgorithm( 'CP::AsgViewFromSelectionAlg', + 'TauDeepCopyMaker' + postfix ) + alg.deepCopy = True + alg.selection = selectionDecorNames[ : ] + seq.append( alg, inputPropName = 'input', outputPropName = 'output', + stageName = 'selection' ) + pass + + # Return the sequence: + return seq diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/__init__.py b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5ccb446532599c01cc3844e5b1b18db06f721002 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/python/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +__version__ = '1.0.0' diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/share/TauAnalysisAlgorithmsTest_eljob.py b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/share/TauAnalysisAlgorithmsTest_eljob.py new file mode 100755 index 0000000000000000000000000000000000000000..0b1755dd1058de72bf62c41d341da48ec2301d72 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/share/TauAnalysisAlgorithmsTest_eljob.py @@ -0,0 +1,81 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + + +# Read the submission directory as a command line argument. You can +# extend the list of arguments with your private ones later on. +import optparse +parser = optparse.OptionParser() +parser.add_option( '-d', '--data-type', dest = 'data_type', + action = 'store', type = 'string', default = 'data', + help = 'Type of data to run over. Valid options are data, mc, afii' ) +parser.add_option( '-s', '--submission-dir', dest = 'submission_dir', + action = 'store', type = 'string', default = 'submitDir', + help = 'Submission directory for EventLoop' ) +parser.add_option( '-u', '--unit-test', dest='unit_test', + action = 'store_true', default = False, + help = 'Run the job in "unit test mode"' ) +( options, args ) = parser.parse_args() + +# Set up (Py)ROOT. +import ROOT +ROOT.xAOD.Init().ignore() + +# this forces the tau algorithms dictionary to be loaded before +# anything else, which works around some strange dictionary issues I +# don't understand. +ROOT.CP.TauSmearingAlg ("dummy", None) + +# ideally we'd run over all of them, but we don't have a mechanism to +# configure per-sample right now + +dataType = options.data_type + +if dataType not in ["data", "mc", "afii"] : + raise ValueError ("invalid data type: " + dataType) + +# Set up the sample handler object. See comments from the C++ macro +# for the details about these lines. +import os +sh = ROOT.SH.SampleHandler() +sh.setMetaString( 'nc_tree', 'CollectionTree' ) +sample = ROOT.SH.SampleLocal (dataType) +if dataType == "data" : + sample.add (os.getenv ('ASG_TEST_FILE_DATA')) + pass +if dataType == "mc" : + sample.add (os.getenv ('ASG_TEST_FILE_MC')) + pass +if dataType == "afii" : + sample.add (os.getenv ('ASG_TEST_FILE_MC_AFII')) + pass +sh.add (sample) +sh.printContent() + +# Create an EventLoop job. +job = ROOT.EL.Job() +job.sampleHandler( sh ) +job.options().setDouble( ROOT.EL.Job.optMaxEvents, 500 ) + +from TauAnalysisAlgorithms.TauAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging +for alg in algSeq: + job.algsAdd( alg ) + pass + +# Find the right output directory: +submitDir = options.submission_dir +if options.unit_test: + import os + import tempfile + submitDir = tempfile.mkdtemp( prefix = 'tauTest_'+dataType+'_', dir = os.getcwd() ) + os.rmdir( submitDir ) + pass + +# Run the job using the direct driver. +driver = ROOT.EL.DirectDriver() +driver.submit( job, submitDir ) diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/share/TauAnalysisAlgorithmsTest_jobOptions.py b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/share/TauAnalysisAlgorithmsTest_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..fb9d15adaf94ab997419cd5864a1fd628ce01f6f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/share/TauAnalysisAlgorithmsTest_jobOptions.py @@ -0,0 +1,44 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Nils Krumnack + +# User options, which can be set from command line after a "-" character +# athena EgammaAlgorithmsTest_jobOptions.py - --myOption ... +from AthenaCommon.AthArgumentParser import AthArgumentParser +athArgsParser = AthArgumentParser() +athArgsParser.add_argument("--data-type", action = "store", dest = "data_type", + default = "data", + help = "Type of input to run over. Valid options are 'data', 'mc', 'afii'") +athArgs = athArgsParser.parse_args() + +dataType = athArgs.data_type +if not dataType in ["data", "mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +print("Running on data type: " + dataType) + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +# Set up the reading of the input file: +import AthenaRootComps.ReadAthenaxAODHybrid +theApp.EvtMax = 500 +testFile = os.getenv ( inputfile[dataType] ) +svcMgr.EventSelector.InputCollections = [testFile] + +from TauAnalysisAlgorithms.TauAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging + +# Add all algorithms from the sequence to the job. +athAlgSeq += algSeq + +# Set up a histogram output file for the job: +ServiceMgr += CfgMgr.THistSvc() +ServiceMgr.THistSvc.Output += [ + "ANALYSIS DATAFILE='TauAnalysisAlgorithmsTest." + dataType + ".hist.root' OPT='RECREATE'" + ] + +# Reduce the printout from Athena: +include( "AthAnalysisBaseComps/SuppressLogging.py" ) diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/src/components/TauAnalysisAlgorithms_entries.cxx b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/src/components/TauAnalysisAlgorithms_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..2100a92e42f2491eee51b2041fb5786d81a11248 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/src/components/TauAnalysisAlgorithms_entries.cxx @@ -0,0 +1,26 @@ +// AsgExampleTools_entries.cxx + +#include <GaudiKernel/DeclareFactoryEntries.h> + +#include <TauAnalysisAlgorithms/DiTauEfficiencyCorrectionsAlg.h> +#include <TauAnalysisAlgorithms/DiTauSmearingAlg.h> +#include <TauAnalysisAlgorithms/DiTauTruthMatchingAlg.h> +#include <TauAnalysisAlgorithms/TauEfficiencyCorrectionsAlg.h> +#include <TauAnalysisAlgorithms/TauSmearingAlg.h> +#include <TauAnalysisAlgorithms/TauTruthMatchingAlg.h> + +DECLARE_ALGORITHM_FACTORY (CP::DiTauEfficiencyCorrectionsAlg) +DECLARE_ALGORITHM_FACTORY (CP::DiTauSmearingAlg) +DECLARE_ALGORITHM_FACTORY (CP::DiTauTruthMatchingAlg) +DECLARE_ALGORITHM_FACTORY (CP::TauEfficiencyCorrectionsAlg) +DECLARE_ALGORITHM_FACTORY (CP::TauSmearingAlg) +DECLARE_ALGORITHM_FACTORY (CP::TauTruthMatchingAlg) + +DECLARE_FACTORY_ENTRIES(TauAnalysisAlgorithms) { + DECLARE_ALGORITHM (CP::DiTauEfficiencyCorrectionsAlg) + DECLARE_ALGORITHM (CP::DiTauSmearingAlg) + DECLARE_ALGORITHM (CP::DiTauTruthMatchingAlg) + DECLARE_ALGORITHM (CP::TauEfficiencyCorrectionsAlg) + DECLARE_ALGORITHM (CP::TauSmearingAlg) + DECLARE_ALGORITHM (CP::TauTruthMatchingAlg) +} diff --git a/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/src/components/TauAnalysisAlgorithms_load.cxx b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/src/components/TauAnalysisAlgorithms_load.cxx new file mode 100644 index 0000000000000000000000000000000000000000..30ea7bbd909d6498c1dec164c40961ed0b717acb --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TauAnalysisAlgorithms/src/components/TauAnalysisAlgorithms_load.cxx @@ -0,0 +1,5 @@ +// AsgExampleTools_load.cxx + +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(TauAnalysisAlgorithms) diff --git a/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/CMakeLists.txt b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..70e73676e4d5941da8e471cf143a53ef17d5b471 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +# The name of the package: +atlas_subdir( TrackingAnalysisAlgorithms ) + +# The package's dependencies: +atlas_depends_on_subdirs( + PUBLIC + PhysicsAnalysis/D3PDTools/AnaAlgorithm + PRIVATE + Event/xAOD/xAODTracking ) + +# Components in the package: +atlas_add_library( TrackingAnalysisAlgorithmsLib + TrackingAnalysisAlgorithms/*.h Root/*.cxx + PUBLIC_HEADERS TrackingAnalysisAlgorithms + LINK_LIBRARIES AnaAlgorithmLib + PRIVATE_LINK_LIBRARIES xAODTracking ) + +atlas_add_dictionary( TrackingAnalysisAlgorithmsDict + TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithmsDict.h + TrackingAnalysisAlgorithms/selection.xml + LINK_LIBRARIES TrackingAnalysisAlgorithmsLib ) + +if( NOT XAOD_STANDALONE ) + atlas_add_component( TrackingAnalysisAlgorithms + src/*.h src/*.cxx src/components/*.cxx + LINK_LIBRARIES GaudiKernel TrackingAnalysisAlgorithmsLib ) +endif() diff --git a/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/README.md b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/README.md new file mode 100644 index 0000000000000000000000000000000000000000..eb7a319d1dab7dc54009b3806322bfa513c5f34b --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/README.md @@ -0,0 +1,10 @@ +Tracking Analysis Algorithms +============================ + +This package is meant to collect dual-use/analysis algorithms that are +related to tracking. + +Current algorithm(s) in the package: + - [CP::VertexSelectionAlg](TrackingAlgorithms/VertexSelectionAlg.h): + Filter algorithm requiring a certain number of primary vertices in + the event. diff --git a/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/Root/VertexSelectionAlg.cxx b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/Root/VertexSelectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..33c6098aa6b3851724e530f361c97a661fcac9b2 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/Root/VertexSelectionAlg.cxx @@ -0,0 +1,82 @@ +// +// Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +// + +// Local include(s): +#include "TrackingAnalysisAlgorithms/VertexSelectionAlg.h" + +// EDM include(s): +#include "xAODTracking/VertexContainer.h" + +#include "AnaAlgorithm/FilterReporter.h" + +namespace CP { + + VertexSelectionAlg::VertexSelectionAlg( const std::string& name, + ISvcLocator* svcLoc ) + : EL::AnaAlgorithm( name, svcLoc ) { + + // Declare the algorithm's properties: + declareProperty( "VertexContainer", m_vertexKey = "PrimaryVertices", + "Vertex container to check" ); + declareProperty( "MinVertices", m_minVertices = 1, + "Minimum number of vertices required" ); + declareProperty( "MinTracks", m_minTracks = 0, + "Minimum number of track particles required per " + "vertex" ); + } + + StatusCode VertexSelectionAlg::initialize() { + + // Greet the user: + ATH_MSG_INFO( "Requiring " << m_minVertices << " vertex/vertices from \"" + << m_vertexKey << "\" with " << m_minTracks + << " track(s) each" ); + + ANA_CHECK (m_filterParams.initialize()); + + // Return gracefully: + return StatusCode::SUCCESS; + } + + StatusCode VertexSelectionAlg::finalize() { + ANA_CHECK (m_filterParams.finalize()); + + // Return gracefully: + return StatusCode::SUCCESS; + } + + StatusCode VertexSelectionAlg::execute() { + + EL::FilterReporter filter (m_filterParams, false); + + // Retrieve the vertex container: + const xAOD::VertexContainer* vertices = nullptr; + ATH_CHECK( evtStore()->retrieve( vertices, m_vertexKey ) ); + + // The number of "good" vertices found: + unsigned goodVertices = 0; + + // Check how many "good" vertices we have in the current event: + for( const xAOD::Vertex* vx : *vertices ) { + // It has to be either a primary or a pileup vertex: + if( ( vx->vertexType() != xAOD::VxType::PriVtx ) && + ( vx->vertexType() != xAOD::VxType::PileUp ) ) { + continue; + } + // With the minimum number of tracks specified: + if( vx->nTrackParticles() < m_minTracks ) { + continue; + } + // Apparently this is a "good" vertex: + ++goodVertices; + } + + // Decide about the event: + filter.setPassed( goodVertices >= m_minVertices ); + + // Return gracefully: + return StatusCode::SUCCESS; + } + +} // namespace CP diff --git a/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithmsDict.h b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithmsDict.h new file mode 100644 index 0000000000000000000000000000000000000000..05600c0795bde4f634529dbcc0668c5f1ba78ba2 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithmsDict.h @@ -0,0 +1,11 @@ +// Dear emacs, this is -*- c++ -*- +// +// Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +// +#ifndef TRACKINGANALYSISALGORITHMS_TRACKINGANALYSISALGORITHMSDICT_H +#define TRACKINGANALYSISALGORITHMS_TRACKINGANALYSISALGORITHMSDICT_H + +// Local include(s): +#include "TrackingAnalysisAlgorithms/VertexSelectionAlg.h" + +#endif // TRACKINGANALYSISALGORITHMS_TRACKINGANALYSISALGORITHMSDICT_H diff --git a/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithms/VertexSelectionAlg.h b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithms/VertexSelectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..669118234ec529640477c52ed3fc97a8ebc5e471 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithms/VertexSelectionAlg.h @@ -0,0 +1,64 @@ +// Dear emacs, this is -*- c++ -*- +// +// Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +// +#ifndef TRACKINGANALYSISALGORITHMS_VERTEXSELECTIONALG_H +#define TRACKINGANALYSISALGORITHMS_VERTEXSELECTIONALG_H + +// Framework include(s): +#include "AnaAlgorithm/AnaAlgorithm.h" +#include "AnaAlgorithm/FilterReporterParams.h" + +// System include(s): +#include <string> + +namespace CP { + + /// Algorithm meant to select events with "some" vertex requirements + /// + /// This algorithm is meant to be used to pose vertex requirements for the + /// analysed event. Most commonly requiring at least one primary vertex with + /// some number of track particles associated to it. + /// + /// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> + /// + class VertexSelectionAlg final : public EL::AnaAlgorithm { + + public: + /// Algorithm constructor + VertexSelectionAlg( const std::string& name, ISvcLocator* svcLoc ); + + /// @name Function(s) inherited from @c EL::AnaAlgorithm + /// @{ + + /// Function initialising the algorithm + virtual StatusCode initialize() override; + + /// Function executing the algorithm + virtual StatusCode execute() override; + + /// Function finalize the algorithm + virtual StatusCode finalize() override; + + /// @} + + private: + /// @name Algorithm properties + /// @{ + + /// Event store key of the vertex container + std::string m_vertexKey; + /// Number of vertices required in the event + unsigned m_minVertices; + /// Number of track particles required per vertex + unsigned m_minTracks; + + EL::FilterReporterParams m_filterParams {this, "vertex selection"}; + + /// @} + + }; // class VertexSelectionAlg + +} // namespace CP + +#endif // TRACKINGANALYSISALGORITHMS_VERTEXSELECTIONALG_H diff --git a/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithms/selection.xml b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithms/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..1b18e4184646d3966d9a309e6dd99504ab7b99e4 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/TrackingAnalysisAlgorithms/selection.xml @@ -0,0 +1,6 @@ +<!-- Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration --> +<lcgdict> + + <class name="CP::VertexSelectionAlg" /> + +</lcgdict> diff --git a/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/src/components/TrackingAnalysisAlgorithms_entries.cxx b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/src/components/TrackingAnalysisAlgorithms_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e536726f483a2a9851883e1864af62787e181cc8 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/src/components/TrackingAnalysisAlgorithms_entries.cxx @@ -0,0 +1,18 @@ +// +// Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +// + +// Local include(s): +#include "TrackingAnalysisAlgorithms/VertexSelectionAlg.h" + +// Framework include(s): +#include "GaudiKernel/DeclareFactoryEntries.h" + +// Declare the component(s) of the package: +DECLARE_NAMESPACE_ALGORITHM_FACTORY( CP, VertexSelectionAlg ) + +DECLARE_FACTORY_ENTRIES( TrackingAnalysisAlgorithms ) { + + DECLARE_NAMESPACE_ALGORITHM( CP, VertexSelectionAlg ) + +} diff --git a/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/src/components/TrackingAnalysisAlgorithms_load.cxx b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/src/components/TrackingAnalysisAlgorithms_load.cxx new file mode 100644 index 0000000000000000000000000000000000000000..241f0be8c02ed62c86ae19560cbf89880bbcad14 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TrackingAnalysisAlgorithms/src/components/TrackingAnalysisAlgorithms_load.cxx @@ -0,0 +1,9 @@ +// +// Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +// + +// Framework include(s): +#include "GaudiKernel/LoadFactoryEntries.h" + +// Declare the library to Gaudi: +LOAD_FACTORY_ENTRIES( TrackingAnalysisAlgorithms ) diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/CMakeLists.txt b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3a32fb71c0055535e837f92e0ed95fbc66e96d8a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/CMakeLists.txt @@ -0,0 +1,63 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Tadej Novak + +atlas_subdir( TriggerAnalysisAlgorithms ) + +atlas_depends_on_subdirs( + PUBLIC + Event/xAOD/xAODEventInfo + PhysicsAnalysis/Algorithms/SelectionHelpers + PhysicsAnalysis/Algorithms/SystematicsHandles + PhysicsAnalysis/D3PDTools/AnaAlgorithm + PhysicsAnalysis/Interfaces/AsgAnalysisInterfaces + Trigger/TrigEvent/TrigDecisionInterface + PRIVATE + PhysicsAnalysis/D3PDTools/RootCoreUtils ) + +atlas_add_library( TriggerAnalysisAlgorithmsLib + TriggerAnalysisAlgorithms/*.h TriggerAnalysisAlgorithms/*.icc Root/*.cxx + PUBLIC_HEADERS TriggerAnalysisAlgorithms + LINK_LIBRARIES xAODEventInfo SelectionHelpersLib SystematicsHandlesLib + AnaAlgorithmLib AsgAnalysisInterfaces + PRIVATE_LINK_LIBRARIES RootCoreUtils ) + +atlas_add_dictionary( TriggerAnalysisAlgorithmsDict + TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithmsDict.h + TriggerAnalysisAlgorithms/selection.xml + LINK_LIBRARIES TriggerAnalysisAlgorithmsLib ) + +if( NOT XAOD_STANDALONE ) + atlas_add_component( TriggerAnalysisAlgorithms + src/*.h src/*.cxx src/components/*.cxx + LINK_LIBRARIES GaudiKernel TriggerAnalysisAlgorithmsLib ) +endif() + +atlas_install_python_modules( python/*.py ) +atlas_install_joboptions( share/*_jobOptions.py ) +atlas_install_scripts( share/*_eljob.py ) + +if( XAOD_STANDALONE ) + atlas_add_test( TriggerAlgorithmsTestJobData + SCRIPT TriggerAlgorithmsTest_eljob.py --data-type data --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( TriggerAlgorithmsTestJobFullSim + SCRIPT TriggerAlgorithmsTest_eljob.py --data-type mc --unit-test + PROPERTIES TIMEOUT 600 ) + atlas_add_test( TriggerAlgorithmsTestJobFastSim + SCRIPT TriggerAlgorithmsTest_eljob.py --data-type afii --unit-test + PROPERTIES TIMEOUT 600 ) +else() + atlas_add_test( TriggerAlgorithmsTestJobData + SCRIPT athena.py + TriggerAnalysisAlgorithms/TriggerAlgorithmsTest_jobOptions.py - --data-type data + PROPERTIES TIMEOUT 600 ) + atlas_add_test( TriggerAlgorithmsTestJobFullSim + SCRIPT athena.py + TriggerAnalysisAlgorithms/TriggerAlgorithmsTest_jobOptions.py - --data-type mc + PROPERTIES TIMEOUT 600 ) + atlas_add_test( TriggerAlgorithmsTestJobFastSim + SCRIPT athena.py + TriggerAnalysisAlgorithms/TriggerAlgorithmsTest_jobOptions.py - --data-type afii + PROPERTIES TIMEOUT 600 ) +endif() diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/Root/TrigEventSelectorAlg.cxx b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/Root/TrigEventSelectorAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a66ce3f0369b823e11ba83781d1958bceb1927b3 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/Root/TrigEventSelectorAlg.cxx @@ -0,0 +1,71 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + +#include <AnaAlgorithm/FilterReporter.h> +#include <RootCoreUtils/StringUtil.h> +#include <TriggerAnalysisAlgorithms/TrigEventSelectionAlg.h> +#include <xAODEventInfo/EventInfo.h> + +CP::TrigEventSelectionAlg::TrigEventSelectionAlg(const std::string &name, + ISvcLocator *svcLoc) + : EL::AnaAlgorithm(name, svcLoc), + m_trigDecisionTool("Trig::TrigDecisionTool/TrigDecisionTool") +{ + declareProperty("tool", m_trigDecisionTool, "trigger decision tool"); + declareProperty("triggers", m_trigList, "trigger selection list"); + declareProperty("selectionDecoration", m_selectionDecoration, "the decoration the trigger pass status"); +} + +StatusCode CP::TrigEventSelectionAlg::initialize() +{ + if (m_trigList.empty()) { + ATH_MSG_ERROR("A list of triggers needs to be provided"); + return StatusCode::FAILURE; + } + + ANA_CHECK(m_trigDecisionTool.retrieve()); + + if (!m_selectionDecoration.empty()) { + for (const std::string &chain : m_trigList) { + m_selectionAccessors.emplace_back(m_selectionDecoration + "_" + RCU::substitute (chain, "-", "_")); + } + } + + ANA_CHECK (m_filterParams.initialize()); + + return StatusCode::SUCCESS; +} + +StatusCode CP::TrigEventSelectionAlg::execute() +{ + EL::FilterReporter filter (m_filterParams, false); + + if (m_trigList.empty()) { + filter.setPassed(true); + return StatusCode::SUCCESS; + } + + const xAOD::EventInfo *evtInfo = 0; + ANA_CHECK(evtStore()->retrieve(evtInfo, "EventInfo")); + + for (size_t i = 0; i < m_trigList.size(); i++) { + bool trigPassed = m_trigDecisionTool->isPassed(m_trigList[i]); + if (!m_selectionDecoration.empty()) { + m_selectionAccessors[i](*evtInfo) = trigPassed; + } + if (trigPassed) + filter.setPassed (true); + } + + return StatusCode::SUCCESS; +} + +StatusCode CP::TrigEventSelectionAlg::finalize() +{ + ANA_CHECK (m_filterParams.finalize()); + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/Root/TrigPrescalesAlg.cxx b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/Root/TrigPrescalesAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..db63776700c525fd4cc495bff87658a529f245b9 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/Root/TrigPrescalesAlg.cxx @@ -0,0 +1,98 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +// +// includes +// + +#include <TriggerAnalysisAlgorithms/TrigPrescalesAlg.h> + +#include <RootCoreUtils/StringUtil.h> +#include <xAODEventInfo/EventInfo.h> + +// +// method implementations +// + +namespace CP +{ + TrigPrescalesAlg :: + TrigPrescalesAlg (const std::string& name, + ISvcLocator* pSvcLocator) + : AnaAlgorithm (name, pSvcLocator) + , m_pileupReweightingTool ("CP::PileupReweightingTool", this) + { + declareProperty ("pileupReweightingTool", m_pileupReweightingTool, "the pileup reweighting tool to be used"); + declareProperty ("triggers", m_trigList, "trigger list"); + declareProperty ("triggersAll", m_trigListAll, "all trigger list"); + declareProperty ("prescaleDecoration", m_prescaleDecoration, "decoration to store prescales"); + } + + + + StatusCode TrigPrescalesAlg :: + initialize () + { + if (m_prescaleDecoration.empty()) + { + ANA_MSG_ERROR ("The decoration should not be empty"); + return StatusCode::FAILURE; + } + + if (m_trigList.empty()) + { + ANA_MSG_ERROR ("A list of triggers needs to be provided"); + return StatusCode::FAILURE; + } + + if (m_trigListAll.empty()) + { + m_trigListAll = m_trigList; + } + + for (const std::string &chain : m_trigListAll) + { + m_prescaleAccessors.emplace_back(m_prescaleDecoration + "_" + RCU::substitute (chain, "-", "_")); + + // Generate helper functions + if (std::find(m_trigList.begin(), m_trigList.end(), chain) != m_trigList.end()) + { + m_prescaleFunctions.emplace_back([this](const xAOD::EventInfo *evtInfo, const std::string &trigger) + { + return m_pileupReweightingTool->getDataWeight (*evtInfo, trigger, true); + }); + } + else + { + m_prescaleFunctions.emplace_back([](const xAOD::EventInfo *, const std::string &) + { + return invalidTriggerPrescale(); + }); + } + } + + ANA_CHECK (m_pileupReweightingTool.retrieve()); + + return StatusCode::SUCCESS; + } + + + + StatusCode TrigPrescalesAlg :: + execute () + { + const xAOD::EventInfo *evtInfo{}; + ANA_CHECK (evtStore()->retrieve(evtInfo, "EventInfo")); + + for (size_t i = 0; i < m_trigListAll.size(); i++) + { + (m_prescaleAccessors[i]) (*evtInfo) = (m_prescaleFunctions[i]) (evtInfo, m_trigListAll[i]); + } + + return StatusCode::SUCCESS; + } +} diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/TrigEventSelectionAlg.h b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/TrigEventSelectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..8ed2a020d793a81fce07e2f330968b8c9784dc1a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/TrigEventSelectionAlg.h @@ -0,0 +1,46 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + +#ifndef TRIGGER_ANALYSIS_ALGORITHMS__TRIG_EVENT_SELECTION_ALG_H +#define TRIGGER_ANALYSIS_ALGORITHMS__TRIG_EVENT_SELECTION_ALG_H + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AnaAlgorithm/FilterReporterParams.h> +#include <AsgTools/ToolHandle.h> +#include <AthContainers/AuxElement.h> +#include <TrigDecisionInterface/ITrigDecisionTool.h> + +namespace CP +{ + class TrigEventSelectionAlg : public EL::AnaAlgorithm + { + public: + TrigEventSelectionAlg(const std::string &name, + ISvcLocator *svcLoc = nullptr); + + virtual StatusCode initialize() final; + virtual StatusCode execute() final; + virtual StatusCode finalize() final; + + private: + /// \brief trigger decision tool handle + ToolHandle<Trig::ITrigDecisionTool> m_trigDecisionTool; + + /// \brief list of triggers or trigger chains + std::vector<std::string> m_trigList; + + /// \brief the decoration for trigger selection + std::string m_selectionDecoration; + + /// \brief the accessors for \ref m_selectionDecoration and \ref m_trigList combination + std::vector<SG::AuxElement::Decorator<bool>> m_selectionAccessors; + + /// \brief the filter reporter parameters + EL::FilterReporterParams m_filterParams {this, "trigger event selection"}; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/TrigPrescalesAlg.h b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/TrigPrescalesAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..a6148e03355c72ff8248badd1846dc279baa05cb --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/TrigPrescalesAlg.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +#ifndef TRIGGER_ANALYSIS_ALGORITHMS__TRIG_PRESCALES_ALG_H +#define TRIGGER_ANALYSIS_ALGORITHMS__TRIG_PRESCALES_ALG_H + +#include <functional> + +#include <AnaAlgorithm/AnaAlgorithm.h> +#include <AsgAnalysisInterfaces/IPileupReweightingTool.h> + +namespace CP +{ + /// \brief the decoration value to use if there is no valid + /// trigger prescale information + constexpr float invalidTriggerPrescale () {return -1;} + + + + /// \brief an algorithm for retrieving trigger prescales + + class TrigPrescalesAlg final : public EL::AnaAlgorithm + { + /// \brief the standard constructor + public: + TrigPrescalesAlg (const std::string& name, + ISvcLocator* pSvcLocator); + + + public: + StatusCode initialize () override; + + public: + StatusCode execute () override; + + + /// \brief the pile-up reweighting tool + private: + ToolHandle<IPileupReweightingTool> m_pileupReweightingTool; + + /// \brief list of prescaled triggers or trigger chains + private: + std::vector<std::string> m_trigList; + + /// \brief list of all triggers or trigger chains + private: + std::vector<std::string> m_trigListAll; + + /// \brief list of helper functions to compute the prescales + private: + std::vector<std::function<float(const xAOD::EventInfo *, const std::string &)>> m_prescaleFunctions; + + /// \brief the decoration for trigger prescales + private: + std::string m_prescaleDecoration; + + /// \brief the accessors for \ref m_prescaleDecoration and \ref m_trigList combination + private: + std::vector<SG::AuxElement::Decorator<float>> m_prescaleAccessors; + }; +} + +#endif diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithmsDict.h b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithmsDict.h new file mode 100644 index 0000000000000000000000000000000000000000..e86f6bb0300e7f053194ccaff336275923bbad3e --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithmsDict.h @@ -0,0 +1,14 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +#ifndef TRIGGER_ANALYSIS_ALGORITHMS__TRIGGER_ANALYSIS_ALGORITHMS_DICT_H +#define TRIGGER_ANALYSIS_ALGORITHMS__TRIGGER_ANALYSIS_ALGORITHMS_DICT_H + +#include <TriggerAnalysisAlgorithms/TrigEventSelectionAlg.h> +#include <TriggerAnalysisAlgorithms/TrigPrescalesAlg.h> + +#endif diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/selection.xml b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/selection.xml new file mode 100644 index 0000000000000000000000000000000000000000..677efcf89427a25b3066bad75f590d0da329561a --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/TriggerAnalysisAlgorithms/selection.xml @@ -0,0 +1,6 @@ +<lcgdict> + + <class name="CP::TrigEventSelectionAlg" /> + <class name="CP::TrigPrescalesAlg" /> + +</lcgdict> diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/python/TriggerAnalysisAlgorithmsTest.py b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/python/TriggerAnalysisAlgorithmsTest.py new file mode 100644 index 0000000000000000000000000000000000000000..c0d82335ddd0c6c11bafdfa3e860b04a253974fb --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/python/TriggerAnalysisAlgorithmsTest.py @@ -0,0 +1,49 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Tadej Novak +# @author Nils Krumnack + +from AnaAlgorithm.AlgSequence import AlgSequence +from AnaAlgorithm.DualUseConfig import createAlgorithm + +def makeSequence (dataType) : + + # Config: + triggerChains = [ + 'HLT_2mu14', + 'HLT_mu20_mu8noL1', + 'HLT_2e17_lhvloose_nod0' + ] + + + algSeq = AlgSequence() + + # Set up the systematics loader/handler algorithm: + alg = createAlgorithm( 'CP::SysListLoaderAlg', 'SysLoaderAlg' ) + alg.sigmaRecommended = 1 + algSeq += alg + + # Include, and then set up the pileup analysis sequence: + from TriggerAnalysisAlgorithms.TriggerAnalysisSequence import \ + makeTriggerAnalysisSequence + triggerSequence = makeTriggerAnalysisSequence( dataType, triggerChains=triggerChains ) + algSeq += triggerSequence + + # Set up an ntuple to check the job with: + treeMaker = createAlgorithm( 'CP::TreeMakerAlg', 'TreeMaker' ) + treeMaker.TreeName = 'events' + algSeq += treeMaker + ntupleMaker = createAlgorithm( 'CP::AsgxAODNTupleMakerAlg', 'NTupleMaker' ) + ntupleMaker.TreeName = 'events' + ntupleMaker.Branches = [ + 'EventInfo.runNumber -> runNumber', + 'EventInfo.eventNumber -> eventNumber', + ] + ntupleMaker.Branches += ['EventInfo.trigPassed_' + t + ' -> trigPassed_' + t for t in triggerChains] + ntupleMaker.systematicsRegex = '.*' + algSeq += ntupleMaker + treeFiller = createAlgorithm( 'CP::TreeFillerAlg', 'TreeFiller' ) + treeFiller.TreeName = 'events' + algSeq += treeFiller + + return algSeq diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/python/TriggerAnalysisSequence.py b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/python/TriggerAnalysisSequence.py new file mode 100644 index 0000000000000000000000000000000000000000..68e6dcfbc0bcacdcb3e35ebe39813ba29e8853be --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/python/TriggerAnalysisSequence.py @@ -0,0 +1,58 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +# AnaAlgorithm import(s): +from AnaAlgorithm.AnaAlgSequence import AnaAlgSequence +from AnaAlgorithm.DualUseConfig import addPrivateTool, createAlgorithm, createPublicTool + + +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 diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/python/__init__.py b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/python/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..a37d36f3512db5b18b69e65df7aff2568fa8d2aa --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/python/__init__.py @@ -0,0 +1,3 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration + +__version__ = '1.0.0' diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/share/TriggerAlgorithmsTest_eljob.py b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/share/TriggerAlgorithmsTest_eljob.py new file mode 100755 index 0000000000000000000000000000000000000000..ffcf2f3e48d094cfd01f7a222259706ee2cfa53c --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/share/TriggerAlgorithmsTest_eljob.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Tadej Novak + + +# Read the submission directory as a command line argument. You can +# extend the list of arguments with your private ones later on. +import optparse +parser = optparse.OptionParser() +parser.add_option( '-d', '--data-type', dest = 'data_type', + action = 'store', type = 'string', default = 'data', + help = 'Type of data to run over. Valid options are data, mc, afii' ) +parser.add_option( '-s', '--submission-dir', dest = 'submission_dir', + action = 'store', type = 'string', default = 'submitDir', + help = 'Submission directory for EventLoop' ) +parser.add_option( '-u', '--unit-test', dest='unit_test', + action = 'store_true', default = False, + help = 'Run the job in "unit test mode"' ) +( options, args ) = parser.parse_args() + +# Set up (Py)ROOT. +import ROOT +ROOT.xAOD.Init().ignore() + +# ideally we'd run over all of them, but we don't have a mechanism to +# configure per-sample right now + +dataType = options.data_type + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +if dataType not in ["data", "mc", "afii"] : + raise ValueError ("invalid data type: " + dataType) + +# Set up the sample handler object. See comments from the C++ macro +# for the details about these lines. +import os +sh = ROOT.SH.SampleHandler() +sh.setMetaString( 'nc_tree', 'CollectionTree' ) +sample = ROOT.SH.SampleLocal (dataType) +sample.add (os.getenv (inputfile[dataType])) +sh.add (sample) +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" ) + +from TriggerAnalysisAlgorithms.TriggerAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging +for alg in algSeq: + job.algsAdd( alg ) + pass + +# Set up an output file for the job: +job.outputAdd( ROOT.EL.OutputStream( 'ANALYSIS' ) ) + +# Find the right output directory: +submitDir = options.submission_dir +if options.unit_test: + import os + import tempfile + submitDir = tempfile.mkdtemp( prefix = 'triggerTest_', dir = os.getcwd() ) + os.rmdir( submitDir ) + pass + +# Run the job using the direct driver. +driver = ROOT.EL.DirectDriver() +driver.submit( job, submitDir ) diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/share/TriggerAlgorithmsTest_jobOptions.py b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/share/TriggerAlgorithmsTest_jobOptions.py new file mode 100644 index 0000000000000000000000000000000000000000..a2244c9537c4367bf0920072a0f7b72391ca0c6f --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/share/TriggerAlgorithmsTest_jobOptions.py @@ -0,0 +1,44 @@ +# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# +# @author Tadej Novak + +# User options, which can be set from command line after a "-" character +# athena EgammaAlgorithmsTest_jobOptions.py - --myOption ... +from AthenaCommon.AthArgumentParser import AthArgumentParser +athArgsParser = AthArgumentParser() +athArgsParser.add_argument("--data-type", action = "store", dest = "data_type", + default = "data", + help = "Type of input to run over. Valid options are 'data', 'mc', 'afii'") +athArgs = athArgsParser.parse_args() + +dataType = athArgs.data_type +if not dataType in ["data", "mc", "afii"] : + raise Exception ("invalid data type: " + dataType) + +print("Running on data type: " + dataType) + +inputfile = {"data": 'ASG_TEST_FILE_DATA', + "mc": 'ASG_TEST_FILE_MC', + "afii": 'ASG_TEST_FILE_MC_AFII'} + +# Set up the reading of the input file: +import AthenaRootComps.ReadAthenaxAODHybrid +theApp.EvtMax = 500 +testFile = os.getenv ( inputfile[dataType] ) +svcMgr.EventSelector.InputCollections = [testFile] + +from TriggerAnalysisAlgorithms.TriggerAnalysisAlgorithmsTest import makeSequence +algSeq = makeSequence (dataType) +print algSeq # For debugging + +# Add all algorithms from the sequence to the job. +athAlgSeq += algSeq + +# Set up a histogram output file for the job: +ServiceMgr += CfgMgr.THistSvc() +ServiceMgr.THistSvc.Output += [ + "ANALYSIS DATAFILE='TriggerAlgorithmsTest." + dataType + ".hist.root' OPT='RECREATE'" + ] + +# Reduce the printout from Athena: +include( "AthAnalysisBaseComps/SuppressLogging.py" ) diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/src/components/TriggerAnalysisAlgorithms_entries.cxx b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/src/components/TriggerAnalysisAlgorithms_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..aece9a7e751ec8175aa6ec410eb0b793f92ff366 --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/src/components/TriggerAnalysisAlgorithms_entries.cxx @@ -0,0 +1,20 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +#include <GaudiKernel/DeclareFactoryEntries.h> + +#include <TriggerAnalysisAlgorithms/TrigEventSelectionAlg.h> +#include <TriggerAnalysisAlgorithms/TrigPrescalesAlg.h> + + +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, TrigEventSelectionAlg) +DECLARE_NAMESPACE_ALGORITHM_FACTORY (CP, TrigPrescalesAlg) + +DECLARE_FACTORY_ENTRIES(TriggerAnalysisAlgorithms) { + DECLARE_NAMESPACE_ALGORITHM (CP, TrigEventSelectionAlg) + DECLARE_NAMESPACE_ALGORITHM (CP, TrigPrescalesAlg) +} diff --git a/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/src/components/TriggerAnalysisAlgorithms_load.cxx b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/src/components/TriggerAnalysisAlgorithms_load.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1ba6022270b61d9a459b7d658eabc026ae7190dc --- /dev/null +++ b/PhysicsAnalysis/Algorithms/TriggerAnalysisAlgorithms/src/components/TriggerAnalysisAlgorithms_load.cxx @@ -0,0 +1,10 @@ +/* + Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +*/ + +/// @author Tadej Novak + + +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(TriggerAnalysisAlgorithms) diff --git a/Projects/Athena/package_filters.txt b/Projects/Athena/package_filters.txt index e4383323a0ac882711d458b6235737f56e843f1a..9a7107070e1b4d83e6cf19f43f886b523cdc7722 100644 --- a/Projects/Athena/package_filters.txt +++ b/Projects/Athena/package_filters.txt @@ -29,6 +29,7 @@ # Some analysis packages that are not part of Athena - Control/AthLinksSA +- PhysicsAnalysis/Algorithms/.* - PhysicsAnalysis/AnalysisCommon/CPAnalysisExamples - PhysicsAnalysis/AnalysisCommon/PMGTools - PhysicsAnalysis/D3PDTools/EventLoop.*