From edd2e397456f808cfaff3198996bade31fe4e924 Mon Sep 17 00:00:00 2001 From: Scott Snyder <scott.snyder@cern.ch> Date: Mon, 29 Aug 2016 03:41:24 +0200 Subject: [PATCH] clang warnings: missing override keywords. (EventUtils-00-00-32) * Tagging EventUtils-00-00-32. * clang warnings: missing override keywords. 2016-08-29 scott snyder <snyder@bnl.gov> * Tagging EventUtils-00-00-31. * endreq -> endmsg. * Tagging EventUtils-00-00-30. * Coverity 109084. 2016-08-01 Will Buttinger <will@cern.ch> * Fix cmake compilation * tag EventUtils-00-00-29 2016-06-20 Karsten Koeneke <karsten.koeneke@cern.ch> * Make the selection tools in ParticleSelectionAlg public * tag EventUtils-00-00-27 ... (Long ChangeLog diff - truncated) --- .../AnalysisCommon/EventUtils/CMakeLists.txt | 9 +- .../EventUtils/cmt/requirements | 10 +- .../EventUtils/src/AddVarAlg.cxx | 2 +- .../AnalysisCommon/EventUtils/src/AddVarAlg.h | 2 +- .../EventUtils/src/AddVarTool.h | 4 +- .../AnalysisCommon/EventUtils/src/CutAlg.cxx | 72 ++- .../AnalysisCommon/EventUtils/src/CutAlg.h | 46 +- .../AnalysisCommon/EventUtils/src/CutTool.cxx | 11 +- .../AnalysisCommon/EventUtils/src/CutTool.h | 4 +- .../EventUtils/src/EventDecisionAlg.cxx | 95 ++++ .../EventUtils/src/EventDecisionAlg.h | 66 +++ .../EventUtils/src/EventQualityFilterAlg.cxx | 52 ++- .../EventUtils/src/EventQualityFilterAlg.h | 65 +-- .../EventUtils/src/ParticleCombinerTool.cxx | 73 +-- .../EventUtils/src/ParticleCombinerTool.h | 4 +- .../EventUtils/src/ParticleRemoverAlg.cxx | 315 +++++++++++++ .../EventUtils/src/ParticleRemoverAlg.h | 114 +++++ .../EventUtils/src/ParticleRemoverAlg.icc | 242 ++++++++++ .../EventUtils/src/ParticleSelectionAlg.cxx | 419 +++++++++++++----- .../EventUtils/src/ParticleSelectionAlg.h | 215 ++++----- .../EventUtils/src/ParticleSelectionAlg.icc | 188 ++++++++ .../EventUtils/src/ParticleSelectionTool.cxx | 1 + .../EventUtils/src/ParticleSelectionTool.h | 4 +- .../EventUtils/src/ParticleSortingTool.cxx | 43 +- .../EventUtils/src/ParticleSortingTool.h | 60 ++- .../EventUtils/src/TriggerSelectionAlg.cxx | 130 ++++++ .../EventUtils/src/TriggerSelectionAlg.h | 85 ++++ .../src/components/EventUtils_entries.cxx | 24 +- 28 files changed, 1936 insertions(+), 419 deletions(-) create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventDecisionAlg.cxx create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventDecisionAlg.h create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.cxx create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.h create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.icc create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.icc create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/TriggerSelectionAlg.cxx create mode 100644 PhysicsAnalysis/AnalysisCommon/EventUtils/src/TriggerSelectionAlg.h diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/CMakeLists.txt b/PhysicsAnalysis/AnalysisCommon/EventUtils/CMakeLists.txt index de8fc1a7f68..9e38cea5081 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/CMakeLists.txt +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/CMakeLists.txt @@ -7,15 +7,19 @@ atlas_subdir( EventUtils ) # Declare the package's dependencies: atlas_depends_on_subdirs( PRIVATE + Control/AthAnalysisBaseComps Control/AthContainers + Control/AthContainersInterfaces Control/AthLinks Control/AthenaBaseComps + Control/AthenaKernel Control/CxxUtils Event/EventInfo Event/xAOD/xAODBTagging Event/xAOD/xAODBase Event/xAOD/xAODCaloEvent Event/xAOD/xAODCore + Event/xAOD/xAODCutFlow Event/xAOD/xAODEgamma Event/xAOD/xAODEventInfo Event/xAOD/xAODJet @@ -33,14 +37,15 @@ atlas_depends_on_subdirs( PRIVATE Trigger/TrigAnalysis/TrigDecisionTool ) # External dependencies: +find_package( Boost COMPONENTS filesystem thread system ) find_package( ROOT COMPONENTS Core Tree MathCore Hist RIO pthread ) # Component(s) in the package: atlas_add_component( EventUtils src/*.cxx src/components/*.cxx - INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} - LINK_LIBRARIES ${ROOT_LIBRARIES} AthContainers AthLinks AthenaBaseComps CxxUtils EventInfo xAODBTagging xAODBase xAODCaloEvent xAODCore xAODEgamma xAODEventInfo xAODJet xAODMissingET xAODMuon xAODPFlow xAODParticleEvent xAODTau xAODTracking xAODTruth GaudiKernel PATCoreLib ExpressionEvaluationLib TrigDecisionToolLib ) + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} ${Boost_LIBRARIES} AthAnalysisBaseCompsLib AthContainers AthLinks AthenaBaseComps AthenaKernel CxxUtils EventInfo xAODBTagging xAODBase xAODCaloEvent xAODCore xAODCutFlow xAODEgamma xAODEventInfo xAODJet xAODMissingET xAODMuon xAODPFlow xAODParticleEvent xAODTau xAODTracking xAODTruth GaudiKernel PATCoreLib ExpressionEvaluationLib TrigDecisionToolLib ) # Install files from the package: atlas_install_python_modules( python/*.py ) diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/cmt/requirements b/PhysicsAnalysis/AnalysisCommon/EventUtils/cmt/requirements index 121353452fd..5cac883e799 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/cmt/requirements +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/cmt/requirements @@ -7,21 +7,26 @@ public use AtlasPolicy AtlasPolicy-* private +use AthAnalysisBaseComps AthAnalysisBaseComps-* Control use AthContainers AthContainers-* Control use AthLinks AthLinks-* Control use AthenaBaseComps AthenaBaseComps-* Control -use AtlasROOT AtlasROOT-* External use CxxUtils CxxUtils-* Control +use AthContainersInterfaces AthContainersInterfaces-* Control +use AthenaKernel AthenaKernel-* Control +use AtlasROOT AtlasROOT-* External +use AtlasBoost AtlasBoost-* External use DerivationFrameworkInterfaces DerivationFrameworkInterfaces-* PhysicsAnalysis/DerivationFramework -use EventInfo EventInfo-* Event use ExpressionEvaluation ExpressionEvaluation-* PhysicsAnalysis/CommonTools use GaudiInterface GaudiInterface-* External use PATCore PATCore-* PhysicsAnalysis/AnalysisCommon use TrigDecisionTool TrigDecisionTool-* Trigger/TrigAnalysis +use EventInfo EventInfo-* Event use xAODBTagging xAODBTagging-* Event/xAOD use xAODBase xAODBase-* Event/xAOD use xAODCaloEvent xAODCaloEvent-* Event/xAOD use xAODCore xAODCore-* Event/xAOD +use xAODCutFlow xAODCutFlow-* Event/xAOD use xAODEgamma xAODEgamma-* Event/xAOD use xAODEventInfo xAODEventInfo-* Event/xAOD use xAODJet xAODJet-* Event/xAOD @@ -32,6 +37,7 @@ use xAODParticleEvent xAODParticleEvent-* Event/xAOD use xAODTau xAODTau-* Event/xAOD use xAODTracking xAODTracking-* Event/xAOD use xAODTruth xAODTruth-* Event/xAOD +use AthenaBaseComps AthenaBaseComps-* Control end_private diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.cxx index db27674119d..4a410005e11 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.cxx +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.cxx @@ -29,7 +29,7 @@ //////////////// AddVarAlg::AddVarAlg( const std::string& name, ISvcLocator* pSvcLocator ) : - ::AthFilterAlgorithm( name, pSvcLocator ), + ::AthAlgorithm( name, pSvcLocator ), m_jos("JobOptionsSvc", name), m_tool("AddVarTool/AddVarTool", this), m_setInCollKey(false), diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.h index 1bc1ab742ca..fbbfe12fc87 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.h +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.h @@ -29,7 +29,7 @@ namespace DerivationFramework { class AddVarAlg - : public ::AthFilterAlgorithm + : public ::AthAlgorithm { /////////////////////////////////////////////////////////////////// diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarTool.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarTool.h index 70cf3b52627..2cb652d0ae9 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarTool.h +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarTool.h @@ -52,10 +52,10 @@ public: virtual ~AddVarTool(); /// Athena algtool's initialize - virtual StatusCode initialize(); + virtual StatusCode initialize() override; /// Athena algtool's finalize - virtual StatusCode finalize(); + virtual StatusCode finalize() override; /// Implement the method from the ISkimmingTool interface diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.cxx index 05fec3da403..1b4211dd5cc 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.cxx +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.cxx @@ -16,9 +16,13 @@ // FrameWork includes #include "GaudiKernel/Property.h" -#include "GaudiKernel/IJobOptionsSvc.h" -#include "DerivationFrameworkInterfaces/ISkimmingTool.h" - +#include "ExpressionEvaluation/ExpressionParser.h" +#include "ExpressionEvaluation/SGxAODProxyLoader.h" +#include "ExpressionEvaluation/SGNTUPProxyLoader.h" +#include "ExpressionEvaluation/MultipleProxyLoader.h" +#include "ExpressionEvaluation/StackElement.h" +#include "TrigDecisionTool/TrigDecisionTool.h" +#include "ExpressionEvaluation/TriggerDecisionProxyLoader.h" /////////////////////////////////////////////////////////////////// @@ -30,18 +34,13 @@ CutAlg::CutAlg( const std::string& name, ISvcLocator* pSvcLocator ) : ::AthFilterAlgorithm( name, pSvcLocator ), - m_jos("JobOptionsSvc", name), - m_skimTool("CutTool/CutTool", this), + m_trigDecisionTool("Trig::TrigDecisionTool/TrigDecisionTool"), + m_parser(0), m_cut(""), - m_setCut(false), m_nEventsProcessed(0) { - declareProperty("JobOptionsSvc", m_jos, "The JobOptionService instance."); - - declareProperty("SkimTool", m_skimTool, "The private SkimmingTool" ); - - declareProperty("Cut", m_cut="", "The name of the output container" ); - m_cut.declareUpdateHandler( &CutAlg::setupCut, this ); + declareProperty("Cut", m_cut="", "The name of the output container" ); + declareProperty("TrigDecisionTool", m_trigDecisionTool, "If you do not use trigger decisions and want to ensure the TrigDecisionTool is not loaded, set this to a blank string"); } @@ -60,36 +59,27 @@ StatusCode CutAlg::initialize() ATH_MSG_DEBUG ("Initializing " << name() << "..."); // Print out the used configuration - ATH_MSG_DEBUG ( " using JobOptionsSvc = " << m_jos ); - ATH_MSG_DEBUG ( " using SkimTool = " << m_skimTool ); - ATH_MSG_DEBUG ( " using Cut = " << m_cut ); - + ATH_MSG_DEBUG ( " using = " << m_trigDecisionTool ); + ATH_MSG_DEBUG ( " using = " << m_cut ); // Initialize the counters to zero m_nEventsProcessed = 0 ; + // initialize proxy loaders for expression parsing + ExpressionParsing::MultipleProxyLoader *proxyLoaders = new ExpressionParsing::MultipleProxyLoader(); - // Get the JobOptionService - // We will use this to set the properties of our private skimming tool - // from the properties of this algorithm. - ATH_MSG_VERBOSE( "Getting the JobOptionService"); - ATH_CHECK( m_jos.retrieve() ); - - // Get the full name of the private skimTool - ATH_MSG_VERBOSE( "Getting the full name of the tool"); - const std::string& fullToolName = this->name() + "." + m_skimTool.name(); - ATH_MSG_DEBUG( "Got the full name of the tool: " << fullToolName ); - - // Now, set all properties of the private skimTool that were acutally configured - if (m_setCut) { - ATH_MSG_DEBUG( "Setting property" << m_cut - << " of private tool with name: '" << fullToolName << "'" ); - ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_cut) ); + // initialise TDT explicitly, needed for the tool to properly work with trigger decisions in AthAnalysisBase (until fixed) + if( !m_trigDecisionTool.empty() ) { + ATH_CHECK( m_trigDecisionTool.retrieve() ); + proxyLoaders->push_back(new ExpressionParsing::TriggerDecisionProxyLoader(m_trigDecisionTool)); } - ATH_MSG_DEBUG( "Done setting properties of the tool"); - // Get the skimming tool - ATH_CHECK( m_skimTool.retrieve() ); + proxyLoaders->push_back(new ExpressionParsing::SGxAODProxyLoader(evtStore())); + proxyLoaders->push_back(new ExpressionParsing::SGNTUPProxyLoader(evtStore())); + + // load the expressions + m_parser = new ExpressionParsing::ExpressionParser(proxyLoaders); + m_parser->loadExpression( m_cut.value() ); ATH_MSG_DEBUG ( "==> done with initialize " << name() << "..." ); @@ -103,8 +93,10 @@ StatusCode CutAlg::finalize() ATH_MSG_DEBUG ("Finalizing " << name() << "..."); // Release all tools and services - ATH_CHECK( m_jos.release() ); - ATH_CHECK( m_skimTool.release() ); + if (m_parser) { + delete m_parser; + m_parser = 0; + } return StatusCode::SUCCESS; } @@ -118,9 +110,11 @@ StatusCode CutAlg::execute() // Simple status message at the beginning of each event execute, ATH_MSG_DEBUG ( "==> execute " << name() << " on " << m_nEventsProcessed << ". event..." ); + ATH_MSG_VERBOSE ( "Dumping event store: " << evtStore()->dump() ); - // Call the skimming tool and set its result - bool eventPasses = m_skimTool->eventPassesFilter(); + // Make the pass/fail decision + bool eventPasses = true; + eventPasses = m_parser->evaluateAsBool(); this->setFilterPassed( eventPasses ); ATH_MSG_DEBUG("Event passes/fails: " << eventPasses ); diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.h index 0ec6805d8f1..07e6e2d4030 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.h +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.h @@ -16,18 +16,17 @@ // FrameWork includes #include "GaudiKernel/ToolHandle.h" -#include "GaudiKernel/ServiceHandle.h" #include "AthenaBaseComps/AthFilterAlgorithm.h" +#include "TrigDecisionTool/TrigDecisionTool.h" - -// forward declarations -class IJobOptionsSvc; -namespace DerivationFramework { - class ISkimmingTool; +// Forward declarations +namespace ExpressionParsing { + class ExpressionParser; } + class CutAlg : public ::AthFilterAlgorithm { @@ -55,53 +54,26 @@ class CutAlg virtual StatusCode finalize(); -private: - // The update handlers - - /// This internal method will realize if a user sets the 'Cut' property - void setupCut( Property& /*prop*/ ); - /////////////////////////////////////////////////////////////////// // Private data: /////////////////////////////////////////////////////////////////// private: - /// The job options service (will be used to forward this algs properties to - /// the private tool) - ServiceHandle<IJobOptionsSvc> m_jos; + /// The trigger decision tool + ToolHandle<Trig::TrigDecisionTool> m_trigDecisionTool; - /// The ToolHandle to the SkimmingTool - ToolHandle<DerivationFramework::ISkimmingTool> m_skimTool; + /// The expression parser + ExpressionParsing::ExpressionParser *m_parser; /// The cut string StringProperty m_cut; - /// This boolean is true if the user sets the 'Cut' property - bool m_setCut; - - - /// Internal event counter unsigned long m_nEventsProcessed; }; -// I/O operators -////////////////////// - -/////////////////////////////////////////////////////////////////// -// Inline methods: -/////////////////////////////////////////////////////////////////// - -/// This internal method will realize if a user sets the 'Cut' property -inline void CutAlg::setupCut( Property& /*prop*/ ) { - m_setCut = true; - return; -} - - - #endif //> !EVENTUTILS_CUTALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.cxx index 817bef0b155..87354401b7a 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.cxx +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.cxx @@ -43,7 +43,8 @@ CutTool::CutTool( const std::string& type, { declareInterface< DerivationFramework::ISkimmingTool >(this); - declareProperty("Cut", m_cut="", "The name of the output container" ); + declareProperty("Cut", m_cut="", "The cut expression" ); + declareProperty("TrigDecisionTool",m_trigDecisionTool,"If you do not use trigger decisions and want to ensure the TrigDecisionTool is not loaded, set this to a blank string"); } // Destructor @@ -61,7 +62,13 @@ StatusCode CutTool::initialize() // initialize proxy loaders for expression parsing ExpressionParsing::MultipleProxyLoader *proxyLoaders = new ExpressionParsing::MultipleProxyLoader(); - proxyLoaders->push_back(new ExpressionParsing::TriggerDecisionProxyLoader(m_trigDecisionTool)); + + // initialise TDT explicitly, needed for the tool to properly work with trigger decisions in AthAnalysisBase (until fixed) + if( !m_trigDecisionTool.empty() ) { + ATH_CHECK( m_trigDecisionTool.retrieve() ); + proxyLoaders->push_back(new ExpressionParsing::TriggerDecisionProxyLoader(m_trigDecisionTool)); + } + proxyLoaders->push_back(new ExpressionParsing::SGxAODProxyLoader(evtStore())); proxyLoaders->push_back(new ExpressionParsing::SGNTUPProxyLoader(evtStore())); diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.h index 0314ee70201..71b77e76439 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.h +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.h @@ -48,10 +48,10 @@ class CutTool virtual ~CutTool(); /// Athena algtool's initialize - virtual StatusCode initialize(); + virtual StatusCode initialize() override; /// Athena algtool's finalize - virtual StatusCode finalize(); + virtual StatusCode finalize() override; /// Implement the method from the ISkimmingTool interface diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventDecisionAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventDecisionAlg.cxx new file mode 100644 index 00000000000..de769b8900b --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventDecisionAlg.cxx @@ -0,0 +1,95 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// EventDecisionAlg.cxx +// Implementation file for class EventDecisionAlg +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// + +// EventUtils includes +#include "EventDecisionAlg.h" + +// STL includes + +// FrameWork includes +#include "GaudiKernel/Property.h" +#include "AthenaKernel/IDecisionSvc.h" + + +// Constructors +//////////////// +EventDecisionAlg::EventDecisionAlg( const std::string& name, + ISvcLocator* pSvcLocator ) : + ::AthFilterAlgorithm( name, pSvcLocator ), + m_decSvc("DecisionSvc/DecisionSvc", name), + m_streamNames() +{ + declareProperty("DecisionService", m_decSvc, "The handle to the IDecisionSvc" ); + declareProperty("OutputStreamNames", m_streamNames, "The names of all output streams to check"); +} + + +// Destructor +/////////////// +EventDecisionAlg::~EventDecisionAlg() +{} + + + +// Athena Algorithm's Hooks +//////////////////////////// +StatusCode EventDecisionAlg::initialize() +{ + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + + // Print out the used configuration + ATH_MSG_DEBUG ( " using = " << m_decSvc ); + ATH_MSG_DEBUG ( " using = " << m_streamNames ); + + // Retrieve the services + ATH_CHECK( m_decSvc.retrieve() ); + + ATH_MSG_DEBUG ( "==> done with initialize " << name() << "..." ); + return StatusCode::SUCCESS; +} + + + +StatusCode EventDecisionAlg::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + + // Release all tools and services + ATH_CHECK( m_decSvc.release() ); + + return StatusCode::SUCCESS; +} + + + +StatusCode EventDecisionAlg::execute() +{ + // Simple status message at the beginning of each event execute, + ATH_MSG_DEBUG ( "==> execute " << name() ); + ATH_MSG_VERBOSE ( "Dumping event store: " << evtStore()->dump() ); + + // Make the pass/fail decision + // Ensure that the even passes if no stream name is given + bool eventPasses = true; + for ( const std::string& streamName : m_streamNames.value() ){ + // Ensure that the even passes if no stream name is given + eventPasses = false; + eventPasses = m_decSvc->isEventAccepted(streamName); + if (eventPasses){ + ATH_MSG_DEBUG("Got an event accept from stream name " << streamName); + break; + } + } + this->setFilterPassed( eventPasses ); + ATH_MSG_DEBUG("Event passes/fails: " << eventPasses ); + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventDecisionAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventDecisionAlg.h new file mode 100644 index 00000000000..401471df97b --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventDecisionAlg.h @@ -0,0 +1,66 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// EventDecisionAlg.h +// Header file for class EventDecisionAlg +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef EVENTUTILS_EVENTDECISIONALG_H +#define EVENTUTILS_EVENTDECISIONALG_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaBaseComps/AthFilterAlgorithm.h" + +// forward declarations +class IDecisionSvc; + + +class EventDecisionAlg + : public ::AthFilterAlgorithm +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + // Copy constructor: + + /// Constructor with parameters: + EventDecisionAlg( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~EventDecisionAlg(); + + /// Athena algorithm's initalize hook + virtual StatusCode initialize(); + + /// Athena algorithm's execute hook + virtual StatusCode execute(); + + /// Athena algorithm's finalize hook + virtual StatusCode finalize(); + + + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + // The handle to the IDecisionSvc; + ServiceHandle<IDecisionSvc> m_decSvc; + + /// The names of all output streams to check + StringArrayProperty m_streamNames; + +}; + + +#endif //> !EVENTUTILS_EVENTDECISIONALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.cxx index 77976dd5dc1..86e11806ff2 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.cxx +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.cxx @@ -13,14 +13,8 @@ // SelectionUtils includes #include "EventQualityFilterAlg.h" -// STL includes - -// FrameWork includes -#include "GaudiKernel/Property.h" - // EDM includes -#include "EventInfo/EventInfo.h" -#include "EventInfo/EventType.h" +#include "xAODEventInfo/EventInfo.h" /////////////////////////////////////////////////////////////////// @@ -31,15 +25,20 @@ //////////////// EventQualityFilterAlg::EventQualityFilterAlg( const std::string& name, ISvcLocator* pSvcLocator ) : - ::AthFilterAlgorithm( name, pSvcLocator ) + ::AthFilterAlgorithm( name, pSvcLocator ), + m_useLArError(true), + m_useTileError(true), + m_useSCTError(true), + m_useCoreError(true) { // // Property declaration // - declareProperty( "VetoLArError", m_useLArError = false, "Veto events with a LAr error" ); - declareProperty( "VetoTileError", m_useTileError = false, "Veto events with a Tile error" ); - declareProperty( "VetoCoreError", m_useCoreError = false, "Veto events with a Core error" ); - declareProperty( "VetoTileTrips", m_useTileTripReader = false, "Veto events with a Tile trip error" ); + declareProperty( "VetoLArError", m_useLArError, "Veto events with a LAr error" ); + declareProperty( "VetoTileError", m_useTileError, "Veto events with a Tile error" ); + declareProperty( "VetoSCTError", m_useSCTError, "Veto events with an SCT error" ); + declareProperty( "VetoCoreError", m_useCoreError, "Veto events with a Core error" ); + //declareProperty( "VetoTileTrips", m_useTileTripReader, "Veto events with a Tile trip error" ); } @@ -58,6 +57,11 @@ EventQualityFilterAlg::~EventQualityFilterAlg() StatusCode EventQualityFilterAlg::initialize() { ATH_MSG_DEBUG ("Initializing " << name() << "..."); + ATH_MSG_DEBUG( "Using: " << m_useLArError ); + ATH_MSG_DEBUG( "Using: " << m_useTileError ); + ATH_MSG_DEBUG( "Using: " << m_useSCTError ); + ATH_MSG_DEBUG( "Using: " << m_useCoreError ); + // ATH_MSG_DEBUG( "Using: " << m_useTileTripReader ); return StatusCode::SUCCESS; } @@ -77,28 +81,28 @@ StatusCode EventQualityFilterAlg::execute() // Get the EventInfo object - const EventInfo* eventInfo(NULL); + const xAOD::EventInfo* eventInfo = nullptr; ATH_CHECK( evtStore()->retrieve(eventInfo) ); // Only do the event vetoing on data - bool isSim = eventInfo->event_type()->test(EventType::IS_SIMULATION); - if ( isSim ) - { - ATH_MSG_DEBUG ("It is an MC event... not vetoing..."); - setFilterPassed(true); - return StatusCode::SUCCESS; - } + const bool isSim = eventInfo->eventType(xAOD::EventInfo::EventType::IS_SIMULATION); + if ( isSim ) { + ATH_MSG_DEBUG ("It is an MC event... not vetoing..."); + this->setFilterPassed(true); + return StatusCode::SUCCESS; + } // Now make the event decision bool passEvent(true); - // if ( eventInfo->errorState(EventInfo::LAr) == EventInfo::Error ){ passEvent = false; } - // if ( eventInfo->errorState(EventInfo::Tile) == EventInfo::Error ){ passEvent = false; } - // if ( eventInfo->eventFlags(EventInfo::Core) & 0x40000 ){ passEvent = false; } + if ( m_useLArError.value() && eventInfo->errorState(xAOD::EventInfo::LAr) == xAOD::EventInfo::Error ){ passEvent = false; } + if ( m_useTileError.value() && eventInfo->errorState(xAOD::EventInfo::Tile) == xAOD::EventInfo::Error ){ passEvent = false; } + if ( m_useSCTError.value() && eventInfo->errorState(xAOD::EventInfo::SCT) == xAOD::EventInfo::Error ){ passEvent = false; } + if ( m_useCoreError.value() && eventInfo->isEventFlagBitSet(xAOD::EventInfo::Core, 18) ){ passEvent = false; } // Set the final decision - setFilterPassed(passEvent); + this->setFilterPassed(passEvent); return StatusCode::SUCCESS; } diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.h index 4edb4215435..b62e0516700 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.h +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.h @@ -4,11 +4,11 @@ Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration */ -// EventQualityFilterAlg.h +// EventQualityFilterAlg.h // Header file for class EventQualityFilterAlg // Author: Karsten Koeneke <karsten.koeneke@cern.ch> // Description: Algorithm to filter out events with a bad Event errors -/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// #ifndef EVENTUTILS_EVENTQUALITYFILTERALG_H #define EVENTUTILS_EVENTQUALITYFILTERALG_H 1 @@ -22,53 +22,62 @@ class EventQualityFilterAlg : public ::AthFilterAlgorithm -{ +{ - /////////////////////////////////////////////////////////////////// - // Public methods: - /////////////////////////////////////////////////////////////////// - public: + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: - // Copy constructor: - /// Constructor with parameters: + /// Constructor with parameters: EventQualityFilterAlg( const std::string& name, ISvcLocator* pSvcLocator ); - /// Destructor: - virtual ~EventQualityFilterAlg(); + /// Destructor: + virtual ~EventQualityFilterAlg(); // Athena algorithm's Hooks virtual StatusCode initialize(); virtual StatusCode execute(); virtual StatusCode finalize(); - /////////////////////////////////////////////////////////////////// - // Const methods: /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + + /// Flag to turn on/off checking of LAr calorimeter error flag + BooleanProperty m_useLArError; + + /// Flag to turn on/off checking of tile calorimter error flag + BooleanProperty m_useTileError; - /////////////////////////////////////////////////////////////////// - // Non-const methods: - /////////////////////////////////////////////////////////////////// + /// Flag to turn on/off checking of SCT error flag + BooleanProperty m_useSCTError; - /////////////////////////////////////////////////////////////////// - // Private data: - /////////////////////////////////////////////////////////////////// - private: + /// Flag to turn on/off checking of core error flag + BooleanProperty m_useCoreError; - bool m_useLArError; - bool m_useTileError; - bool m_useCoreError; - bool m_useTileTripReader; + // /// Flag to turn on/off checking of tile trip information + // BooleanProperty m_useTileTripReader; -}; +}; // I/O operators ////////////////////// -/////////////////////////////////////////////////////////////////// -// Inline methods: -/////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// #endif //> !EVENTUTILS_EVENTQUALITYFILTERALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.cxx index 6fd7766ae5b..a231dd86f46 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.cxx +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.cxx @@ -404,7 +404,7 @@ StatusCode ParticleCombinerTool::addBranches() const for ( unsigned int ichoice = 0; ichoice < aUniqueChoice.size(); ichoice++ ) { msg(MSG::VERBOSE) << aUniqueChoice.at(ichoice) << ","; } - msg(MSG::VERBOSE) << endreq; + msg(MSG::VERBOSE) << endmsg; } // Loop over all containers @@ -424,7 +424,9 @@ StatusCode ParticleCombinerTool::addBranches() const } // end the loop over the available containers to build INav4MomLink objects // Now, actually build the CompositeParticle from the list of ElementLinks to INavigable4Momentum + ATH_MSG_DEBUG("building composite particle"); ATH_CHECK( buildComposite( outContainer, m_anIPartLinkList, metObject ) ); + ATH_MSG_DEBUG("done"); } // End: while ( anOdometer.increment() ) @@ -492,22 +494,29 @@ StatusCode ParticleCombinerTool::buildComposite( xAOD::CompositeParticleContaine bool ParticlesAreValid = true; + ATH_MSG_VERBOSE("Now in buildComposite with outContainer size=" << outContainer->size() + << ", anIPartLinkList size=" << anIPartLinkList.size() << ", and a met object with address=" << metObject ); + //Loop over all ElementLinks to INavigable4Momenta and get the INavigable4Momenta for ( const xAOD::IParticleLink& aParticleLink : anIPartLinkList ) { + ATH_MSG_VERBOSE("buildComposite: Looping over a particle link"); // Check if this ElementLink is valid if ( aParticleLink.isValid() ) { // Get the particle from the ElementLink const xAOD::IParticle* aParticle = *aParticleLink; + ATH_MSG_VERBOSE("buildComposite: Particle is valid"); if (aParticle) { + ATH_MSG_VERBOSE("buildComposite: Have a particle"); // determine if the particle has any daughter in common with // a previous particle in the composite: for ( const xAOD::IParticleLink* otherPartLink : theParticleLinks ) { + ATH_MSG_VERBOSE("Looking for shared daughters"); // Now, make the check for having any constituent shared. // Note that we don't need to check if the otherPartLink is valid // since this happened already when we filled that vector - if ( shareSameConstituents( aParticle, **otherPartLink ) ) { - ATH_MSG_DEBUG ( "Found aParticle overlaps with another INavigable4Momentum in the composite!" ); + if ( this->shareSameConstituents( aParticle, **otherPartLink ) ) { + ATH_MSG_DEBUG ( "buildComposite: Found aParticle overlaps with another INavigable4Momentum in the composite!" ); ParticlesAreValid &= false; break; } @@ -515,29 +524,34 @@ StatusCode ParticleCombinerTool::buildComposite( xAOD::CompositeParticleContaine // push the particle onto the candidate's input list if ( ParticlesAreValid ) { + ATH_MSG_VERBOSE("buildComposite: Particles are valid"); theParticleLinks.push_back( &aParticleLink ); } } else { - ATH_MSG_DEBUG ( "Found non-valid particle at an ElementLink location!" ); + ATH_MSG_DEBUG ( "buildComposite: Found non-valid particle at an ElementLink location!" ); ParticlesAreValid &= false; } // check if aParticle exists at all } else { - ATH_MSG_DEBUG ( "Found non-valid ElementLink for a particle!" ); + ATH_MSG_DEBUG ( "buildComposite: Found non-valid ElementLink for a particle!" ); ParticlesAreValid &= false; } // check the link to a particle if ( false == ParticlesAreValid ) { + ATH_MSG_VERBOSE("buildComposite: particles are not valid"); break; } } // End: loop over vector of ElementLinks + ATH_MSG_VERBOSE("buildComposite: Done looping over vector of ElementLinks"); + //----------------------------------------- // Do the combination //----------------------------------------- if ( ParticlesAreValid ) { + ATH_MSG_VERBOSE("buildComposite: Particles are valid"); // Sort the constituents in decending pt order, if requested if ( m_sortConstit.value() ) { std::sort( anIPartLinkList.begin(), anIPartLinkList.end(), @@ -545,6 +559,7 @@ StatusCode ParticleCombinerTool::buildComposite( xAOD::CompositeParticleContaine return CxxUtils::fpcompare::greater( (*a)->pt(), (*b)->pt() ); } ); } + ATH_MSG_VERBOSE("buildComposite: Particles are sorted"); // Actually create the composite particle //-------------------------------------------------------------- @@ -554,22 +569,24 @@ StatusCode ParticleCombinerTool::buildComposite( xAOD::CompositeParticleContaine xAOD::CompositeParticle* compPart = new xAOD::CompositeParticle(); compPart->makePrivateStore(); for ( const xAOD::IParticleLink& aParticleLink : anIPartLinkList ) { + ATH_MSG_VERBOSE("buildComposite: Adding constituet"); chargeSum += this->getCharge( aParticleLink, hasCharge ); compPart->addPart( aParticleLink ); } // Add also the missing ET object to the composite particle, if we have one if (metObject) { + ATH_MSG_VERBOSE("buildComposite: Adding met object"); compPart->setMissingET(metObject); } // Set the PDG ID for this composite particle compPart->setPdgId( m_pdgId.value() ); // Set the charge (if we were able to calculate it) for this composite particle if ( hasCharge ) { - ATH_MSG_VERBOSE("Setting the charge of the current composite particle to " << chargeSum ); + ATH_MSG_VERBOSE("buildComposite: Setting the charge of the current composite particle to " << chargeSum ); compPart->setCharge(chargeSum); } else { - ATH_MSG_DEBUG("Couldn't set the charge of the composite particle"); + ATH_MSG_DEBUG("buildComposite: Couldn't set the charge of the composite particle"); } // Check if this composite particle has been found before @@ -608,20 +625,19 @@ StatusCode ParticleCombinerTool::buildComposite( xAOD::CompositeParticleContaine // AK: Commented the conditional statements until "passAll" is actually // used here. To silence a Coverity warning. // if ( passAll ) { - outContainer->push_back( compPart ); -// } -// else { -// delete compPart; -// } + ATH_MSG_VERBOSE("buildComposite: Adding composite particle to container"); + outContainer->push_back( compPart ); } else { - // Output message - ATH_MSG_DEBUG ( "Found this composite particle already before..." ); + ATH_MSG_VERBOSE("buildComposite: deleting composite particle"); delete compPart; - } // End: if compositeParticleAlreadyFound - + } + + ATH_MSG_VERBOSE("buildComposite: End: if compositeParticleAlreadyFound"); + } // End: Saveguard check if all particles are valide + ATH_MSG_VERBOSE("Returning from buildComposite"); return StatusCode::SUCCESS; } @@ -776,12 +792,13 @@ bool ParticleCombinerTool::isEqual( const xAOD::IParticle* part1, // composite particles, that they don't share the same constitutents //============================================================================= bool ParticleCombinerTool::shareSameConstituents( const xAOD::IParticle* part1, - const xAOD::IParticle* part2 ) const + const xAOD::IParticle* part2 ) const { const xAOD::CompositeParticle* compPart1 = dynamic_cast<const xAOD::CompositeParticle*> (part1) ; const xAOD::CompositeParticle* compPart2 = dynamic_cast<const xAOD::CompositeParticle*> (part2) ; + ATH_MSG_VERBOSE("in shareSameConstituents('IParticle','IParticle')"); // Neither of the two is a composite particle if ( !compPart1 && !compPart2 ) { @@ -789,17 +806,17 @@ bool ParticleCombinerTool::shareSameConstituents( const xAOD::IParticle* part1, } // One of them is a composite else if ( compPart1 && !compPart2 ) { - return shareSameConstituents( part2, compPart1 ); + return this->shareSameConstituents( part2, compPart1 ); } else if ( !compPart1 && compPart2 ) { - return shareSameConstituents( part1, compPart2 ); + return this->shareSameConstituents( part1, compPart2 ); } // Both are composite candidates // AK: By this time only one options remains: That both of them are composite // particles. So it's not necessary to do any more checks. This silences // a Covery warning. else { - return shareSameConstituents( compPart1, compPart2 ); + return this->shareSameConstituents( compPart1, compPart2 ); } } @@ -815,7 +832,8 @@ bool ParticleCombinerTool::shareSameConstituents( const xAOD::IParticle* part1, { // Default return bool isConstituent = false; - + ATH_MSG_VERBOSE("in shareSameConstituents('IParticle','CompositeParticle')"); + // Loop over all constituents of the composite particle to be tested const std::size_t nConstit = compPart2->nParts(); for( std::size_t i=0; i<nConstit; ++i ) { @@ -851,18 +869,21 @@ bool ParticleCombinerTool::shareSameConstituents( const xAOD::CompositeParticle* { // Default return bool isConstituent = false; + ATH_MSG_VERBOSE("in shareSameConstituents('CompositeParticle','CompositeParticle')"); // Loop over all constituents of the composite particle to be tested const std::size_t nConstit1 = compPart1->nParts(); const std::size_t nConstit2 = compPart2->nParts(); for( std::size_t i=0; i<nConstit1; ++i ) { const xAOD::IParticle* part1 = compPart1->part(i); - + ATH_MSG_VERBOSE("looking at compositeParticle1 constituent " << i << "/" << nConstit1); + // Check if this constituent itself is a composite particle const xAOD::CompositeParticle* constitCP1 = dynamic_cast<const xAOD::CompositeParticle*> (part1) ; - for( std::size_t j=0; i<nConstit2; ++j ) { + for( std::size_t j=0; j<nConstit2; ++j ) { + ATH_MSG_VERBOSE("looking at compositeParticle2 constituent " << j << "/" << nConstit2); const xAOD::IParticle* part2 = compPart2->part(j); // Check if this constituent itself is a composite particle @@ -873,13 +894,13 @@ bool ParticleCombinerTool::shareSameConstituents( const xAOD::CompositeParticle* isConstituent = this->isEqual( part1, part2 ); } if ( !constitCP1 && constitCP2 ) { - isConstituent = shareSameConstituents( part1, constitCP2 ); + isConstituent = this->shareSameConstituents( part1, constitCP2 ); } if ( constitCP1 && !constitCP2 ) { - isConstituent = shareSameConstituents( part2, constitCP1 ); + isConstituent = this->shareSameConstituents( part2, constitCP1 ); } if ( constitCP1 && constitCP2 ) { - isConstituent = shareSameConstituents( constitCP1, constitCP2 ); + isConstituent = this->shareSameConstituents( constitCP1, constitCP2 ); } if ( isConstituent ) { return true; diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.h index 052441347a1..a521ae857da 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.h +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.h @@ -61,10 +61,10 @@ public: public: /** Gaudi Service Interface method implementations - initialize */ - StatusCode initialize() ; + virtual StatusCode initialize() override; /** Gaudi Service Interface method implementations - finalize */ - StatusCode finalize() ; + virtual StatusCode finalize() override; /// Implement the method from the IAugmentationTool interface virtual StatusCode addBranches() const final override; diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.cxx new file mode 100644 index 00000000000..4dcc740a171 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.cxx @@ -0,0 +1,315 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// EventUtils includes +#include "ParticleRemoverAlg.h" + +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainersInterfaces/IAuxTypeVectorFactory.h" + +#include "xAODBase/IParticleContainer.h" +#include "xAODBase/IParticle.h" +#include "xAODCore/AuxContainerBase.h" +#include "xAODCore/ShallowCopy.h" +#include "xAODEgamma/PhotonContainer.h" +#include "xAODEgamma/ElectronContainer.h" +#include "xAODMuon/MuonContainer.h" +#include "xAODTau/TauJetContainer.h" +#include "xAODJet/JetContainer.h" +#include "xAODPFlow/PFOContainer.h" +#include "xAODTracking/NeutralParticleContainer.h" +#include "xAODTracking/TrackParticleContainer.h" +#include "xAODParticleEvent/ParticleContainer.h" +#include "xAODCaloEvent/CaloClusterContainer.h" +#include "xAODTruth/TruthParticleContainer.h" +#include "xAODParticleEvent/CompositeParticleContainer.h" + +// boost includes +#include <boost/algorithm/string/predicate.hpp> + + +ParticleRemoverAlg::ParticleRemoverAlg( const std::string& name, ISvcLocator* pSvcLocator ) + : AthAlgorithm( name, pSvcLocator ), + m_inCont(""), + m_separator("___"), + m_outCont(""), + m_suffixes(), + m_viewContNames(), + m_resetViewConts(true), + m_outPrefix(""), + m_inContNameList(), + m_outContNameList(), + m_inContList(), + m_outContList(), + m_inViewContNameListList(), + m_outViewContNameListList(), + m_contType(UNKNOWN) +{ + // + // Property declaration + // + declareProperty("Input", m_inCont, "Input container name" ); + declareProperty("Output", m_outCont, + "The name of the output container with the deep copy of input objects" ); + + declareProperty("Separator", m_separator, + "The string seperator between the output container name and the sytematic variation (default='___')" ); + + declareProperty("Suffixes", m_suffixes, + "The names of all suffixes for the input and output container names" ); + + declareProperty("SelectedViewContainers", m_viewContNames, + "The names of all view containers that contain particles that we want to retain" ); + + declareProperty("RemapViewContainers", m_resetViewConts, + "Boolean to decide if the existing view containers should be re-mapped (default: true)" ); + + declareProperty("OutputViewContainerPrefix", m_outPrefix, + "Prefix to be used for all created output view containers" ); +} + + +ParticleRemoverAlg::~ParticleRemoverAlg() {} + + +StatusCode ParticleRemoverAlg::initialize() +{ + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + + // Print the configuration to the log file + ATH_MSG_DEBUG( "Using: " << m_inCont ); + ATH_MSG_DEBUG( "Using: " << m_outCont ); + ATH_MSG_DEBUG( "Using: " << m_separator ); + ATH_MSG_DEBUG( "Using: " << m_suffixes ); + ATH_MSG_DEBUG( "Using: " << m_viewContNames ); + ATH_MSG_DEBUG( "Using: " << m_resetViewConts ); + ATH_MSG_DEBUG( "Using: " << m_outPrefix ); + + // Perform some sanity checks on the given container names + if ( m_inCont.value().empty() || m_outCont.value().empty() || m_viewContNames.value().empty() ) { + ATH_MSG_ERROR("Wrong user setup! You need to give a valid name for both the Input, Output, and SelectedViewContainers!"); + return StatusCode::FAILURE; + } + + // Abort on an unchecked systematics code + // CP::SystematicCode::enableFailure(); + + // Build the vector of all input and output container names + const std::size_t totSize = 1 + m_suffixes.value().size(); // the '1' comes from the InputContainer + m_inContNameList.resize(totSize); + m_inContList.resize(totSize); + m_outContNameList.resize(totSize); + m_inContNameList[0] = m_inCont.value(); + m_outContNameList[0] = m_outCont.value(); + for ( std::size_t i=1; i<totSize; ++i ) { + const std::string& currentSuffix = m_suffixes.value()[i-1]; + ATH_MSG_VERBOSE("Using current suffix " << currentSuffix << " to search for matching containers"); + if (boost::starts_with( currentSuffix, m_separator.value() )) { + m_inContNameList[i] = m_inCont.value() + currentSuffix; + m_outContNameList[i] = m_outCont.value() + currentSuffix; + } + else { + m_inContNameList[i] = m_inCont.value() + m_separator.value() + currentSuffix; + m_outContNameList[i] = m_outCont.value() + m_separator.value() + currentSuffix; + } + } + // Print out the matches that we found + if ( msgLvl(MSG::VERBOSE) ) { + for ( std::size_t i=0; i<m_inContNameList.size(); ++i ){ + ATH_MSG_VERBOSE("Matched input number " << i << " with input name " << m_inContNameList[i] << " to output name " << m_outContNameList[i]); + } + } + + + + // Now, also try to map all the view container names to the input (shallow + // copy) containers. Set up with that the correct mapping of the new output + // view container names. + // Assume that all names where we have a suffix, but where we cannot match it + // to a suffix of the input container, it belongs to the origninal one. + if ( m_resetViewConts.value() || !(m_outPrefix.value().empty()) ){ + ATH_MSG_VERBOSE("Going to iterate over " << totSize << " elements"); + m_inViewContNameListList.reserve(totSize); + m_outViewContNameListList.reserve(totSize); + for ( std::size_t i=0; i<totSize; ++i ) { + ATH_MSG_VERBOSE("At " << i << "-th element"); + if (i==0){ + // This is the master container without any "___" in its name + std::vector<std::string> inViewNames; + std::vector<std::string> outViewNames; + for ( const std::string& inViewName : m_viewContNames.value() ){ + ATH_MSG_VERBOSE("Looking at input view container name: " << inViewName); + std::size_t pos = inViewName.find(m_separator.value()); + if ( pos == std::string::npos ){ // the separator is not found + ATH_MSG_VERBOSE("No seperator found"); + inViewNames.push_back(inViewName); + outViewNames.push_back( m_outPrefix.value() + inViewName ); + ATH_MSG_VERBOSE("Added input name " << inViewNames.back() << " and output name " << outViewNames.back()); + } + else { + pos += m_separator.value().length(); + const std::string foundSuffix = inViewName.substr(pos, std::string::npos); + ATH_MSG_VERBOSE("Seperator found and suffix found: " << foundSuffix); + // the separator is found, but the found suffix doesn't match any of the provided ones + if ( std::find( m_suffixes.value().begin(), m_suffixes.value().end(), foundSuffix) == m_suffixes.value().end() ){ + inViewNames.push_back(inViewName); + outViewNames.push_back( m_outPrefix.value() + inViewName ); + ATH_MSG_VERBOSE("Added2 input name " << inViewNames.back() << " and output name " << outViewNames.back()); + } + } + } + m_inViewContNameListList.push_back(inViewNames); + m_outViewContNameListList.push_back(outViewNames); + } + else { + const std::string& currentSuffix = m_suffixes.value()[i-1]; + ATH_MSG_VERBOSE("Looking at current suffix: " << currentSuffix); + std::vector<std::string> inViewNames; + std::vector<std::string> outViewNames; + for ( const std::string& inViewName : m_viewContNames.value() ){ + ATH_MSG_VERBOSE("Looking at current input view container name: " << inViewName); + if ( inViewName.find(m_separator.value()+currentSuffix) != std::string::npos ){ // the suffix is found + inViewNames.push_back(inViewName); + outViewNames.push_back( m_outPrefix.value() + inViewName ); + ATH_MSG_VERBOSE("Added3 input name " << inViewNames.back() << " and output name " << outViewNames.back()); + } + } + m_inViewContNameListList.push_back(inViewNames); + m_outViewContNameListList.push_back(outViewNames); + } + } // End: loop over all containers + } + // Some sanity printouts + if ( msgLvl(MSG::VERBOSE) ) { + ATH_MSG_VERBOSE("Printing final input and output names..."); + for ( std::size_t i=0; i<m_inViewContNameListList.size(); ++i ){ + ATH_MSG_VERBOSE(" At i=" << i << "-th element"); + const std::vector<std::string>& inViewNameList = m_inViewContNameListList[i]; + const std::vector<std::string>& outViewNameList = m_outViewContNameListList[i]; + ATH_MSG_VERBOSE(" Have " << inViewNameList.size() << " in view elements and " << outViewNameList.size() << " out view elements"); + for ( std::size_t j=0; j<inViewNameList.size(); ++j ){ + ATH_MSG_VERBOSE(" At j=" << j << "-th element"); + const std::string& inName = inViewNameList[j]; + const std::string& outName = outViewNameList[j]; + ATH_MSG_VERBOSE(" Have input name " << inName << " paired with out name " << outName); + } + } + } + + return StatusCode::SUCCESS; +} + + + +StatusCode ParticleRemoverAlg::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + + return StatusCode::SUCCESS; +} + + + +StatusCode ParticleRemoverAlg::execute() +{ + ATH_MSG_DEBUG ("Executing " << name() << "..."); + // Let's first clear some stuff + m_inContList.clear(); + m_inContList.resize(m_inContNameList.size()); + m_outContList.clear(); + + // Figure out what type the input container has, if we didn't do it yet + if ( m_contType == UNKNOWN ){ + if ( evtStore()->contains<xAOD::PhotonContainer>(m_inCont.value()) ){ m_contType = PHOTON; } + else if ( evtStore()->contains<xAOD::ElectronContainer>(m_inCont.value()) ){ m_contType = ELECTRON; } + else if ( evtStore()->contains<xAOD::MuonContainer>(m_inCont.value()) ){ m_contType = MUON; } + else if ( evtStore()->contains<xAOD::TauJetContainer>(m_inCont.value()) ){ m_contType = TAU; } + else if ( evtStore()->contains<xAOD::JetContainer>(m_inCont.value()) ){ m_contType = JET; } + else if ( evtStore()->contains<xAOD::TruthParticleContainer>(m_inCont.value()) ){ m_contType = TRUTHPARTICLE; } + else if ( evtStore()->contains<xAOD::CompositeParticleContainer>(m_inCont.value()) ){ m_contType = COMPOSITEPARTICLE; } + else if ( evtStore()->contains<xAOD::PFOContainer>(m_inCont.value()) ){ m_contType = PARITCLEFLOW; } + else if ( evtStore()->contains<xAOD::NeutralParticleContainer>(m_inCont.value()) ){ m_contType = NEUTRALPARTICLE; } + else if ( evtStore()->contains<xAOD::TrackParticleContainer>(m_inCont.value()) ){ m_contType = TRACKPARTICLE; } + else if ( evtStore()->contains<xAOD::ParticleContainer>(m_inCont.value()) ){ m_contType = PARTICLE; } + else if ( evtStore()->contains<xAOD::CaloClusterContainer>(m_inCont.value()) ){ m_contType = CALOCLUSTER; } + } + if ( m_contType == UNKNOWN ){ + ATH_MSG_FATAL("We couldn't determine the type of the container... abort!"); + return StatusCode::FAILURE; + } + + // Open the input container + for ( std::size_t i=0; i<m_inContNameList.size(); ++i ) { + ATH_CHECK( evtStore()->retrieve( m_inContList[i], m_inContNameList.at(i) )); + } + + // Make a quick check that all input containers have the same size + const std::size_t inContSize = m_inContList[0]->size(); + for ( const xAOD::IParticleContainer* inCont : m_inContList ){ + if ( inContSize != inCont->size() ){ + ATH_MSG_FATAL("The input container and its shallow copies don't have the same size! Aborting..."); + return StatusCode::FAILURE; + } + } + + // Create a vector of bools with the same size as the input container. This + // will be used to say if we want to keep that particular object. + // All entries will be initialized to false. + std::vector<bool> keepParticleVec (inContSize, false); + // Now, loop over all view containers and flag the particles that we want to + // keep with true in the above vector of bools. + for ( const std::string& viewContName : m_viewContNames.value() ){ + const xAOD::IParticleContainer* inViewCont = nullptr; + ATH_CHECK( evtStore()->retrieve( inViewCont, viewContName ) ); + // Make a quick check that the provided view containers are not larger + if ( inViewCont->size() > inContSize ){ + ATH_MSG_FATAL("One of the input view containers is larger than the input container... aborting."); + return StatusCode::FAILURE; + } + for ( const xAOD::IParticle* part : *inViewCont ){ + const std::size_t idx = part->index(); + keepParticleVec[idx] = true; + } + } + + // Do the heavy lifting of actually creating the new and reduced output container(s) + if ( m_contType == PHOTON ){ + ATH_CHECK( this->removeParticles<xAOD::PhotonContainer>(keepParticleVec) ); + } + else if ( m_contType == ELECTRON ){ + ATH_CHECK( this->removeParticles<xAOD::ElectronContainer>(keepParticleVec) ); + } + else if ( m_contType == MUON ){ + ATH_CHECK( this->removeParticles<xAOD::MuonContainer>(keepParticleVec) ); + } + else if ( m_contType == TAU ){ + ATH_CHECK( this->removeParticles<xAOD::TauJetContainer>(keepParticleVec) ); + } + else if ( m_contType == JET ){ + ATH_CHECK( this->removeParticles<xAOD::JetContainer>(keepParticleVec) ); + } + else if ( m_contType == TRUTHPARTICLE ){ + ATH_CHECK( this->removeParticles<xAOD::TruthParticleContainer>(keepParticleVec) ); + } + else if ( m_contType == COMPOSITEPARTICLE ){ + ATH_CHECK( this->removeParticles<xAOD::CompositeParticleContainer>(keepParticleVec) ); + } + else if ( m_contType == PARITCLEFLOW ){ + ATH_CHECK( this->removeParticles<xAOD::PFOContainer>(keepParticleVec) ); + } + else if ( m_contType == NEUTRALPARTICLE ){ + ATH_CHECK( this->removeParticles<xAOD::NeutralParticleContainer>(keepParticleVec) ); + } + else if ( m_contType == TRACKPARTICLE ){ + ATH_CHECK( this->removeParticles<xAOD::TrackParticleContainer>(keepParticleVec) ); + } + else if ( m_contType == PARTICLE ){ + ATH_CHECK( this->removeParticles<xAOD::ParticleContainer>(keepParticleVec) ); + } + else if ( m_contType == CALOCLUSTER ){ + ATH_CHECK( this->removeParticles<xAOD::CaloClusterContainer>(keepParticleVec) ); + } + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.h new file mode 100644 index 00000000000..bbef8d8161f --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.h @@ -0,0 +1,114 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef EVENTUTILS_PARTICLEREMOVERALG_H +#define EVENTUTILS_PARTICLEREMOVERALG_H 1 + +#include "AthenaBaseComps/AthAlgorithm.h" + +#include "xAODBase/IParticleContainer.h" + + + +class ParticleRemoverAlg: public ::AthAlgorithm { + public: + /// Standard constructor + ParticleRemoverAlg( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Standard destructor + virtual ~ParticleRemoverAlg(); + + /// Standard Gaudi initialize method called once before the event loop + virtual StatusCode initialize(); + + /// Standard Gaudi execute method called once for every event + virtual StatusCode execute(); + + /// Standard Gaudi finalize method called once after the event loop + virtual StatusCode finalize(); + + private: + /// Private function to perform the actualy work + template<class CONT> + StatusCode removeParticles( const std::vector<bool>& keepParticleVec ); + + private: + + /// @name The properties that can be defined via the python job options + /// @{ + + /// The input container name + StringProperty m_inCont; + + /// The string separator between the output container name and the sytematic variation (default="___") + StringProperty m_separator; + + /// The output container name + StringProperty m_outCont; + + /// The names of all suffixes for the input and output container names + StringArrayProperty m_suffixes; + + /// The names of all view containers that contain particles that we want to retain + StringArrayProperty m_viewContNames; + + /// Boolean to decide if the existing view containers should be re-mapped (default: true) + BooleanProperty m_resetViewConts; + + /// Prefix to be used for all created output view containers + StringProperty m_outPrefix; + + /// @} + + + /// @name Internal members + /// @{ + + /// Vector of all input container names + std::vector<std::string> m_inContNameList; + + /// Vector of all output container names + std::vector<std::string> m_outContNameList; + + /// Vector of all input containers + std::vector< const xAOD::IParticleContainer* > m_inContList; + + /// Vector of all output containers + std::vector< xAOD::IParticleContainer* > m_outContList; + + /// Vector of all input view container names + std::vector< std::vector<std::string> > m_inViewContNameListList; + + /// Vector of all output view container names + std::vector< std::vector<std::string> > m_outViewContNameListList; + + + /// An enumaration for the actual container type + enum contType_t { + UNKNOWN, + PHOTON, + ELECTRON, + MUON, + TAU, + JET, + PARITCLEFLOW, + NEUTRALPARTICLE, + TRACKPARTICLE, + TRUTHPARTICLE, + COMPOSITEPARTICLE, + PARTICLE, + CALOCLUSTER + }; + + /// The variable that holds the value that we find for the input container + contType_t m_contType; + + /// @} + +}; + +// Include the templated code here. This must be done from this header file. +#include "ParticleRemoverAlg.icc" + +#endif //> !EVENTUTILS_PARTICLEREMOVERALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.icc b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.icc new file mode 100644 index 00000000000..5a1c5f5f37c --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleRemoverAlg.icc @@ -0,0 +1,242 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "xAODBase/IParticle.h" +#include "AthContainers/AuxTypeRegistry.h" +#include "AthContainersInterfaces/IAuxTypeVectorFactory.h" +#include "xAODCore/AuxContainerBase.h" +#include "xAODCore/ShallowCopy.h" +#include "AthContainers/ConstDataVector.h" + +// boost includes +#include <boost/algorithm/string/predicate.hpp> + + + +template<class CONT> +StatusCode ParticleRemoverAlg::removeParticles( const std::vector<bool>& keepParticleVec ) +{ + ATH_MSG_DEBUG ("removeParticles(...) " << name() << "..."); + + // Get the type of particle that the current container CONT has + typedef typename CONT::base_value_type PART; + + // First, get the size of the current input container + const std::size_t inContSize = m_inContList[0]->size(); + + // Create a new output container and its associated auxiliary container + CONT* outCont = new CONT(SG::OWN_ELEMENTS); + outCont->reserve(inContSize); + ATH_CHECK( evtStore()->record ( outCont, m_outContNameList.at(0) ) ); + xAOD::AuxContainerBase* outAuxContainer = new xAOD::AuxContainerBase(); + outAuxContainer->reserve(inContSize); + ATH_CHECK( evtStore()->record( outAuxContainer, m_outContNameList.at(0) + "Aux." ) ); + outCont->setStore( outAuxContainer ); + m_outContList.push_back(outCont); + + // Create a vector for the original indices of the input particles in their container + std::vector< std::size_t > inPartIdxList; + inPartIdxList.reserve(inContSize); + // Also, create a map from the old index to the new one using a vector with + // the same size as the old input containers has. + std::vector<int> oldToNewIndex; + oldToNewIndex.reserve(inContSize); + + // Now, copy the elements that we want to keep from the input container to the + // output container. + for ( std::size_t i=0; i<inContSize; ++i ){ + if ( keepParticleVec[i] == false ){ + oldToNewIndex.push_back(-1); + continue; // we don't want to keep this particle + } + const xAOD::IParticle* inPart = m_inContList[0]->at(i); + const std::size_t inPartIdx = inPart->index(); + // Now, copy over the input particle to the output particle + // (use a pre-processor macro for this repeated task) + PART* outPart = new PART(); + outCont->push_back(outPart); + *outPart = *(static_cast<const PART*>(inPart)); + // Store also the orignial index for this particle + inPartIdxList.push_back(inPartIdx); + oldToNewIndex.push_back( inPartIdxList.size() - 1 ); + } + + // Get the size of the output container + const std::size_t outContSize = outCont->size(); + + // Get the global registry for all aux data: + SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance(); + + + // Now, do also the selection for all shallow copy containers, i.e., create + // new ones for the outCont that we just created and copy the values + // from the original input shallow copy containers over to these new ones + for ( std::size_t contIdx=1; contIdx<m_outContNameList.size(); ++contIdx ) { + // Get the original electron shallow copy container + const auto* originalShallowCopyCont = m_inContList.at(contIdx); + ATH_MSG_VERBOSE("Got input ShallowCopyContainer with name: " << m_inContNameList.at(contIdx)); + + // Create the current shallow copy container and record it to StoreGate + auto outContShallowCopy = xAOD::shallowCopyContainer( *outCont ); + ATH_CHECK( evtStore()->record( outContShallowCopy.first, m_outContNameList.at(contIdx) ) ); + ATH_CHECK( evtStore()->record( outContShallowCopy.second, m_outContNameList.at(contIdx) + "Aux." ) ); + ATH_MSG_VERBOSE("Recorded new output ShallowCopyContainer with name: " << m_outContNameList.at(contIdx)); + + // Also add the output shallow copy to the list of output containers + m_outContList.push_back(outContShallowCopy.first); + + // Copy the variables that are stored in the input ShallowCopyContainer + // locally (i.e., NOT only present in the master container, but where the + // variable lives in the ShallowCopyContainer) from there + // If the input had size zero, we are done + if ( originalShallowCopyCont->size() == 0 ) { + ATH_MSG_VERBOSE("Input ShallowCopy container has size zero... we are done"); + continue; + } + + // Get the auxIDs, i.e., the identifiers from the input ShallowCopyContainer + const xAOD::ShallowAuxContainer* originalShallowCopyAuxCont + = dynamic_cast<const xAOD::ShallowAuxContainer*>(originalShallowCopyCont->getStore()); + if ( !originalShallowCopyAuxCont ) { + ATH_MSG_ERROR("We don't seem to have a ShallowAuxContainer"); + return StatusCode::FAILURE; + } + const SG::IAuxStore* auxStore = originalShallowCopyAuxCont->getStore(); + if (!auxStore) { + ATH_MSG_FATAL("Could not get the aux store of the original ShallowCopyContainer"); + return StatusCode::FAILURE; + } + const SG::auxid_set_t& auxIDs = auxStore->getAuxIDs(); + ATH_MSG_DEBUG("We have " << auxIDs.size() << " variables to copy over for this ShallowCopyContainer"); + + // Iterate over all auxIDs and copy each one over + for ( auto auxid : auxIDs ) { + ATH_MSG_VERBOSE("We are now at auxID=" << auxid ); + + // Get the type of this variable: + const std::type_info* type = reg.getType( auxid ); + if ( ! type ) { + ATH_MSG_FATAL("Could not get the type of auxid: " << auxid ); + return StatusCode::FAILURE; + } + ATH_MSG_VERBOSE("Got the type with name: " << type->name() ); + + // First let's get the vector factory of this variable: + const SG::IAuxTypeVectorFactory* factory = + SG::AuxTypeRegistry::instance().getFactory( *type ); + if ( ! factory ) { + ATH_MSG_FATAL("Could not get the vector factory for type: " << type->name() ); + return StatusCode::FAILURE; + } + ATH_MSG_VERBOSE("Got the vector factory for type: " << type->name() ); + + + // If the parent doesn't have this variable, then we're done already: + const void* originalShallowAuxDataVector = auxStore->getData( auxid ); + if ( ! originalShallowAuxDataVector ) { + ATH_MSG_WARNING("Could not get the aux data vector of the original ShallowCopyContainer for auxid=" << auxid + << ". The input container had size " << originalShallowCopyCont->size() + << ", and the output container had size " << outContSize ); + continue; + //return StatusCode::FAILURE; + } + ATH_MSG_VERBOSE("This auxID=" << auxid << " is part of the ShallowCopyAuxStore..."); + + // Create the variable in the dynamic store of the new ShallowCopyContainer + void* outContAuxDataVec = outContShallowCopy.second->getData( auxid, outContSize, outContSize ); + + + // Then, loop over these, get the index of the corresponding object in the + // input shallow copy container and copy the variables that are stored there + // locally (i.e., NOT only present in the master container, but where the + // variable lives in the ShallowCopyContainer) from there + for ( std::size_t i=0; i<outContSize; ++i ) { + // Get the original shallow copy particle + const std::size_t inIdx = inPartIdxList.at(i); + factory->copy( outContAuxDataVec, i, originalShallowAuxDataVector, inIdx ); + } + + } // End: Loop over all aux-ids + + } // End: loop over output shallow copy containers + + + // Now, also create the new view containers that point to the objects in the + // new, reduced, containers that we just produced above (both the master + // container and all its shallow copy containers). + /// This will only be done if we have a valid prefix. + if ( !(m_outPrefix.value().empty()) ){ + ATH_MSG_DEBUG("Will now also go and create new output view containers with the prefix " << m_outPrefix.value() ); + for ( std::size_t i=0; i<m_inViewContNameListList.size(); ++i ){ + const std::vector<std::string>& inViewNames = m_inViewContNameListList[i]; + const std::vector<std::string>& outViewNames = m_outViewContNameListList[i]; + const xAOD::IParticleContainer* currentOutCont = m_outContList[i]; + for ( std::size_t j=0; j<inViewNames.size(); ++j ){ + const std::string& inViewName = inViewNames[j]; + const std::string& outViewName = outViewNames[j]; + ATH_MSG_VERBOSE("Going to create a new view container with name '" << outViewName + << "' from original view container with name '" << inViewName << "'" ); + const xAOD::IParticleContainer* inViewCont = nullptr; + ATH_CHECK( evtStore()->retrieve( inViewCont, inViewName ) ); + ConstDataVector<CONT>* outViewCont = new ConstDataVector<CONT>(SG::VIEW_ELEMENTS); + outViewCont->reserve(inViewCont->size()); + ATH_CHECK( evtStore()->record ( outViewCont, outViewName ) ); + for ( const xAOD::IParticle* inViewPart : *inViewCont ){ + const std::size_t oldIdx = inViewPart->index(); + const std::size_t newIdx = oldToNewIndex[oldIdx]; + const xAOD::IParticle* outPart = (*currentOutCont)[newIdx]; + outViewCont->push_back(static_cast<const PART*>(outPart)); + } + } + } + } + + + // Now, also try to re-bend the existing view containers to point to the new + // containers. + if (m_resetViewConts.value()){ + ATH_MSG_DEBUG("Will now also go and try to re-map the input view containers to the new containers"); + for ( std::size_t i=0; i<m_inViewContNameListList.size(); ++i ){ + const std::vector<std::string>& inViewNames = m_inViewContNameListList[i]; + const xAOD::IParticleContainer* currentOutCont = m_outContList[i]; + for ( std::size_t j=0; j<inViewNames.size(); ++j ){ + const std::string& inViewName = inViewNames[j]; + ATH_MSG_VERBOSE("Going to re-map existing view container with name '" << inViewName << "'" ); + const CONT* inViewCont = nullptr; + ATH_CHECK( evtStore()->retrieve( inViewCont, inViewName ) ); + ATH_MSG_DEBUG("Got the input view container with name: " << inViewName << " and size: " << inViewCont->size() ); + ConstDataVector<CONT>* outViewCont = new ConstDataVector<CONT>(SG::VIEW_ELEMENTS); + outViewCont->reserve(inViewCont->size()); + for ( std::size_t partIdx=0; partIdx<inViewCont->size(); ++partIdx ){ + const PART* inViewPart = inViewCont->at(partIdx); + const SG::AuxVectorData* oldCont = inViewPart->container(); + const std::size_t oldIdx = inViewPart->index(); + const std::size_t newIdx = oldToNewIndex[oldIdx]; + const xAOD::IParticle* outPart = (*currentOutCont)[newIdx]; + outViewCont->push_back(static_cast<const PART*>(outPart)); + ATH_MSG_VERBOSE("Did re-map particle from old index " << oldIdx + << " to new index " << inViewCont->at(partIdx)->index() + << " and old container " << oldCont + << " to new container " << inViewCont->at(partIdx)->container() ); + } + ATH_MSG_DEBUG("Going to overwrite view container with name: " << inViewName << " and size: " << outViewCont->size() ); + for ( const PART* part : *outViewCont ){ + ATH_MSG_VERBOSE("Have an old pointer adress of: " << part ); + ATH_MSG_VERBOSE("Have an old particle with pt= " << 0.001*(part->pt()) ); + } + ATH_CHECK( evtStore()->overwrite( outViewCont, inViewName ) ); + ATH_MSG_DEBUG("Did overwrite view container with name: " << inViewName << " and size: " << outViewCont->size() ); + for ( const PART* part : *outViewCont ){ + ATH_MSG_VERBOSE("Have a new pointer adress of: " << part ); + ATH_MSG_VERBOSE("Have a new particle with pt= " << 0.001*(part->pt()) ); + } + } + } + } + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.cxx index 58e97ac28b6..8b1ed66e746 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.cxx +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.cxx @@ -18,7 +18,45 @@ #include "GaudiKernel/Property.h" #include "GaudiKernel/IJobOptionsSvc.h" #include "DerivationFrameworkInterfaces/IAugmentationTool.h" - +#include "ExpressionEvaluation/ExpressionParser.h" +#include "ExpressionEvaluation/SGxAODProxyLoader.h" +#include "ExpressionEvaluation/MultipleProxyLoader.h" +#include "ExpressionEvaluation/StackElement.h" +// #include "TrigDecisionTool/TrigDecisionTool.h" +// #include "ExpressionEvaluation/TriggerDecisionProxyLoader.h" + +// EDM includes +#include "EventInfo/EventStreamInfo.h" +#include "xAODBase/IParticleContainer.h" +#include "xAODBase/IParticle.h" +#include "xAODCore/AuxContainerBase.h" +#include "xAODEgamma/PhotonContainer.h" +#include "xAODEgamma/PhotonAuxContainer.h" +#include "xAODEgamma/ElectronContainer.h" +#include "xAODEgamma/ElectronAuxContainer.h" +#include "xAODMuon/MuonContainer.h" +#include "xAODMuon/MuonAuxContainer.h" +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJetAuxContainer.h" +#include "xAODJet/JetContainer.h" +#include "xAODJet/JetAuxContainer.h" +#include "xAODPFlow/PFOContainer.h" +#include "xAODPFlow/PFOAuxContainer.h" +#include "xAODTracking/NeutralParticleContainer.h" +#include "xAODTracking/NeutralParticleAuxContainer.h" +#include "xAODTracking/TrackParticleContainer.h" +#include "xAODTracking/TrackParticleAuxContainer.h" +#include "xAODParticleEvent/ParticleContainer.h" +#include "xAODParticleEvent/ParticleAuxContainer.h" +#include "xAODCaloEvent/CaloClusterContainer.h" +#include "xAODCaloEvent/CaloClusterAuxContainer.h" +#include "xAODTruth/TruthParticleContainer.h" +#include "xAODTruth/TruthParticleAuxContainer.h" +#include "xAODParticleEvent/CompositeParticleContainer.h" +#include "xAODParticleEvent/CompositeParticleAuxContainer.h" +#include "xAODCutFlow/CutBookkeeper.h" +#include "xAODCutFlow/CutBookkeeperContainer.h" +#include "xAODCutFlow/CutBookkeeperAuxContainer.h" /////////////////////////////////////////////////////////////////// @@ -29,55 +67,47 @@ //////////////// ParticleSelectionAlg::ParticleSelectionAlg( const std::string& name, ISvcLocator* pSvcLocator ) : - ::AthAlgorithm( name, pSvcLocator ), - m_jos("JobOptionsSvc", name), - m_tool("ParticleSelectionTool/ParticleSelectionTool", this), + ::AthAnalysisAlgorithm( name, pSvcLocator ), + m_selTools(), // makes these tools public + m_selWVtxTools(), // makes these tools public + m_evtInfoName("EventInfo"), + m_inPrimVtxCont("PrimaryVertices"), m_inCollKey(""), - m_setInCollKey(false), m_outCollKey(""), - m_setOutCollKey(false), - m_outCollType(""), - m_setOutCollType(false), - m_writeSplitAux(false), - m_setWriteSplitAux(false), - m_outOwnPolicyName("OWN_ELEMENTS"), - m_setOwnPolicy(false), - m_outLinkCollKey(""), - m_setOutLinkCollKey(false), + m_writeSplitAux(true), + m_outOwnPolicyName("VIEW_ELEMENTS"), m_selection(""), - m_setSelection(false), - m_nEventsProcessed(0) + m_doCutFlow(false), + m_cutBKCName(name), + m_parser(nullptr), + // m_trigDecisionTool("Trig::TrigDecisionTool/TrigDecisionTool"), + m_nEventsProcessed(0), + m_outOwnPolicy(SG::VIEW_ELEMENTS), + m_contType(UNKNOWN), + m_cutBKStartIdx(0), + m_selToolIdxOffset(), + m_selWPVToolIdxOffset(), + m_idxSelParster(0) { - declareProperty("JobOptionsSvc", m_jos, "The JobOptionService instance."); - - declareProperty("SelectionTool", m_tool, "The private tool that will select the particles within a container" ); - - declareProperty("InputContainer", m_inCollKey="", "Input container name" ); - m_inCollKey.declareUpdateHandler( &ParticleSelectionAlg::setupInputContainer, this ); - - declareProperty("OutputContainer", m_outCollKey="", - "The name of the output container with the deep copy of selected xAOD::IParticles" ); - m_outCollKey.declareUpdateHandler( &ParticleSelectionAlg::setupOutputContainer, this ); - - declareProperty("OutputContainerType", m_outCollType="", - "The type of the output container, e.g., 'xAOD::JetContainer'" ); - m_outCollType.declareUpdateHandler( &ParticleSelectionAlg::setupOutputContainerType, this ); - - declareProperty("WriteSplitOutputContainer", m_writeSplitAux=false, - "Decide if we want to write a fully-split AuxContainer such that we can remove any variables" ); - m_writeSplitAux.declareUpdateHandler( &ParticleSelectionAlg::setupWriteSplitOutputContainer, this ); - - declareProperty("OutputContainerOwnershipPolicy", m_outOwnPolicyName="OWN_ELEMENTS", - "Defines the ownership policy of the output container (default: 'OWN_ELEMENTS'; also allowed: 'VIEW_ELEMENTS')" ); - m_outOwnPolicyName.declareUpdateHandler( &ParticleSelectionAlg::setupOutputContainerOwnPolicy, this ); - - declareProperty("OutputLinkContainer", m_outLinkCollKey="", - "The name of the output container of ElementLinks to the selected xAOD::IParticles" ); - m_outLinkCollKey.declareUpdateHandler( &ParticleSelectionAlg::setupOutputLinkContainer, this ); - - declareProperty("Selection", m_selection="", - "The selection string that defines which xAOD::IParticles to select from the container" ); - m_selection.declareUpdateHandler( &ParticleSelectionAlg::setupSelection, this ); + declareProperty("EventInfo", m_evtInfoName, "Input container name"); + declareProperty("PrimaryVertexContainer", m_inPrimVtxCont, "The input primary vertex container name"); + declareProperty("InputContainer", m_inCollKey, "Input container name"); + declareProperty("OutputContainer", m_outCollKey, + "The name of the output container with the deep copy of selected xAOD::IParticles"); + declareProperty("WriteSplitOutputContainer", m_writeSplitAux, + "Decide if we want to write a fully-split AuxContainer such that we can remove any variables"); + declareProperty("OutputContainerOwnershipPolicy", m_outOwnPolicyName, + "Defines the ownership policy of the output container (default: 'OWN_ELEMENTS'; also allowed: 'VIEW_ELEMENTS')"); + + declareProperty("SelectionToolList", m_selTools, "The list of IAsgSelectionTools"); + declareProperty("SelectionWithPVToolList", m_selWVtxTools, "The list of IAsgSelectionWithVertexTools"); + declareProperty("Selection", m_selection, + "The selection string that defines which xAOD::IParticles to select from the container"); + + declareProperty("DoCutBookkeeping", m_doCutFlow, + "If true (deault: false), do the bookkeeping of how many particles passed which selection cuts"); + declareProperty("CutBookkeeperContainer", m_cutBKCName, + "The name of the resulting xAOD::CutBookkeeperContainer"); } @@ -96,75 +126,44 @@ StatusCode ParticleSelectionAlg::initialize() ATH_MSG_DEBUG ("Initializing " << name() << "..."); // Print out the used configuration - ATH_MSG_DEBUG ( " using = " << m_jos ); - ATH_MSG_DEBUG ( " using = " << m_tool ); ATH_MSG_DEBUG ( " using = " << m_inCollKey ); ATH_MSG_DEBUG ( " using = " << m_outCollKey ); - ATH_MSG_DEBUG ( " using = " << m_outCollType ); ATH_MSG_DEBUG ( " using = " << m_writeSplitAux ); ATH_MSG_DEBUG ( " using = " << m_outOwnPolicyName ); - ATH_MSG_DEBUG ( " using = " << m_outLinkCollKey ); ATH_MSG_DEBUG ( " using = " << m_selection ); + ATH_MSG_DEBUG ( " using DoCutBookkeeping = " << m_doCutFlow ); + ATH_MSG_DEBUG ( " using = " << m_cutBKCName ); + + // initialize proxy loaders for expression parsing + if ( !(m_selection.value().empty()) ){ + ExpressionParsing::MultipleProxyLoader *proxyLoaders = new ExpressionParsing::MultipleProxyLoader(); + // proxyLoaders->push_back(new ExpressionParsing::TriggerDecisionProxyLoader(m_trigDecisionTool)); + proxyLoaders->push_back(new ExpressionParsing::SGxAODProxyLoader(evtStore())); + // load the expressions + m_parser = new ExpressionParsing::ExpressionParser(proxyLoaders); + m_parser->loadExpression( m_selection.value() ); + } + // initialize the counters + m_nEventsProcessed = 0; - // Initialize the counters to zero - m_nEventsProcessed = 0 ; - - - // Get the JobOptionService - // We will use this to set the properties of our private skimming tool - // from the properties of this algorithm. - ATH_MSG_VERBOSE( "Getting the JobOptionService"); - ATH_CHECK( m_jos.retrieve() ); - - // Get the full name of the private skimTool - ATH_MSG_VERBOSE( "Getting the full name of the tool"); - const std::string& fullToolName = this->name() + "." + m_tool.name(); - ATH_MSG_DEBUG( "Got the full name of the tool: " << fullToolName ); - - // Now, set all properties of the private skimTool that were acutally configured - if (m_setInCollKey) { - ATH_MSG_DEBUG( "Setting property" << m_inCollKey - << " of private tool with name: '" << fullToolName << "'" ); - ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_inCollKey) ); + // Determine the ownership policy of the output container + if ( m_outOwnPolicyName.value() == "OWN_ELEMENTS" ) { + m_outOwnPolicy = SG::OWN_ELEMENTS; } - if (m_setOutCollKey) { - ATH_MSG_DEBUG( "Setting property" << m_outCollKey - << " of private tool with name: '" << fullToolName << "'" ); - ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_outCollKey) ); + else if ( m_outOwnPolicyName.value() == "VIEW_ELEMENTS" ) { + m_outOwnPolicy = SG::VIEW_ELEMENTS; } - if (m_setOutCollType) { - ATH_MSG_DEBUG( "Setting property" << m_outCollType - << " of private tool with name: '" << fullToolName << "'" ); - ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_outCollType) ); + else { + ATH_MSG_ERROR("Unrecognized ownership policy for the output container: " << m_outOwnPolicyName ); + return StatusCode::FAILURE; } - if (m_setWriteSplitAux) { - ATH_MSG_DEBUG( "Setting property" << m_writeSplitAux - << " of private tool with name: '" << fullToolName << "'" ); - ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_writeSplitAux) ); - } - if (m_setOwnPolicy) { - ATH_MSG_DEBUG( "Setting property" << m_outOwnPolicyName - << " of private tool with name: '" << fullToolName << "'" ); - ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_outOwnPolicyName) ); - } - if (m_setOutLinkCollKey) { - ATH_MSG_DEBUG( "Setting property" << m_outLinkCollKey - << " of private tool with name: '" << fullToolName << "'" ); - ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_outLinkCollKey) ); - } - if (m_setSelection) { - ATH_MSG_DEBUG( "Setting property" << m_selection - << " of private tool with name: '" << fullToolName << "'" ); - ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_selection) ); - } - ATH_MSG_DEBUG( "Done setting properties of the tool"); - // Get the skimming tool - ATH_CHECK( m_tool.retrieve() ); + // Retrieve all tools + ATH_CHECK( m_selTools.retrieve() ); + ATH_CHECK( m_selWVtxTools.retrieve() ); ATH_MSG_DEBUG ( "==> done with initialize " << name() << "..." ); - return StatusCode::SUCCESS; } @@ -175,24 +174,230 @@ StatusCode ParticleSelectionAlg::finalize() ATH_MSG_DEBUG ("Finalizing " << name() << "..."); // Release all tools and services - ATH_CHECK( m_jos.release() ); - ATH_CHECK( m_tool.release() ); + ATH_CHECK( m_selTools.release() ); + ATH_CHECK( m_selWVtxTools.release() ); + + // Clean up the memory + if (m_parser) { + delete m_parser; + m_parser = 0; + } return StatusCode::SUCCESS; } +StatusCode ParticleSelectionAlg::beginRun() +{ + ATH_MSG_DEBUG ("BeginRun " << name() << "..."); + + // Nothing to be done here, if cut-flow bookkeeping was not requested + if (!m_doCutFlow){ return StatusCode::SUCCESS; } + + // Get some properties from the input meta data + std::string inputStreamName = "Stream"; + const CLID clid = ClassID_traits<EventStreamInfo>::ID(); + std::vector<std::string> streamNameList; + inputMetaStore()->keys(clid, streamNameList); + if ( streamNameList.size() >=1 ){ inputStreamName = streamNameList[0]; } + // Get the processing cycle number that we need to set for us + int maxInputCycle = -1; + if ( inputMetaStore()->contains<xAOD::CutBookkeeperContainer>(m_cutBKCName.value()) ){ + xAOD::CutBookkeeperContainer* inCutBKCont = nullptr; + ATH_CHECK( inputMetaStore()->retrieve(inCutBKCont, m_cutBKCName.value() ) ); + if (inCutBKCont){ + maxInputCycle = inCutBKCont->maxCycle(); + } + } + if (maxInputCycle<0){ maxInputCycle = 0; } + else { maxInputCycle += 1; } + + // Check if we already have a container in the output meta-data store + xAOD::CutBookkeeperContainer* cutBKCont = nullptr; + if ( outputMetaStore()->contains<xAOD::CutBookkeeperContainer>(m_cutBKCName.value()) ){ + ATH_CHECK( inputMetaStore()->retrieve(cutBKCont, m_cutBKCName.value() ) ); + // Set the index where we will start having our CutBookkeepers in this container + m_cutBKStartIdx = cutBKCont->size(); + } + else { + // Create and register the container that will hold the cut-flow information + cutBKCont = new xAOD::CutBookkeeperContainer(); + // Take care of the peculiarities of the new xAOD EDM, i.e., create the needed AuxStore + xAOD::CutBookkeeperAuxContainer* cutBKAuxCont = new xAOD::CutBookkeeperAuxContainer(); + cutBKCont->setStore( cutBKAuxCont ); //gives it a new associated aux container + ATH_CHECK( outputMetaStore()->record( cutBKCont, m_cutBKCName.value() ) ); + ATH_CHECK( outputMetaStore()->record( cutBKAuxCont, m_cutBKCName.value()+"Aux." ) ); + ATH_MSG_VERBOSE( "Recorded xAOD::CutBookkeeperContainer " << m_cutBKCName.value() << "Aux." ); + } + + //------------- for the AsgSelectionTools -------------- + // Now, register one CutBookkeeper per cut that will be applied. + // For each of the registered tools, get the TAccept and ask it for all known cuts. + for ( std::size_t toolIdx=0; toolIdx < m_selTools.size(); ++toolIdx ){ + const auto& tool = m_selTools[toolIdx]; + // Fill the index bookkeeping at what index in the CutBookkeeperContainer + // the CutBookkeepers for this tool start. + m_selToolIdxOffset.push_back( cutBKCont->size() ); + // Get some needed quantities + const std::string toolName = tool->name(); + const Root::TAccept& tAccept = tool->getTAccept(); + const unsigned int nCuts = tAccept.getNCuts(); + for ( unsigned int iCut=0; iCut<nCuts; ++iCut ){ + // Get the name and description of this cut + const std::string cutName = (tAccept.getCutName(iCut)).Data(); + const std::string cutDescr = (tAccept.getCutDescription(iCut)).Data(); + // Create a new xAOD::CutBookkeeper and add it to the container + xAOD::CutBookkeeper* cutBK = new xAOD::CutBookkeeper(); + cutBKCont->push_back(cutBK); + // Now, set its properties + cutBK->setName(toolName+"_"+cutName); + cutBK->setDescription(cutDescr); + cutBK->setCutLogic(xAOD::CutBookkeeper::CutLogic::REQUIRE); // Each cut must be passed, thus REQUIRE, i.e, logical AND + cutBK->setInputStream(inputStreamName); + cutBK->setCycle(maxInputCycle); + } + } + + //------------- for the AsgSelectionWithVertexTools -------------- + // Now, register one CutBookkeeper per cut that will be applied. + // For each of the registered tools, get the TAccept and ask it for all known cuts. + for ( std::size_t toolIdx=0; toolIdx < m_selWVtxTools.size(); ++toolIdx ){ + const auto& tool = m_selWVtxTools[toolIdx]; + // Fill the index bookkeeping at what index in the CutBookkeeperContainer + // the CutBookkeepers for this tool start. + m_selWPVToolIdxOffset.push_back( cutBKCont->size() ); + // Get some needed quantities + const std::string toolName = tool->name(); + const Root::TAccept& tAccept = tool->getTAccept(); + const unsigned int nCuts = tAccept.getNCuts(); + for ( unsigned int iCut=0; iCut<nCuts; ++iCut ){ + // Get the name and description of this cut + const std::string cutName = (tAccept.getCutName(iCut)).Data(); + const std::string cutDescr = (tAccept.getCutDescription(iCut)).Data(); + // Create a new xAOD::CutBookkeeper and add it to the container + xAOD::CutBookkeeper* cutBK = new xAOD::CutBookkeeper(); + cutBKCont->push_back(cutBK); + // Now, set its properties + cutBK->setName(toolName+"_"+cutName); + cutBK->setDescription(cutDescr); + cutBK->setCutLogic(xAOD::CutBookkeeper::CutLogic::REQUIRE); // Each cut must be passed, thus REQUIRE, i.e, logical AND + cutBK->setInputStream(inputStreamName); + cutBK->setCycle(maxInputCycle); + } + } + + //------------- for the ExpressionParsing in this algorithm -------------- + if ( !(m_selection.value().empty()) ){ + // Create a new xAOD::CutBookkeeper and add it to the container + xAOD::CutBookkeeper* cutBK = new xAOD::CutBookkeeper(); + cutBKCont->push_back(cutBK); + // Now, set its properties + cutBK->setName(this->name()); + cutBK->setDescription(m_selection.value()); + cutBK->setCutLogic(xAOD::CutBookkeeper::CutLogic::REQUIRE); // Each cut must be passed, thus REQUIRE, i.e, logical AND + cutBK->setInputStream(inputStreamName); + cutBK->setCycle(maxInputCycle); + m_idxSelParster = cutBK->index(); + } + + return StatusCode::SUCCESS; +} + + + + StatusCode ParticleSelectionAlg::execute() { // Increase the event counter ++m_nEventsProcessed; - // Simple status message at the beginning of each event execute, ATH_MSG_DEBUG ( "==> execute " << name() << " on " << m_nEventsProcessed << ". event..." ); - // Call the tool and record resulting containers into StoreGate - ATH_CHECK( m_tool->addBranches() ); + + // Figure out what type the input container has, if we didn't do it yet + if ( m_contType == UNKNOWN ){ + if ( evtStore()->contains<xAOD::PhotonContainer>(m_inCollKey.value()) ){ m_contType = PHOTON; } + else if ( evtStore()->contains<xAOD::ElectronContainer>(m_inCollKey.value()) ){ m_contType = ELECTRON; } + else if ( evtStore()->contains<xAOD::MuonContainer>(m_inCollKey.value()) ){ m_contType = MUON; } + else if ( evtStore()->contains<xAOD::TauJetContainer>(m_inCollKey.value()) ){ m_contType = TAU; } + else if ( evtStore()->contains<xAOD::JetContainer>(m_inCollKey.value()) ){ m_contType = JET; } + else if ( evtStore()->contains<xAOD::TruthParticleContainer>(m_inCollKey.value()) ){ m_contType = TRUTHPARTICLE; } + else if ( evtStore()->contains<xAOD::CompositeParticleContainer>(m_inCollKey.value()) ){ m_contType = COMPOSITEPARTICLE; } + else if ( evtStore()->contains<xAOD::PFOContainer>(m_inCollKey.value()) ){ m_contType = PARITCLEFLOW; } + else if ( evtStore()->contains<xAOD::NeutralParticleContainer>(m_inCollKey.value()) ){ m_contType = NEUTRALPARTICLE; } + else if ( evtStore()->contains<xAOD::TrackParticleContainer>(m_inCollKey.value()) ){ m_contType = TRACKPARTICLE; } + else if ( evtStore()->contains<xAOD::ParticleContainer>(m_inCollKey.value()) ){ m_contType = PARTICLE; } + else if ( evtStore()->contains<xAOD::CaloClusterContainer>(m_inCollKey.value()) ){ m_contType = CALOCLUSTER; } + } + if ( m_contType == UNKNOWN ){ + ATH_MSG_FATAL("We couldn't determine the type of the container... abort!"); + return StatusCode::FAILURE; + } + + // Get the input container and create the output containers + const xAOD::IParticleContainer* inContainer = nullptr; + ATH_CHECK( evtStore()->retrieve( inContainer, m_inCollKey.value() ) ); + ATH_MSG_DEBUG ( "Input collection = " << m_inCollKey.value() + << " retrieved from StoreGate which has " << inContainer->size() << " entries." ); + + // -------------------------------------------------------------------------- + // Do the expression parsing once per event already here + // -------------------------------------------------------------------------- + std::vector<int> resultVec; + resultVec.reserve(inContainer->size()); + if ( !(m_selection.value().empty()) ){ + resultVec = m_parser->evaluateAsVector(); + // Check that the lengths of the input container and the result vector are the same + if ( inContainer && inContainer->size() != resultVec.size() ) { + ATH_MSG_ERROR("We got an input container, but its size (" << inContainer->size() + << ") doesn't match the size of the result vector: " << resultVec.size() ); + return StatusCode::FAILURE; + } + ATH_MSG_VERBOSE("Have a container of size " << inContainer->size() + << " and a result vector of size " << resultVec.size() ); + } // End: If expression parsing was requested in the first place + + + // -------------------------------------------------------------------------- + // Do the heavy lifting of actually creating the new and reduced output container(s) + // -------------------------------------------------------------------------- + if ( m_contType == PHOTON ){ + ATH_CHECK( (this->selectParticles<xAOD::PhotonContainer,xAOD::PhotonAuxContainer>(inContainer,resultVec)) ); + } + else if ( m_contType == ELECTRON ){ + ATH_CHECK( (this->selectParticles<xAOD::ElectronContainer,xAOD::ElectronAuxContainer>(inContainer,resultVec)) ); + } + else if ( m_contType == MUON ){ + ATH_CHECK( (this->selectParticles<xAOD::MuonContainer,xAOD::MuonAuxContainer>(inContainer,resultVec)) ); + } + else if ( m_contType == TAU ){ + ATH_CHECK( (this->selectParticles<xAOD::TauJetContainer,xAOD::TauJetAuxContainer>(inContainer,resultVec)) ); + } + else if ( m_contType == JET ){ + ATH_CHECK( (this->selectParticles<xAOD::JetContainer,xAOD::JetAuxContainer>(inContainer,resultVec)) ); + } + else if ( m_contType == TRUTHPARTICLE ){ + ATH_CHECK( (this->selectParticles<xAOD::TruthParticleContainer,xAOD::TruthParticleAuxContainer>(inContainer,resultVec)) ); + } + else if ( m_contType == COMPOSITEPARTICLE ){ + ATH_CHECK( (this->selectParticles<xAOD::CompositeParticleContainer,xAOD::CompositeParticleAuxContainer>(inContainer,resultVec)) ); + } + else if ( m_contType == PARITCLEFLOW ){ + ATH_CHECK( (this->selectParticles<xAOD::PFOContainer,xAOD::PFOAuxContainer>(inContainer,resultVec)) ); + } + else if ( m_contType == NEUTRALPARTICLE ){ + ATH_CHECK( (this->selectParticles<xAOD::NeutralParticleContainer,xAOD::NeutralParticleAuxContainer>(inContainer,resultVec)) ); + } + else if ( m_contType == TRACKPARTICLE ){ + ATH_CHECK( (this->selectParticles<xAOD::TrackParticleContainer,xAOD::TrackParticleAuxContainer>(inContainer,resultVec)) ); + } + else if ( m_contType == PARTICLE ){ + ATH_CHECK( (this->selectParticles<xAOD::ParticleContainer,xAOD::ParticleAuxContainer>(inContainer,resultVec)) ); + } + else if ( m_contType == CALOCLUSTER ){ + ATH_CHECK( (this->selectParticles<xAOD::CaloClusterContainer,xAOD::CaloClusterAuxContainer>(inContainer,resultVec)) ); + } return StatusCode::SUCCESS; } diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.h index 84c0885f0b7..e332ae73b3c 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.h +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.h @@ -13,23 +13,30 @@ // STL includes #include <string> +#include <vector> // FrameWork includes #include "GaudiKernel/ToolHandle.h" -#include "GaudiKernel/ServiceHandle.h" -#include "AthenaBaseComps/AthAlgorithm.h" - - -// forward declarations -class IJobOptionsSvc; -namespace DerivationFramework { - class IAugmentationTool; +// #include "GaudiKernel/ServiceHandle.h" +// #include "AthenaBaseComps/AthAlgorithm.h" +#include "AthAnalysisBaseComps/AthAnalysisAlgorithm.h" +#include "xAODBase/IParticleContainer.h" +//#include "TrigDecisionTool/TrigDecisionTool.h" +#include "PATCore/IAsgSelectionTool.h" +#include "PATCore/IAsgSelectionWithVertexTool.h" + +// // Forward declarations +// namespace Trig{ +// class TrigDecisionTool; +// } +// Forward declarations +namespace ExpressionParsing { + class ExpressionParser; } - class ParticleSelectionAlg - : public ::AthAlgorithm + : public ::AthAnalysisAlgorithm { /////////////////////////////////////////////////////////////////// @@ -49,6 +56,10 @@ class ParticleSelectionAlg /// Athena algorithm's initalize hook virtual StatusCode initialize(); + /// Athena algorithm's beginRun hook + /// (called once before running over the events, after initialize) + virtual StatusCode beginRun(); + /// Athena algorithm's execute hook virtual StatusCode execute(); @@ -56,150 +67,114 @@ class ParticleSelectionAlg virtual StatusCode finalize(); -private: - // The update handlers - - /// This internal method will realize if a user sets the 'InputContainer' property - void setupInputContainer( Property& /*prop*/ ); - - /// This internal method will realize if a user sets the 'OutputContainer' property - void setupOutputContainer( Property& /*prop*/ ); - - /// This internal method will realize if a user sets the 'OutputContainerType' property - void setupOutputContainerType( Property& /*prop*/ ); - - /// This internal method will realize if a user sets the 'WriteSplitOutputContainer' property - void setupWriteSplitOutputContainer( Property& /*prop*/ ); - - /// This internal method will realize if a user sets the 'OutputContainerOwnershipPolicy' property - void setupOutputContainerOwnPolicy( Property& /*prop*/ ); - - /// This internal method will realize if a user sets the 'OutputLinkContainer' property - void setupOutputLinkContainer( Property& /*prop*/ ); - - /// This internal method will realize if a user sets the 'Selection' property - void setupSelection( Property& /*prop*/ ); + private: + /// Private function to perform the actualy work + template<class CONT, class AUXCONT> + StatusCode selectParticles(const xAOD::IParticleContainer* inContainer, + const std::vector<int>& resultVec) const; /////////////////////////////////////////////////////////////////// // Private data: /////////////////////////////////////////////////////////////////// private: - /// The job options service (will be used to forward this algs properties to - /// the private tool) - ServiceHandle<IJobOptionsSvc> m_jos; + /// The list of IAsgSelectionTools + ToolHandleArray<IAsgSelectionTool> m_selTools; - /// The ToolHandle to the SkimmingTool - ToolHandle<DerivationFramework::IAugmentationTool> m_tool; + /// The list of IAsgSelectionWithVertexTools + ToolHandleArray<IAsgSelectionWithVertexTool> m_selWVtxTools; - /// Input container name - StringProperty m_inCollKey; + /// Name of the EventInfo object + StringProperty m_evtInfoName; - /// This boolean is true if the user sets the 'InputContainer' property - bool m_setInCollKey; + /// Name of the PrimaryVertex container + StringProperty m_inPrimVtxCont; + /// Input container name + StringProperty m_inCollKey; /// Output collection name (deep copies of the original ones) StringProperty m_outCollKey; - /// This boolean is true if the user sets the 'OutputContainer' property - bool m_setOutCollKey; - - - /// The type of the output container, e.g., 'xAOD::JetContainer' - StringProperty m_outCollType; - - /// This boolean is true if the user sets the 'OutputContainerType' property - bool m_setOutCollType; - - /// Decide if we want to write a fully-split AuxContainer such that we can remove any variables BooleanProperty m_writeSplitAux; - /// This boolean is true if the user sets the 'WriteSplitOutputContainer' property - bool m_setWriteSplitAux; - - /// Defines the ownership policy of the output container - /// (default: 'OWN_ELEMENTS'; also allowed: 'VIEW_ELEMENTS')" + /// (default: 'VIEW_ELEMENTS'; also allowed: 'OWN_ELEMENTS')". + /// TO see what this means, go here: + /// https://twiki.cern.ch/twiki/bin/view/AtlasComputing/SoftwareTutorialxAODAnalysisInAthena#Understanding_the_different_type StringProperty m_outOwnPolicyName; - /// This boolean is true if the user sets the 'OutputContainerOwnershipPolicy' property - bool m_setOwnPolicy; - - - /// Output link collection name (ElementLinks to selected IParticles) - StringProperty m_outLinkCollKey; - - /// This boolean is true if the user sets the 'OutputLinkContainer' property - bool m_setOutLinkCollKey; - - /// The selection string that will select which xAOD::IParticles to keep from /// an xAOD::IParticleContainer StringProperty m_selection; - /// This boolean is true if the user sets the 'Selection' property - bool m_setSelection; - - - - /// Internal event counter - unsigned long m_nEventsProcessed; - - -}; - -// I/O operators -////////////////////// + /// If true (deault: false), do the bookkeeping of how many particles passed + /// which selection cuts + bool m_doCutFlow; -/////////////////////////////////////////////////////////////////// -// Inline methods: -/////////////////////////////////////////////////////////////////// + /// The name of the resulting xAOD::CutBookkeeperContainer. + /// If an empty name is given (default), the name of the algorithm instance is used. + StringProperty m_cutBKCName; -/// This internal method will realize if a user sets the 'InputContainer' property -inline void ParticleSelectionAlg::setupInputContainer( Property& /*prop*/ ) { - m_setInCollKey = true; - return; -} -/// This internal method will realize if a user sets the 'OutputContainer' property -inline void ParticleSelectionAlg::setupOutputContainer( Property& /*prop*/ ) { - m_setOutCollKey = true; - return; -} -/// This internal method will realize if a user sets the 'OutputContainerType' property -inline void ParticleSelectionAlg::setupOutputContainerType( Property& /*prop*/ ) { - m_setOutCollType = true; - return; -} + /// @name Internal members + /// @{ -/// This internal method will realize if a user sets the 'WriteSplitOutputContainer' property -inline void ParticleSelectionAlg::setupWriteSplitOutputContainer( Property& /*prop*/ ) { - m_setWriteSplitAux = true; - return; -} + /// The expression parser + ExpressionParsing::ExpressionParser *m_parser; -/// This internal method will realize if a user sets the 'OutputContainerOwnPolicy' property -inline void ParticleSelectionAlg::setupOutputContainerOwnPolicy( Property& /*prop*/ ) { - m_setOwnPolicy = true; - return; -} + // /// The trigger decision tool + // ToolHandle<Trig::TrigDecisionTool> m_trigDecisionTool; -/// This internal method will realize if a user sets the 'OutputLinkContainer' property -inline void ParticleSelectionAlg::setupOutputLinkContainer( Property& /*prop*/ ) { - m_setOutLinkCollKey = true; - return; -} + /// Internal event counter + unsigned long m_nEventsProcessed; -/// This internal method will realize if a user sets the 'Selection' property -inline void ParticleSelectionAlg::setupSelection( Property& /*prop*/ ) { - m_setSelection = true; - return; -} + /// The internally used translation for the ownership policy + SG::OwnershipPolicy m_outOwnPolicy; + + /// An enumaration for the actual container type + enum contType_t { + UNKNOWN, + PHOTON, + ELECTRON, + MUON, + TAU, + JET, + PARITCLEFLOW, + NEUTRALPARTICLE, + TRACKPARTICLE, + TRUTHPARTICLE, + COMPOSITEPARTICLE, + PARTICLE, + CALOCLUSTER + }; + + /// The variable that holds the value that we find for the input container + contType_t m_contType; + + /// The starting index of where in the CutBookkeeperContainer our new CutBookkeepers start + std::size_t m_cutBKStartIdx; + + /// The list of pairs of the tool index of the AsgSelectionTools and the + /// starting index of the corresponding CutBookKeeper inside the CutBookkeeperContainer. + std::vector<std::size_t> m_selToolIdxOffset; + + /// The list of pairs of the tool index of the AsgSelectionWithVertexTools and the + /// starting index of the corresponding CutBookKeeper inside the CutBookkeeperContainer. + std::vector<std::size_t> m_selWPVToolIdxOffset; + + /// Store the index of the CutBookKeeper in the CutBookkeeperContainer for the + /// selection using the ExpressionParser + std::size_t m_idxSelParster; + + /// @} +}; +// Include the templated code here. This must be done from this header file. +#include "ParticleSelectionAlg.icc" #endif //> !EVENTUTILS_PARTICLESELECTIONALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.icc b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.icc new file mode 100644 index 00000000000..7e88f764b4e --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.icc @@ -0,0 +1,188 @@ +// Dear emacs, this is -*- c++ -*- + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + + +#include "xAODBase/IParticle.h" +#include "xAODCore/AuxContainerBase.h" +#include "AthContainers/ConstDataVector.h" +#include "xAODEventInfo/EventInfo.h" +#include "xAODTracking/VertexContainer.h" +#include "xAODTracking/Vertex.h" +#include "xAODCutFlow/CutBookkeeperContainer.h" +#include "PATCore/TAccept.h" + + + +template<class CONT, class AUXCONT> +StatusCode ParticleSelectionAlg::selectParticles(const xAOD::IParticleContainer* inContainer, + const std::vector<int>& resultVec) const +{ + ATH_MSG_DEBUG ("selectParticlesStepTwo<CONT,AUXCONT>(...) " << name() << "..."); + + // Get the type of particle that the current container CONT has + typedef typename CONT::base_value_type PART; + + // Create a new output container and its associated auxiliary container + CONT* outCont = nullptr; + ConstDataVector<CONT>* outContConst = nullptr; + + if ( m_outOwnPolicy == SG::OWN_ELEMENTS ) { + outCont = new CONT( m_outOwnPolicy ); + ATH_CHECK( evtStore()->record ( outCont, m_outCollKey.value() ) ); + if ( m_writeSplitAux.value() ) { + xAOD::AuxContainerBase* outAuxContainer = new xAOD::AuxContainerBase(); + ATH_CHECK( evtStore()->record( outAuxContainer, m_outCollKey.value() + "Aux." ) ); + outCont->setStore( outAuxContainer ); + ATH_MSG_VERBOSE("Recorded xAOD::AuxContainerBase for container: " << m_outCollKey.value() ); + } + else { + AUXCONT* outAuxContainer = new AUXCONT(); + ATH_CHECK( evtStore()->record( outAuxContainer, m_outCollKey.value() + "Aux." ) ); + outCont->setStore( outAuxContainer ); + ATH_MSG_VERBOSE("Recorded AuxContainer for container: " << m_outCollKey.value() ); + } + } + else { + outContConst = new ConstDataVector<CONT>( m_outOwnPolicy ); + ATH_CHECK( evtStore()->record ( outContConst, m_outCollKey.value() ) ); + ATH_MSG_VERBOSE("Recorded ConstDataVector for container: " << m_outCollKey.value() ); + } + // ATH_MSG_VERBOSE("StoreGate dump: " << evtStore()->dump() ); + + // Get the CutBookkeeperContainer, if cut-flow bookkeeping was requested + double eventWeight = 1.0; + xAOD::CutBookkeeperContainer* cutBKCont = nullptr; + const xAOD::EventInfo* evtInfo = nullptr; + if (m_doCutFlow){ + ATH_CHECK( outputMetaStore()->retrieve(cutBKCont, m_cutBKCName.value() ) ); + // Also, get the event info as we need to get the MC-weight for this event + ATH_CHECK( evtStore()->retrieve( evtInfo, m_evtInfoName.value() )); + const bool isSim = evtInfo->eventType(xAOD::EventInfo::EventType::IS_SIMULATION); + if (isSim){ + eventWeight = static_cast<double>( evtInfo->mcEventWeight() ); + ATH_MSG_VERBOSE("Got MC event weight of " << eventWeight ); + } + } + + + // Now, loop over the input container and check which particles to write out + ATH_MSG_DEBUG("Input container has size " << inContainer->size() ); + for ( std::size_t i=0; i<inContainer->size(); ++i ) { + const xAOD::IParticle* partBase = inContainer->at(i); + const PART* part = static_cast<const PART*>(partBase); + + // ================================ + // Apply the selection tools + // ================================ + // The default object pass value. As soon as one cut is not passed, then + // the remainder of the cuts will not even be tried + bool passEverything = true; + + //------------- for the AsgSelectionTools -------------- + // Loop over all selection tools + ATH_MSG_VERBOSE("Loop over all selection tools"); + for ( std::size_t toolIdx=0; toolIdx < m_selTools.size(); ++toolIdx ){ + if (passEverything){ + ATH_MSG_VERBOSE("Now going to try AsgSelectionTools number " << toolIdx ); + const Root::TAccept& tAccept = m_selTools[toolIdx]->accept(part); + if (!m_doCutFlow){ passEverything &= static_cast<bool>(tAccept); } + else { + const std::size_t cbkStartIdx = m_selToolIdxOffset[toolIdx]; + const unsigned int nCuts = tAccept.getNCuts(); + for ( unsigned int iCut=0; iCut<nCuts; ++iCut ){ + passEverything &= tAccept.getCutResult(iCut); + if (passEverything){ + const std::size_t currentCBKIdx = cbkStartIdx + iCut; + xAOD::CutBookkeeper* cutBK = cutBKCont->at(currentCBKIdx); + cutBK->addNAcceptedEvents(1); + cutBK->addSumOfEventWeights(eventWeight); + cutBK->addSumOfEventWeightsSquared(eventWeight*eventWeight); + } + } + } // Done doing detailed particle cut-flow for this tool + ATH_MSG_VERBOSE("AsgSelectionTools number " << toolIdx << " passed/failed: " << passEverything ); + } + } + + //------------- for the AsgSelectionWithVertexTools -------------- + // If we have at least one, we have to get the primary vertex + if ( m_selWVtxTools.size() ){ + // Get the primary vertex container + const xAOD::VertexContainer* primVtxCont = nullptr; + ATH_CHECK( evtStore()->retrieve( primVtxCont, m_inPrimVtxCont.value() ) ); + const xAOD::Vertex* primVtx = nullptr; + for ( const xAOD::Vertex* vtx : *primVtxCont ) { + // Get THE primary vertex + if ( vtx->vertexType() == xAOD::VxType::PriVtx ) { + primVtx = vtx; + break; + } + } + if ( !primVtx ) { + ATH_MSG_WARNING("Couldn't find a primary vertex in this event!"); + } + // Now, we go ahead and loop over the tools + ATH_MSG_VERBOSE("Loop over all selection with vertex tools: " << passEverything); + for ( std::size_t toolIdx=0; toolIdx < m_selWVtxTools.size(); ++toolIdx ){ + if (passEverything){ + ATH_MSG_VERBOSE("Now going to try AsgSelectionWithVertexTools number " << toolIdx ); + const Root::TAccept& tAccept = m_selWVtxTools[toolIdx]->accept(part,primVtx); + if (!m_doCutFlow){ passEverything &= static_cast<bool>(tAccept); } + else { + const std::size_t cbkStartIdx = m_selWPVToolIdxOffset[toolIdx]; + const unsigned int nCuts = tAccept.getNCuts(); + for ( unsigned int iCut=0; iCut<nCuts; ++iCut ){ + passEverything &= tAccept.getCutResult(iCut); + if (passEverything){ + const std::size_t currentCBKIdx = cbkStartIdx + iCut; + xAOD::CutBookkeeper* cutBK = cutBKCont->at(currentCBKIdx); + cutBK->addNAcceptedEvents(1); + cutBK->addSumOfEventWeights(eventWeight); + cutBK->addSumOfEventWeightsSquared(eventWeight*eventWeight); + } + } + } // Done doing detailed particle cut-flow for this tool + ATH_MSG_VERBOSE("AsgSelectionWithVertexTools number " << toolIdx << " passed/failed: " << passEverything ); + } + }// Done looping over the selection tools + } // End: if ( m_selWVtxTools.size() ){ + + //------------- for the ExpressionParsing in this algorithm -------------- + ATH_MSG_VERBOSE("Looking at expression parser result: " << passEverything); + if ( passEverything && !(resultVec.empty()) ){ + // If this particle is not accepted by the expression parser, go to the next one + ATH_MSG_VERBOSE("Now going to try expression '" << m_selection.value() << "'" ); + passEverything &= static_cast<bool>(resultVec.at(i)); + ATH_MSG_VERBOSE("Expression '" << m_selection.value() << "' passed/failed: " << passEverything + << ", particle index=" << part->index() <<", pt=" << 0.001*(part->pt()) << " GeV, eta=" + << part->eta() << ", phi=" << part->phi() ); + if (passEverything && m_doCutFlow){ + xAOD::CutBookkeeper* cutBK = cutBKCont->at(m_idxSelParster); + cutBK->addNAcceptedEvents(1); + cutBK->addSumOfEventWeights(eventWeight); + cutBK->addSumOfEventWeightsSquared(eventWeight*eventWeight); + } + } + + // Now, if all cuts are passed, write out the current particle to the + // output container + if (passEverything){ + ATH_MSG_VERBOSE("Going to fill output container with particle with pt=" << 0.001*(part->pt()) + << " GeV, eta=" << part->eta() ); + if ( m_outOwnPolicy == SG::OWN_ELEMENTS ) { + PART* newPart = new PART(); + outCont->push_back(newPart); + *newPart = *part; + } + else { + outContConst->push_back(part); + } + } + + } // End: Loop over input particles + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.cxx index e50264e3906..117a4d9c4cb 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.cxx +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.cxx @@ -89,6 +89,7 @@ ParticleSelectionTool::ParticleSelectionTool( const std::string& type, m_outCollKey(""), m_outCollType(""), m_writeSplitAux(false), + m_outOwnPolicy(SG::VIEW_ELEMENTS), m_outLinkCollKey(""), m_selection(""), m_contID(0), diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.h index 8ed3441cf40..38ef486aa79 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.h +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.h @@ -54,10 +54,10 @@ public: virtual ~ParticleSelectionTool(); /// Athena algtool's initialize - virtual StatusCode initialize(); + virtual StatusCode initialize() override; /// Athena algtool's finalize - virtual StatusCode finalize(); + virtual StatusCode finalize() override; /// Implement the method from the ISkimmingTool interface diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.cxx index f966284daa0..66e180f0977 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.cxx +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.cxx @@ -34,6 +34,7 @@ #include "xAODParticleEvent/CompositeParticleContainer.h" #include "xAODParticleEvent/ParticleContainer.h" #include "xAODCaloEvent/CaloClusterContainer.h" +#include "AthContainers/ConstDataVector.h" @@ -101,7 +102,7 @@ StatusCode ParticleSortingTool::initialize() m_sortID = 7; } if ( m_sortDescending.value() ) { m_sortID *= -1; } - + return StatusCode::SUCCESS; } @@ -130,6 +131,20 @@ else if ( evtStore()->contains<CONTAINERTYPE>( m_inCollKey.value() ) ) { } +// Declare a short pre-processor macro to deal with the different container types +#define OVERWRITE_AND_SORT_CONTAINER( CONTAINERTYPE ) \ +else if ( evtStore()->contains<CONTAINERTYPE>( m_inCollKey.value() ) ) { \ + ATH_MSG_DEBUG("Trying to copy, sort, and overwrite container of type "#CONTAINERTYPE ); \ + const CONTAINERTYPE* inCont; \ + ATH_CHECK( evtStore()->retrieve( inCont, m_inCollKey.value() ) ); \ + ConstDataVector<CONTAINERTYPE>* outCont = new ConstDataVector<CONTAINERTYPE>( SG::VIEW_ELEMENTS ); \ + for ( const CONTAINERTYPE::base_value_type* inPart : *inCont ){ \ + outCont->push_back(inPart); \ + } \ + ATH_CHECK( evtStore()->overwrite( outCont, m_inCollKey.value() ) ); \ + ATH_CHECK( this->doSortConst<CONTAINERTYPE>(outCont) ); \ +} + StatusCode ParticleSortingTool::addBranches() const @@ -145,7 +160,31 @@ StatusCode ParticleSortingTool::addBranches() const ATH_MSG_DEBUG("Got an empty 'OutputCollection' property. " << "Trying to retrieve a non-const version of the 'InputContainer'..."); xAOD::IParticleContainer* inCont = evtStore()->tryRetrieve<xAOD::IParticleContainer>( m_inCollKey.value() ); - ATH_CHECK( this->doSort(inCont) ); + if (inCont){ ATH_CHECK( this->doSort(inCont) ); } + else { + ATH_MSG_DEBUG("We couldn't retrieve a non-const version of the input container... try const."); + const xAOD::IParticleContainer* inCont2 = nullptr; + ATH_CHECK( evtStore()->retrieve( inCont2, m_inCollKey.value()) ); + // Now, do the copy and sorting and overwriting of all known container types + if (false) { + } + OVERWRITE_AND_SORT_CONTAINER(xAOD::MuonContainer) + OVERWRITE_AND_SORT_CONTAINER(xAOD::ElectronContainer) + OVERWRITE_AND_SORT_CONTAINER(xAOD::PhotonContainer) + OVERWRITE_AND_SORT_CONTAINER(xAOD::TauJetContainer) + OVERWRITE_AND_SORT_CONTAINER(xAOD::JetContainer) + OVERWRITE_AND_SORT_CONTAINER(xAOD::PFOContainer) + OVERWRITE_AND_SORT_CONTAINER(xAOD::NeutralParticleContainer) + OVERWRITE_AND_SORT_CONTAINER(xAOD::TrackParticleContainer) + OVERWRITE_AND_SORT_CONTAINER(xAOD::TruthParticleContainer) + OVERWRITE_AND_SORT_CONTAINER(xAOD::CompositeParticleContainer) + OVERWRITE_AND_SORT_CONTAINER(xAOD::ParticleContainer) + OVERWRITE_AND_SORT_CONTAINER(xAOD::CaloClusterContainer) + else { + ATH_MSG_ERROR("Couln't find the provided intput container in store gate for later overwriting"); + return StatusCode::FAILURE; + } + } } else { ATH_MSG_DEBUG("Got a non-empty 'OutputCollection' property. " diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.h index 5101324aefa..8700fabf0ce 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.h +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.h @@ -23,6 +23,7 @@ // EDM inlcudes #include "xAODBase/IParticle.h" #include "xAODBase/IParticleContainer.h" +#include "AthContainers/ConstDataVector.h" @@ -47,10 +48,10 @@ public: virtual ~ParticleSortingTool(); /// Athena algtool's initialize - virtual StatusCode initialize(); + virtual StatusCode initialize() override; /// Athena algtool's finalize - virtual StatusCode finalize(); + virtual StatusCode finalize() override; /// Implement the method from the ISkimmingTool interface @@ -64,6 +65,10 @@ private: /// Helper method that implements the call to the right sort function StatusCode doSort( xAOD::IParticleContainer* cont ) const; + /// Helper method to sort a ConstDataVector + template<class CONTAINERTYPE> + StatusCode doSortConst( ConstDataVector<CONTAINERTYPE>* cont ) const; + /// The method to compare the particle's pt bool comparePt( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const; @@ -125,4 +130,55 @@ inline bool ParticleSortingTool::compareDouble( double a, double b ) const else { return CxxUtils::fpcompare::less(a,b); } } + +template<class CONTAINERTYPE> +StatusCode ParticleSortingTool::doSortConst( ConstDataVector<CONTAINERTYPE>* cont ) const +{ + if ( !cont ) { + ATH_MSG_ERROR("No ConstDataVector to be sorted"); + return StatusCode::FAILURE; + } + // Actually do the sorting, using a C++11 lambda function construct + // to be able to use the member function here + if ( abs(m_sortID) == 1 ) { + cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) { + return this->comparePt(a,b); + } ); + } + else if ( abs(m_sortID) == 2 ) { + cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) { + return this->compareEta(a,b); + } ); + } + else if ( abs(m_sortID) == 3 ) { + cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) { + return this->comparePhi(a,b); + } ); + } + else if ( abs(m_sortID) == 4 ) { + cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) { + return this->compareMass(a,b); + } ); + } + else if ( abs(m_sortID) == 5 ) { + cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) { + return this->compareEnergy(a,b); + } ); + } + else if ( abs(m_sortID) == 6 ) { + cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) { + return this->compareRapidity(a,b); + } ); + } + else if ( abs(m_sortID) == 7 ) { + cont->sort( [this](const xAOD::IParticle* a, const xAOD::IParticle* b) { + return this->compareAuxData(a,b); + } ); + } + + return StatusCode::SUCCESS; +} + + + #endif //> !EVENTUTILS_PARTICLESORTINGTOOL_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/TriggerSelectionAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/TriggerSelectionAlg.cxx new file mode 100644 index 00000000000..e5ad7aca704 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/TriggerSelectionAlg.cxx @@ -0,0 +1,130 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// includes +#include "TriggerSelectionAlg.h" + +// Tool includes +#include "TrigDecisionTool/TrigDecisionTool.h" +#include "xAODEventInfo/EventInfo.h" + + +TriggerSelectionAlg::TriggerSelectionAlg( const std::string& name, ISvcLocator* pSvcLocator ): + AthFilterAlgorithm( name, pSvcLocator ), + m_trigDecisionTool("Trig::TrigDecisionTool/TrigDecisionTool"), + m_triggerList(), + m_decoEvtInfo(true), + m_evtInfoName("EventInfo"), + m_varPrefix("pass_"), + m_storePrescaleInfo(false), + m_varNameList() +{ + declareProperty("TrigDecisionTool", m_trigDecisionTool, "The TrigDecisionTool" ); + declareProperty("TriggerList", m_triggerList, "The list of triggers to cut on" ); + declareProperty("DecorateEventInfo", m_decoEvtInfo, + "Decide if we also want to decorate the xAOD::EventInfo object with the pass/fail information" ); + declareProperty("EventInfoName", m_evtInfoName, "Name of the xAOD::EventInfo object that we want to decorate" ); + declareProperty("VarNamePrefix", m_varPrefix, "Prefix used for the decoration variables" ); + declareProperty("StorePrescaleInfo", m_storePrescaleInfo, + "Decide if we also want to decorate the xAOD::EventInfo object with the full-chain prescale information" ); +} + + +TriggerSelectionAlg::~TriggerSelectionAlg() {} + + +StatusCode TriggerSelectionAlg::initialize() +{ + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + + // Print the configuration to the log file + ATH_MSG_DEBUG( "Using: " << m_trigDecisionTool ); + ATH_MSG_DEBUG( "Using: " << m_triggerList ); + ATH_MSG_DEBUG( "Using: " << m_decoEvtInfo ); + ATH_MSG_DEBUG( "Using: " << m_evtInfoName ); + ATH_MSG_DEBUG( "Using: " << m_varPrefix ); + ATH_MSG_DEBUG( "Using: " << m_storePrescaleInfo ); + + // Retrieve the TrigDecisionTool + ATH_CHECK(m_trigDecisionTool.retrieve()); + + // Create the list of decoration variables + for ( const std::string& trigName : m_triggerList.value() ){ + m_varNameList.push_back( m_varPrefix.value() + trigName ); + } + + return StatusCode::SUCCESS; +} + + +StatusCode TriggerSelectionAlg::finalize() +{ + ATH_MSG_DEBUG("Finalizing " << name() << "..."); + + // Release all tools + ATH_CHECK( m_trigDecisionTool.release() ); + + return StatusCode::SUCCESS; +} + + +StatusCode TriggerSelectionAlg::execute() +{ + ATH_MSG_DEBUG("Executing " << name() << "..."); + + // Get the xAOD::EventInfo object, if requested + const xAOD::EventInfo* evtInfo = nullptr; + if ( m_decoEvtInfo.value() ){ + ATH_CHECK( evtStore()->retrieve( evtInfo, m_evtInfoName.value() ) ); + } + + // Create a results Vector + std::vector<bool> trigResultsVec( m_triggerList.value().size(), false ); + std::vector<float> trigPrescalesVec( m_triggerList.value().size(), 0. ); + + //Check if event passes trigger selection + bool eventPasses = false; + if( !(m_triggerList.value().empty()) ) { + for( std::size_t i=0; i<m_triggerList.value().size(); ++i ) { + if( m_trigDecisionTool->isPassed(m_triggerList.value().at(i)) ) { + trigResultsVec[i] = true; + eventPasses = true; + ATH_MSG_VERBOSE("Name of passed trigger: " << m_triggerList.value().at(i)); + if ( !(m_decoEvtInfo.value()) ){ + break; // Found a trigger which we passed, nothing more to do here + } + } + //We sometimes want to keep track of the chain prescale + if (m_storePrescaleInfo) { + trigPrescalesVec[i] = m_trigDecisionTool->getPrescale(m_triggerList.value().at(i)); + ATH_MSG_VERBOSE("Retrieved prescale of " << trigPrescalesVec[i] << " for trigger: " << m_triggerList.value().at(i)); + } + } + } + + // Decorate the EventInfo, if requested + if ( m_decoEvtInfo.value() ){ + const size_t decoSize = trigResultsVec.size(); + if ( decoSize != m_varNameList.size() ){ + ATH_MSG_FATAL("Different number of trigger results and variable names"); + return StatusCode::FAILURE; + } + // We also want to decorate the xAOD::EventInfo object with the results + for( std::size_t i=0; i<decoSize; ++i ) { + SG::AuxElement::Decorator<char> decoPassTrig(m_varNameList[i]); + decoPassTrig(*evtInfo) = static_cast<char>(trigResultsVec[i]); + //We sometimes want to keep track of the chain prescale + if (m_storePrescaleInfo) { + SG::AuxElement::Decorator<float> decoPrescaleTrig("prescale_"+m_triggerList.value().at(i)); + decoPrescaleTrig(*evtInfo) = static_cast<float>(trigPrescalesVec[i]); + } + } + } + + // Say if this event should be accepted or not + this->setFilterPassed( eventPasses ); + ATH_MSG_DEBUG("Event passes trigger selection: " << eventPasses ); + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/TriggerSelectionAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/TriggerSelectionAlg.h new file mode 100644 index 00000000000..7154df7e760 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/TriggerSelectionAlg.h @@ -0,0 +1,85 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef EVENTUTILS_TRIGGERSELECTIONALG_H +#define EVENTUTILS_TRIGGERSELECTIONALG_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "AthenaBaseComps/AthFilterAlgorithm.h" +#include "GaudiKernel/ToolHandle.h" + +// EDM includes +#include "AthContainers/AuxElement.h" + +// Forward declarations +namespace Trig{ + class TrigDecisionTool; +} + + +class TriggerSelectionAlg + : public ::AthFilterAlgorithm +{ + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + /// Constructor with parameters: + TriggerSelectionAlg( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~TriggerSelectionAlg(); + + /// Athena algorithm's initalize hook + virtual StatusCode initialize(); + + /// Athena algorithm's execute hook + virtual StatusCode execute(); + + /// Athena algorithm's finalize hook + virtual StatusCode finalize(); + + + private: + + /// @name The properties that can be defined via the python job options + /// @{ + + /// The ToolHandle for the TrigDecisionTool + ToolHandle<Trig::TrigDecisionTool> m_trigDecisionTool; + + /// The list of triggers to cut on + StringArrayProperty m_triggerList; + + /// Decide if we also want to decorate the xAOD::EventInfo object with the pass/fail information + BooleanProperty m_decoEvtInfo; + + /// Name of the xAOD::EventInfo object that we want to decorate + StringProperty m_evtInfoName; + + /// Prefix used for the decoration variables + StringProperty m_varPrefix; + + /// Decide if we also want to decorate the xAOD::EventInfo object with the (full-chain) prescale information + BooleanProperty m_storePrescaleInfo; + + /// @} + + /// @name Other private members + /// @{ + + /// The list of all variables names + std::vector<std::string> m_varNameList; + + /// @} + +}; + + + +#endif //> !EVENTUTILS_TRIGGERSELECTIONALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_entries.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_entries.cxx index aef3acf2942..9a2df65720a 100644 --- a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_entries.cxx +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_entries.cxx @@ -11,7 +11,9 @@ #include "../ParticleCombinerTool.h" #include "../ParticleCombinerAlg.h" #include "../EventQualityFilterAlg.h" -//#include "../SkimDecisionRunPeriodAwareFilterAlg.h" +#include "../ParticleRemoverAlg.h" +#include "../TriggerSelectionAlg.h" +#include "../EventDecisionAlg.h" DECLARE_TOOL_FACTORY( ParticleSortingTool ) DECLARE_ALGORITHM_FACTORY( ParticleSortingAlg ) @@ -24,20 +26,6 @@ DECLARE_ALGORITHM_FACTORY( ParticleSelectionAlg ) DECLARE_TOOL_FACTORY( ParticleCombinerTool ) DECLARE_ALGORITHM_FACTORY( ParticleCombinerAlg ) DECLARE_ALGORITHM_FACTORY( EventQualityFilterAlg ) -//DECLARE_ALGORITHM_FACTORY( SkimDecisionRunPeriodAwareFilterAlg ) - -DECLARE_FACTORY_ENTRIES( EventUtils ) -{ - DECLARE_TOOL( ParticleSortingTool ); - DECLARE_ALGORITHM( ParticleSortingAlg ); - DECLARE_TOOL( AddVarTool ); - DECLARE_ALGORITHM( AddVarAlg ); - DECLARE_TOOL( CutTool ); - DECLARE_ALGORITHM( CutAlg ); - DECLARE_TOOL( ParticleSelectionTool ); - DECLARE_ALGORITHM( ParticleSelectionAlg ); - DECLARE_TOOL( ParticleCombinerTool ); - DECLARE_ALGORITHM( ParticleCombinerAlg ); - DECLARE_ALGORITHM( EventQualityFilterAlg ); - //DECLARE_ALGORITHM( SkimDecisionRunPeriodAwareFilterAlg ); -} +DECLARE_ALGORITHM_FACTORY( ParticleRemoverAlg ) +DECLARE_ALGORITHM_FACTORY( TriggerSelectionAlg ) +DECLARE_ALGORITHM_FACTORY( EventDecisionAlg ) -- GitLab