diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/cmt/requirements b/PhysicsAnalysis/AnalysisCommon/EventUtils/cmt/requirements new file mode 100644 index 0000000000000000000000000000000000000000..b7499369f981783ebe2d4c603fd74aae91a49228 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/cmt/requirements @@ -0,0 +1,48 @@ +## automatically generated CMT requirements file +package EventUtils +author kkoeneke + +public +## for athena policies: this has to be the first use statement +use AtlasPolicy AtlasPolicy-* + +private +use AnalysisUtils AnalysisUtils-* PhysicsAnalysis/AnalysisCommon +use AthContainers AthContainers-* Control +use AthLinks AthLinks-* Control +use AthenaBaseComps AthenaBaseComps-* Control +use AtlasBoost AtlasBoost-* External +use AtlasROOT AtlasROOT-* External +use DerivationFrameworkInterfaces DerivationFrameworkInterfaces-* PhysicsAnalysis/DerivationFramework +use EventBookkeeperMetaData EventBookkeeperMetaData-* Event +use EventInfo EventInfo-* Event +use ExpressionEvaluation ExpressionEvaluation-* PhysicsAnalysis/CommonTools +use GaudiInterface GaudiInterface-* External +use TrigDecisionTool TrigDecisionTool-* Trigger/TrigAnalysis +use xAODBTagging xAODBTagging-* Event/xAOD +use xAODBase xAODBase-* Event/xAOD +use xAODCaloEvent xAODCaloEvent-* Event/xAOD +use xAODEgamma xAODEgamma-* Event/xAOD +use xAODEventInfo xAODEventInfo-* Event/xAOD +use xAODJet xAODJet-* Event/xAOD +use xAODMissingET xAODMissingET-* Event/xAOD +use xAODMuon xAODMuon-* Event/xAOD +use xAODPFlow xAODPFlow-* Event/xAOD +use xAODParticleEvent xAODParticleEvent-* Event/xAOD +use xAODTau xAODTau-* Event/xAOD +use xAODTracking xAODTracking-* Event/xAOD +use xAODTruth xAODTruth-* Event/xAOD +end_private + + +branches src src/components python share + +private +## default is to make component library +library EventUtils *.cxx components/*.cxx + +apply_pattern component_library +apply_pattern declare_joboptions files="*.py" +apply_pattern declare_python_modules files="*.py" + +end_private diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..3372d60028f6719bba730fa5312efa4d83cbbdae --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.cxx @@ -0,0 +1,159 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AddVarAlg.cxx +// Implementation file for class AddVarAlg +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// + +// EventUtils includes +#include "AddVarAlg.h" + +// STL includes + +// FrameWork includes +#include "GaudiKernel/Property.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "DerivationFrameworkInterfaces/IAugmentationTool.h" + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +AddVarAlg::AddVarAlg( const std::string& name, + ISvcLocator* pSvcLocator ) : + ::AthFilterAlgorithm( name, pSvcLocator ), + m_jos("JobOptionsSvc", name), + m_tool("AddVarTool/AddVarTool", this), + m_setInCollKey(false), + m_setVarName(false), + m_setVarType(false), + m_setSelection(false), + m_nEventsProcessed(0) +{ + declareProperty("JobOptionsSvc", m_jos, "The JobOptionService instance."); + + declareProperty("AddVarTool", m_tool, "The private AddVarTool" ); + + declareProperty("AddVarTo", m_inCollKey="", + "Name of the container or object where the new variable will be added to" ); + m_inCollKey.declareUpdateHandler( &AddVarAlg::setupInputContainer, this ); + + declareProperty("VarName", m_varName="", "The name of the new variable" ); + m_varName.declareUpdateHandler( &AddVarAlg::setupVarName, this ); + + declareProperty("VarType", m_varType="float", + "The type of the new variable (allowed values are: 'bool', 'int', 'float')" ); + m_varType.declareUpdateHandler( &AddVarAlg::setupVarType, this ); + + declareProperty("Selection", m_selection="", + "The selection string that defines which xAOD::IParticles to select from the container" ); + m_selection.declareUpdateHandler( &AddVarAlg::setupSelection, this ); +} + + + +// Destructor +/////////////// +AddVarAlg::~AddVarAlg() +{} + + + +// Athena Algorithm's Hooks +//////////////////////////// +StatusCode AddVarAlg::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_varName ); + ATH_MSG_DEBUG ( " using = " << m_varType ); + ATH_MSG_DEBUG ( " using = " << m_selection ); + + + // 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) ); + } + if (m_setVarName) { + ATH_MSG_DEBUG( "Setting property" << m_varName + << " of private tool with name: '" << fullToolName << "'" ); + ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_varName) ); + } + if (m_setVarType) { + ATH_MSG_DEBUG( "Setting property" << m_varType + << " of private tool with name: '" << fullToolName << "'" ); + ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_varType) ); + } + 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() ); + + ATH_MSG_DEBUG ( "==> done with initialize " << name() << "..." ); + + return StatusCode::SUCCESS; +} + + + +StatusCode AddVarAlg::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + + // Release all tools and services + ATH_CHECK( m_jos.release() ); + ATH_CHECK( m_tool.release() ); + + return StatusCode::SUCCESS; +} + + + +StatusCode AddVarAlg::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 + ATH_CHECK( m_tool->addBranches() ); + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..1bc1ab742ca8756b4efeaec113134d893d32ba5c --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarAlg.h @@ -0,0 +1,154 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AddVarAlg.h +// Header file for class AddVarAlg +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef EVENTUTILS_ADDVARALG_H +#define EVENTUTILS_ADDVARALG_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaBaseComps/AthFilterAlgorithm.h" + + +// forward declarations +class IJobOptionsSvc; +namespace DerivationFramework { + class IAugmentationTool; +} + + + +class AddVarAlg + : public ::AthFilterAlgorithm +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + // Copy constructor: + + /// Constructor with parameters: + AddVarAlg( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~AddVarAlg(); + + /// 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: + // The update handlers + + /// This internal method will realize if a user sets the 'AddVarTo' property + void setupInputContainer( Property& /*prop*/ ); + + /// This internal method will realize if a user sets the 'VarName' property + void setupVarName( Property& /*prop*/ ); + + /// This internal method will realize if a user sets the 'VarType' property + void setupVarType( Property& /*prop*/ ); + + /// This internal method will realize if a user sets the 'Selection' property + void setupSelection( 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 ToolHandle to the augmentation tool + ToolHandle<DerivationFramework::IAugmentationTool> m_tool; + + + /// Input container name + StringProperty m_inCollKey; + + /// This boolean is true if the user sets the 'InputContainer' property + bool m_setInCollKey; + + + /// The name of the new variable + StringProperty m_varName; + + /// This boolean is true if the user sets the 'OutputContainer' property + bool m_setVarName; + + + /// The type of the new variable (allowed values are: 'bool', 'int', 'float') + StringProperty m_varType; + + /// This boolean is true if the user sets the 'OutputLinkContainer' property + bool m_setVarType; + + + /// The string that describes how the new variable should be calculated + StringProperty m_selection; + + /// This boolean is true if the user sets the 'Cut' property + bool m_setSelection; + + + + /// Internal event counter + unsigned long m_nEventsProcessed; + + +}; + +// I/O operators +////////////////////// + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +/// This internal method will realize if a user sets the 'AddVarTo' property +inline void AddVarAlg::setupInputContainer( Property& /*prop*/ ) { + m_setInCollKey = true; + return; +} + +/// This internal method will realize if a user sets the 'VarName' property +inline void AddVarAlg::setupVarName( Property& /*prop*/ ) { + m_setVarName = true; + return; +} + +/// This internal method will realize if a user sets the 'VarType' property +inline void AddVarAlg::setupVarType( Property& /*prop*/ ) { + m_setVarType = true; + return; +} + +/// This internal method will realize if a user sets the 'Selection' property +inline void AddVarAlg::setupSelection( Property& /*prop*/ ) { + m_setSelection = true; + return; +} + + +#endif //> !EVENTUTILS_ADDVARALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarTool.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..adc92c2eabfd3c51c42213829f8fcc6c4017cd32 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarTool.cxx @@ -0,0 +1,288 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AddVarTool.cxx +// Implementation file for class AddVarTool +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// + +// EventUtils includes +#include "AddVarTool.h" + +// STL includes +#include <vector> +#include <string> + +// FrameWork includes +#include "ExpressionEvaluation/ExpressionParser.h" +#include "TrigDecisionTool/TrigDecisionTool.h" +#include "ExpressionEvaluation/TriggerDecisionProxyLoader.h" +#include "ExpressionEvaluation/SGxAODProxyLoader.h" +#include "ExpressionEvaluation/SGNTUPProxyLoader.h" +#include "ExpressionEvaluation/MultipleProxyLoader.h" +#include "ExpressionEvaluation/StackElement.h" + +// EDM includes +#include "AthContainers/AuxElement.h" +#include "xAODEventInfo/EventInfo.h" +#include "xAODBase/IParticleContainer.h" +#include "xAODMissingET/MissingETContainer.h" +#include "xAODTracking/VertexContainer.h" +#include "xAODTruth/TruthEventContainer.h" +#include "xAODTruth/TruthVertexContainer.h" +#include "xAODBTagging/BTaggingContainer.h" +// #include "xAODBTagging/BTagVertexContainer.h" + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +AddVarTool::AddVarTool( const std::string& type, + const std::string& name, + const IInterface* parent ) : + ::AthAlgTool ( type, name, parent ), + m_trigDecisionTool("Trig::TrigDecisionTool/TrigDecisionTool"), + m_parser(0), + m_inCollKey(""), + m_selection(""), + m_varTypeIndex(-1), + m_inContIdx(-1), + m_nEventsProcessed(0) +{ + declareInterface< DerivationFramework::IAugmentationTool >(this); + + declareProperty("AddVarTo", m_inCollKey="", + "Name of the container or object where the new variable will be added to" ); + + declareProperty("VarName", m_varName="", "The name of the new variable" ); + declareProperty("VarType", m_varType="float", + "The type of the new variable (allowed values are: 'bool', 'int', 'float')" ); + + declareProperty("Selection", m_selection="", + "The selection string that defines which xAOD::IParticles to select from the container" ); +} + +// Destructor +/////////////// +AddVarTool::~AddVarTool() +{} + + + +// Athena algtool's Hooks +//////////////////////////// +StatusCode AddVarTool::initialize() +{ + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + + // Print out the used configuration + ATH_MSG_DEBUG ( " using = " << m_inCollKey ); + ATH_MSG_DEBUG ( " using = " << m_varName ); + ATH_MSG_DEBUG ( " using = " << m_varType ); + ATH_MSG_DEBUG ( " using = " << m_selection ); + + // Try to decode the variable type + if ( m_varType.value() == "int" ) { + m_varTypeIndex = 1; + } + else if ( m_varType.value() == "bool" ) { + m_varTypeIndex = 2; + } + else if ( m_varType.value() == "float" ) { + m_varTypeIndex = 11; + } + else { + ATH_MSG_ERROR("Didn't recognize the variable type. " + << "Allowed values for the property 'VarType' are: " + << "'bool', 'int', 'float'"); + return StatusCode::FAILURE; + } + + // initialize proxy loaders for expression parsing + ExpressionParsing::MultipleProxyLoader *proxyLoaders = new ExpressionParsing::MultipleProxyLoader(); + proxyLoaders->push_back(new ExpressionParsing::TriggerDecisionProxyLoader(m_trigDecisionTool)); + 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_selection.value() ); + + return StatusCode::SUCCESS; +} + + + + +StatusCode AddVarTool::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + + if (m_parser) { + delete m_parser; + m_parser = 0; + } + + return StatusCode::SUCCESS; +} + + + + +#define EVALUATE_CONTAINERTYPE( CONTAINERTYPE ) \ +else if ( evtStore()->contains< CONTAINERTYPE >( m_inCollKey.value() ) ) { \ + const CONTAINERTYPE* inContainer(0); \ + ATH_CHECK( evtStore()->retrieve( inContainer, m_inCollKey.value() ) ); \ + ATH_MSG_DEBUG ( "Input collection = '" << m_inCollKey.value() \ + << "' retrieved from StoreGate which has " << inContainer->size() << " entries." ); \ + if ( !inContainer ) { \ + ATH_MSG_ERROR( "We don't have a valid pointer to "#CONTAINERTYPE"." ); \ + return StatusCode::FAILURE; \ + } \ + ExpressionParsing::StackElement selectionResult = m_parser->evaluate(); \ + if ( !(selectionResult.isVector()) ) { \ + ATH_MSG_ERROR ("Some unexpected format of the expression parser result. Should be vector-type."); \ + return StatusCode::FAILURE; \ + } \ + if ( m_varTypeIndex == 1 ) { \ + const std::vector<int>& resultVec( selectionResult.vectorValue<int>() ); \ + if ( resultVec.size() != inContainer->size() ) { \ + ATH_MSG_ERROR("The result vector doesn't have the same size as the container to decorate!"); \ + return StatusCode::FAILURE; \ + } \ + SG::AuxElement::Decorator<int> intDeco (m_varName.value()); \ + for ( std::size_t i=0; i<resultVec.size(); ++i ) { \ + ATH_MSG_VERBOSE("Got a container integer result: " << resultVec.at(i) ); \ + const auto* part = inContainer->at(i); \ + intDeco(*part) = resultVec.at(i); \ + } \ + } \ + else if ( m_varTypeIndex == 2 ) { \ + const std::vector<int>& resultVec( selectionResult.vectorValue<int>() ); \ + if ( resultVec.size() != inContainer->size() ) { \ + ATH_MSG_ERROR("The result vector doesn't have the same size as the container to decorate!"); \ + return StatusCode::FAILURE; \ + } \ + SG::AuxElement::Decorator<bool> boolDeco (m_varName.value()); \ + for ( std::size_t i=0; i<resultVec.size(); ++i ) { \ + ATH_MSG_VERBOSE("Got a container boolean result: " << static_cast<bool>(resultVec.at(i)) ); \ + const auto* part = inContainer->at(i); \ + boolDeco(*part) = static_cast<bool>(resultVec.at(i)); \ + } \ + } \ + else if ( m_varTypeIndex == 11 ) { \ + const std::vector<double>& resultVec( selectionResult.vectorValue<double>() ); \ + if ( resultVec.size() != inContainer->size() ) { \ + ATH_MSG_ERROR("The result vector doesn't have the same size as the container to decorate!"); \ + return StatusCode::FAILURE; \ + } \ + SG::AuxElement::Decorator<float> floatDeco (m_varName.value()); \ + for ( std::size_t i=0; i<resultVec.size(); ++i ) { \ + ATH_MSG_VERBOSE("Got a container float result: " << static_cast<float>(resultVec.at(i)) ); \ + const auto* part = inContainer->at(i); \ + floatDeco(*part) = static_cast<float>(resultVec.at(i)); \ + } \ + } \ +} + + + +StatusCode AddVarTool::addBranches() const +{ + // Increase the event counter + ++m_nEventsProcessed; + + // Simple status message at the beginning of each event execute, + ATH_MSG_DEBUG ( "==> addBranches " << name() << " on " << m_nEventsProcessed << ". event..." ); + + + //----------------------------------------- + // Get the input container where we want to add the variable to + //----------------------------------------- + const SG::AuxElement* inAuxElement(0); + + // if ( evtStore()->contains< SG::AuxElement >( m_inCollKey.value() ) ) { + // // This file holds an SG::AuxElement + // ATH_CHECK( evtStore()->retrieve( inAuxElement, m_inCollKey.value() ) ); + // ATH_MSG_DEBUG ( "Input SG::AuxElement = '" << m_inCollKey.value() << "' retrieved from StoreGate" ); + // } + if ( evtStore()->contains< xAOD::EventInfo >( m_inCollKey.value() ) ) { + // This file holds an xAOD::EventInfo + const xAOD::EventInfo* eventInfo; + ATH_CHECK( evtStore()->retrieve( eventInfo, m_inCollKey.value() ) ); + ATH_MSG_DEBUG ( "Input xAOD::EventInfo = '" << m_inCollKey.value() << "' retrieved from StoreGate" ); + inAuxElement = dynamic_cast<const xAOD::EventInfo*>(eventInfo); + ATH_CHECK( this->evaluateAuxElement(inAuxElement) ); + } + + // Use a pre-processor macro do generate the code for all container types, + // i.e., DataVector< SomeObjectInheritingFrom : public SG::AuxElement > + EVALUATE_CONTAINERTYPE(xAOD::IParticleContainer) + EVALUATE_CONTAINERTYPE(xAOD::VertexContainer) + //EVALUATE_CONTAINERTYPE(xAOD::BTagVertexContainer) + EVALUATE_CONTAINERTYPE(xAOD::BTaggingContainer) + //EVALUATE_CONTAINERTYPE(xAOD::MissingETComponentMap) + EVALUATE_CONTAINERTYPE(xAOD::MissingETContainer) + EVALUATE_CONTAINERTYPE(xAOD::TruthEventContainer) + EVALUATE_CONTAINERTYPE(xAOD::TruthVertexContainer) + + else { + if ( m_nEventsProcessed <= 10 ) { + ATH_MSG_WARNING ( "Input collection = '" << m_inCollKey.value() + << "' could not be retrieved from StoreGate! " + << " This message will only be repeated 10 times..." ); + } + else { + ATH_MSG_DEBUG ( "Input collection = '" << m_inCollKey.value() + << "' could not be retrieved from StoreGate! " ); + } + return StatusCode::SUCCESS; + } // End: if/elif/else on input container type + + + return StatusCode::SUCCESS; +} + + + + +StatusCode AddVarTool::evaluateAuxElement( const SG::AuxElement* inAuxElement ) const +{ + if ( !inAuxElement ) { + ATH_MSG_ERROR( "We don't have a valid pointer to SG::AuxElement" ); + return StatusCode::FAILURE; + } + + // Evaluate the string expression for this event + ExpressionParsing::StackElement selectionResult = m_parser->evaluate(); + if ( !(selectionResult.isScalar()) ) { + ATH_MSG_ERROR ("Some unexpected format of the expression parser result. Should be scalar-type."); + return StatusCode::FAILURE; + } + + // Now, get the result and record it to the object + if ( m_varTypeIndex == 1 ) { // This is an integer + int result = selectionResult.scalarValue<int>(); + ATH_MSG_VERBOSE("Got an integer result: " << result ); + inAuxElement->auxdecor<int> (m_varName.value()) = result; + } + else if ( m_varTypeIndex == 2 ) { // This is a boolean + bool result = selectionResult.scalarValue<bool>(); + ATH_MSG_VERBOSE("Got a boolean result: " << result ); + inAuxElement->auxdecor<bool> (m_varName.value()) = result; + } + else if ( m_varTypeIndex == 11 ) { // This is a float + float result = selectionResult.scalarValue<float>(); + ATH_MSG_VERBOSE("Got a float result: " << result ); + inAuxElement->auxdecor<float> (m_varName.value()) = result; + } + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarTool.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarTool.h new file mode 100644 index 0000000000000000000000000000000000000000..f8a9cedb87ec14608c9487c25b1a062fb643d834 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/AddVarTool.h @@ -0,0 +1,114 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// AddVarTool.h +// Header file for class AddVarTool +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef EVENTUTILS_ADDVARTOOL_H +#define EVENTUTILS_ADDVARTOOL_H 1 + +// STL includes +#include <vector> +#include <string> + +// FrameWork includes +#include "AthenaBaseComps/AthAlgTool.h" +#include "DerivationFrameworkInterfaces/IAugmentationTool.h" +#include "TrigDecisionTool/TrigDecisionTool.h" + +// Forward declarations +namespace ExpressionParsing { + class ExpressionParser; +} +namespace SG { + class AuxElement; +} + + + + +class AddVarTool + : virtual public ::DerivationFramework::IAugmentationTool, + public ::AthAlgTool +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// +public: + + // Copy constructor: + + /// Constructor with parameters: + AddVarTool( const std::string& type, + const std::string& name, + const IInterface* parent ); + + /// Destructor: + virtual ~AddVarTool(); + + /// Athena algtool's initialize + virtual StatusCode initialize(); + + /// Athena algtool's finalize + virtual StatusCode finalize(); + + + /// Implement the method from the ISkimmingTool interface + virtual StatusCode addBranches() const final override; + + + +// Private methods +private: + /// Helper methods + StatusCode evaluateAuxElement( const SG::AuxElement* inAuxElement ) const; + + + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// +private: + /// The trigger decision tool + ToolHandle<Trig::TrigDecisionTool> m_trigDecisionTool; + + /// The expression parser + ExpressionParsing::ExpressionParser *m_parser; + + + /// Input container name + StringProperty m_inCollKey; + + /// The name of the new variable + StringProperty m_varName; + + /// The type of the new variable (allowed values are: 'bool', 'int', 'float') + StringProperty m_varType; + + /// The string that describes how the new variable should be calculated + StringProperty m_selection; + + + /// Index to specify the variable type + mutable int m_varTypeIndex; + + /// An internal integer to keep track of the type of the input container + mutable int m_inContIdx; + + /// Internal event counter + mutable unsigned long m_nEventsProcessed; + + +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + + +#endif //> !EVENTUTILS_ADDVARTOOL_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..68873f19dae6d4a09b113586321647cab292a0c4 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.cxx @@ -0,0 +1,128 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// CutAlg.cxx +// Implementation file for class CutAlg +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// + +// EventUtils includes +#include "CutAlg.h" + +// STL includes + +// FrameWork includes +#include "GaudiKernel/Property.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "DerivationFrameworkInterfaces/ISkimmingTool.h" + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +CutAlg::CutAlg( const std::string& name, + ISvcLocator* pSvcLocator ) : + ::AthFilterAlgorithm( name, pSvcLocator ), + m_jos("JobOptionsSvc", name), + m_skimTool("CutTool/CutTool", this), + 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 ); +} + + + +// Destructor +/////////////// +CutAlg::~CutAlg() +{} + + + +// Athena Algorithm's Hooks +//////////////////////////// +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 ); + + + // 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_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) ); + } + ATH_MSG_DEBUG( "Done setting properties of the tool"); + + // Get the skimming tool + ATH_CHECK( m_skimTool.retrieve() ); + + ATH_MSG_DEBUG ( "==> done with initialize " << name() << "..." ); + + return StatusCode::SUCCESS; +} + + + +StatusCode CutAlg::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + + // Release all tools and services + ATH_CHECK( m_jos.release() ); + ATH_CHECK( m_skimTool.release() ); + + return StatusCode::SUCCESS; +} + + + +StatusCode CutAlg::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 skimming tool and set its result + bool eventPasses = m_skimTool->eventPassesFilter(); + this->setFilterPassed( eventPasses ); + ATH_MSG_DEBUG("Event passes/fails: " << eventPasses ); + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..4293391ad908ad7c6304e9cfdf70de2ec544a84a --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutAlg.h @@ -0,0 +1,154 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// CutAlg.h +// Header file for class CutAlg +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef EVENTUTILS_CUTALG_H +#define EVENTUTILS_CUTALG_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaBaseComps/AthFilterAlgorithm.h" + + +// forward declarations +class IJobOptionsSvc; +namespace DerivationFramework { + class ISkimmingTool; +} + + + +class CutAlg + : public ::AthFilterAlgorithm +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + // Copy constructor: + + /// Constructor with parameters: + CutAlg( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~CutAlg(); + + /// 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: + // 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 'OutputLinkContainer' property + void setupOutputLinkContainer( Property& /*prop*/ ); + + /// 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 ToolHandle to the SkimmingTool + ToolHandle<DerivationFramework::ISkimmingTool> m_skimTool; + + /// Input container name + StringProperty m_inCollKey; + + /// This boolean is true if the user sets the 'InputContainer' property + bool m_setInCollKey; + + + /// 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; + + + /// 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 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 'InputContainer' property +inline void CutAlg::setupInputContainer( Property& /*prop*/ ) { + m_setInCollKey = true; + return; +} + +/// This internal method will realize if a user sets the 'OutputContainer' property +inline void CutAlg::setupOutputContainer( Property& /*prop*/ ) { + m_setOutCollKey = true; + return; +} + +/// This internal method will realize if a user sets the 'OutputLinkContainer' property +inline void CutAlg::setupOutputLinkContainer( Property& /*prop*/ ) { + m_setOutLinkCollKey = true; + return; +} + +/// 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 new file mode 100644 index 0000000000000000000000000000000000000000..808fc825ffac9702f7c73e9c68387f07119d4d1f --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.cxx @@ -0,0 +1,101 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// CutTool.cxx +// Implementation file for class CutTool +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// + +// EventUtils includes +#include "CutTool.h" + +// STL includes +#include <vector> +#include <string> + +// FrameWork includes +#include "ExpressionEvaluation/ExpressionParser.h" +#include "TrigDecisionTool/TrigDecisionTool.h" +#include "ExpressionEvaluation/TriggerDecisionProxyLoader.h" +#include "ExpressionEvaluation/SGxAODProxyLoader.h" +#include "ExpressionEvaluation/SGNTUPProxyLoader.h" +#include "ExpressionEvaluation/MultipleProxyLoader.h" +#include "ExpressionEvaluation/StackElement.h" + + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +CutTool::CutTool( const std::string& type, + const std::string& name, + const IInterface* parent ) : + ::AthAlgTool ( type, name, parent ), + m_trigDecisionTool("Trig::TrigDecisionTool/TrigDecisionTool"), + m_parser(0), + m_cut(""), + m_nEventsProcessed(0) +{ + declareInterface< DerivationFramework::ISkimmingTool >(this); + + declareProperty("Cut", m_cut="", "The name of the output container" ); +} + +// Destructor +/////////////// +CutTool::~CutTool() +{} + + + +// Athena algtool's Hooks +//////////////////////////// +StatusCode CutTool::initialize() +{ + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + + // initialize proxy loaders for expression parsing + ExpressionParsing::MultipleProxyLoader *proxyLoaders = new ExpressionParsing::MultipleProxyLoader(); + proxyLoaders->push_back(new ExpressionParsing::TriggerDecisionProxyLoader(m_trigDecisionTool)); + 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() ); + + return StatusCode::SUCCESS; +} + + + +StatusCode CutTool::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + + if (m_parser) { + delete m_parser; + m_parser = 0; + } + + return StatusCode::SUCCESS; +} + + + +// Implement the method from the ISkimmingTool interface +bool CutTool::eventPassesFilter() const +{ + ATH_MSG_DEBUG ( "==> eventPassesFilter() " << name() ); + ATH_MSG_VERBOSE ( "Dumping event store: " << evtStore()->dump() ); + + return m_parser->evaluateAsBool(); + return true; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.h new file mode 100644 index 0000000000000000000000000000000000000000..22fad231637a64bda38008065ca7922d164b8840 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/CutTool.h @@ -0,0 +1,89 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// CutTool.h +// Header file for class CutTool +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef EVENTUTILS_CUTTOOL_H +#define EVENTUTILS_CUTTOOL_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "AthenaBaseComps/AthAlgTool.h" +#include "DerivationFrameworkInterfaces/ISkimmingTool.h" +#include "TrigDecisionTool/TrigDecisionTool.h" + + +// Forward declarations +namespace ExpressionParsing { + class ExpressionParser; +} + + + + +class CutTool + : virtual public ::DerivationFramework::ISkimmingTool, + public ::AthAlgTool +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + // Copy constructor: + + /// Constructor with parameters: + CutTool( const std::string& type, + const std::string& name, + const IInterface* parent ); + + /// Destructor: + virtual ~CutTool(); + + /// Athena algtool's initialize + virtual StatusCode initialize(); + + /// Athena algtool's finalize + virtual StatusCode finalize(); + + + /// Implement the method from the ISkimmingTool interface + virtual bool eventPassesFilter() const final override; + + + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + /// The trigger decision tool + ToolHandle<Trig::TrigDecisionTool> m_trigDecisionTool; + + /// The expression parser + ExpressionParsing::ExpressionParser *m_parser; + + + /// The cut string + StringProperty m_cut; + + + /// Internal event counter + mutable unsigned long m_nEventsProcessed; + + +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + + +#endif //> !EVENTUTILS_CUTTOOL_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..87465c1dfc21a9971f4a692733a146da5643adfc --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.cxx @@ -0,0 +1,104 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// EventQualityFilterAlg.cxx +// Implementation file for class EventQualityFilterAlg +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +// Description: Algorithm to filter out events with a bad Event error +/////////////////////////////////////////////////////////////////// + +// SelectionUtils includes +#include "EventQualityFilterAlg.h" + +// STL includes + +// FrameWork includes +#include "GaudiKernel/Property.h" + +// EDM includes +#include "EventInfo/EventInfo.h" +#include "EventInfo/EventType.h" + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +EventQualityFilterAlg::EventQualityFilterAlg( const std::string& name, + ISvcLocator* pSvcLocator ) : + ::AthFilterAlgorithm( name, pSvcLocator ) +{ + // + // 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" ); +} + + + + +// Destructor +/////////////// +EventQualityFilterAlg::~EventQualityFilterAlg() +{} + + + + +// Athena Algorithm's Hooks +//////////////////////////// +StatusCode EventQualityFilterAlg::initialize() +{ + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + return StatusCode::SUCCESS; +} + + + +StatusCode EventQualityFilterAlg::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + return StatusCode::SUCCESS; +} + + + +StatusCode EventQualityFilterAlg::execute() +{ + ATH_MSG_DEBUG ("Executing " << name() << "..."); + + + // Get the EventInfo object + const EventInfo* eventInfo(NULL); + 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; + } + + + // 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; } + + // Set the final decision + setFilterPassed(passEvent); + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..4edb4215435afcb6662b602abd54f2aa529836a2 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/EventQualityFilterAlg.h @@ -0,0 +1,74 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// 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 + +// STL includes +#include <string> + +// FrameWork includes +#include "AthenaBaseComps/AthFilterAlgorithm.h" + + + +class EventQualityFilterAlg + : public ::AthFilterAlgorithm +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + // Copy constructor: + + /// Constructor with parameters: + EventQualityFilterAlg( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~EventQualityFilterAlg(); + + // Athena algorithm's Hooks + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + + bool m_useLArError; + bool m_useTileError; + bool m_useCoreError; + bool m_useTileTripReader; + + +}; + +// I/O operators +////////////////////// + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + + +#endif //> !EVENTUTILS_EVENTQUALITYFILTERALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..272246426b350867b99619c6b712698a8ff5a0a1 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerAlg.cxx @@ -0,0 +1,187 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//============================================================================ +// Name: ParticleCombinerAlg.cxx +// +/** + @class ParticleCombinerAlg + + @author Karsten Koeneke <karsten.koeneke@cernSPAMNOT.ch> + + @date July 2014 + + @brief Combine particles to composite particles + + Class to combine two or more particles from a given list of + input containers. All combinations will be tried and only the + ones passing the used selections will be written to StoreGate. +*/ +//============================================================================= + +// This classes header +#include "ParticleCombinerAlg.h" + +// STL includes +#include <string> +#include <vector> +#include <cfloat> +#include <climits> + +// Framework includes +#include "GaudiKernel/IJobOptionsSvc.h" +#include "DerivationFrameworkInterfaces/IAugmentationTool.h" + + + +//============================================================================= +// Constructor +//============================================================================= +ParticleCombinerAlg::ParticleCombinerAlg(const std::string& name, + ISvcLocator* pSvcLocator) : + AthAlgorithm( name, pSvcLocator ), + m_jos("JobOptionsSvc", name), + m_tool("ParticleCombinerTool/ParticleCombinerTool", this), + m_inCollKeyList(), + m_setInCollKeyList(false), + m_outCollKey(""), + m_setOutCollKey(false), + m_metName(""), + m_setMetName(false), + m_pdgId(0), + m_setPdgId(false), + m_nEventsProcessed(0) +{ + declareProperty("JobOptionsSvc", m_jos, "The JobOptionService instance."); + + declareProperty("ParticleCombinerTool", m_tool, "The private tool that will do the particle combinatorics" ); + + declareProperty("InputContainerList", m_inCollKeyList, "List of input collection keys" ); + m_inCollKeyList.declareUpdateHandler( &ParticleCombinerAlg::setupInputContainerList, this ); + + declareProperty("MissingETObject", m_metName="Final", "The name of the xAOD::MissingET object (default: 'Final'" ); + m_metName.declareUpdateHandler( &ParticleCombinerAlg::setupMissingETObject, this ); + + declareProperty("OutputContainer", m_outCollKey="", "The name of the output container" ); + m_outCollKey.declareUpdateHandler( &ParticleCombinerAlg::setupOutputContainer, this ); + + declareProperty("SetPdgId", m_pdgId=0, "PDG ID of the new output xAOD::CompositeParticle" ); + m_pdgId.declareUpdateHandler( &ParticleCombinerAlg::setupSetPdgId, this ); +} + + + + + + + +//============================================================================= +// Destructor +//============================================================================= +ParticleCombinerAlg::~ParticleCombinerAlg() +{ +} + + + +//============================================================================= +// Athena initialize method +//============================================================================= +StatusCode ParticleCombinerAlg::initialize() +{ + // Print the used configuration + ATH_MSG_DEBUG ( "==> initialize " << name() << "..." ); + + // Print out the used configuration + ATH_MSG_DEBUG ( " using JobOptionsSvc = " << m_jos ); + ATH_MSG_DEBUG ( " using ParticleCombinerTool = " << m_tool ); + ATH_MSG_DEBUG ( " using InputContainerList = " << m_inCollKeyList ); + ATH_MSG_DEBUG ( " using MissingETObjectName = " << m_metName ); + ATH_MSG_DEBUG ( " using OutputContainer = " << m_outCollKey ); + ATH_MSG_DEBUG ( " using SetPdgId = " << m_pdgId ); + + + // Initialize the counters to zero + m_nEventsProcessed = 0 ; + + + // Get the JobOptionService + // We will use this to set the properties of our private 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_setInCollKeyList) { + ATH_MSG_DEBUG( "Setting property" << m_inCollKeyList + << " of private tool with name: '" << fullToolName << "'" ); + ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_inCollKeyList) ); + } + if (m_setMetName) { + ATH_MSG_DEBUG( "Setting property" << m_metName + << " of private tool with name: '" << fullToolName << "'" ); + ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_metName) ); + } + if (m_setOutCollKey) { + ATH_MSG_DEBUG( "Setting property" << m_outCollKey + << " of private tool with name: '" << fullToolName << "'" ); + ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_outCollKey) ); + } + if (m_setPdgId) { + ATH_MSG_DEBUG( "Setting property" << m_pdgId + << " of private tool with name: '" << fullToolName << "'" ); + ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_pdgId) ); + } + ATH_MSG_DEBUG( "Done setting properties of the tool"); + + // Get the tool + ATH_CHECK( m_tool.retrieve() ); + + ATH_MSG_DEBUG ( "==> done with initialize " << name() << "..." ); + return StatusCode::SUCCESS; +} + + + +//============================================================================= +// Athena execute method +//============================================================================= +StatusCode ParticleCombinerAlg::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 to build the particle combinatorics and record the result to StoreGate + ATH_CHECK( m_tool->addBranches() ); + + return StatusCode::SUCCESS; +} + + + + + +//============================================================================= +// Athena finalize method +//============================================================================= +StatusCode ParticleCombinerAlg::finalize() +{ + ATH_MSG_DEBUG ( "FINALIZING AFTER ALL EVENTS ARE PROCESSED. " + << "Saw " << m_nEventsProcessed << " events." ); + + // Release all tools and services + ATH_CHECK( m_jos.release() ); + ATH_CHECK( m_tool.release() ); + + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..6ddea51acb07449f8a4fbdf544eaa5d163d56a65 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerAlg.h @@ -0,0 +1,158 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Dear emacs, this is -*-c++-*- +#ifndef EVENTUTILS_PARTICLECOMBINERALG_H +#define EVENTUTILS_PARTICLECOMBINERALG_H + +//============================================================================ +// Name: ParticleCombinerAlg.h +// +/** + @class ParticleCombinerAlg + + @author Karsten Koeneke <karsten.koeneke@cernSPAMNOT.ch> + + @date July 2014 + + @brief Combine particles to composite particles + + Class to combine two or more particles from a given list of + input containers. All combinations will be tried and only the + ones passing the used selections will be written to StoreGate. +*/ +//============================================================================= + + +// STL includes +#include <string> +#include <vector> + +// Gaudi includes +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" + +// Athena includes +#include "AthenaBaseComps/AthAlgorithm.h" + + +// forward declarations +class IJobOptionsSvc; +namespace DerivationFramework { + class IAugmentationTool; +} + + + +class ParticleCombinerAlg : public AthAlgorithm +{ +public: + + /** Default constructor */ + ParticleCombinerAlg(const std::string& name, ISvcLocator* pSvcLocator); + + /** Default destructor */ + virtual ~ParticleCombinerAlg() ; + + +public: + /** Gaudi Service Interface method implementations - initialize */ + StatusCode initialize() ; + + /** Gaudi Service Interface method implementations - execute */ + StatusCode execute() ; + + /** Gaudi Service Interface method implementations - finalize */ + StatusCode finalize() ; + + +private: + // The update handlers + + /// This internal method will realize if a user sets the 'InputContainerList' property + void setupInputContainerList( Property& /*prop*/ ); + + /// This internal method will realize if a user sets the 'MissingETObject' property + void setupMissingETObject( 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 'SetPdgId' property + void setupSetPdgId( Property& /*prop*/ ); + + + +private: + /// The job options service (will be used to forward this algs properties to + /// the private tool) + ServiceHandle<IJobOptionsSvc> m_jos; + + /// The ToolHandle to the AugmentationTool + ToolHandle<DerivationFramework::IAugmentationTool> m_tool; + + /// List of input collection names + StringArrayProperty m_inCollKeyList; + + /// This boolean is true if the user sets the 'InputContainerList' property + bool m_setInCollKeyList; + + + /// Output collection name (the composite particles) + StringProperty m_outCollKey; + + /// This boolean is true if the user sets the 'OutputContainer' property + bool m_setOutCollKey; + + + /// The name of the missing ET object, e.g., "Final" + StringProperty m_metName; + + /// This boolean is true if the user sets the 'MissingETObject' property + bool m_setMetName; + + + /// The PDG_ID of the CompositeParticle + IntegerProperty m_pdgId; + + /// This boolean is true if the user sets the 'SetPdgId' property + bool m_setPdgId; + + + + /// Internal event counter + unsigned long m_nEventsProcessed; + + +}; // End class ParticleCombinerAlg + + +// Inline methods + +/// This internal method will realize if a user sets the 'InputContainerList' property +inline void ParticleCombinerAlg::setupInputContainerList( Property& /*prop*/ ) { + m_setInCollKeyList = true; + return; +} + +/// This internal method will realize if a user sets the 'MissingETObject' property +inline void ParticleCombinerAlg::setupMissingETObject( Property& /*prop*/ ) { + m_setMetName = true; + return; +} + +/// This internal method will realize if a user sets the 'OutputContainer' property +inline void ParticleCombinerAlg::setupOutputContainer( Property& /*prop*/ ) { + m_setOutCollKey = true; + return; +} + +/// This internal method will realize if a user sets the 'SetPdgId' property +inline void ParticleCombinerAlg::setupSetPdgId( Property& /*prop*/ ) { + m_setPdgId = true; + return; +} + + +#endif // EVENTUTILS_PARTICLECOMBINERALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5c7cfb2ce9a0a5c1ec26ddc03f0febab7cbe449c --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.cxx @@ -0,0 +1,968 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +//============================================================================ +// Name: ParticleCombinerTool.cxx +// +/** + @class ParticleCombinerTool + + @author Karsten Koeneke <karsten.koeneke@cernSPAMNOT.ch> + + @date July 2014 + + @brief Combine particles to composite particles + + Class to combine two or more particles from a given list of + input containers. All combinations will be tried and only the + ones passing the used selections will be written to StoreGate. +*/ +//============================================================================= + +// This classes header +#include "ParticleCombinerTool.h" + +// STL includes +#include <string> +#include <vector> +#include <cfloat> +#include <climits> + +// The composite particle +#include "xAODParticleEvent/CompositeParticle.h" +#include "xAODParticleEvent/CompositeParticleContainer.h" +#include "xAODParticleEvent/CompositeParticleAuxContainer.h" + +// Other EDM includes +#include "AthLinks/ElementLink.h" +#include "xAODBase/IParticle.h" +#include "xAODBase/IParticleContainer.h" +#include "xAODParticleEvent/IParticleLink.h" +#include "xAODParticleEvent/IParticleLinkContainer.h" +#include "xAODMissingET/MissingET.h" +#include "xAODMissingET/MissingETContainer.h" + +// MC Truth includes +// #include "GeneratorObjects/McEventCollection.h" +// #include "McParticleEvent/TruthParticle.h" +// #include "McParticleEvent/TruthParticleContainer.h" +// #include "HepMC/GenParticle.h" +// #include "HepMC/GenVertex.h" + +// include the Odometer Algorithm +#include "AnalysisUtils/CombinatoricsOdometer.h" + + + +//============================================================================= +// Constructor +//============================================================================= +ParticleCombinerTool::ParticleCombinerTool(const std::string& type, + const std::string& name, + const IInterface* parent ) : + AthAlgTool( type, name, parent ), + m_inCollKeyList(), + m_outCollKey(""), + m_metName(""), + m_pdgId(0), + m_nEventsProcessed(0), + m_anIPartLinkList(), + m_inputLinkContainerList(), + m_inputLinkContainerListToDelete(), + m_inputLinkContainerNames(), + m_alreadyUsedInputContainers(), + m_containerLabels(), + m_containerMaxN(), + m_alreadyUsedContainers() +{ + declareInterface<DerivationFramework::IAugmentationTool>(this); + + declareProperty("InputContainerList", m_inCollKeyList, "List of input collection keys" ); + declareProperty("MissingETObject", m_metName="Final", "The name of the xAOD::MissingET object (default: 'Final'" ); + declareProperty("OutputContainer", m_outCollKey="DefaultCompositeParticleContainer", + "The name of the output container (default: 'DefaultCompositeParticleContainer')" ); + declareProperty("SetPdgId", m_pdgId=0, "PDG ID of the new output xAOD::CompositeParticle" ); + + // declareProperty("mcTruthRequireSameMotherPdgID", + // m_mcTruthRequireSameMotherPdgID=false, + // "Require that the truth mother has the same PDG_ID defined with compositeParticlePDG_ID" ); + // declareProperty("mcTruthRequireSameMotherBarcode", + // m_mcTruthRequireSameMotherBarcode=false, + // "Require that the truth mother has the identical MC Truth barcode" ); +} + + + + + + + +//============================================================================= +// Destructor +//============================================================================= +ParticleCombinerTool::~ParticleCombinerTool() +{ +} + + + + + + +//============================================================================= +// Athena initialize method +//============================================================================= +StatusCode ParticleCombinerTool::initialize() +{ + // Print the used configuration + ATH_MSG_DEBUG ( "==> initialize " << name() << "..." ); + + // Print out the used configuration + ATH_MSG_DEBUG ( " using = " << m_inCollKeyList ); + ATH_MSG_DEBUG ( " using = " << m_metName ); + ATH_MSG_DEBUG ( " using = " << m_outCollKey ); + ATH_MSG_DEBUG ( " using = " << m_pdgId ); + + // ATH_MSG_DEBUG ( " using mcTruthRequireSameMotherPdgID = " << m_mcTruthRequireSameMotherPdgID ); + // ATH_MSG_DEBUG ( " using mcTruthRequireSameMotherBarcode = " << m_mcTruthRequireSameMotherBarcode ); + + // Initialize the counters to zero + m_nEventsProcessed = 0 ; + + return StatusCode::SUCCESS; +} + + + +//============================================================================= +// Run once per event +//============================================================================= +StatusCode ParticleCombinerTool::addBranches() const +{ + // Increase the event counter + ++m_nEventsProcessed; + + // Simple status message at the beginning of each event execute, + ATH_MSG_DEBUG ( "==> addBranches " << name() << " on " << m_nEventsProcessed << ". event..." ); + + + //----------------------------------------- + // Retrieve and store the input containers + //----------------------------------------- + + // Create some objects that are needed later on + bool allInputContainersAreFull = true; + const xAOD::MissingET* metObject(0); + int nMet(0); + + // Clear the vector of LinkContainers and a map of their names. + // use a map to determine if a given input container + // has already been seen, and simply point to the + // link container corresponding to that already-used + // input container + m_inputLinkContainerListToDelete.clear(); + m_inputLinkContainerList.clear(); + m_inputLinkContainerNames.clear(); + m_alreadyUsedInputContainers.clear(); + + // Loop over the list of input containers + for ( const std::string& anInputCollName : m_inCollKeyList.value() ) { + // Check if the current input container name is a LinkContainer + if ( evtStore()->contains< xAOD::IParticleLinkContainer >( anInputCollName ) ) { + // Actually retrieve the LinkContainer from StoreGate + const xAOD::IParticleLinkContainer* aLinkContainer(0); + ATH_CHECK( evtStore()->retrieve( aLinkContainer , anInputCollName ) ); + ATH_MSG_DEBUG ( "Input link collection = '" << anInputCollName + << "' retrieved from StoreGate which has " << aLinkContainer->size() << " entries." ); + + // If any input container has zero size, we won't be able to build a + // CompositeParticle. Thus, we can stop here. + if ( aLinkContainer->size() == 0 ) { + allInputContainersAreFull &= false; + ATH_MSG_VERBOSE("Found an empty input link container"); + break; + } + + if ( m_inputLinkContainerNames.find(aLinkContainer) == m_inputLinkContainerNames.end() ) { + m_inputLinkContainerNames[ aLinkContainer ] = &anInputCollName; + } + m_inputLinkContainerList.push_back( aLinkContainer ); + } + else if ( evtStore()->contains< xAOD::IParticleContainer >( anInputCollName ) ) { + // This container holds an xAOD::IParticleContainer + const xAOD::IParticleContainer* aContainer(0); + ATH_CHECK( evtStore()->retrieve( aContainer, anInputCollName ) ); + ATH_MSG_DEBUG ( "Input collection = '" << anInputCollName + << "' retrieved from StoreGate which has " << aContainer->size() << " entries." ); + + // If any input container has zero size, we won't be able to build a + // CompositeParticle. Thus, we can stop here. + if (aContainer->size() == 0) { + allInputContainersAreFull &= false; + ATH_MSG_VERBOSE("Found an empty input container"); + break; + } + + // Now, create the vector of ElementLinks pointing to the real container + if ( m_alreadyUsedInputContainers.find( aContainer ) == m_alreadyUsedInputContainers.end() ) { + xAOD::IParticleLinkContainer* newLinkContainer = new xAOD::IParticleLinkContainer(); + newLinkContainer->reserve( aContainer->size() ); + m_inputLinkContainerListToDelete.push_back( newLinkContainer ); + + for ( std::size_t i=0; i < aContainer->size(); ++i ) { + xAOD::IParticleLink iPartLink( *aContainer, i ); + newLinkContainer->push_back( iPartLink ); + } + + m_alreadyUsedInputContainers[ aContainer ] = newLinkContainer; + + + if ( m_inputLinkContainerNames.find( newLinkContainer ) == m_inputLinkContainerNames.end() ) { + m_inputLinkContainerNames[ newLinkContainer ] = &anInputCollName; + } + // Add this new container of ElementLinks to the vector + m_inputLinkContainerList.push_back( newLinkContainer ); + } + else { + // Add an already existing container of ElementLinks again to the vector + m_inputLinkContainerList.push_back( m_alreadyUsedInputContainers[ aContainer ] ); + } + } + else if ( evtStore()->contains< xAOD::MissingETContainer >( anInputCollName ) ) { + // This container holds an xAOD::IParticleContainer + const xAOD::MissingETContainer* aMetContainer(0); + ATH_CHECK( evtStore()->retrieve( aMetContainer, anInputCollName ) ); + ATH_MSG_DEBUG ( "Input missing et container = '" << anInputCollName + << "' retrieved from StoreGate." ); + + nMet += 1; + metObject = (*aMetContainer)[m_metName.value()]; + if ( !metObject ) { + ATH_MSG_WARNING( "There was a problem getting the xAOD::MissingET " + << " object with name '" << m_metName + << "' from the xAOD::MissingETContainer with " + << "name '" << anInputCollName << "'." ); + } + } + else { + if ( m_nEventsProcessed <= 10 ) { + ATH_MSG_WARNING ( "Input link collection = '" << anInputCollName + << "' could not be retrieved from StoreGate! " + << " This message will only be repeated 10 times..." ); + } + else { + ATH_MSG_DEBUG ( "Input link collection = '" << anInputCollName + << "' could not be retrieved from StoreGate! " ); + } + return StatusCode::SUCCESS; + } // End: if/elif/else is link container + } // End: Loop over the list of input containers + + // Make sure that we have at most one missing ET container + if ( nMet > 1 ) { + ATH_MSG_ERROR( "We seem to have gotten " << nMet << " xAOD::MissingETContainers " + << "in the InputContainerList. At most one is allowed... exiting!" ); + return StatusCode::FAILURE; + } + + // One more sanity check that we didn't loose a container in between + if ( m_inCollKeyList.value().size() != ( m_inputLinkContainerList.size() + nMet ) ) { + ATH_MSG_DEBUG( "Inconsistent number of input containers after some processing!" + << " This should only happen when any of the input containers has zero size." ); + ATH_MSG_DEBUG( " m_inCollKeyList.size() = " << m_inCollKeyList.value().size() ); + ATH_MSG_DEBUG( " m_inputLinkContainerList.size() = " << m_inputLinkContainerList.size() ); + ATH_MSG_DEBUG( " nMet = " << nMet ); + ATH_MSG_DEBUG( " allInputContainersAreFull = " << allInputContainersAreFull ); + } + + + // //----------------------------------------- + // // Retrieve the MCEventCollection, if needed + // //----------------------------------------- + // if ( !m_mcEventCollKey.empty() && ( + // m_mcTruthRequireSameMotherPdgID || + // m_mcTruthRequireSameMotherBarcode + // ) + // ) + // { + // ATH_CHECK( evtStore()->retrieve( m_mcEventColl, m_mcEventCollKey ) ); + // ATH_MSG_DEBUG ( "MCEventCollection = '" << m_mcEventCollKey << "' retrieved from StoreGate" ); + // } // End: need to retrieve MCEventCollection + + + + + //----------------------------------------- + // Create the output composite particle container and record it in StoreGate + //----------------------------------------- + xAOD::CompositeParticleContainer* outContainer = new xAOD::CompositeParticleContainer( SG::OWN_ELEMENTS ); + ATH_CHECK( evtStore()->record ( outContainer, m_outCollKey.value() ) ); + xAOD::CompositeParticleAuxContainer* compPartAuxCont = new xAOD::CompositeParticleAuxContainer(); + ATH_CHECK( evtStore()->record( compPartAuxCont, m_outCollKey.value() + "Aux." ) ); + outContainer->setStore( compPartAuxCont ); + ATH_MSG_DEBUG( "Recorded xAOD composite particles with key: " << m_outCollKey.value() ); + + + + //----------------------------------------- + // In case at least one of the input containers has zero size, + // no CompositeParticle can be found. So only try building + // CompositeParticles if every input container has at least + // one entry. + //----------------------------------------- + if ( allInputContainersAreFull ) { + + //----------------------------------------- + // Do the combinations of particles + //----------------------------------------- + + // Use the odometer algorithm to perform the combination of particles + // m_inputLinkContainerList is the std::vector of links + + // get the label and number of elements in each link container. + // pass those to the OdoMeter, and ask the OdoMeter to return + // the unique sets of indices for objects in the containers + + // To create the odometer object, we need to assign each container pointer + // a string name that uniquely idenfies that container. The same container + // (even used multiple times) will always have the same name. The name/entries + // info will be used to initialize the odometer. + ATH_MSG_DEBUG ( "Input LinkContainer list contains " << m_inputLinkContainerList.size() << " entries." ); + + // Clear needed vectors and maps + m_containerLabels.clear(); + m_containerMaxN.clear(); + m_alreadyUsedContainers.clear(); + + for ( const xAOD::IParticleLinkContainer* aLinkContainer : m_inputLinkContainerList ) { + const std::string& containerName = *(m_inputLinkContainerNames[ aLinkContainer ]); + + // determine if this container has already been used in the list. + // if not, assign it a unique name. If so, get the name of the existing container + if ( m_containerLabels.size() == 0 || + m_alreadyUsedContainers.find( aLinkContainer ) == m_alreadyUsedContainers.end() ) { + m_containerLabels.push_back( containerName ); + m_containerMaxN[ containerName ] = aLinkContainer->size(); + m_alreadyUsedContainers[ aLinkContainer ] = containerName; + } + else { + // already used this container. Use the old container's name + m_containerLabels.push_back( containerName ); + } + ATH_MSG_DEBUG ( "A container/size pair for the Odometer: " + << m_containerLabels.at( m_containerLabels.size() - 1) << "/" + << m_containerMaxN[ m_containerLabels.at( m_containerLabels.size() - 1) ] ); + } + + + // Create and initialize an instance of the odometer + OdoMeter anOdometer(m_containerLabels, m_containerMaxN); + + // find all unique groupings and build composites + while ( anOdometer.increment() ) { + // Clear the vector + m_anIPartLinkList.clear(); + + // Get the current combinatoric + std::vector<int> aUniqueChoice = anOdometer.getVector(); + int nContainers = static_cast<int>(aUniqueChoice.size()); + + if (msgLvl(MSG::VERBOSE)) { + msg(MSG::VERBOSE) << "Odometer - using this unique combination: "; + for ( unsigned int ichoice = 0; ichoice < aUniqueChoice.size(); ichoice++ ) { + msg(MSG::VERBOSE) << aUniqueChoice.at(ichoice) << ","; + } + msg(MSG::VERBOSE) << endreq; + } + + // Loop over all containers + for( int aContainerIndex = 0; aContainerIndex < nContainers; ++aContainerIndex ) { + const xAOD::IParticleLinkContainer* aLinkContainer = m_inputLinkContainerList.at( aContainerIndex ); + int indexInContainer = aUniqueChoice.at( aContainerIndex ); + + const xAOD::IParticleLink& aPartLink = aLinkContainer->at( indexInContainer ); + + const xAOD::IParticleContainer* ptrIPartCont = + dynamic_cast< const xAOD::IParticleContainer* >( aPartLink.getStorableObjectPointer() ); + + if ( ptrIPartCont != NULL ) { + const xAOD::IParticleLink aParticleLink(*ptrIPartCont, aPartLink.index()); + m_anIPartLinkList.push_back( aParticleLink ); + } + } // end the loop over the available containers to build INav4MomLink objects + + // Now, actually build the CompositeParticle from the list of ElementLinks to INavigable4Momentum + ATH_CHECK( buildComposite( outContainer, m_anIPartLinkList ) ); + + } // End: while ( anOdometer.increment() ) + + } // End: Found an empty input collection; thus no CompositeParticle can be possible... do nothing. + + + //----------------------------------------- + // Set the output container of composite particles as const + // Actually, for now, don't do this as analyzers might want to decorate the + // new xAOD::CompositeParticles further downstream. + //----------------------------------------- + // ATH_CHECK( evtStore()->setConst( outContainer ) ); + // ATH_CHECK( evtStore()->setConst( compPartAuxCont ) ); + // ATH_MSG_DEBUG ( "Output collection = '" << m_outCollKey.value() << "' set to const in StoreGate" ); + + // Print a final message about the composite particles + ATH_MSG_DEBUG ( "Found " << outContainer->size() << " composite particles in event number " << m_nEventsProcessed ); + + // // Delete needed things + for ( std::size_t i=0; i<m_inputLinkContainerListToDelete.size(); ++i ) { + if ( m_inputLinkContainerListToDelete[i] ) { + delete m_inputLinkContainerListToDelete[i]; + } + } + + return StatusCode::SUCCESS; +} + + + + + +//============================================================================= +// Athena finalize method +//============================================================================= +StatusCode ParticleCombinerTool::finalize() +{ + ATH_MSG_DEBUG ( "FINALIZING AFTER ALL EVENTS ARE PROCESSED" ); + + return StatusCode::SUCCESS; +} + + + + + + +//============================================================================= +// Building the composite particle +// Here, we check if any of the potential constituents (anIPartLinkList) is +// overlapping (is the same or share the same constituent) with any of the other +// potential constituents +//============================================================================= +StatusCode ParticleCombinerTool::buildComposite( xAOD::CompositeParticleContainer* outContainer, + xAOD::IParticleLinkContainer& anIPartLinkList ) const +{ + // Check if the vector does not have zero size + if ( anIPartLinkList.size() == 0 ) { + return StatusCode::SUCCESS; + } + + // Create a list of all ParticleLinks that are already checked + std::vector< const xAOD::IParticleLink* > theParticleLinks; + + bool ParticlesAreValid = true; + + //Loop over all ElementLinks to INavigable4Momenta and get the INavigable4Momenta + for ( const xAOD::IParticleLink& aParticleLink : anIPartLinkList ) { + // Check if this ElementLink is valid + if ( aParticleLink.isValid() ) { + // Get the particle from the ElementLink + const xAOD::IParticle* aParticle = *aParticleLink; + + if (aParticle) { + // determine if the particle has any daughter in common with + // a previous particle in the composite: + for ( const xAOD::IParticleLink* otherPartLink : theParticleLinks ) { + // 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!" ); + ParticlesAreValid &= false; + break; + } + } // End: loop over all already checked particle links + + // push the particle onto the candidate's input list + if ( ParticlesAreValid ) { + theParticleLinks.push_back( &aParticleLink ); + } + } + else { + ATH_MSG_DEBUG ( "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!" ); + ParticlesAreValid &= false; + } // check the link to a particle + + if ( false == ParticlesAreValid ) { + break; + } + } // End: loop over vector of ElementLinks + + + //----------------------------------------- + // Do the combination + //----------------------------------------- + if ( ParticlesAreValid ) { + // Actually create the composite particle + //-------------------------------------------------------------- + xAOD::CompositeParticle* compPart = new xAOD::CompositeParticle(); + compPart->makePrivateStore(); + for ( const xAOD::IParticleLink& aParticleLink : anIPartLinkList ) { + compPart->addConstituent( aParticleLink ); + } + compPart->setPdgId( m_pdgId.value() ); + + // Check if this composite particle has been found before + if ( !compositeParticleAlreadyFound( outContainer, compPart ) ) { + // Add this composite particle to the output container + // if it passes all the selections + //-------------------------------------------------------------- + bool passAll = true; + + // // charge selection + // if ( passAll ) { + // passAll = m_filterTool->chargeFilter( compPart, + // m_chargeMin, + // m_chargeMax, + // m_allowChargeConj ); + // } + + // // MC Truth selection + // // ONLY run this if MCTruth information is available AND + // // MCTruth selections are configured! + // if ( !m_mcEventCollKey.empty() && ( + // m_mcTruthRequireSameMotherPdgID || + // m_mcTruthRequireSameMotherBarcode + // ) + // ) + // { + // if ( passAll ) + // { + // passAll = mcTruthSelections( compPart ); + // } + // } + + + + // Write out the composite particles if all cuts are passed + if ( passAll ) { + outContainer->push_back( compPart ); + } + else { + delete compPart; + } + } + else { + // Output message + ATH_MSG_DEBUG ( "Found this composite particle already before..." ); + delete compPart; + } // End: if compositeParticleAlreadyFound + + } // End: Saveguard check if all particles are valide + + return StatusCode::SUCCESS; +} + + + + + + +//============================================================================= +// Check if the composite particle at hand was already found before +//============================================================================= +bool ParticleCombinerTool::compositeParticleAlreadyFound( xAOD::CompositeParticleContainer* compContainer, + xAOD::CompositeParticle* compPart ) const +{ + // default return + bool foundIdentical = false; + + // Count the number of constituents of the test particle + std::size_t nConstituentsTest = compPart->nConstituents(); + + // Get the first input container and loop over it + for ( const xAOD::CompositeParticle* contCompPart : *compContainer ) { + // Check if an identical composite particle is already found + if ( !foundIdentical ) { + // Count the number of constituents of the reference particle + std::size_t nConstituentsReference = contCompPart->nConstituents(); + + // Check that both have the same number of constituents + if ( nConstituentsTest==nConstituentsReference ) { + // Loop over all constituents of the composite particle to be tested + bool allConstituentsSame = true; + for ( const xAOD::IParticleLink& constitLink : compPart->constituentLinks() ) { + if ( allConstituentsSame && contCompPart->contains(constitLink) ) { + allConstituentsSame = true; + } + else { + allConstituentsSame = false; + } + } // End: loop over constituents + + // Now, propagete the decission + if ( allConstituentsSame ) { + foundIdentical = true; + } + else { + foundIdentical = false; + } + } // End: if ( nConstituentsTest==nConstituentsReference ) + else { + foundIdentical = false; + } // End: if/else ( nConstituentsTest==nConstituentsReference ) + } // End: if ( !foundIdentical ) + } // End: loop over container + + // Output message + ATH_MSG_VERBOSE ( "Checking if this composite particle was already found before..." + << " foundIdentical=" << foundIdentical ); + + return foundIdentical; +} + + +// The test if two particles are equal. +// One would need a barcode to do this proper +bool ParticleCombinerTool::isEqual( const xAOD::IParticle* part1, + const xAOD::IParticle* part2 ) const +{ + // TODO: Add special implementation for TruthParticle, i.e., check barcode + + // Since we don't have a barcode here, we have to rely on pointer equality + if ( part1 && part1 == part2 ) { + return true; + } + else { + return false; + } + // This would be better: + // part1->hasSameAthenaBarCodeExceptVersion(*part2); +} + + + +//============================================================================= +// Check that two particles are not the same or, if they are +// composite particles, that they don't share the same constitutents +//============================================================================= +bool ParticleCombinerTool::shareSameConstituents( const xAOD::IParticle* part1, + 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) ; + + // Neither of the two is a composite particle + if ( !compPart1 && !compPart2 ) { + return this->isEqual( part1, part2 ); + } + // One of them is a composite + else if ( compPart1 && !compPart2 ) { + return shareSameConstituents( part2, compPart1 ); + } + else if ( !compPart1 && compPart2 ) { + return shareSameConstituents( part1, compPart2 ); + } + // Both are composite candidates + else if ( compPart1 && compPart2 ) { + return shareSameConstituents( compPart1, compPart2 ); + } + + return false; +} + + + +//============================================================================= +// Check that two particles are not the same or, if they are +// composite particles, that they don't share the same constitutents +// -------------------------- HELPER --------------------- +//============================================================================= +bool ParticleCombinerTool::shareSameConstituents( const xAOD::IParticle* part1, + const xAOD::CompositeParticle* compPart2 ) const +{ + // Default return + bool isConstituent = false; + + // Loop over all constituents of the composite particle to be tested + const std::size_t nConstit = compPart2->nConstituents(); + for( std::size_t i=0; i<nConstit; ++i ) { + const xAOD::IParticle* part2 = compPart2->constituent(i); + + // Check if this constituent itself is a composite particle + const xAOD::CompositeParticle* constitCP = + dynamic_cast<const xAOD::CompositeParticle*> (part2) ; + + if ( !constitCP ) { + isConstituent = this->isEqual( part1, part2 ); + } + else { + isConstituent = shareSameConstituents( part1, constitCP ); + } + if ( isConstituent ) { + return true; + } + } // End: loop over constituents + + return isConstituent; +} + + + +//============================================================================= +// Check that two particles are not the same or, if they are +// composite particles, that they don't share the same constitutents +// -------------------------- HELPER --------------------- +//============================================================================= +bool ParticleCombinerTool::shareSameConstituents( const xAOD::CompositeParticle* compPart1, + const xAOD::CompositeParticle* compPart2 ) const +{ + // Default return + bool isConstituent = false; + + // Loop over all constituents of the composite particle to be tested + const std::size_t nConstit1 = compPart1->nConstituents(); + const std::size_t nConstit2 = compPart2->nConstituents(); + for( std::size_t i=0; i<nConstit1; ++i ) { + const xAOD::IParticle* part1 = compPart1->constituent(i); + + // 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 ) { + const xAOD::IParticle* part2 = compPart2->constituent(j); + + // Check if this constituent itself is a composite particle + const xAOD::CompositeParticle* constitCP2 = + dynamic_cast<const xAOD::CompositeParticle*> (part2) ; + + if ( !constitCP1 && !constitCP1 ) { + isConstituent = this->isEqual( part1, part2 ); + } + if ( !constitCP1 && constitCP2 ) { + isConstituent = shareSameConstituents( part1, constitCP2 ); + } + if ( constitCP1 && !constitCP2 ) { + isConstituent = shareSameConstituents( part2, constitCP1 ); + } + if ( constitCP1 && constitCP2 ) { + isConstituent = shareSameConstituents( constitCP1, constitCP2 ); + } + if ( isConstituent ) { + return true; + } + } // End: loop over constituents 2 + } // End: loop over constituents 1 + + return isConstituent; +} + + + +// +// //============================================================================= +// // Do the selection based on the MC Truth record +// // -------------------------- HELPER --------------------- +// //============================================================================= +// bool D2PDParticleCombiner::mcTruthSelections( const CompositeParticle* compPart ) const +// { +// // Default return +// bool isPassed = true; +// +// // If the MCEventCollection is not available, I can't do anything +// if ( !m_mcEventColl ) +// { +// ATH_MSG_WARNING ( "No MCEventCollection available... skipping!" ); +// return true; +// } +// +// +// // Get the daughters of the composite particle and check if all of them are TruthParticles +// unsigned int counter(0); +// std::vector<const TruthParticle*> truthParticles; +// CompositeParticle::ConstituentsIter_t cpItr = compPart->constituents_begin(); +// CompositeParticle::ConstituentsIter_t cpItrEnd = compPart->constituents_end(); +// for( ; cpItr != cpItrEnd; ++cpItr ) +// { +// ++counter; +// const TruthParticle* part = dynamic_cast<const TruthParticle*>(*cpItr); +// +// // if the cast was successfull, add it to the vector of truth particles +// if ( part ) +// { +// truthParticles.push_back( part ); +// } +// } +// +// +// // If all of the constituents are TruthParticles... +// if ( truthParticles.size() != counter ) +// { +// ATH_MSG_WARNING ( "Not all of the constituents of this CompositeParticle are TruthParticles... skipping!" ); +// return true; +// } +// +// +// //------------------------------------------------ +// // Now, do the actual selections +// //------------------------------------------------ +// +// std::vector<int> pdgIDList; +// std::vector<int> barcodeList; +// +// // Loop over the TruthParticles +// std::vector<const TruthParticle*>::const_iterator partItr = truthParticles.begin(); +// std::vector<const TruthParticle*>::const_iterator partItrEnd = truthParticles.end(); +// for ( ; partItr != partItrEnd; ++partItr ) +// { +// // Get the GenParticle from the TruthParticle +// const TruthParticle* part = (*partItr); +// const HepMC::GenParticle* genPart = part->genParticle(); +// const int pdgID = genPart->pdg_id(); +// +// // Now, get the origin of this generated particle +// McEventCollection::const_iterator mcEventItr = m_mcEventColl->begin(); +// const int primaryBarcode = genPart->barcode()%1000000; +// const HepMC::GenParticle* primaryPart = (*mcEventItr)->barcode_to_particle(primaryBarcode); +// +// // Check that we really have the primaryPart +// if ( !primaryPart ) +// { +// ATH_MSG_WARNING ( "Could not get the primaryParticle... skipping!" ); +// return true; +// } +// +// // Now get the production vertex +// const HepMC::GenVertex* prodVert = primaryPart->production_vertex(); +// if ( !prodVert ) +// { +// ATH_MSG_WARNING ( "Could not get the ProductionVertex... skipping!" ); +// return true; +// } +// +// // Check that we have only one mother +// if ( prodVert->particles_in_size() > 1 ) +// { +// ATH_MSG_WARNING ( "The ProductionVertex has more than one incomming particles... skipping!" ); +// return true; +// } +// +// +// // Loop over the mother particles +// // Make sure that we ignore bremsstrahlung and decays into itself +// const HepMC::GenVertex* originVert = prodVert ; +// //const HepMC::GenVertex* tmpVert(0); +// int originPdgID = pdgID; +// int originBarcode(0); +// int counter(0); +// do +// { +// ++counter; +// HepMC::GenVertex::particles_in_const_iterator motherItr = originVert->particles_in_const_begin(); +// HepMC::GenVertex::particles_in_const_iterator motherItrEnd = originVert->particles_in_const_end(); +// for ( ; motherItr != motherItrEnd; ++motherItr ) +// { +// originPdgID = (*motherItr)->pdg_id(); +// originVert = (*motherItr)->production_vertex(); +// originBarcode = (*motherItr)->barcode(); +// } +// +// // Protect against infinite loop +// if ( counter > 100 ) +// { +// ATH_MSG_WARNING ( "Stuck in an infinite while loop... breaking out!" ); +// break; +// } +// } while ( abs(originPdgID) == abs(pdgID) && originVert != 0 ); +// +// // Attach the PDG_ID and barcode of the origin particle to the vectors +// pdgIDList.push_back( originPdgID ); +// barcodeList.push_back( originBarcode ); +// +// } // End: loop over all the daughter TruthParticles from the CompositeParticle +// +// // Get the decissions +// bool isSamePdgID(true); +// bool isSameBarcode(true); +// std::vector<int>::const_iterator pdgItr = pdgIDList.begin(); +// std::vector<int>::const_iterator pdgItrEnd = pdgIDList.end(); +// for ( ; pdgItr != pdgItrEnd; ++pdgItr ) +// { +// if ( m_pdgId != (*pdgItr) ) +// { +// isSamePdgID = false; +// } +// } // End: Loop over pdg_ID list +// +// std::vector<int>::const_iterator barcodeItr = barcodeList.begin(); +// std::vector<int>::const_iterator barcodeItrEnd = barcodeList.end(); +// for ( ; barcodeItr != barcodeItrEnd; ++barcodeItr ) +// { +// if ( barcodeList[0] != (*barcodeItr) ) +// { +// isSameBarcode = false; +// } +// } // End: Loop over barcode list +// +// +// +// // Now, do the final decission +// if ( m_mcTruthRequireSameMotherPdgID && !isSamePdgID ) +// { +// isPassed = false; +// } +// if ( m_mcTruthRequireSameMotherBarcode && !isSameBarcode ) +// { +// isPassed = false; +// } +// +// +// return isPassed; +// } + + + +// const HepMC::GenVertex* MothVert(0); +// long NumOfParents(-1); +// int MotherBarcode(0); +// m_MotherPDG=0; +// m_PhotonMotherPDG=0; + +// const HepMC::GenVertex* oriMothVert(0); +// HepMC::GenVertex::particles_in_const_iterator itrMother = PriOriVert->particles_in_const_begin(); +// for ( ; itrMother != PriOriVert->particles_in_const_end(); +// ++itrMother) +// { +// m_MotherPDG = (*itrMother)->pdg_id(); +// MothVert = (*itrMother)->production_vertex(); +// oriMothVert = (*itrMother)->production_vertex(); +// MotherBarcode = (*itrMother)->barcode(); +// }// cycle itrMother + +// // radiation in the final state +// if ( abs(m_MotherPDG)==11 && PriBarcode<200000 && oriMothVert!=0 ) +// { +// int itr=0; +// do +// { +// PriOriVert = oriMothVert; +// PriBarcode = MotherBarcode; +// for (HepMC::GenVertex::particles_in_const_iterator +// itrMother = PriOriVert->particles_in_const_begin(); +// itrMother!=PriOriVert->particles_in_const_end(); ++itrMother){ + +// m_MotherPDG = (*itrMother)->pdg_id(); +// MothVert = (*itrMother)->production_vertex(); +// oriMothVert = (*itrMother)->production_vertex(); +// MotherBarcode=(*itrMother)->barcode(); +// }// cycle itrMother +// itr++; +// if(itr>100) {std::cout<<"infinite while"<<std::endl;break;} +// } while ( oriMothVert!=0 && abs(m_MotherPDG)==11 ); +// } diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.h new file mode 100644 index 0000000000000000000000000000000000000000..ea60fe5587f18e6e3c143a6e0cb95b6e35c12f94 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleCombinerTool.h @@ -0,0 +1,177 @@ +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// Dear emacs, this is -*-c++-*- +#ifndef EVENTUTILS_PARTICLECOMBINERTOOL_H +#define EVENTUTILS_PARTICLECOMBINERTOOL_H + +//============================================================================ +// Name: ParticleCombinerTool.h +// +/** + @class ParticleCombinerTool + + @author Karsten Koeneke <karsten.koeneke@cernSPAMNOT.ch> + + @date July 2014 + + @brief Combine particles to composite particles + + Class to combine two or more particles from a given list of + input containers. All combinations will be tried and the unique ones will + be written to StoreGate. +*/ +//============================================================================= + + +// STL includes +#include <string> +#include <vector> + +// Athena includes +#include "GaudiKernel/Property.h" +#include "AthenaBaseComps/AthAlgTool.h" +#include "DerivationFrameworkInterfaces/IAugmentationTool.h" + +// CompositeParticle +#include "xAODParticleEvent/CompositeParticleContainerFwd.h" +#include "xAODParticleEvent/CompositeParticleFwd.h" +#include "xAODParticleEvent/IParticleLinkContainer.h" + +// MC Truth +// #include "GeneratorObjects/McEventCollection.h" + + +class ParticleCombinerTool : public AthAlgTool, + virtual public DerivationFramework::IAugmentationTool +{ +public: + + /** Default constructor */ + ParticleCombinerTool(const std::string& type, + const std::string& name, + const IInterface* parent); + + /** Default destructor */ + virtual ~ParticleCombinerTool() ; + + +public: + /** Gaudi Service Interface method implementations - initialize */ + StatusCode initialize() ; + + /** Gaudi Service Interface method implementations - finalize */ + StatusCode finalize() ; + + /// Implement the method from the IAugmentationTool interface + virtual StatusCode addBranches() const final override; + + + + +private: + /// The test if two particles are equal. + /// One would need a barcode, i.e., particle-unique identifier, to do this proper + bool isEqual( const xAOD::IParticle* part1, const xAOD::IParticle* part2 ) const; + + /** Build the composite candidates */ + StatusCode buildComposite( xAOD::CompositeParticleContainer* outContainer, + xAOD::IParticleLinkContainer& anIPartLinkList ) const; + + /** Check if the composite particle at hand was already found before */ + bool compositeParticleAlreadyFound( xAOD::CompositeParticleContainer* compContainer, + xAOD::CompositeParticle* compPart ) const; + + /** Check that two particles are not the same or, if they are + composite particles, that they don't share the same constitutents */ + bool shareSameConstituents( const xAOD::IParticle* part1, + const xAOD::IParticle* part2 ) const; + + /** Check that two particles are not the same or, if they are + composite particles, that they don't share the same constitutents */ + bool shareSameConstituents( const xAOD::IParticle* part1, + const xAOD::CompositeParticle* compPart2 ) const; + + /** Check that two particles are not the same or, if they are + composite particles, that they don't share the same constitutents */ + bool shareSameConstituents( const xAOD::CompositeParticle* compPart1, + const xAOD::CompositeParticle* compPart2 ) const; + + /** Do the MC Truth selections */ + // bool mcTruthSelections( const xAOD::CompositeParticle* compPart ); + + + +private: + //------------------------------------------------------ + // Tools and Containers + //------------------------------------------------------ + + /// List of input collection names + StringArrayProperty m_inCollKeyList; + + /// Output collection name (the composite particles) + StringProperty m_outCollKey; + + /// The name of the missing ET object, e.g., "Final" + StringProperty m_metName; + + /// The PDG_ID of the CompositeParticle + IntegerProperty m_pdgId; + + // /** MCEventCollection name */ + // StringProperty m_mcEventCollKey; + // + // /** MCEventCollection */ + // const McEventCollection* m_mcEventColl; + + + +private: + /** Internal event counter */ + mutable unsigned long m_nEventsProcessed; + + +private: + //------------------------------------------------------ + // Internal variables + //------------------------------------------------------ + /** Create a vector that will hold all the INav4MomLinks for one CompositeParticle */ + mutable xAOD::IParticleLinkContainer m_anIPartLinkList; + + + /** Create a vector of LinkContainers and a map of their names */ + mutable std::vector< const xAOD::IParticleLinkContainer* > m_inputLinkContainerList; + + /** create a vector that will contain pointers to the + * xAOD::IParticleLinkContainers that need to be deleted manually. + * This is because these containers never get registered to StoreGate and + * thus, the ownership resides inside this class instance. */ + mutable std::vector< const xAOD::IParticleLinkContainer* > m_inputLinkContainerListToDelete; + + /** A map to store the name associated to each input link container object */ + mutable std::map< const xAOD::IParticleLinkContainer*, const std::string* > m_inputLinkContainerNames; + + /** A map to store the input container that are already used. + * use a map to determine if a given input container + * has already been seen, and simply point to the + * link container corresponding to that already-used + * input container */ + mutable std::map< const xAOD::IParticleContainer*, const xAOD::IParticleLinkContainer* > m_alreadyUsedInputContainers; + + + /** Vector of the labels/keys of all input containers (all converted to link containers) */ + mutable std::vector<std::string> m_containerLabels; + + /** A map to store the size of each input container */ + mutable std::map<std::string, int> m_containerMaxN; + + /** A map to store the container that are already used */ + mutable std::map< const xAOD::IParticleLinkContainer*, std::string > m_alreadyUsedContainers; + + +}; // End class ParticleCombinerTool + + +#endif // EVENTUTILS_PARTICLECOMBINERTOOL_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..a3c7fa0095ed5b7a92cbc04a3b7d4a4f39af35a4 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.cxx @@ -0,0 +1,184 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ParticleSelectionAlg.cxx +// Implementation file for class ParticleSelectionAlg +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// + +// EventUtils includes +#include "ParticleSelectionAlg.h" + +// STL includes + +// FrameWork includes +#include "GaudiKernel/Property.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "DerivationFrameworkInterfaces/IAugmentationTool.h" + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +ParticleSelectionAlg::ParticleSelectionAlg( const std::string& name, + ISvcLocator* pSvcLocator ) : + ::AthAlgorithm( name, pSvcLocator ), + m_jos("JobOptionsSvc", name), + m_tool("ParticleSelectionTool/ParticleSelectionTool", this), + m_inCollKey(""), + m_setInCollKey(false), + m_outCollKey(""), + m_setOutCollKey(false), + m_outCollType(""), + m_setOutCollType(false), + m_setOwnPolicy(false), + m_outLinkCollKey(""), + m_setOutLinkCollKey(false), + m_selection(""), + m_setSelection(false), + m_nEventsProcessed(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("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 ); +} + + + +// Destructor +/////////////// +ParticleSelectionAlg::~ParticleSelectionAlg() +{} + + + +// Athena Algorithm's Hooks +//////////////////////////// +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_outLinkCollKey ); + ATH_MSG_DEBUG ( " using = " << m_selection ); + + + // 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) ); + } + if (m_setOutCollKey) { + ATH_MSG_DEBUG( "Setting property" << m_outCollKey + << " of private tool with name: '" << fullToolName << "'" ); + ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_outCollKey) ); + } + if (m_setOutCollType) { + ATH_MSG_DEBUG( "Setting property" << m_outCollType + << " of private tool with name: '" << fullToolName << "'" ); + ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_outCollType) ); + } + 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() ); + + ATH_MSG_DEBUG ( "==> done with initialize " << name() << "..." ); + + return StatusCode::SUCCESS; +} + + + +StatusCode ParticleSelectionAlg::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + + // Release all tools and services + ATH_CHECK( m_jos.release() ); + ATH_CHECK( m_tool.release() ); + + 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() ); + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..dffc6aec97ec00bd7bd326a0aca31faa438cdaf9 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionAlg.h @@ -0,0 +1,189 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ParticleSelectionAlg.h +// Header file for class ParticleSelectionAlg +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef EVENTUTILS_PARTICLESELECTIONALG_H +#define EVENTUTILS_PARTICLESELECTIONALG_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaBaseComps/AthAlgorithm.h" + + +// forward declarations +class IJobOptionsSvc; +namespace DerivationFramework { + class IAugmentationTool; +} + + + +class ParticleSelectionAlg + : public ::AthAlgorithm +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + // Copy constructor: + + /// Constructor with parameters: + ParticleSelectionAlg( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~ParticleSelectionAlg(); + + + /// 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: + // 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 '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 data: + /////////////////////////////////////////////////////////////////// + private: + /// The job options service (will be used to forward this algs properties to + /// the private tool) + ServiceHandle<IJobOptionsSvc> m_jos; + + /// The ToolHandle to the SkimmingTool + ToolHandle<DerivationFramework::IAugmentationTool> m_tool; + + /// Input container name + StringProperty m_inCollKey; + + /// This boolean is true if the user sets the 'InputContainer' property + bool m_setInCollKey; + + + /// 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; + + + /// Defines the ownership policy of the output container + /// (default: 'OWN_ELEMENTS'; also allowed: 'VIEW_ELEMENTS')" + 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 +////////////////////// + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +/// 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; +} + +/// This internal method will realize if a user sets the 'OutputContainerOwnPolicy' property +inline void ParticleSelectionAlg::setupOutputContainerOwnPolicy( Property& /*prop*/ ) { + m_setOwnPolicy = true; + return; +} + +/// This internal method will realize if a user sets the 'OutputLinkContainer' property +inline void ParticleSelectionAlg::setupOutputLinkContainer( Property& /*prop*/ ) { + m_setOutLinkCollKey = true; + return; +} + +/// This internal method will realize if a user sets the 'Selection' property +inline void ParticleSelectionAlg::setupSelection( Property& /*prop*/ ) { + m_setSelection = true; + return; +} + + + + +#endif //> !EVENTUTILS_PARTICLESELECTIONALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..1b202576ff393ba8a3f9f0d69c835974c92c35ee --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.cxx @@ -0,0 +1,570 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ParticleSelectionTool.cxx +// Implementation file for class ParticleSelectionTool +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// + + +// EventUtils includes +#include "ParticleSelectionTool.h" + +// STL includes +#include <vector> +#include <string> + +// FrameWork includes +#include "ExpressionEvaluation/ExpressionParser.h" +#include "TrigDecisionTool/TrigDecisionTool.h" +#include "ExpressionEvaluation/TriggerDecisionProxyLoader.h" +#include "ExpressionEvaluation/SGxAODProxyLoader.h" +#include "ExpressionEvaluation/SGNTUPProxyLoader.h" +#include "ExpressionEvaluation/MultipleProxyLoader.h" +#include "ExpressionEvaluation/StackElement.h" + +// EDM includes +#include "AthLinks/ElementLink.h" +#include "xAODBase/IParticle.h" +#include "xAODBase/IParticleContainer.h" +#include "xAODParticleEvent/IParticleLink.h" +#include "xAODParticleEvent/IParticleLinkContainer.h" +#include "xAODMuon/Muon.h" +#include "xAODMuon/MuonContainer.h" +#include "xAODMuon/MuonAuxContainer.h" +#include "xAODJet/Jet.h" +#include "xAODJet/JetContainer.h" +#include "xAODJet/JetAuxContainer.h" +#include "xAODEgamma/Electron.h" +#include "xAODEgamma/ElectronContainer.h" +#include "xAODEgamma/ElectronAuxContainer.h" +#include "xAODEgamma/Photon.h" +#include "xAODEgamma/PhotonContainer.h" +#include "xAODEgamma/PhotonAuxContainer.h" +#include "xAODTau/TauJet.h" +#include "xAODTau/TauJetContainer.h" +#include "xAODTau/TauJetAuxContainer.h" +#include "xAODPFlow/PFO.h" +#include "xAODPFlow/PFOContainer.h" +#include "xAODPFlow/PFOAuxContainer.h" +#include "xAODTracking/NeutralParticle.h" +#include "xAODTracking/NeutralParticleContainer.h" +#include "xAODTracking/NeutralParticleAuxContainer.h" +#include "xAODTracking/TrackParticle.h" +#include "xAODTracking/TrackParticleContainer.h" +#include "xAODTracking/TrackParticleAuxContainer.h" +#include "xAODTruth/TruthParticle.h" +#include "xAODTruth/TruthParticleContainer.h" +#include "xAODTruth/TruthParticleAuxContainer.h" +#include "xAODParticleEvent/CompositeParticle.h" +#include "xAODParticleEvent/CompositeParticleContainer.h" +#include "xAODParticleEvent/CompositeParticleAuxContainer.h" +#include "xAODParticleEvent/Particle.h" +#include "xAODParticleEvent/ParticleContainer.h" +#include "xAODParticleEvent/ParticleAuxContainer.h" +#include "xAODCaloEvent/CaloCluster.h" +#include "xAODCaloEvent/CaloClusterContainer.h" +#include "xAODCaloEvent/CaloClusterAuxContainer.h" + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +ParticleSelectionTool::ParticleSelectionTool( const std::string& type, + const std::string& name, + const IInterface* parent ) : + ::AthAlgTool ( type, name, parent ), + m_trigDecisionTool("Trig::TrigDecisionTool/TrigDecisionTool"), + m_parser(0), + m_inCollKey(""), + m_outCollKey(""), + m_outCollType(""), + m_outLinkCollKey(""), + m_selection(""), + m_contID(0), + m_nEventsProcessed(0) +{ + declareInterface< DerivationFramework::IAugmentationTool >(this); + + declareProperty("InputContainer", m_inCollKey="", "Input container name" ); + + declareProperty("OutputContainer", m_outCollKey="", + "The name of the output container with the copy of the selected xAOD::IParticles" ); + + declareProperty("OutputContainerType", m_outCollType="", + "The type of the output container, e.g., 'xAOD::JetContainer'" ); + + declareProperty("OutputContainerOwnershipPolicy", m_outOwnPolicyName="OWN_ELEMENTS", + "Defines the ownership policy of the output container (default: 'OWN_ELEMENTS'; also allowed: 'VIEW_ELEMENTS')" ); + + declareProperty("OutputLinkContainer", m_outLinkCollKey="", + "The name of the output container of ElementLinks to the selected xAOD::IParticles" ); + + declareProperty("Selection", m_selection="", + "The selection string that defines which xAOD::IParticles to select from the container" ); +} + +// Destructor +/////////////// +ParticleSelectionTool::~ParticleSelectionTool() +{} + + + +// Athena algtool's Hooks +//////////////////////////// +StatusCode ParticleSelectionTool::initialize() +{ + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + + // Print out the used configuration + ATH_MSG_DEBUG ( " using = " << m_inCollKey ); + ATH_MSG_DEBUG ( " using = " << m_outCollKey ); + ATH_MSG_DEBUG ( " using = " << m_outCollType ); + ATH_MSG_DEBUG ( " using = " << m_outOwnPolicyName ); + ATH_MSG_DEBUG ( " using = " << m_outLinkCollKey ); + ATH_MSG_DEBUG ( " using = " << m_selection ); + + + // initialize proxy loaders for expression parsing + ExpressionParsing::MultipleProxyLoader *proxyLoaders = new ExpressionParsing::MultipleProxyLoader(); + proxyLoaders->push_back(new ExpressionParsing::TriggerDecisionProxyLoader(m_trigDecisionTool)); + 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_selection.value() ); + + // initialize the counters + m_contID = 0; + m_nEventsProcessed = 0; + + // Determine the output container type + if ( !(m_outCollType.value().empty()) ) { + if ( m_outCollType.value() == "xAOD::MuonContainer" ) { m_contID = 1; } + else if ( m_outCollType.value() == "xAOD::JetContainer" ) { m_contID = 2; } + else if ( m_outCollType.value() == "xAOD::ElectronContainer" ) { m_contID = 3; } + else if ( m_outCollType.value() == "xAOD::PhotonContainer" ) { m_contID = 4; } + else if ( m_outCollType.value() == "xAOD::TauJetContainer" ) { m_contID = 5; } + else if ( m_outCollType.value() == "xAOD::PFOContainer" ) { m_contID = 6; } + else if ( m_outCollType.value() == "xAOD::NeutralParticleContainer" ) { m_contID = 7; } + else if ( m_outCollType.value() == "xAOD::TrackParticleContainer" ) { m_contID = 8; } + else if ( m_outCollType.value() == "xAOD::TruthParticleContainer" ) { m_contID = 9; } + else if ( m_outCollType.value() == "xAOD::CompositeParticleContainer" ) { m_contID = 10; } + else if ( m_outCollType.value() == "xAOD::ParticleContainer" ) { m_contID = 11; } + else if ( m_outCollType.value() == "xAOD::CaloClusterContainer" ) { m_contID = 12; } + else { + ATH_MSG_WARNING("I got a non-empty string for the OutputContainerType property " + << "with value " << m_outCollType.value() + << " which I don't understand. Possible values are: " + << "'xAOD::MuonContainer', " + << "'xAOD::JetContainer', " + << "'xAOD::ElectronContainer', " + << "'xAOD::PhotonContainer', " + << "'xAOD::TauJetContainer', " + << "'xAOD::PFOContainer', " + << "'xAOD::NeutralParticleContainer', " + << "'xAOD::TrackParticleContainer', " + << "'xAOD::TruthParticleContainer', " + << "'xAOD::CompositeParticleContainer', " + << "'xAOD::ParticleContainer', " + << "'xAOD::CaloClusterContainer'" ); + } + } + + // Determine the ownership policy of the output container + if ( m_outOwnPolicyName.value() == "OWN_ELEMENTS" ) { + m_outOwnPolicy = SG::OWN_ELEMENTS; + } + else if ( m_outOwnPolicyName.value() == "VIEW_ELEMENTS" ) { + m_outOwnPolicy = SG::VIEW_ELEMENTS; + } + else { + ATH_MSG_ERROR("Unrecognized ownership policy for the output container: " << m_outOwnPolicyName ); + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + + + + +StatusCode ParticleSelectionTool::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + + if (m_parser) { + delete m_parser; + m_parser = 0; + } + + return StatusCode::SUCCESS; +} + + + + +StatusCode ParticleSelectionTool::addBranches() const +{ + // Increase the event counter + ++m_nEventsProcessed; + + // Simple status message at the beginning of each event execute, + ATH_MSG_DEBUG ( "==> addBranches " << name() << " on " << m_nEventsProcessed << ". event..." ); + + //----------------------------------------- + // The meat happens here + //----------------------------------------- + ExpressionParsing::StackElement selectionResult = m_parser->evaluate(); + + if ( selectionResult.isScalar() ) { + ATH_MSG_ERROR( "We are expecting a vector result such that we can deduct " + << "which xAOD::IParticle inside the container passes and which doesn't. " + << "For example: 'Muons.pt>10*GeV', but NOT 'count(Muons.pt>10*GeV)>1'; here, " + << "the former gives us a boolean answer for every muon while " + << "the later gives us a boolean answer for the whole container of muons." ); + return StatusCode::FAILURE; + } + + if ( selectionResult.isVector() ) { + // We found a vector. Now, we can go ahead and retrieve the input container + // and book the output container(s) + const std::vector<int>& resultVec( selectionResult.vectorValue<int>() ); + + + // Get the input container and create the output containers + const xAOD::IParticleLinkContainer* inLinkContainer(0); + const xAOD::IParticleContainer* inContainer(0); + xAOD::IParticleLinkContainer* outLinkContainer(0); + + // Prepare all containers as needed + ATH_CHECK( this->prepareContainers( inLinkContainer, + inContainer, + outLinkContainer ) ); + + + // Check that the lengths are the same + if ( inLinkContainer && inLinkContainer->size() != resultVec.size() ) { + ATH_MSG_ERROR("We got an input link container, but its size (" << inLinkContainer->size() + << ") doesn't match the size of the result vector: " << resultVec.size() ); + return StatusCode::FAILURE; + } + 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; + } + + + + + // Actually, evaluate the result + ATH_CHECK( this->evaluate( resultVec, inLinkContainer, inContainer, outLinkContainer ) ); + + + } + else { + // what we found in the event store is neither a scalar nor a vector + // it must be of some awkward type that can't be used. + // Therefore, we fail + ATH_MSG_ERROR ("Some unexpected format of the expression parser result"); + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + + + + +StatusCode +ParticleSelectionTool::prepareContainers( const xAOD::IParticleLinkContainer*& inLinkContainer, + const xAOD::IParticleContainer*& inContainer, + xAOD::IParticleLinkContainer*& outLinkContainer ) const +{ + if ( evtStore()->contains< xAOD::IParticleLinkContainer >( m_inCollKey ) ) { + // Actually retrieve the LinkContainer from StoreGate + ATH_CHECK( evtStore()->retrieve( inLinkContainer , m_inCollKey ) ); + ATH_MSG_DEBUG ( "Input link collection = '" << m_inCollKey + << "' retrieved from StoreGate which has " << inLinkContainer->size() << " entries." ); + } + else if ( evtStore()->contains< xAOD::IParticleContainer >( m_inCollKey ) ) { + // This container holds an xAOD::IParticleContainer + ATH_CHECK( evtStore()->retrieve( inContainer, m_inCollKey ) ); + ATH_MSG_DEBUG ( "Input collection = " << m_inCollKey + << " retrieved from StoreGate which has " << inContainer->size() << " entries." ); + } + else { + if ( m_nEventsProcessed <= 10 ) { + ATH_MSG_WARNING ( "Input collection = " << m_inCollKey + << " could not be retrieved from StoreGate! " + << " This message will only be repeated 10 times..." ); + } + else { + ATH_MSG_DEBUG ( "Input collection = " << m_inCollKey + << " could not be retrieved from StoreGate! " ); + } + return StatusCode::SUCCESS; + } // End: if/elif/else is link container + + + // Create the IParticleLinkContainer for the output, if requested + if ( !(m_outLinkCollKey.value().empty()) ) { + outLinkContainer = new xAOD::IParticleLinkContainer(); + ATH_CHECK( evtStore()->record( outLinkContainer, m_outLinkCollKey.value() ) ); + ATH_MSG_DEBUG( "Recorded xAOD::IParticleLinkContainer with key: "<< m_outLinkCollKey.value() ); + } + + return StatusCode::SUCCESS; +} + + +// Define a pre-processor macro to easily create the new output containers. +// First, create all needed zero pointers. +// Second, create the output container and record it in StoreGate. +// Finally, try to figure out the most derived type of the input container and +// create the xAOD container and its auxiliary store: +#define CREATE_OUT_CONTAINERS( CONTAINERTYPE, AUXCONTAINERTYPE, \ + INCONTAINERNAME, OUTCONTAINERNAME, CONTID ) \ + const CONTAINERTYPE* INCONTAINERNAME(0); \ + CONTAINERTYPE* OUTCONTAINERNAME(0); \ + if ( (m_contID==0 || m_contID==CONTID) && !(m_outCollKey.value().empty()) ) { \ + if ( inContainer ) { \ + ATH_MSG_VERBOSE("Trying to cast input container to type const "#CONTAINERTYPE"*" ); \ + INCONTAINERNAME = dynamic_cast<const CONTAINERTYPE*>(inContainer); \ + if ( INCONTAINERNAME ) { \ + ATH_MSG_VERBOSE("Successfully casted input container to type const "#CONTAINERTYPE"*" ); \ + OUTCONTAINERNAME = new CONTAINERTYPE( m_outOwnPolicy ); \ + ATH_CHECK( evtStore()->record ( OUTCONTAINERNAME, m_outCollKey.value() ) ); \ + if ( m_outOwnPolicy == SG::OWN_ELEMENTS ) { \ + AUXCONTAINERTYPE* outAuxContainer = new AUXCONTAINERTYPE(); \ + ATH_CHECK( evtStore()->record( outAuxContainer, m_outCollKey.value() + "Aux." ) ); \ + OUTCONTAINERNAME->setStore( outAuxContainer ); \ + } \ + m_contID=CONTID; \ + ATH_MSG_DEBUG( "Recorded "#CONTAINERTYPE" with key: " << m_outCollKey.value() \ + << ", container identifier " << m_contID \ + << " and address " << OUTCONTAINERNAME ); \ + } \ + else { \ + ATH_MSG_DEBUG("Couldn't cast input container to type const "#CONTAINERTYPE"*" ); \ + } \ + } \ + else if ( inLinkContainer && m_contID==CONTID ) { \ + OUTCONTAINERNAME = new CONTAINERTYPE( m_outOwnPolicy ); \ + ATH_CHECK( evtStore()->record ( OUTCONTAINERNAME, m_outCollKey.value() ) ); \ + if ( m_outOwnPolicy == SG::OWN_ELEMENTS ) { \ + AUXCONTAINERTYPE* outAuxContainer = new AUXCONTAINERTYPE(); \ + ATH_CHECK( evtStore()->record( outAuxContainer, m_outCollKey.value() + "Aux." ) ); \ + OUTCONTAINERNAME->setStore( outAuxContainer ); \ + } \ + m_contID=CONTID; \ + ATH_MSG_DEBUG( "Recorded "#CONTAINERTYPE" with key: " << m_outCollKey.value() \ + << ", container identifier " << m_contID \ + << " and address " << OUTCONTAINERNAME ); \ + } \ + } + + + +// Fill the output container, if requested +#define FILL_OUT_CONTAINER( CONTAINERTYPE, PARTICLETYPE, \ + INCONTAINERNAME, OUTCONTAINERNAME ) \ + if ( OUTCONTAINERNAME ) { \ + if ( inLinkContainer ) { \ + ATH_MSG_VERBOSE(" Going to fill output container of type "#CONTAINERTYPE" from link input" ); \ + const xAOD::IParticleLink& partLink = inLinkContainer->at(i); \ + if ( partLink.isValid() ) { \ + const PARTICLETYPE* partPtr = dynamic_cast<const PARTICLETYPE*>(*partLink); \ + if (partPtr) { \ + if ( m_outOwnPolicy == SG::OWN_ELEMENTS ) { \ + PARTICLETYPE* newPart = new PARTICLETYPE(); \ + newPart->makePrivateStore(*partPtr); \ + OUTCONTAINERNAME->push_back( newPart ); \ + } \ + else { \ + OUTCONTAINERNAME->push_back( const_cast<PARTICLETYPE*>(partPtr) ); \ + } \ + ATH_MSG_VERBOSE("Adding an "#PARTICLETYPE" to the output " \ + "from the input xAOD::IParticleLinkContainer"); \ + } \ + else { \ + ATH_MSG_WARNING("Couldn't cast to a "#PARTICLETYPE". This should NOT happen!"); \ + } \ + } \ + else { \ + ATH_MSG_WARNING("Couldn't add an xAOD::IParticle to the output " \ + << "because the input ElementLink is not valid!"); \ + } \ + } \ + if ( INCONTAINERNAME ) { \ + ATH_MSG_VERBOSE(" Going to fill output container of type "#CONTAINERTYPE" from input" ); \ + const PARTICLETYPE* partPtr = INCONTAINERNAME->at(i); \ + if ( m_outOwnPolicy == SG::OWN_ELEMENTS ) { \ + PARTICLETYPE* newPart = new PARTICLETYPE(); \ + newPart->makePrivateStore(*partPtr); \ + OUTCONTAINERNAME->push_back( newPart ); \ + } \ + else { \ + OUTCONTAINERNAME->push_back( const_cast<PARTICLETYPE*>(partPtr) ); \ + } \ + ATH_MSG_VERBOSE("Adding an "#PARTICLETYPE" to the output " \ + "from the input "#CONTAINERTYPE ); \ + } \ + } /* End: if ( outContainer ) */ + + + + + +StatusCode +ParticleSelectionTool::evaluate( const std::vector<int>& resultVec, + const xAOD::IParticleLinkContainer* inLinkContainer, + const xAOD::IParticleContainer* inContainer, + xAOD::IParticleLinkContainer* outLinkContainer ) const +{ + // See if we already found the right container type + CREATE_OUT_CONTAINERS( xAOD::MuonContainer, xAOD::MuonAuxContainer, + muonInCont, muonOutContainer, 1 ) + CREATE_OUT_CONTAINERS( xAOD::JetContainer, xAOD::JetAuxContainer, + jetInCont, jetOutContainer, 2 ) + CREATE_OUT_CONTAINERS( xAOD::ElectronContainer, xAOD::ElectronAuxContainer, + electronInCont, electronOutContainer, 3 ) + CREATE_OUT_CONTAINERS( xAOD::PhotonContainer, xAOD::PhotonAuxContainer, + photonInCont, photonOutContainer, 4 ) + CREATE_OUT_CONTAINERS( xAOD::TauJetContainer, xAOD::TauJetAuxContainer, + tauJetInCont, tauJetOutContainer, 5 ) + CREATE_OUT_CONTAINERS( xAOD::PFOContainer, xAOD::PFOAuxContainer, + pfoInCont, pfoOutContainer, 6 ) + CREATE_OUT_CONTAINERS( xAOD::NeutralParticleContainer, xAOD::NeutralParticleAuxContainer, + neutralParticleInCont, neutralParticleOutContainer, 7 ) + CREATE_OUT_CONTAINERS( xAOD::TrackParticleContainer, xAOD::TrackParticleAuxContainer, + trackParticleInCont, trackParticleOutContainer, 8 ) + CREATE_OUT_CONTAINERS( xAOD::TruthParticleContainer, xAOD::TruthParticleAuxContainer, + truthParticleInCont, truthParticleOutContainer, 9 ) + CREATE_OUT_CONTAINERS( xAOD::CompositeParticleContainer, xAOD::CompositeParticleAuxContainer, + compositeParticleInCont, compositeParticleOutContainer, 10 ) + CREATE_OUT_CONTAINERS( xAOD::ParticleContainer, xAOD::ParticleAuxContainer, + particleInCont, particleOutContainer, 11 ) + CREATE_OUT_CONTAINERS( xAOD::CaloClusterContainer, xAOD::CaloClusterAuxContainer, + caloClusterInCont, caloClusterOutContainer, 12 ) + + + // Now, loop over the result vector and check which particles to write out + for ( std::size_t i=0; i<resultVec.size(); ++i ) { + // If this particle is not accepted, go to the next one + if ( !(resultVec[i]) ) { continue; } + + // Fill the output IParticleLinkContainer, if requested + if ( outLinkContainer ) { + ATH_MSG_VERBOSE("Going to fill output link container"); + if ( inLinkContainer ) { + outLinkContainer->push_back( inLinkContainer->at(i) ); + ATH_MSG_VERBOSE("Adding an xAOD::IParticleLink to the output " + "from the input xAOD::IParticleLinkContainer"); + } + if ( inContainer ) { + xAOD::IParticleLink partLink = xAOD::IParticleLink( *inContainer, i ); + outLinkContainer->push_back( partLink ); + ATH_MSG_VERBOSE("Adding an xAOD::IParticleLink to the output " + "from the input xAOD::IParticleContainer"); + } + } // End: if ( outLinkContainer ) + + if ( !(m_outCollKey.value().empty()) ) { + ATH_MSG_VERBOSE("Going to fill output container"); + FILL_OUT_CONTAINER( xAOD::MuonContainer, xAOD::Muon, + muonInCont, muonOutContainer ) + FILL_OUT_CONTAINER( xAOD::JetContainer, xAOD::Jet, + jetInCont, jetOutContainer ) + FILL_OUT_CONTAINER( xAOD::ElectronContainer, xAOD::Electron, + electronInCont, electronOutContainer ) + FILL_OUT_CONTAINER( xAOD::PhotonContainer, xAOD::Photon, + photonInCont, photonOutContainer ) + FILL_OUT_CONTAINER( xAOD::TauJetContainer, xAOD::TauJet, + tauJetInCont, tauJetOutContainer ) + FILL_OUT_CONTAINER( xAOD::PFOContainer, xAOD::PFO, + pfoInCont, pfoOutContainer ) + FILL_OUT_CONTAINER( xAOD::NeutralParticleContainer, xAOD::NeutralParticle, + neutralParticleInCont, neutralParticleOutContainer ) + FILL_OUT_CONTAINER( xAOD::TrackParticleContainer, xAOD::TrackParticle, + trackParticleInCont, trackParticleOutContainer ) + FILL_OUT_CONTAINER( xAOD::TruthParticleContainer, xAOD::TruthParticle, + truthParticleInCont, truthParticleOutContainer ) + FILL_OUT_CONTAINER( xAOD::CompositeParticleContainer, xAOD::CompositeParticle, + compositeParticleInCont, compositeParticleOutContainer ) + FILL_OUT_CONTAINER( xAOD::ParticleContainer, xAOD::Particle, + particleInCont, particleOutContainer ) + FILL_OUT_CONTAINER( xAOD::CaloClusterContainer, xAOD::CaloCluster, + caloClusterInCont, caloClusterOutContainer ) + } + + } // End: Loop over result vector (and input particle(link) vector) + + // Some final debug messages + if ( !(m_outLinkCollKey.value().empty()) ) { + ATH_MSG_DEBUG("Output link container with name " << m_outLinkCollKey.value() + << " has " << outLinkContainer->size() << " entries." ); + } + if ( !(m_outCollKey.value().empty()) && msgLvl(MSG::DEBUG) ) { + if (muonOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << muonOutContainer->size() << " entries." ); + } + else if (jetOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << jetOutContainer->size() << " entries." ); + } + else if (electronOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << electronOutContainer->size() << " entries." ); + } + else if (photonOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << photonOutContainer->size() << " entries." ); + } + else if (tauJetOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << tauJetOutContainer->size() << " entries." ); + } + else if (pfoOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << pfoOutContainer->size() << " entries." ); + } + else if (neutralParticleOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << neutralParticleOutContainer->size() << " entries." ); + } + else if (trackParticleOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << trackParticleOutContainer->size() << " entries." ); + } + else if (truthParticleOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << truthParticleOutContainer->size() << " entries." ); + } + else if (compositeParticleOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << compositeParticleOutContainer->size() << " entries." ); + } + else if (particleOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << particleOutContainer->size() << " entries." ); + } + else if (caloClusterOutContainer) { + ATH_MSG_DEBUG("Output container with name " << m_outCollKey.value() + << " has " << caloClusterOutContainer->size() << " entries." ); + } + } + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.h new file mode 100644 index 0000000000000000000000000000000000000000..69767598a1f6ad0a2694114bac1a858c70b3f4e7 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSelectionTool.h @@ -0,0 +1,137 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ParticleSelectionTool.h +// Header file for class ParticleSelectionTool +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef EVENTUTILS_PARTICLESELECTIONTOOL_H +#define EVENTUTILS_PARTICLESELECTIONTOOL_H 1 + +// STL includes +#include <vector> +#include <string> + +// FrameWork includes +#include "AthenaBaseComps/AthAlgTool.h" +#include "DerivationFrameworkInterfaces/IAugmentationTool.h" +#include "TrigDecisionTool/TrigDecisionTool.h" + +// EDM includes +#include "AthContainers/OwnershipPolicy.h" +#include "xAODBase/IParticleContainer.h" +#include "xAODParticleEvent/IParticleLinkContainer.h" + + +// Forward declarations +namespace ExpressionParsing { + class ExpressionParser; +} + + + +class ParticleSelectionTool + : virtual public ::DerivationFramework::IAugmentationTool, + public ::AthAlgTool +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// +public: + + // Copy constructor: + + /// Constructor with parameters: + ParticleSelectionTool( const std::string& type, + const std::string& name, + const IInterface* parent ); + + /// Destructor: + virtual ~ParticleSelectionTool(); + + /// Athena algtool's initialize + virtual StatusCode initialize(); + + /// Athena algtool's finalize + virtual StatusCode finalize(); + + + /// Implement the method from the ISkimmingTool interface + virtual StatusCode addBranches() const final override; + + + +// Private methods +private: + + /// A helper method to get the input containers is and + /// create and record the output link container + StatusCode + prepareContainers( const xAOD::IParticleLinkContainer*& inLinkContainer, + const xAOD::IParticleContainer*& inContainer, + xAOD::IParticleLinkContainer*& outLinkContainer ) const; + + + /// Helper method to actually iterate over the input particles and selection + /// results and fill the output container(s) + StatusCode + evaluate( const std::vector<int>& resultVec, + const xAOD::IParticleLinkContainer* inLinkContainer, + const xAOD::IParticleContainer* inContainer, + xAOD::IParticleLinkContainer* outLinkContainer ) const; + + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// +private: + /// The trigger decision tool + ToolHandle<Trig::TrigDecisionTool> m_trigDecisionTool; + + /// The expression parser + ExpressionParsing::ExpressionParser *m_parser; + + + /// Input container name + StringProperty m_inCollKey; + + /// Output collection name (deep copies of the original ones) + StringProperty m_outCollKey; + + /// The type of the output container, e.g., 'xAOD::JetContainer' + StringProperty m_outCollType; + + /// Defines the ownership policy of the output container + /// (default: 'OWN_ELEMENTS'; also allowed: 'VIEW_ELEMENTS')" + StringProperty m_outOwnPolicyName; + + /// The internally used translation for the ownership policy + SG::OwnershipPolicy m_outOwnPolicy; + + /// Output link collection name (ElementLinks to selected IParticles) + StringProperty m_outLinkCollKey; + + /// The cut string + StringProperty m_selection; + + + /// Internal container type identifier + mutable unsigned int m_contID; + + + /// Internal event counter + mutable unsigned long m_nEventsProcessed; + + +}; + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + + +#endif //> !EVENTUTILS_PARTICLESELECTIONTOOL_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..5893e290a0bb4ef9c137547657076e11727ec052 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.cxx @@ -0,0 +1,162 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ParticleSortingAlg.cxx +// Implementation file for class ParticleSortingAlg +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// + +// EventUtils includes +#include "ParticleSortingAlg.h" + +// STL includes + +// FrameWork includes +#include "GaudiKernel/Property.h" +#include "GaudiKernel/IJobOptionsSvc.h" +#include "DerivationFrameworkInterfaces/IAugmentationTool.h" + + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +ParticleSortingAlg::ParticleSortingAlg( const std::string& name, + ISvcLocator* pSvcLocator ) : + ::AthAlgorithm( name, pSvcLocator ), + m_jos("JobOptionsSvc", name), + m_tool("ParticleSortingTool/ParticleSortingTool", this), + m_inCollKey(""), + m_setInCollKey(false), + m_outCollKey(""), + m_setOutCollKey(false), + m_sortVar("pt"), + m_setSortVar(false), + m_sortDecending(true), + m_setSortDecending(false), + m_nEventsProcessed(0) +{ + declareProperty("JobOptionsSvc", m_jos, "The JobOptionService instance."); + + declareProperty("SkimTool", m_tool, "The private ParticleSortingTool" ); + + declareProperty("InputContainer", m_inCollKey="", "Input container name" ); + m_inCollKey.declareUpdateHandler( &ParticleSortingAlg::setupInputContainer, this ); + + declareProperty("OutputContainer", m_outCollKey="", + "The name of the output container with the sorted deep copy of input objects" ); + m_outCollKey.declareUpdateHandler( &ParticleSortingAlg::setupOutputContainer, this ); + + declareProperty("SortVariable", m_sortVar="pt", + "Define by what parameter to sort (default: 'pt'; allowed: 'pt', 'eta', 'phi', 'm', 'e', 'rapidity')" ); + m_sortVar.declareUpdateHandler( &ParticleSortingAlg::setupSortVar, this ); + + declareProperty("SortDecending", m_sortDecending=true, + "Define if the container should be sorted in a decending order (default=true)" ); + m_sortDecending.declareUpdateHandler( &ParticleSortingAlg::setupSortDecending, this ); +} + + + +// Destructor +/////////////// +ParticleSortingAlg::~ParticleSortingAlg() +{} + + + +// Athena Algorithm's Hooks +//////////////////////////// +StatusCode ParticleSortingAlg::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_sortVar ); + ATH_MSG_DEBUG ( " using = " << m_sortDecending ); + + + // 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) ); + } + if (m_setOutCollKey) { + ATH_MSG_DEBUG( "Setting property" << m_outCollKey + << " of private tool with name: '" << fullToolName << "'" ); + ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_outCollKey) ); + } + if (m_setSortVar) { + ATH_MSG_DEBUG( "Setting property" << m_sortVar + << " of private tool with name: '" << fullToolName << "'" ); + ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_sortVar) ); + } + if (m_setSortDecending) { + ATH_MSG_DEBUG( "Setting property" << m_sortDecending + << " of private tool with name: '" << fullToolName << "'" ); + ATH_CHECK( m_jos->addPropertyToCatalogue (fullToolName,m_sortDecending) ); + } + ATH_MSG_DEBUG( "Done setting properties of the tool"); + + // Get the skimming tool + ATH_CHECK( m_tool.retrieve() ); + + ATH_MSG_DEBUG ( "==> done with initialize " << name() << "..." ); + + return StatusCode::SUCCESS; +} + + + +StatusCode ParticleSortingAlg::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + + // Release all tools and services + ATH_CHECK( m_jos.release() ); + ATH_CHECK( m_tool.release() ); + + return StatusCode::SUCCESS; +} + + + +StatusCode ParticleSortingAlg::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 + ATH_CHECK( m_tool->addBranches() ); + + return StatusCode::SUCCESS; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..b07ac4afb0c233fd38ad16858f26e98dccd56d99 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingAlg.h @@ -0,0 +1,153 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ParticleSortingAlg.h +// Header file for class ParticleSortingAlg +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef EVENTUTILS_PARTICLESORTINGALG_H +#define EVENTUTILS_PARTICLESORTINGALG_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "GaudiKernel/ToolHandle.h" +#include "GaudiKernel/ServiceHandle.h" +#include "AthenaBaseComps/AthAlgorithm.h" + + +// forward declarations +class IJobOptionsSvc; +namespace DerivationFramework { + class IAugmentationTool; +} + + + + +class ParticleSortingAlg + : public ::AthAlgorithm +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + // Copy constructor: + + /// Constructor with parameters: + ParticleSortingAlg( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~ParticleSortingAlg(); + + /// 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: + // 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 'SortVariable' property + void setupSortVar( Property& /*prop*/ ); + + /// This internal method will realize if a user sets the 'SortDeceding' property + void setupSortDecending( 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 ToolHandle to the private ParticleSortingTool + ToolHandle<DerivationFramework::IAugmentationTool> m_tool; + + /// Input container name + StringProperty m_inCollKey; + + /// This boolean is true if the user sets the 'InputContainer' property + bool m_setInCollKey; + + + /// 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; + + + /// Define by what parameter to sort (default: 'pt') + StringProperty m_sortVar; + + /// This boolean is true if the user sets the 'SortVariable' property + bool m_setSortVar; + + + /// Define if the container should be sorted in a decending order (default=true) + BooleanProperty m_sortDecending; + + /// This boolean is true if the user sets the 'SortDecending' property + bool m_setSortDecending; + + + /// Internal event counter + unsigned long m_nEventsProcessed; + +}; + + + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + +/// This internal method will realize if a user sets the 'InputContainer' property +inline void ParticleSortingAlg::setupInputContainer( Property& /*prop*/ ) { + m_setInCollKey = true; + return; +} + +/// This internal method will realize if a user sets the 'OutputContainer' property +inline void ParticleSortingAlg::setupOutputContainer( Property& /*prop*/ ) { + m_setOutCollKey = true; + return; +} + +/// This internal method will realize if a user sets the 'SortVariable' property +inline void ParticleSortingAlg::setupSortVar( Property& /*prop*/ ) +{ + m_setSortVar = true; + return; +} + +/// This internal method will realize if a user sets the 'SortDeceding' property +inline void ParticleSortingAlg::setupSortDecending( Property& /*prop*/ ) +{ + m_setSortDecending = true; + return; +} + + +#endif //> !EVENTUTILS_PARTICLESORTINGALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.cxx new file mode 100644 index 0000000000000000000000000000000000000000..8e38247f585d16ea507d693bc034e40a9bfec89b --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.cxx @@ -0,0 +1,269 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ParticleSortingTool.cxx +// Implementation file for class ParticleSortingTool +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// + + +// EventUtils includes +#include "ParticleSortingTool.h" + +// STL includes +#include <vector> +#include <string> + +// FrameWork includes + +// EDM includes +#include "xAODBase/IParticle.h" +#include "xAODBase/IParticleContainer.h" +#include "xAODMuon/MuonContainer.h" +#include "xAODJet/JetContainer.h" +#include "xAODEgamma/ElectronContainer.h" +#include "xAODEgamma/PhotonContainer.h" +#include "xAODTau/TauJetContainer.h" +#include "xAODPFlow/PFOContainer.h" +#include "xAODTracking/NeutralParticleContainer.h" +#include "xAODTracking/TrackParticleContainer.h" +#include "xAODTruth/TruthParticleContainer.h" +#include "xAODParticleEvent/CompositeParticleContainer.h" +#include "xAODParticleEvent/ParticleContainer.h" +#include "xAODCaloEvent/CaloClusterContainer.h" + + + +// Constructors +//////////////// +ParticleSortingTool::ParticleSortingTool( const std::string& type, + const std::string& name, + const IInterface* parent ) : + ::AthAlgTool ( type, name, parent ), + m_inCollKey(""), + m_outCollKey(""), + m_sortVar("pt"), + m_sortDecending(true), + m_contID(0), + m_sortID(0), + m_nEventsProcessed(0) +{ + declareInterface< DerivationFramework::IAugmentationTool >(this); + + declareProperty("InputContainer", m_inCollKey="", "Input container name" ); + + declareProperty("OutputContainer", m_outCollKey="", + "The name of the output container with the sorted deep copy of input objects" ); + + declareProperty("SortVariable", m_sortVar="pt", + "Define by what parameter to sort (default: 'pt'; allowed: 'pt', 'eta', 'phi', 'm', 'e', 'rapidity')" ); + + declareProperty("SortDecending", m_sortDecending=true, + "Define if the container should be sorted in a decending order (default=true)" ); +} + + +// Destructor +/////////////// +ParticleSortingTool::~ParticleSortingTool() +{} + + + +// Athena algtool's Hooks +//////////////////////////// +StatusCode ParticleSortingTool::initialize() +{ + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + + // Print out the used configuration + ATH_MSG_DEBUG ( " using = " << m_inCollKey ); + ATH_MSG_DEBUG ( " using = " << m_outCollKey ); + + // initialize the counters + m_contID = 0; + m_sortID = 0; + m_nEventsProcessed = 0; + + // Figure out how to sort + if ( m_sortVar.value() == "pt" ) { m_sortID = 1; } + else if ( m_sortVar.value() == "eta" ) { m_sortID = 2; } + else if ( m_sortVar.value() == "phi" ) { m_sortID = 3; } + else if ( m_sortVar.value() == "m" ) { m_sortID = 4; } + else if ( m_sortVar.value() == "e" ) { m_sortID = 5; } + else if ( m_sortVar.value() == "rapidity" ) { m_sortID = 6; } + else { + ATH_MSG_ERROR("Didn't find a valid value for 'SortVariable'." + << " Allowed values are: 'pt', 'eta', 'phi', 'm', 'e', 'rapidity'"); + return StatusCode::FAILURE; + } + if ( m_sortDecending.value() ) { m_sortID *= -1; } + + return StatusCode::SUCCESS; +} + + + + +StatusCode ParticleSortingTool::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + + return StatusCode::SUCCESS; +} + + + +// Declare a short pre-processor macro to deal with the different container types +#define COPY_AND_SORT_CONTAINER( CONTAINERTYPE ) \ +ATH_MSG_DEBUG("Trying to copy, sort, and record container of type "#CONTAINERTYPE ); \ +if ( evtStore()->contains<CONTAINERTYPE>( m_inCollKey.value() ) ) { \ + const CONTAINERTYPE* inCont; \ + ATH_CHECK( evtStore()->retrieve( inCont, m_inCollKey.value() ) ); \ + CONTAINERTYPE* outCont = new CONTAINERTYPE( SG::VIEW_ELEMENTS ); \ + *outCont = *inCont; \ + ATH_CHECK( evtStore()->record ( outCont, m_outCollKey.value() ) ); \ + ATH_CHECK( this->doSort(outCont) ); \ +} + + + + +StatusCode ParticleSortingTool::addBranches() const +{ + // Increase the event counter + ++m_nEventsProcessed; + + // Simple status message at the beginning of each event execute, + ATH_MSG_DEBUG ( "==> addBranches " << name() << " on " << m_nEventsProcessed << ". event..." ); + + if ( m_outCollKey.value().empty() ) { + // Try to get the input container as non-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) ); + } + else { + ATH_MSG_DEBUG("Got a non-empty 'OutputCollection' property. " + << "Trying to retrieve a const version of the 'InputContainer'..."); + + // Now, do the copy and sorting of all known container types + COPY_AND_SORT_CONTAINER(xAOD::MuonContainer); + COPY_AND_SORT_CONTAINER(xAOD::ElectronContainer); + COPY_AND_SORT_CONTAINER(xAOD::PhotonContainer); + COPY_AND_SORT_CONTAINER(xAOD::TauJetContainer); + COPY_AND_SORT_CONTAINER(xAOD::JetContainer); + COPY_AND_SORT_CONTAINER(xAOD::PFOContainer); + COPY_AND_SORT_CONTAINER(xAOD::NeutralParticleContainer); + COPY_AND_SORT_CONTAINER(xAOD::TrackParticleContainer); + COPY_AND_SORT_CONTAINER(xAOD::TruthParticleContainer); + COPY_AND_SORT_CONTAINER(xAOD::CompositeParticleContainer); + COPY_AND_SORT_CONTAINER(xAOD::ParticleContainer); + COPY_AND_SORT_CONTAINER(xAOD::CaloClusterContainer); + + } + + return StatusCode::SUCCESS; +} + + + +StatusCode ParticleSortingTool::doSort( xAOD::IParticleContainer* cont ) const +{ + if ( !cont ) { + ATH_MSG_ERROR("No container 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); + } ); + } + + return StatusCode::SUCCESS; +} + + +bool ParticleSortingTool::comparePt( const xAOD::IParticle* partA, + const xAOD::IParticle* partB ) const +{ + const double a = partA->pt(); + const double b = partB->pt(); + return this->compareDouble(a,b); +} + + +bool ParticleSortingTool::compareEta( const xAOD::IParticle* partA, + const xAOD::IParticle* partB ) const +{ + const double a = partA->eta(); + const double b = partB->eta(); + return this->compareDouble(a,b); +} + + +bool ParticleSortingTool::comparePhi( const xAOD::IParticle* partA, + const xAOD::IParticle* partB ) const +{ + const double a = partA->phi(); + const double b = partB->phi(); + return this->compareDouble(a,b); +} + + +bool ParticleSortingTool::compareMass( const xAOD::IParticle* partA, + const xAOD::IParticle* partB ) const +{ + const double a = partA->m(); + const double b = partB->m(); + return this->compareDouble(a,b); +} + + +bool ParticleSortingTool::compareEnergy( const xAOD::IParticle* partA, + const xAOD::IParticle* partB ) const +{ + const double a = partA->e(); + const double b = partB->e(); + return this->compareDouble(a,b); +} + + +bool ParticleSortingTool::compareRapidity( const xAOD::IParticle* partA, + const xAOD::IParticle* partB ) const +{ + const double a = partA->rapidity(); + const double b = partB->rapidity(); + return this->compareDouble(a,b); +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.h new file mode 100644 index 0000000000000000000000000000000000000000..d4b8bb66f6e22a39fd168326d869a2a41c2d5a2f --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/ParticleSortingTool.h @@ -0,0 +1,124 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// ParticleSortingTool.h +// Header file for class ParticleSortingTool +// Author: Karsten Koeneke <karsten.koeneke@cern.ch> +/////////////////////////////////////////////////////////////////// +#ifndef EVENTUTILS_PARTICLESORTINGTOOL_H +#define EVENTUTILS_PARTICLESORTINGTOOL_H 1 + +// STL includes +#include <vector> +#include <string> + +// FrameWork includes +#include "AthenaBaseComps/AthAlgTool.h" +#include "DerivationFrameworkInterfaces/IAugmentationTool.h" + +// EDM inlcudes +#include "xAODBase/IParticle.h" +#include "xAODBase/IParticleContainer.h" + + + +class ParticleSortingTool + : virtual public ::DerivationFramework::IAugmentationTool, + public ::AthAlgTool +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// +public: + + // Copy constructor: + + /// Constructor with parameters: + ParticleSortingTool( const std::string& type, + const std::string& name, + const IInterface* parent ); + + /// Destructor: + virtual ~ParticleSortingTool(); + + /// Athena algtool's initialize + virtual StatusCode initialize(); + + /// Athena algtool's finalize + virtual StatusCode finalize(); + + + /// Implement the method from the ISkimmingTool interface + virtual StatusCode addBranches() const final override; + + + +// Private methods +private: + + /// Helper method that implements the call to the right sort function + StatusCode doSort( xAOD::IParticleContainer* cont ) const; + + /// The method to compare the particle's pt + bool comparePt( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const; + + /// The method to compare the particle's eta + bool compareEta( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const; + + /// The method to compare the particle's phi + bool comparePhi( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const; + + /// The method to compare the particle's mass + bool compareMass( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const; + + /// The method to compare the particle's energy + bool compareEnergy( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const; + + /// The method to compare the particle's rapidity + bool compareRapidity( const xAOD::IParticle* partA, const xAOD::IParticle* partB ) const; + + /// Method to compare two doubles + inline bool compareDouble( double a, double b ) const; + + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// +private: + + /// Input container name + StringProperty m_inCollKey; + + /// Output collection name (deep copies of the original ones) + StringProperty m_outCollKey; + + /// Define by what parameter to sort (default: 'pt') + StringProperty m_sortVar; + + /// Define if the container should be sorted in a decending order (default=true) + BooleanProperty m_sortDecending; + + + /// Internal container type identifier + mutable unsigned int m_contID; + + /// Internal identifier for the type of sorting + mutable int m_sortID; + + /// Internal event counter + mutable unsigned long m_nEventsProcessed; + +}; + + +inline bool ParticleSortingTool::compareDouble( double a, double b ) const +{ + if ( m_sortID < 0 ) { return ( a > b ); } + else { return ( a < b ); } +} + +#endif //> !EVENTUTILS_PARTICLESORTINGTOOL_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/SkimDecisionRunPeriodAwareFilterAlg.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/SkimDecisionRunPeriodAwareFilterAlg.cxx new file mode 100644 index 0000000000000000000000000000000000000000..dd979d4bbb16b0d8e177d672b2be082aaf8db022 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/SkimDecisionRunPeriodAwareFilterAlg.cxx @@ -0,0 +1,361 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// SkimDecisionRunPeriodAwareFilterAlg.cxx +// Implementation file for class SkimDecisionRunPeriodAwareFilterAlg +// Author: Karsten Koeneke karsten.koeneke@cern.ch +/////////////////////////////////////////////////////////////////// + +// SelectionUtils includes +#include "SkimDecisionRunPeriodAwareFilterAlg.h" + +// STL includes +#include <string> +#include <vector> + +// boost includes +#include <boost/algorithm/string.hpp> + +// FrameWork includes +#include "GaudiKernel/Property.h" + +// EDM includes +#include "EventBookkeeperMetaData/SkimDecisionCollection.h" +#include "EventBookkeeperMetaData/SkimDecision.h" +#include "EventInfo/EventInfo.h" +#include "EventInfo/EventType.h" +#include "EventInfo/EventID.h" + +// ROOT includes +#include "TRandom3.h" + + +/////////////////////////////////////////////////////////////////// +// Public methods: +/////////////////////////////////////////////////////////////////// + +// Constructors +//////////////// +SkimDecisionRunPeriodAwareFilterAlg::SkimDecisionRunPeriodAwareFilterAlg( const std::string& name, + ISvcLocator* pSvcLocator ) : + ::AthFilterAlgorithm( name, pSvcLocator ) +{ + // + // Property declaration + // + declareProperty( "SkimDecisionCollection", m_skimDecContName, "The name (key) of the SkimDecisionCollection to use" ); + declareProperty( "SkimDecisionNameList", m_skimDecNameList, + "The list of SkimDecision names to accept; within one run number block, use ',' as seperator" ); + declareProperty( "DataBeginRunNumberList", m_dataBeginRunNumList, "The list of run numbers where a block begins (for data)" ); + declareProperty( "DataEndRunNumberList", m_dataEndRunNumList, "The list of run numbers where a block ends (for data)" ); + declareProperty( "MCBeginRunNumberList", m_mcBeginRunNumList, "The list of run numbers where a block begins (for MC)" ); + declareProperty( "MCEndRunNumberList", m_mcEndRunNumList, "The list of run numbers where a block ends (for MC)" ); + declareProperty( "MCRelativeLumiList", m_mcRelLumiList, + "The list of relate integrated luminosities (fractional) for each MC run-number block (set to something larger than 1.0 if valid for a whole range)" ); +} + + + +// Destructor +/////////////// +SkimDecisionRunPeriodAwareFilterAlg::~SkimDecisionRunPeriodAwareFilterAlg() +{} + + + +// Athena Algorithm's Hooks +//////////////////////////// + +// Called once before the event loop starts by the Athena framework +StatusCode SkimDecisionRunPeriodAwareFilterAlg::initialize() +{ + ATH_MSG_DEBUG ("Initializing " << name() << "..."); + ATH_MSG_DEBUG (" using SkimDecisionCollection = " << m_skimDecContName ); + ATH_MSG_DEBUG (" using SkimDecisionNameList = " << m_skimDecNameList ); + ATH_MSG_DEBUG (" using DataBeginRunNumberList = " << m_dataBeginRunNumList ); + ATH_MSG_DEBUG (" using DataEndRunNumberList = " << m_dataEndRunNumList ); + ATH_MSG_DEBUG (" using MCBeginRunNumberList = " << m_mcBeginRunNumList ); + ATH_MSG_DEBUG (" using MCEndRunNumberList = " << m_mcEndRunNumList ); + ATH_MSG_DEBUG (" using MCRelativeLumiList = " << m_mcRelLumiList ); + + // Try to find the commas in the SkimDecisionNameList and make a list of lists + // and initialize the index vectors to -1 + for ( unsigned int i=0; i<m_skimDecNameList.size(); ++i ) + { + std::vector<std::string> tokens; + boost::split(tokens, m_skimDecNameList[i], boost::is_any_of(",")); + m_skimDecNameListList.push_back(tokens); + std::vector<int> indices; + for ( unsigned int j=0; j<tokens.size(); ++j ) + { + indices.push_back(-1); + } + m_skimDecIdxListList.push_back(indices); + } + + // Make some sanity checks + bool allOK(true); + if ( m_skimDecNameListList.size() != m_dataBeginRunNumList.size() + || m_skimDecNameListList.size() != m_dataEndRunNumList.size() ) + { + ATH_MSG_FATAL ("SkimDecisionNameList has different size from DataBeginRunNumberList or DataEndRunNumberList" ); + allOK = false; + } + if ( m_mcBeginRunNumList.size() != 0 || m_mcEndRunNumList.size() != 0 ) + { + if ( m_skimDecNameListList.size() != m_mcBeginRunNumList.size() + || m_skimDecNameListList.size() != m_mcEndRunNumList.size() + || m_skimDecNameListList.size() != m_mcRelLumiList.size() ) + { + ATH_MSG_FATAL ("SkimDecisionNameList has different size from MCBeginRunNumberList or MCEndRunNumberList or MCRelativeLumiList" ); + allOK = false; + } + } + + if ( !allOK ) + { + return StatusCode::FAILURE; + } + + return StatusCode::SUCCESS; +} + + + +// Called once after the event loop is finished by the Athena framework +StatusCode SkimDecisionRunPeriodAwareFilterAlg::finalize() +{ + ATH_MSG_DEBUG ("Finalizing " << name() << "..."); + + return StatusCode::SUCCESS; +} + + + +// Called once per event by the Athena framework +StatusCode SkimDecisionRunPeriodAwareFilterAlg::execute() +{ + ATH_MSG_DEBUG ("Executing " << name() << "..."); + + // Get the EventInfo object + const EventInfo* eventInfo(NULL); + ATH_CHECK( evtStore()->retrieve(eventInfo) ); + + // Get the SkimDecisionCollection + const SkimDecisionCollection* skimDecCont(NULL); + ATH_CHECK( evtStore()->retrieve( skimDecCont, m_skimDecContName ) ); + + + // See if we have MC or data and get the run number + bool isSim = eventInfo->event_type()->test(EventType::IS_SIMULATION); + unsigned int runnumber = eventInfo->event_ID()->run_number(); + unsigned int eventnumber = eventInfo->event_ID()->event_number(); + + + // Event pass decision + bool passAccept(false); + + // For data =================================================== + if ( !isSim ) + { + ATH_MSG_VERBOSE( "Detected that I am running on data. Current run number=" << runnumber ); + unsigned int outerSize( m_dataBeginRunNumList.size() ); + if ( outerSize == 0 ) passAccept = true; + for ( unsigned int i=0; i<outerSize; ++i ) + { + // Get the right run number range + if ( runnumber >= m_dataBeginRunNumList[i] && runnumber <= m_dataEndRunNumList[i] ) + { + ATH_MSG_VERBOSE( "Found right run number range with index i=" << i ); + // Now, loop over the inner list for the current run-number range + unsigned int innerSize( m_skimDecNameListList[i].size() ); + for ( unsigned int j=0; j<innerSize; ++j ) + { + if ( this->skimDecisionNameIsAccepted( skimDecCont, m_skimDecNameListList[i][j], m_skimDecIdxListList, i, j ) ) + { + ATH_MSG_DEBUG( "Found SkimDecision in data with name " << m_skimDecNameListList[i][j] + << " from SkimDecisionNameList in SkimDecisionCollection with key " << m_skimDecContName ); + setFilterPassed( true ); + return StatusCode::SUCCESS; + } + } // End: inner loop over all accept requests + } // End: check that we are in the right run number range + } // End: loop over run number ranges + } + // For MC =================================================== + else + { + ATH_MSG_VERBOSE( "Detected that I am running on simulation. Current run number=" << runnumber ); + // First, get the MC channel number and calculate the seed for the random number generator + unsigned int mcchannelnumber = eventInfo->event_type()->mc_channel_number(); + unsigned int seed = mcchannelnumber * eventnumber; + + // Get the random number generator + TRandom3 random3; + + unsigned int outerSize( m_mcBeginRunNumList.size() ); + if ( outerSize == 0 ) passAccept = true; + for ( unsigned int i=0; i<outerSize; ++i ) + { + // Get the right run number range + if ( runnumber >= m_mcBeginRunNumList[i] && runnumber <= m_mcEndRunNumList[i] ) + { + ATH_MSG_VERBOSE( "Found right run number range with index i=" << i ); + // Get the current fraction of lumi for this range + double lumiFrac = m_mcRelLumiList[i]; + bool needIncrement(false); + if ( lumiFrac < 1.0 ) + { + random3.SetSeed(seed); + double rdmNum = random3.Uniform(); + if ( rdmNum >= lumiFrac ) // go to the next outer index + { + i += 1; + } + else + { + needIncrement = true; + } + } + + // Check that we didn't leave the boundary of the vector + if ( i >= outerSize ) + { + ATH_MSG_FATAL ("We ran over the lenghts of the vector of the SkimDecisionNameList!" ); + setFilterPassed( false ); + return StatusCode::FAILURE; + } + + // Now, loop over the inner list for the current run-number range + unsigned int innerSize( m_skimDecNameListList[i].size() ); + for ( unsigned int j=0; j<innerSize; ++j ) + { + if ( this->skimDecisionNameIsAccepted( skimDecCont, m_skimDecNameListList[i][j], m_skimDecIdxListList, i, j ) ) + { + ATH_MSG_DEBUG( "Found SkimDecision in MC with name " << m_skimDecNameListList[i][j] + << " from SkimDecisionNameList in SkimDecisionCollection with key " << m_skimDecContName ); + setFilterPassed( true ); + return StatusCode::SUCCESS; + } + } // End: inner loop over all accept requests + + // Increment to jump over the next entry in this run period + if ( needIncrement ) + { + i += 1; + } + + } // End: check that we are in the right run number range + } // End: loop over run number ranges + + } // End: if/else !isMC + + + // Determine the global event passing decision + setFilterPassed( passAccept ); + + return StatusCode::SUCCESS; +} + + + + + + + + + +// Private helper method to find the SkimDecision isAccepted() answer +bool SkimDecisionRunPeriodAwareFilterAlg::skimDecisionNameIsAccepted( const SkimDecisionCollection* skimDecCont, + std::string& skimDecName, + std::vector< std::vector<int> >& skimDecIdxList, + unsigned int idxA, + unsigned int idxB ) +{ + // Pointer check + if ( !skimDecCont ) + { + ATH_MSG_WARNING( "Got a zero pointer of type SkimDecisionCollection with key " << m_skimDecContName ); + return false; + } + + // Get the size of the SkimDecisionCollection + const unsigned int skimCollSize = skimDecCont->size(); + + // If we already have an index, choose the fast path + if ( skimDecIdxList[idxA][idxB] >= 0 && skimDecIdxList[idxA][idxB] < (int)skimCollSize ) + { + const SkimDecision* skimDec = skimDecCont->at(skimDecIdxList[idxA][idxB]); + if ( !skimDec ) + { + ATH_MSG_WARNING( "Couldn't find SkimDecision with name " << skimDecName + << " in SkimDecisionCollection with key " << m_skimDecContName ); + return false; + } + + // If the name is correct for the given index + if ( skimDec->getName() == skimDecName ) + { + return skimDec->isAccepted(); + } + else // The index was wrong and we need to search for the name + { + // Loop over all SkimDecisions in the SkimDecisionCollection + bool foundSkimDec(false); + for ( unsigned int i=0; i<skimCollSize; ++i ) + { + // Get the current SkimDecision + const SkimDecision* skimDec = skimDecCont->at(i); + if ( !skimDec ) continue; + + // Found the right skim decision + if ( skimDecName == skimDec->getName() ) + { + skimDecIdxList[idxA][idxB] = (int)i; // Set the index to the found one + foundSkimDec = true; + return skimDec->isAccepted(); + } + } + // If none of the SkimDecision names matched + if ( !foundSkimDec ) + { + ATH_MSG_WARNING( "Couldn't find SkimDecision with name " << skimDecName + << " in SkimDecisionCollection with key " << m_skimDecContName ); + return false; + } + } + } // End: if we have a valid index + else // The index was wrong and we need to search for the name + { + // Loop over all SkimDecisions in the SkimDecisionCollection + bool foundSkimDec(false); + for ( unsigned int i=0; i<skimCollSize; ++i ) + { + // Get the current SkimDecision + const SkimDecision* skimDec = skimDecCont->at(i); + if ( !skimDec ) continue; + + // Found the right skim decision + if ( skimDecName == skimDec->getName() ) + { + skimDecIdxList[idxA][idxB] = (int)i; // Set the index to the found one + foundSkimDec = true; + return skimDec->isAccepted(); + } + } + // If none of the SkimDecision names matched + if ( !foundSkimDec ) + { + ATH_MSG_WARNING( "Couldn't find SkimDecision with name " << skimDecName + << " in SkimDecisionCollection with key " << m_skimDecContName ); + return false; + } + } + // If we got to here, something went wrong + ATH_MSG_WARNING( "We should have never reached this part of the code! Tried to search for SkimDecision with name " << skimDecName + << " in SkimDecisionCollection with key " << m_skimDecContName ); + return false; +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/SkimDecisionRunPeriodAwareFilterAlg.h b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/SkimDecisionRunPeriodAwareFilterAlg.h new file mode 100644 index 0000000000000000000000000000000000000000..537c75f14189e9369ce93390cce5a76051aa07af --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/SkimDecisionRunPeriodAwareFilterAlg.h @@ -0,0 +1,122 @@ +///////////////////////// -*- C++ -*- ///////////////////////////// + +/* + Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +*/ + +// SkimDecisionRunPeriodAwareFilterAlg.h +// Header file for class SkimDecisionRunPeriodAwareFilterAlg +// Author: Karsten Koeneke +/////////////////////////////////////////////////////////////////// +#ifndef EVENTUTILS_SKIMDECISIONRUNPERIODAWAREFILTERALG_H +#define EVENTUTILS_SKIMDECISIONRUNPERIODAWAREFILTERALG_H 1 + +// STL includes +#include <string> + +// FrameWork includes +#include "AthenaBaseComps/AthFilterAlgorithm.h" + +// Forward declarations +class SkimDecisionCollection; + + + +class SkimDecisionRunPeriodAwareFilterAlg + : public ::AthFilterAlgorithm +{ + + /////////////////////////////////////////////////////////////////// + // Public methods: + /////////////////////////////////////////////////////////////////// + public: + + // Copy constructor: + + /// Constructor with parameters: + SkimDecisionRunPeriodAwareFilterAlg( const std::string& name, ISvcLocator* pSvcLocator ); + + /// Destructor: + virtual ~SkimDecisionRunPeriodAwareFilterAlg(); + + // Assignment operator: + //SkimDecisionRunPeriodAwareFilterAlg &operator=(const SkimDecisionRunPeriodAwareFilterAlg &alg); + + // Athena algorithm's Hooks + virtual StatusCode initialize(); + virtual StatusCode execute(); + virtual StatusCode finalize(); + + /////////////////////////////////////////////////////////////////// + // Const methods: + /////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////// + // Non-const methods: + /////////////////////////////////////////////////////////////////// +private: + + /// Private method to determine the accept decission + bool skimDecisionNameIsAccepted( const SkimDecisionCollection* skimDecCont, + std::string& skimDecName, + std::vector< std::vector<int> >& skimDecIdxList, + unsigned int idxA, + unsigned int idxB ); + + + + /////////////////////////////////////////////////////////////////// + // Private data: + /////////////////////////////////////////////////////////////////// + private: + + /// Default constructor: + //SkimDecisionRunPeriodAwareFilterAlg(); + + /// Containers + + /// SkimDecisionCollection name + std::string m_skimDecContName; + + + /// The list of SkimDecision names to accept + std::vector< std::string > m_skimDecNameList; + + + /// The list of SkimDecision names to accept for each run period (can be multiple in each run period) + std::vector< std::vector< std::string > > m_skimDecNameListList; + + + /// The list of run numbers where a block begins (for data) + std::vector< unsigned int > m_dataBeginRunNumList; + + /// The list of run numbers where a block ends (for data) + std::vector< unsigned int > m_dataEndRunNumList; + + + /// The list of run numbers where a block begins (for MC) + std::vector< unsigned int > m_mcBeginRunNumList; + + /// The list of run numbers where a block ends (for MC) + std::vector< unsigned int > m_mcEndRunNumList; + + /// The list of relate integrated luminosities (fractional) for each MC run-number block + std::vector< double > m_mcRelLumiList; + + + /// List of the indices where the correct SkimDecision is in the container for the accept (logical OR) method + //std::vector<int> m_skimDecIdxList; + std::vector< std::vector< int > > m_skimDecIdxListList; + + +}; + +// I/O operators +////////////////////// + +/////////////////////////////////////////////////////////////////// +// Inline methods: +/////////////////////////////////////////////////////////////////// + + +#endif //> !EVENTUTILS_SKIMDECISIONRUNPERIODAWAREFILTERALG_H diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_entries.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_entries.cxx new file mode 100644 index 0000000000000000000000000000000000000000..b7cef176dd7a0161c67a0753c74976522532b0ee --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_entries.cxx @@ -0,0 +1,43 @@ +#include "GaudiKernel/DeclareFactoryEntries.h" + +#include "../ParticleSortingTool.h" +#include "../ParticleSortingAlg.h" +#include "../AddVarTool.h" +#include "../AddVarAlg.h" +#include "../CutTool.h" +#include "../CutAlg.h" +#include "../ParticleSelectionTool.h" +#include "../ParticleSelectionAlg.h" +#include "../ParticleCombinerTool.h" +#include "../ParticleCombinerAlg.h" +#include "../EventQualityFilterAlg.h" +#include "../SkimDecisionRunPeriodAwareFilterAlg.h" + +DECLARE_TOOL_FACTORY( ParticleSortingTool ) +DECLARE_ALGORITHM_FACTORY( ParticleSortingAlg ) +DECLARE_TOOL_FACTORY( AddVarTool ) +DECLARE_ALGORITHM_FACTORY( AddVarAlg ) +DECLARE_TOOL_FACTORY( CutTool ) +DECLARE_ALGORITHM_FACTORY( CutAlg ) +DECLARE_TOOL_FACTORY( ParticleSelectionTool ) +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 ); +} diff --git a/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_load.cxx b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_load.cxx new file mode 100644 index 0000000000000000000000000000000000000000..ab3a5223455fd642a6671fcd3d2bacaea277b6d1 --- /dev/null +++ b/PhysicsAnalysis/AnalysisCommon/EventUtils/src/components/EventUtils_load.cxx @@ -0,0 +1,2 @@ +#include "GaudiKernel/LoadFactoryEntries.h" +LOAD_FACTORY_ENTRIES(EventUtils)