Skip to content
Snippets Groups Projects
Commit 9af7f188 authored by Nils Krumnack's avatar Nils Krumnack
Browse files

make AsgxAODMetNTupleMakerAlg for writing out individual MET terms

This is essentially a heavily modified version of
AsgxAODNTupleMakerAlg for the specific purpose at hand, i.e. writing
out MET variables as `float` instead of `std::vector<float>`.

There is probably some overlap of code with the original algorithm,
but I'd rather clean that up at a later point, as I anyways have to
revisit how I handle the output n-tuples in a better way.
parent 884aaf54
No related branches found
No related tags found
No related merge requests found
......@@ -51,7 +51,7 @@ def addOutputCopyAlgorithms (algSeq, postfix, inputContainer, outputContainer, s
algSeq += copyalg
def makeSequenceOld (dataType, algSeq, vars, forCompare, isPhyslite, noPhysliteBroken) :
def makeSequenceOld (dataType, algSeq, vars, metVars, forCompare, isPhyslite, noPhysliteBroken) :
# Include, and then set up the pileup analysis sequence:
prwfiles, lumicalcfiles = pileupConfigFiles(dataType)
......@@ -339,11 +339,10 @@ def makeSequenceOld (dataType, algSeq, vars, forCompare, isPhyslite, noPhysliteB
# Add the sequence to the job:
algSeq += metSequence
vars += [
metVars += [
'AnaMET_%SYS%.mpx -> met_mpx_%SYS%',
'AnaMET_%SYS%.mpy -> met_mpy_%SYS%',
'AnaMET_%SYS%.sumet -> met_sumet_%SYS%',
'AnaMET_%SYS%.name -> met_name_%SYS%',
]
......@@ -448,7 +447,7 @@ def makeSequenceOld (dataType, algSeq, vars, forCompare, isPhyslite, noPhysliteB
def makeSequenceBlocks (dataType, algSeq, vars, forCompare, isPhyslite, noPhysliteBroken) :
def makeSequenceBlocks (dataType, algSeq, vars, metVars, forCompare, isPhyslite, noPhysliteBroken) :
configSeq = ConfigSequence ()
......@@ -621,11 +620,10 @@ def makeSequenceBlocks (dataType, algSeq, vars, forCompare, isPhyslite, noPhysli
muons = 'AnaMuons.medium',
electrons = 'AnaElectrons.loose',
photons = 'AnaPhotons.tight')
vars += [
metVars += [
'AnaMET_%SYS%.mpx -> met_mpx_%SYS%',
'AnaMET_%SYS%.mpy -> met_mpy_%SYS%',
'AnaMET_%SYS%.sumet -> met_sumet_%SYS%',
'AnaMET_%SYS%.name -> met_name_%SYS%',
]
......@@ -699,11 +697,12 @@ def makeSequence (dataType, useBlocks, forCompare, noSystematics, hardCuts = Fal
sysService.sigmaRecommended = 1
vars = []
metVars = []
if not useBlocks :
makeSequenceOld (dataType, algSeq, vars=vars, forCompare=forCompare,
makeSequenceOld (dataType, algSeq, vars=vars, metVars=metVars, forCompare=forCompare,
isPhyslite=isPhyslite, noPhysliteBroken=noPhysliteBroken)
else :
makeSequenceBlocks (dataType, algSeq, vars=vars, forCompare=forCompare,
makeSequenceBlocks (dataType, algSeq, vars=vars, metVars=metVars, forCompare=forCompare,
isPhyslite=isPhyslite, noPhysliteBroken=noPhysliteBroken)
......@@ -718,6 +717,12 @@ def makeSequence (dataType, useBlocks, forCompare, noSystematics, hardCuts = Fal
ntupleMaker.Branches = vars
# ntupleMaker.OutputLevel = 2 # For output validation
algSeq += ntupleMaker
if len (metVars) > 0:
ntupleMaker = createAlgorithm( 'CP::AsgxAODMetNTupleMakerAlg', 'MetNTupleMaker' )
ntupleMaker.TreeName = 'analysis'
ntupleMaker.Branches = metVars
#ntupleMaker.OutputLevel = 2 # For output validation
algSeq += ntupleMaker
treeFiller = createAlgorithm( 'CP::TreeFillerAlg', 'TreeFiller' )
treeFiller.TreeName = 'analysis'
algSeq += treeFiller
......
......@@ -21,6 +21,7 @@
#include <AsgAnalysisAlgorithms/AsgUnionSelectionAlg.h>
#include <AsgAnalysisAlgorithms/AsgViewFromSelectionAlg.h>
#include <AsgAnalysisAlgorithms/AsgxAODNTupleMakerAlg.h>
#include <AsgAnalysisAlgorithms/AsgxAODMetNTupleMakerAlg.h>
#include <AsgAnalysisAlgorithms/EventFlagSelectionAlg.h>
#include <AsgAnalysisAlgorithms/EventSelectionByObjectFlagAlg.h>
#include <AsgAnalysisAlgorithms/IsolationCloseByCorrectionAlg.h>
......
// Dear emacs, this is -*- c++ -*-
//
// Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
//
#ifndef ASGANALYSISALGORITHMS_ASGXAODMETNTUPLEMAKERALG_H
#define ASGANALYSISALGORITHMS_ASGXAODMETNTUPLEMAKERALG_H
// // Framework include(s):
#include "AnaAlgorithm/AnaAlgorithm.h"
#include "AsgMessaging/AsgMessaging.h"
#include "AsgServices/ServiceHandle.h"
#include "AsgTools/PropertyWrapper.h"
#include "CxxUtils/checker_macros.h"
#include "SystematicsHandles/ISystematicsSvc.h"
// EDM include(s):
#include "AthContainers/AuxElement.h"
namespace CP {
/// Algorithm that can write MET variables to a simple ntuple from
/// xAOD objects/variables
///
/// This is a version of \ref AsgxAODNTupleMakerAlg specifically
/// for writing out the MET variables. MET variables are special
/// in that they are in a container, but we really only care about
/// the last entry in that container (i.e. "Final"). So this
/// algorithm retrieves the container and then only writes out
/// variables for a single AuxElement. For details on this
/// algorithm please check the original algorithm.
///
/// @author Attila Krasznahorkay <Attila.Krasznahorkay@cern.ch> (for original algorithm)
/// @author Nils Krumnack <Nils.Erik.Krumnack@cern.ch> (for this algorithm)
///
class ATLAS_NOT_THREAD_SAFE AsgxAODMetNTupleMakerAlg : public EL::AnaAlgorithm {
public:
/// Algorithm constructor
AsgxAODMetNTupleMakerAlg( const std::string& name, ISvcLocator* svcLoc );
/// @name Functions inherited from @c EL::AnaAlgorithm
/// @{
/// Function executed as part of the job initialisation
StatusCode initialize() override;
/// Function executed once per event
StatusCode execute() override;
/// Function executed as part of the job finalisation
StatusCode finalize() override;
/// @}
private:
/// Function setting up the internal data structures on the first event
StatusCode setupTree();
/// Function setting up an individual branch on the first event
StatusCode setupBranch( const std::string &branchDecl,
const CP::SystematicSet &sys );
/// @name Algorithm properties
/// @{
/// The name of the output tree to write
Gaudi::Property<std::string> m_treeName {this, "TreeName", "physics", "Name of the tree to write"};
/// The branches to write into this output tree
Gaudi::Property<std::vector< std::string >> m_branches {this, "Branches", {}, "Branches to write to the output tree"};
/// @}
/// Class writing all variables from one standalone object
///
/// It is designed to work with any type inheriting from
/// @c SG::AuxElement. Like @c xAOD::EventInfo. Which is its main user
/// at the moment...
///
class ElementProcessor : public asg::AsgMessaging {
public:
/// Default constructor
///
/// We have to have a default constructor to initialise the
/// @c asg::AsgMessaging base class correctly. Members of this class
/// would not need an explicit constructor themselves.
///
ElementProcessor();
/// Process the object
///
/// This function is called during the event processing to extract
/// all configured variables from a standalone xAOD object into the
/// output variables set up using @c ElementProcessor::addBranch.
///
/// @param element The xAOD (interface) object to process
/// @return The usual @c StatusCode values
///
StatusCode process( const SG::AuxElement& element );
/// Add one branch to the output tree
///
/// This function is used during the setup of the output tree to create
/// one branch in it, from one specific auxiliary variable. The type of
/// the variable is figured out at runtime using the auxiliary store
/// infrastructure.
///
/// @param tree The tree to create the branch in
/// @param auxName Name of the auxiliary variable to create the branch
/// from
/// @param branchName The name of the branch to create in the tree
/// @param allowMissing Set to @c true to print an error message in case
/// of a failure
/// @param created Used to store if the branch was actually created
/// @return The usual @c StatusCode values
///
StatusCode addBranch( TTree& tree, const std::string& auxName,
const std::string& branchName,
bool allowMissing,
bool &created );
private:
/// Class writing one variable from an xAOD object into a branch
///
/// It is used for both setting up the branch in the outut @c TTree
/// during the setup of the tree, and then to fill the "output
/// variable" with the right payload during the event processing.
///
/// Note that since we may have a *lot* of such objects, I didn't want
/// to make it inherit from @c asg::AsgMessaging. Which means that all
/// of the class's functions need to receive its parent's message
/// stream object to be able to log error messages "nicely".
///
/// Also note that since this is very much an internal class, all of
/// its members are public. Since the owner of such objects should know
/// perfectly well how they behave.
///
class BranchProcessor {
public:
/// Function setting up the object, and the branch
///
/// This is pretty much the constructor of the class. I just decided
/// to implement it as a regular function and not a "real"
/// constructor, to be able to return a @c StatusCode value from the
/// call. Since the setup of the object may very well fail.
///
/// @param tree The tree to set up the new branch in
/// @param auxName The name of the auxiliary variable to create
/// a branch from
/// @param branchName Name of the branch to create in the tree
/// @param msg Reference to the parent's @c MsgStream object
/// @return The usual @c StatusCode values
///
StatusCode setup( TTree& tree, const std::string& auxName,
const std::string& branchName,
MsgStream& msg );
/// Function processing the object, filling the variable
///
/// This function is called by @c ElementProcessor, to extract one
/// variable from the standalone object, and move its payload into
/// the memory address from which the output tree is writing its
/// branch.
///
/// @param element The standalone object to get the auxiliary
/// variable from
/// @param msg Reference to the parent's @c MsgStream object
/// @return The usual @c StatusCode values
///
StatusCode process( const SG::AuxElement& element,
MsgStream& msg );
/// Name of the branch being written
std::string m_branchName;
/// Object accessing the variable in question
std::unique_ptr< SG::AuxElement::TypelessConstAccessor > m_acc;
/// Pointer to the helper object that handles this variable
const SG::IAuxTypeVectorFactory* m_factory = nullptr;
/// The object managing the memory of the written variable
std::unique_ptr< SG::IAuxTypeVector > m_data;
/// Helper variable, pointing at the object to be written
void* m_dataPtr = nullptr;
}; // class BranchProcessor
/// List of branch processors set up for this xAOD object
///
/// Note that when we set up a branch, we tell @c TTree to remember a
/// physical address in memory. To make sure that the address of the
/// object held by the branch processors are not moved in memory after
/// their construction, we have to use an @c std::list container here.
/// @c std::vector would not work. (As it can relocate objects when
/// increasing the size of the container.)
///
std::list< BranchProcessor > m_branches;
}; // class ElementProcessor
/// @name Variables used for the TTree filling
/// @{
/// The tree being written
TTree* m_tree = nullptr;
/// Objects to write branches from
std::unordered_map< std::string, ElementProcessor > m_elements;
/// Internal status flag, showing whether the algorithm is initialised
///
/// This is necessary because we can only set up the output @c TTree while
/// processing the first event, we can't do it in
/// @c CP::AsgxAODMetNTupleMakerAlg::initialize.
///
bool m_isInitialized = false;
Gaudi::Property<std::string> m_termName {this, "termName", "Final", "the name of the MissingET term to save"};
/// \brief the handle for the systematics service
ServiceHandle<ISystematicsSvc> m_systematicsService {this, "systematicsSvc", "SystematicsSvc", "systematics service"};
/// @}
}; // class AsgxAODMetNTupleMakerAlg
} // namespace CP
#endif // ASGANALYSISALGORITHMS_ASGXAODNTUPLEMAKERALG_H
......@@ -14,6 +14,7 @@
<class name="CP::AsgUnionSelectionAlg" />
<class name="CP::AsgViewFromSelectionAlg" />
<class name="CP::AsgxAODNTupleMakerAlg" />
<class name="CP::AsgxAODMetNTupleMakerAlg" />
<class name="CP::EventFlagSelectionAlg" />
<class name="CP::EventSelectionByObjectFlagAlg" />
<class name="CP::IsolationCloseByCorrectionAlg" />
......
......@@ -14,7 +14,7 @@ atlas_add_library( AsgAnalysisAlgorithmsLib
xAODEventInfo xAODCutFlow SelectionHelpersLib SystematicsHandlesLib PATCoreLib
AnaAlgorithmLib AsgAnalysisInterfaces AssociationUtilsLib
EventBookkeeperToolsLib IsolationSelectionLib PMGAnalysisInterfacesLib
PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} PATInterfaces xAODCore xAODMetaData xAODJet xAODMuon xAODTau xAODEgamma
PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} PATInterfaces xAODCore xAODMetaData xAODJet xAODMuon xAODTau xAODEgamma xAODMissingET
xAODTracking xAODTruth xAODRootAccess RootCoreUtils )
atlas_add_dictionary( AsgAnalysisAlgorithmsDict
......
// Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
// Local include(s):
#include "AsgAnalysisAlgorithms/AsgxAODMetNTupleMakerAlg.h"
// EDM include(s):
#include "AthContainers/normalizedTypeinfoName.h"
#include "xAODMissingET/MissingETContainer.h"
// ROOT include(s):
#include <TTree.h>
// System include(s):
#include <regex>
// Framework include(s):
#include "PATInterfaces/SystematicSet.h"
namespace {
/// This function is used internally in the code when creating primitive
/// branches. I just took the code from xAODRootAccess, which itself too it
/// from SFrame... :-P
///
/// @param typeidType The type name coming from typeid(...).name()
/// @param msg The caller's @c MsgStream object
/// @return The character describing this type for @c TTree::Branch
///
char rootType( char typeidType, MsgStream& msg ) {
// Do the hard-coded translation:
switch( typeidType ) {
case 'c':
return 'B';
break;
case 'h':
return 'b';
break;
case 's':
return 'S';
break;
case 't':
return 's';
break;
case 'i':
return 'I';
break;
case 'j':
return 'i';
break;
case 'f':
return 'F';
break;
case 'd':
return 'D';
break;
case 'x':
return 'L';
break;
case 'y':
case 'm': // Not sure how platform-independent this one is...
return 'l';
break;
case 'b':
return 'O';
break;
default:
// If we didn't find this type:
msg << MSG::ERROR << "Received an unknown type: " << typeidType
<< endmsg;
return '\0';
break;
}
}
/// Check if an aux item exists in the aux store
///
/// @param key The name of the container in the event store
/// @return True if branch exists, false if not
///
bool auxItemExists( const std::string& key ) {
// Get a pointer to the vector factory.
const SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance();
// Try to find the aux item
return reg.findAuxID( key ) != SG::null_auxid;
}
} // private namespace
namespace CP {
AsgxAODMetNTupleMakerAlg::AsgxAODMetNTupleMakerAlg( const std::string& name,
ISvcLocator* svcLoc )
: EL::AnaAlgorithm( name, svcLoc ) {
}
StatusCode AsgxAODMetNTupleMakerAlg::initialize() {
// Check that at least one branch is configured.
if( m_branches.empty() ) {
ATH_MSG_ERROR( "No branches set up for writing" );
return StatusCode::FAILURE;
}
// Set up the systematics list.
ATH_CHECK( m_systematicsService.retrieve() );
// Reset the initialisation flag:
m_isInitialized = false;
// Return gracefully.
return StatusCode::SUCCESS;
}
StatusCode AsgxAODMetNTupleMakerAlg::execute() {
// Initialise the processor objects on the first event.
if( ! m_isInitialized ) {
// Initialise the output tree.
m_tree = tree( m_treeName );
if( ! m_tree ) {
ATH_MSG_ERROR( "Could not find output tree \"" << m_treeName
<< "\"" );
return StatusCode::FAILURE;
}
// Call the setup function.
ATH_CHECK( setupTree() );
// The processor objects are now set up.
m_isInitialized = true;
}
// Process the standalone objects:
for( auto& element_itr : m_elements ) {
const xAOD::MissingETContainer *met = nullptr;
ANA_CHECK (evtStore()->retrieve (met, element_itr.first));
ANA_CHECK( element_itr.second.process( *(*met)[m_termName] ) );
}
// Return gracefully.
return StatusCode::SUCCESS;
}
StatusCode AsgxAODMetNTupleMakerAlg::finalize() {
// Return gracefully.
return StatusCode::SUCCESS;
}
StatusCode AsgxAODMetNTupleMakerAlg::setupTree() {
// First process nominal
CP::SystematicSet nominal{};
for( const std::string& branchDecl : m_branches ) {
ATH_CHECK( setupBranch( branchDecl, nominal ) );
}
// Consider all systematics but skip the nominal one
for( const auto& sys : m_systematicsService->makeSystematicsVector() ) {
// Nominal already processed
if( sys.empty() ) {
continue;
}
// Iterate over the branch specifications.
for( const std::string& branchDecl : m_branches ) {
ATH_CHECK( setupBranch( branchDecl, sys ) );
}
}
// Return gracefully.
return StatusCode::SUCCESS;
}
StatusCode AsgxAODMetNTupleMakerAlg::setupBranch( const std::string &branchDecl,
const CP::SystematicSet &sys ) {
// The regular expression used to extract the needed info. The logic
// is supposed to be:
//
// (match[1]).(match[2])<any whitespace>-><any whitespace>(match[3])
//
// Like:
// "Electrons.eta -> el_eta"
//
// , where we would pick up "Electrons", "eta" and "el_eta" as the
// three words using this regexp.
static const std::regex
re( "\\s*([\\w%]+)\\.([\\w%]+)\\s*->\\s*([\\w%]+)" );
// Interpret this branch declaration.
std::smatch match;
if( ! std::regex_match( branchDecl, match, re ) ) {
ATH_MSG_ERROR( "Expression \"" << branchDecl
<< "\" doesn't match \"<object>.<variable> ->"
" <branch>\"" );
return StatusCode::FAILURE;
}
// Check if we are running nominal
bool nominal = sys.empty();
// Check if we are affected by the systematics
bool systematicsContainer{false};
bool systematicsDecoration{false};
bool affectedContainer{true};
bool affectedDecoration{true};
// Event store key for the object under consideration.
std::string key = match[ 1 ];
if( key.find( "%SYS%" ) != std::string::npos )
{
systematicsContainer = true;
const CP::SystematicSet affecting = m_systematicsService->getObjectSystematics( key );
CP::SystematicSet matching;
ANA_CHECK( SystematicSet::filterForAffectingSystematics( sys, affecting, matching ) );
if( !nominal && matching.empty() ) {
ATH_MSG_VERBOSE( "Container \"" << key << "\" is not affected by systematics \"" << sys.name() << "\"" );
affectedContainer = false;
}
ANA_CHECK( m_systematicsService->makeSystematicsName( key, match[ 1 ], matching ) );
}
// Auxiliary variable name for the object under consideration.
std::string auxName = match[ 2 ];
if( auxName.find( "%SYS%" ) != std::string::npos )
{
systematicsDecoration = true;
CP::SystematicSet affecting = m_systematicsService->getDecorSystematics( match[ 1 ], auxName );
if( affecting.empty() )
{
// Sometimes while object systematics were applied we are not interested in them,
// NOSYS will then be used on the container name.
// Decoration systematics however will only be aware of containers with %SYS% included.
// Some special handling is needed to translate from NOSYS back to %SYS%.
const auto nosysInKey = key.find( "NOSYS" );
if( nosysInKey != std::string::npos )
{
std::string sysKey = key;
sysKey.replace (nosysInKey, 5, "%SYS%");
// these will be all systematics (object+decor)
const CP::SystematicSet affectingDecor = m_systematicsService->getDecorSystematics( sysKey, auxName );
// we now need to filter-out object systematics
const CP::SystematicSet affectingObject = m_systematicsService->getObjectSystematics( sysKey );
for( const CP::SystematicVariation &variation : affectingDecor )
{
if( affectingObject.find( variation ) == affectingObject.end() )
{
affecting.insert( variation );
}
}
}
}
CP::SystematicSet matching;
ANA_CHECK( SystematicSet::filterForAffectingSystematics( sys, affecting, matching ) );
if( !nominal && matching.empty() ) {
ATH_MSG_VERBOSE( "Decoration \"" << auxName << "\" is not affected by systematics \"" << sys.name() << "\"" );
affectedDecoration = false;
}
ANA_CHECK( m_systematicsService->makeSystematicsName( auxName, match[ 2 ], matching ) );
}
// Ignore the branch if neither container nor decoration are affected by the systematic
if( !nominal
&& ( ( systematicsContainer && systematicsDecoration && !affectedContainer && !affectedDecoration )
|| ( !systematicsContainer && systematicsDecoration && !affectedDecoration )
|| ( systematicsContainer && !systematicsDecoration && !affectedContainer ) ) )
{
ANA_MSG_VERBOSE( "Neither container nor decoration are affected by systematics \"" << sys.name() << "\""
<< " for branch rule \"" << branchDecl << "\"" );
return StatusCode::SUCCESS;
}
// Branch name for the variable.
std::string brName = match[ 3 ];
if( brName.find( "%SYS%" ) != std::string::npos )
ANA_CHECK (m_systematicsService->makeSystematicsName( brName, match[ 3 ], sys ));
// If the %SYS% pattern was not used in this setup, then stop
// on non-nominal systematic.
if( ! nominal &&
( key == match[ 1 ] ) && ( auxName == match[ 2 ] ) &&
( brName == match[ 3 ] ) ) {
return StatusCode::SUCCESS;
}
// Check that we use the %SYS% pattern reasonably in the names.
if( ( ( key == match[ 1 ] ) && ( auxName == match[ 2 ] ) &&
( brName != match[ 3 ] ) ) ||
( ( ( key != match[ 1 ] ) || ( auxName != match[ 2 ] ) ) &&
( brName == match[ 3 ] ) ) ) {
ATH_MSG_ERROR( "The systematic variation pattern is used "
"inconsistently in: \"" << branchDecl
<< "\"" );
return StatusCode::FAILURE;
}
// Flag keeping track whether any branch was set up for this rule.
static const bool ALLOW_MISSING = false;
bool branchCreated = false;
{
bool created = false;
ATH_CHECK( m_elements[ key ].addBranch( *m_tree,
auxName,
brName,
ALLOW_MISSING,
created ) );
if( created ) {
ATH_MSG_DEBUG( "Writing branch \"" << brName
<< "\" from object/variable \"" << key
<< "." << auxName << "\"" );
branchCreated = true;
} else {
ATH_MSG_DEBUG( "Skipping branch \"" << brName
<< "\" from object/variable \"" << key
<< "." << auxName << "\"" );
}
}
// Check if the rule was meaningful or not:
if( ! branchCreated ) {
ATH_MSG_ERROR( "No branch was created for rule: \""
<< branchDecl << "\""
<< " and systematics: \""
<< sys.name() << "\"" );
return StatusCode::FAILURE;
}
// Return gracefully.
return StatusCode::SUCCESS;
}
AsgxAODMetNTupleMakerAlg::ElementProcessor::ElementProcessor()
: asg::AsgMessaging( "CP::AsgxAODMetNTupleMakerAlg::ElementProcessor" ) {
}
StatusCode AsgxAODMetNTupleMakerAlg::ElementProcessor::
process( const SG::AuxElement& element ) {
// Process all branches.
for( BranchProcessor& p : m_branches ) {
ATH_CHECK( p.process( element, msg() ) );
}
// Return gracefully.
return StatusCode::SUCCESS;
}
StatusCode AsgxAODMetNTupleMakerAlg::ElementProcessor::
addBranch( TTree& tree, const std::string& auxName,
const std::string& branchName,
bool allowMissing,
bool &created ) {
/// Helper class for finding an already existing branch processor.
class BranchFinder {
public:
/// Type of the predicate's argument
typedef const BranchProcessor& argument_type;
/// Constructor with key/name
BranchFinder( const std::string& branchName ) : m_name( branchName ) {}
/// Operator evaluating whether this is the branch we're looking for
bool operator()( argument_type bp ) const {
return ( bp.m_branchName == m_name );
}
private:
std::string m_name; ///< Name of the branch
}; // class BranchFinder
// Check if the corresponding aux item exists
bool validAuxItem = auxItemExists( auxName );
if( ! validAuxItem ) {
if( allowMissing ) {
// Return gracefully.
ATH_MSG_DEBUG( "Aux item \"" << auxName
<< "\" not readable for branch \""
<< branchName << "\"" );
return StatusCode::SUCCESS;
} else {
// Return gracefully.
ATH_MSG_ERROR( "Aux item \"" << auxName
<< "\" not readable for branch \""
<< branchName << "\"" );
return StatusCode::FAILURE;
}
}
// Check whether this branch is already set up:
auto itr = std::find_if( m_branches.begin(), m_branches.end(),
BranchFinder( branchName ) );
if( itr != m_branches.end() ) {
ATH_MSG_WARNING( "Duplicate setup received for branch: " << branchName );
return StatusCode::SUCCESS;
}
created = true;
// Set up the new branch.
m_branches.emplace_back();
ATH_CHECK( m_branches.back().setup( tree, auxName, branchName, msg() ) );
// Return gracefully.
return StatusCode::SUCCESS;
}
StatusCode
AsgxAODMetNTupleMakerAlg::ElementProcessor::BranchProcessor::
setup( TTree& tree, const std::string& auxName,
const std::string& branchName, MsgStream& msg ) {
// Remember the branch name.
m_branchName = branchName;
// Create the accessor.
m_acc.reset( new SG::AuxElement::TypelessConstAccessor( auxName ) );
// Get a pointer to the vector factory.
const SG::AuxTypeRegistry& reg = SG::AuxTypeRegistry::instance();
const std::type_info* ti = reg.getType( m_acc->auxid() );
if( ! ti ) {
msg << MSG::ERROR
<< "No std::type_info available for auxiliary variable: "
<< auxName << endmsg;
return StatusCode::FAILURE;
}
m_factory = reg.getFactory( *ti );
if( ! m_factory ) {
msg << MSG::ERROR << "No factory found for auxiliary variable: "
<< auxName << endmsg;
return StatusCode::FAILURE;
}
// Create the data object.
m_data = m_factory->create( 1, 1 );
// Pointer to the branch, to be created.
TBranch* br = nullptr;
// Decide whether we're dealing with a "primitive" or an "object" branch.
if( strlen( ti->name() ) == 1 ) {
// This is a "primitive" variable...
// Get the type identifier for it that ROOT will understand.
const char rType = rootType( ti->name()[ 0 ], msg );
if( rType == '\0' ) {
msg << MSG::ERROR << "Type not recognised for variable: "
<< branchName << endmsg;
return StatusCode::FAILURE;
}
// Construct the type description.
std::ostringstream typeDesc;
typeDesc << branchName << "/" << rType;
// Create the primitive branch.
br = tree.Branch( branchName.c_str(), m_data->toPtr(),
typeDesc.str().c_str() );
} else {
// This is an "object" variable...
// Get a proper type name for the variable.
const std::string typeName = SG::normalizedTypeinfoName( *ti );
// Access the dictionary for the type.
TClass* cl = TClass::GetClass( *ti );
if( ! cl ) {
cl = TClass::GetClass( typeName.c_str() );
}
if( ! cl ) {
msg << MSG::ERROR << "Couldn't find dictionary for type: "
<< typeName << endmsg;
return StatusCode::FAILURE;
}
if( ! cl->GetStreamerInfo() ) {
msg << MSG::ERROR << "No streamer info available for type: "
<< cl->GetName() << endmsg;
return StatusCode::FAILURE;
}
// Create the object branch.
m_dataPtr = m_data->toPtr();
br = tree.Branch( branchName.c_str(), cl->GetName(), &m_dataPtr );
}
// Check that the branch creation succeeded.
if( ! br ) {
msg << MSG::ERROR << "Failed to create branch: " << branchName
<< endmsg;
return StatusCode::FAILURE;
}
// Return gracefully.
return StatusCode::SUCCESS;
}
StatusCode
AsgxAODMetNTupleMakerAlg::ElementProcessor::BranchProcessor::
process( const SG::AuxElement& element, MsgStream& msg ) {
// A security check.
if( ( ! m_acc ) || ( ! m_factory ) || ( ! m_data ) ) {
msg << MSG::FATAL << "Internal logic error detected" << endmsg;
return StatusCode::FAILURE;
}
// Get the data out of the xAOD object.
const void* auxData = ( *m_acc )( element );
// Copy it into the output variable.
m_factory->copy( m_data->toPtr(), 0, auxData, 0 );
// Return gracefully.
return StatusCode::SUCCESS;
}
} // namespace CP
......@@ -17,6 +17,7 @@
#include <AsgAnalysisAlgorithms/AsgUnionSelectionAlg.h>
#include <AsgAnalysisAlgorithms/AsgViewFromSelectionAlg.h>
#include <AsgAnalysisAlgorithms/AsgxAODNTupleMakerAlg.h>
#include <AsgAnalysisAlgorithms/AsgxAODMetNTupleMakerAlg.h>
#include <AsgAnalysisAlgorithms/EventFlagSelectionAlg.h>
#include <AsgAnalysisAlgorithms/EventSelectionByObjectFlagAlg.h>
#include <AsgAnalysisAlgorithms/IsolationCloseByCorrectionAlg.h>
......@@ -42,6 +43,7 @@ DECLARE_COMPONENT (CP::AsgShallowCopyAlg)
DECLARE_COMPONENT (CP::AsgUnionSelectionAlg)
DECLARE_COMPONENT (CP::AsgViewFromSelectionAlg)
DECLARE_COMPONENT (CP::AsgxAODNTupleMakerAlg)
DECLARE_COMPONENT (CP::AsgxAODMetNTupleMakerAlg)
DECLARE_COMPONENT (CP::EventFlagSelectionAlg)
DECLARE_COMPONENT (CP::EventSelectionByObjectFlagAlg)
DECLARE_COMPONENT (CP::IsolationCloseByCorrectionAlg)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment