From dcf27b2b17483bcd8c3dd9a77922a8d59935cddc Mon Sep 17 00:00:00 2001 From: Graham Richard Lee <graham.richard.lee@cern.ch> Date: Wed, 5 Dec 2018 13:53:05 +0000 Subject: [PATCH] InDetTruthVertexValidation merge request Former-commit-id: 59dcc6cd30155480e0f05ad6007d8e3d9efbeb77 --- .../InDetTruthVertexValidation/CMakeLists.txt | 62 +++ .../IInDetVertexTruthMatchTool.h | 32 ++ .../InDetVertexTruthMatchTool.h | 54 +++ .../InDetVertexTruthMatchUtils.h | 53 +++ .../Root/InDetVertexTruthMatchTool.cxx | 422 ++++++++++++++++++ .../Root/InDetVertexTruthMatchUtils.cxx | 128 ++++++ .../InDetTruthVertexValidation/Root/LinkDef.h | 23 + .../share/VertexTruthMatch_jobOptions.py | 27 ++ .../src/InDetVertexTruthMatchAlgorithm.cxx | 43 ++ .../src/InDetVertexTruthMatchAlgorithm.h | 34 ++ .../InDetTruthVertexValidation_entries.cxx | 13 + .../InDetTruthVertexValidation_load.cxx | 7 + .../util/VertexTruthMatchTest.cxx | 145 ++++++ 13 files changed, 1043 insertions(+) create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/CMakeLists.txt create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/IInDetVertexTruthMatchTool.h create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/InDetVertexTruthMatchTool.h create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/InDetVertexTruthMatchUtils.h create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/InDetVertexTruthMatchTool.cxx create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/InDetVertexTruthMatchUtils.cxx create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/LinkDef.h create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/share/VertexTruthMatch_jobOptions.py create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/src/InDetVertexTruthMatchAlgorithm.cxx create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/src/InDetVertexTruthMatchAlgorithm.h create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/src/components/InDetTruthVertexValidation_entries.cxx create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/src/components/InDetTruthVertexValidation_load.cxx create mode 100644 InnerDetector/InDetValidation/InDetTruthVertexValidation/util/VertexTruthMatchTest.cxx diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/CMakeLists.txt b/InnerDetector/InDetValidation/InDetTruthVertexValidation/CMakeLists.txt new file mode 100644 index 00000000000..8d9c36b25eb --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/CMakeLists.txt @@ -0,0 +1,62 @@ +################################################################################ +# Package: InDetTruthVertexValidation +################################################################################ + +# Declare the package name: +atlas_subdir( InDetTruthVertexValidation ) + +# Extra dependencies, based on the build environment: +set( extra_deps ) +set( extra_libs ) +if( XAOD_STANDALONE ) + set( extra_deps Control/xAODRootAccess + PhysicsAnalysis/D3PDTools/EventLoop ) + set( extra_libs xAODRootAccess EventLoop ) +else() + set( extra_deps PRIVATE Control/AthenaBaseComps PhysicsAnalysis/POOLRootAccess GaudiKernel ) + set( extra_libs AthAnalysisBaseCompsLib ) +endif() + + +# Declare the package's dependencies: +atlas_depends_on_subdirs( PUBLIC + Control/AthToolSupport/AsgTools + Event/xAOD/xAODTracking + Event/xAOD/xAODTruth + Event/EventPrimitives + Event/xAOD/xAODEventInfo + ${extra_deps} ) + +# External dependencies: +find_package( Eigen ) +find_package( ROOT COMPONENTS Core Geometry Tree MathCore Hist RIO pthread TBB ) + +# Generate a CINT dictionary source file: +atlas_add_root_dictionary( InDetTruthVertexValidationLib _cintDictSource + ROOT_HEADERS Root/LinkDef.h + EXTERNAL_PACKAGES ROOT ) + +# Component(s) in the package: +atlas_add_library( InDetTruthVertexValidationLib + Root/*.cxx ${_cintDictSource} + PUBLIC_HEADERS InDetTruthVertexValidation + PRIVATE_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS} + PRIVATE_LINK_LIBRARIES ${ROOT_LIBRARIES} ${EIGEN_LIBRARIES} EventPrimitives xAODTracking AsgTools xAODEventInfo xAODTruth ${extra_libs}) + +if( NOT XAOD_STANDALONE ) + atlas_add_component( InDetTruthVertexValidation + src/*.cxx src/*.h + src/components/*.cxx + INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} ${TBB_INCLUDE_DIRS} ${EIGEN_INCLUDE_DIRS} + LINK_LIBRARIES ${ROOT_LIBRARIES} ${EIGEN_LIBRARIES} ${extra_libs} EventPrimitives xAODTracking AthenaBaseComps AsgTools xAODEventInfo xAODTruth InDetTruthVertexValidationLib ) +endif() + +# Install files from the package: +atlas_install_joboptions( share/*.py ) + +if( XAOD_STANDALONE ) + atlas_add_executable( VertexTruthMatchTest + util/VertexTruthMatchTest.cxx + LINK_LIBRARIES InDetTruthVertexValidationLib xAODTracking xAODEventInfo xAODRootAccess ${ROOT_LIBRARIES} ${EIGEN_LIBRARIES} ${extra_libs}) +endif() + diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/IInDetVertexTruthMatchTool.h b/InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/IInDetVertexTruthMatchTool.h new file mode 100644 index 00000000000..3302f3c0150 --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/IInDetVertexTruthMatchTool.h @@ -0,0 +1,32 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef IInDetVertexTruthMatchTool_h +#define IInDetVertexTruthMatchTool_h + +// Framework include(s): +#include "AsgTools/IAsgTool.h" + +// EDM include(s): +#include "xAODTracking/VertexContainer.h" + + +/** Class for vertex truth matching. + * Match reconstructed vertices to truth level interactions vertices + * through the chain: track -> particle -> genEvent -> genVertex + * Categorize reconstructed vertices depending on their composition. + */ + +class IInDetVertexTruthMatchTool : public virtual asg::IAsgTool { + +ASG_TOOL_INTERFACE( IInDetVertexTruthMatchTool ) + +public: + +//take const collection of vertices, match them, and decorate with matching info + virtual StatusCode matchVertices( const xAOD::VertexContainer & vxContainer ) = 0; + +}; + +#endif diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/InDetVertexTruthMatchTool.h b/InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/InDetVertexTruthMatchTool.h new file mode 100644 index 00000000000..6f11c026103 --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/InDetVertexTruthMatchTool.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef InDetVertexTruthMatchTool_h +#define InDetVertexTruthMatchTool_h + +// Framework include(s): +#include "AsgTools/AsgTool.h" + +// EDM include(s): +#include "xAODTracking/VertexContainerFwd.h" +#include "xAODTruth/TruthParticleFwd.h" +#include "InDetTruthVertexValidation/IInDetVertexTruthMatchTool.h" + +/** Class for vertex truth matching. + * Match reconstructed vertices to truth level interactions vertices + * through the chain: track -> particle -> genEvent -> genVertex + * Categorize reconstructed vertices depending on their composition. + */ + + +class InDetVertexTruthMatchTool : public virtual IInDetVertexTruthMatchTool, + public asg::AsgTool { + + ASG_TOOL_CLASS( InDetVertexTruthMatchTool, IInDetVertexTruthMatchTool ) + + public: + + InDetVertexTruthMatchTool( const std::string & name ); + + virtual StatusCode initialize() override final; + + //take const collection of vertices, match them, and decorate with matching info + virtual StatusCode matchVertices( const xAOD::VertexContainer & vxContainer ) override; + + private: + + const xAOD::TrackParticleContainer* findTrackParticleContainer( const xAOD::VertexContainer& vxContainer ); + + //required MC match probability to consider track a good match + float m_trkMatchProb; + //relative weight threshold to consider vertex matched + float m_vxMatchWeight; + //pt cut to use on tracks + float m_trkPtCut; + + //private methods to check if particles are good to use + bool pass( const xAOD::TruthParticle & truthPart ) const; + bool pass( const xAOD::TrackParticle & trackPart ) const; + +}; + +#endif diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/InDetVertexTruthMatchUtils.h b/InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/InDetVertexTruthMatchUtils.h new file mode 100644 index 00000000000..5871724d924 --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/InDetTruthVertexValidation/InDetVertexTruthMatchUtils.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef InDetVertexTruthMatchUtils_h +#define InDetVertexTruthMatchUtils_h + +#include "xAODTracking/VertexContainerFwd.h" +#include "xAODTruth/TruthEventBaseContainer.h" + +namespace InDetVertexTruthMatchUtils { + + //Namespace for useful analysis things on the truth matching decorations applied to the VertexContainer + //Can be called by algorithms inside or outside Athena to do their analysis + + //How the matching info is stored; link to the truth vertex, a float with its contribution to the relative track weight, and a float with its contribution to the track sumpt2 of the truth vertex + typedef std::tuple<ElementLink<xAOD::TruthEventBaseContainer>, float, float> VertexTruthMatchInfo; + + //type codes for vertex matching on all vertices + enum VertexMatchType { + MATCHED, // > threshold (default 70%) from one truth interaction + MERGED, // not matched + SPLIT, // highest weight truth interaction contributes to >1 vtx (vtx with highest fraction of sumpT2 remains matched/merged) + FAKE, // highest contribution is fake (if pile-up MC info not present those tracks end up as "fakes") + DUMMY, // is the dummy vertex + NTYPES // access to number of types +}; + + //Classification for true hard-scatter interaction + enum HardScatterType { + CLEAN, // matched + LOWPU, // merged, but dominant contributor + HIGHPU, // merged and dominated by pile-up or fakes + HSSPLIT, // split + NONE, // not found + NHSTYPES + }; + + //Find the best reco vertex matching the hard scatter event + //returns 0 in case can't find one + const xAOD::Vertex * bestHardScatterMatch( const xAOD::VertexContainer & vxContainer ); + + //pointers to all reco vertices for which the hard scatter has some contribution + //includes the index in the matching info where to find it + const std::vector<std::pair<const xAOD::Vertex*, size_t> > hardScatterMatches( const xAOD::VertexContainer & vxContainer ); + + //find the hard scatter type + HardScatterType classifyHardScatter( const xAOD::VertexContainer & vxContainer ); + +} + + +#endif diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/InDetVertexTruthMatchTool.cxx b/InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/InDetVertexTruthMatchTool.cxx new file mode 100644 index 00000000000..2869b9d284c --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/InDetVertexTruthMatchTool.cxx @@ -0,0 +1,422 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#include "InDetTruthVertexValidation/InDetVertexTruthMatchTool.h" + +#include "xAODTracking/TrackParticleContainer.h" +#include "xAODTruth/TruthEventContainer.h" + +#include "InDetTruthVertexValidation/InDetVertexTruthMatchUtils.h" +using namespace InDetVertexTruthMatchUtils; + +InDetVertexTruthMatchTool::InDetVertexTruthMatchTool( const std::string & name ) : asg::AsgTool(name) { + declareProperty("trackMatchProb", m_trkMatchProb = 0.7 ); + declareProperty("vertexMatchWeight", m_vxMatchWeight = 0.7 ); + declareProperty("trackPtCut", m_trkPtCut = 100. ); +} + +StatusCode InDetVertexTruthMatchTool::initialize() { + ATH_MSG_INFO("Initializing"); + + return StatusCode::SUCCESS; +} + + +namespace { +//Helper methods for this file only + +//output typedef +// this is defined like this in InDetTruthMatchUtils: +// typedef std::pair<ElementLink<xAOD::TruthEventBaseContainer>, float> VertexTruthMatchInfo; +// std::pair<ElementLink<>, T> is special templated pair in ElementLink.h even +// pair of link to a truth event with relative weight of matched tracks + + +// Create a truth map by decoarting truth particles with a back link to the truth event they live in +// Needed because the track->truth assoc gives us the particles but they don't store event normally +// Add as decoration to avoid full loop for every track ( this time only once per event ) +// Use a vector so any number of truth event collections can be used at once -- but the pointers need to be valid +void createTruthMap(std::vector<const xAOD::TruthEventBaseContainer *> truthEventContainers ) { + + xAOD::TruthParticle::Decorator<ElementLink<xAOD::TruthEventBaseContainer> > backLinkDecor("TruthEventLink"); + + for ( auto cit : truthEventContainers ) { + + const xAOD::TruthEventBaseContainer & truthEvents = *cit; + + for ( size_t i = 0; i < truthEvents.size(); ++i) { + + for ( auto & tkit : truthEvents[i]->truthParticleLinks() ) { //std::vector<ElementLink... + + const ElementLink<xAOD::TruthEventBaseContainer> elLink = ElementLink<xAOD::TruthEventBaseContainer>( truthEvents, i ); + + if (elLink.isValid() && tkit.isValid()) { + backLinkDecor(**tkit) = elLink; + } + + } + + } + + } + +} + +void createTrackTruthMap(std::vector<const xAOD::TruthEventBaseContainer *> truthEventContainers, + const xAOD::TrackParticleContainer & trackParticleContainer, + float matchCut) +{ + + createTruthMap(truthEventContainers); + + xAOD::TrackParticle::ConstAccessor<ElementLink<xAOD::TruthParticleContainer> > trk_truthPartAcc("truthParticleLink"); + xAOD::TrackParticle::ConstAccessor<float> trk_truthProbAcc("truthMatchProbability"); + xAOD::TruthParticle::Decorator<ElementLink<xAOD::TruthEventBaseContainer> > backLinkDecor("TruthEventLink"); + xAOD::TrackParticle::Decorator<ElementLink<xAOD::TruthEventBaseContainer> > trackLinkDecor("TrackEventLink"); + + int nGood = 0; + int nMatch = 0; + int nLink = 0; + for (auto trk : trackParticleContainer) + { + { + nGood++; + if (trk_truthPartAcc.isAvailable(*trk) && trk_truthProbAcc.isAvailable(*trk) + && trk_truthPartAcc(*trk).isValid() && trk_truthProbAcc(*trk) >= matchCut) + { + nMatch++; + auto truthParticle = trk_truthPartAcc(*trk); + if (backLinkDecor.isAvailable(**truthParticle) && backLinkDecor(**truthParticle).isValid()) + { + nLink++; + trackLinkDecor(*trk) = backLinkDecor(**truthParticle); + } + } + } + } + // won't compile, no idea why + //ATH_MSG_DEBUG("Linked/Matched/Good/All: " << nLink << " / " << nMatch << " / " << nGood << " / " << trackParticleContainer.size()); +} + +//In the vector of match info, find the element corresponding to link and return its index; create a new one if necessary +size_t indexOfMatchInfo( std::vector<VertexTruthMatchInfo> & matches, ElementLink<xAOD::TruthEventBaseContainer> & link ) { + for ( size_t i = 0; i < matches.size(); ++i ) { + if ( link.key() == std::get<0>(matches[i]).key() && link.index() == std::get<0>(matches[i]).index() ) + return i; + } + // This is the first time we've seen this truth vertex, so make a new entry + matches.push_back( std::make_tuple( link, 0., 0. ) ); + return matches.size() - 1; +} + + +//for sorting the container -> highest relative match weight first +bool compareMatchPair(const VertexTruthMatchInfo a, const VertexTruthMatchInfo b ) { return std::get<1>(a) > std::get<1>(b); } + +} + + +const xAOD::TrackParticleContainer* +InDetVertexTruthMatchTool::findTrackParticleContainer( const xAOD::VertexContainer& vxContainer ) +{ + for (auto vtx : vxContainer) + { + for (const ElementLink<xAOD::TrackParticleContainer>& tpLink : vtx->trackParticleLinks()) + { + if (tpLink.isValid()) + { + return tpLink.getStorableObjectPointer(); + } + } + } + return 0; +} + +StatusCode InDetVertexTruthMatchTool::matchVertices( const xAOD::VertexContainer & vxContainer ) { + + ATH_MSG_DEBUG("Start vertex matching"); + + // Identify MC vertices to match to -- this is the collection for hard scatter + const xAOD::TruthEventBaseContainer * truthEvents = nullptr; + if ( evtStore()->contains<xAOD::TruthEventBaseContainer>( "TruthEvents" ) ) + ATH_CHECK( evtStore()->retrieve( truthEvents, "TruthEvents" ) ); + else + ATH_CHECK( evtStore()->retrieve( truthEvents, "TruthEvent" ) ); + + std::vector<const xAOD::TruthEventBaseContainer *> truthContainers; + truthContainers.push_back( truthEvents ); + + ATH_MSG_DEBUG("Found Hard Scatter collection"); + + // These are the pile-up truth -- don't want to fail if they don't exist + const xAOD::TruthEventBaseContainer * truthPileup = nullptr; + if ( evtStore()->contains<xAOD::TruthEventBaseContainer>( "TruthPileupEvents" ) ) + ATH_CHECK( evtStore()->retrieve( truthPileup, "TruthPileupEvents" ) ); + if (truthPileup) + truthContainers.push_back( truthPileup ); + + ATH_MSG_DEBUG("Found Pileup collection"); + + // Find the trackParticle container associated with our reconstructed vertices + // We could pass this, but it would break the original interface... + const xAOD::TrackParticleContainer* tkContainer = findTrackParticleContainer(vxContainer); + if (!tkContainer) + { + ATH_MSG_WARNING("Vertex container has no vertices with valid TrackParticle links"); + return StatusCode::SUCCESS; + } + + ATH_MSG_DEBUG("Found track collection"); + + // create the particle links to events to avoid excessive looping + // also decorate reconstructed tracks passing selection with truthEvent links + createTrackTruthMap( truthContainers, *tkContainer, m_trkMatchProb ); + + // Accessor for the links we just created + xAOD::TruthParticle::Decorator<ElementLink<xAOD::TruthEventBaseContainer> > backLinkDecor("TruthEventLink"); + + //setup decorators for truth matching info + xAOD::Vertex::Decorator<std::vector<VertexTruthMatchInfo> > matchInfoDecor("TruthEventMatchingInfos"); + xAOD::Vertex::Decorator<std::vector<VertexTruthMatchInfo> > rawMatchInfoDecor("TruthEventRawMatchingInfos"); + xAOD::Vertex::Decorator<VertexMatchType> matchTypeDecor("VertexMatchType"); + xAOD::Vertex::Decorator<std::vector<ElementLink<xAOD::VertexContainer> > > splitPartnerDecor("SplitPartners"); + + //setup accessors + // can switch to built in method in xAOD::Vertex once don't have to deal with changing names anymore + xAOD::Vertex::ConstAccessor<xAOD::Vertex::TrackParticleLinks_t> trkAcc("trackParticleLinks"); + xAOD::Vertex::ConstAccessor<std::vector<float> > weightAcc("trackWeights"); + + xAOD::TrackParticle::ConstAccessor<ElementLink<xAOD::TruthParticleContainer> > trk_truthPartAcc("truthParticleLink"); + xAOD::TrackParticle::ConstAccessor<float> trk_truthProbAcc("truthMatchProbability"); + + xAOD::TrackParticle::Decorator<ElementLink<xAOD::VertexContainer> > trk_recoVtx("RecoVertex"); + xAOD::TrackParticle::Decorator<float> trk_wtVtx("WeightVertex"); + + //some variables to store + size_t ntracks; + xAOD::VxType::VertexType vxType; + + ATH_MSG_DEBUG("Starting Loop on Vertices"); + + //============================================================================= + //First loop over vertices: get tracks, then TruthParticles, and store relative + //weights of contribution from each TruthEvent + //============================================================================= + size_t vxEntry = 0; + + for ( auto vxit : vxContainer.stdcont() ) { + vxEntry++; + vxType = static_cast<xAOD::VxType::VertexType>( vxit->vertexType() ); + if (vxType == xAOD::VxType::NoVtx) { + //skip dummy vertices -> match info will be empty vector if someone tries to access later + //type will be set to dummy + continue; + } + + + //create the vector we will add as matching info decoration later + std::vector<VertexTruthMatchInfo> matchinfo; + std::vector<VertexTruthMatchInfo> rawMatchinfo; //not normalized to one for each reco vertex + + //if don't have track particles + if (!trkAcc.isAvailable(*vxit) || !weightAcc.isAvailable(*vxit) ) { + ATH_MSG_DEBUG("trackParticles or trackWeights not available, setting fake"); + // Add invalid link for fakes + matchinfo.push_back( std::make_tuple( ElementLink<xAOD::TruthEventBaseContainer>(), 1., 0. ) ); + matchInfoDecor( *vxit ) = matchinfo; + rawMatchinfo.push_back( std::make_tuple( ElementLink<xAOD::TruthEventBaseContainer>(), 1., 0. ) ); + rawMatchInfoDecor( *vxit ) = rawMatchinfo; + continue; + } + + //things we need to do the matching + const xAOD::Vertex::TrackParticleLinks_t & trkParts = trkAcc( *vxit ); + ntracks = trkParts.size(); + const std::vector<float> & trkWeights = weightAcc( *vxit ); + + //double check + if ( trkWeights.size() != ntracks ) { + ATH_MSG_DEBUG("Vertex without same number of tracks and trackWeights, setting fake"); + matchinfo.push_back( std::make_tuple( ElementLink<xAOD::TruthEventBaseContainer>(), 1., 0. ) ); + matchInfoDecor( *vxit ) = matchinfo; + rawMatchinfo.push_back( std::make_tuple( ElementLink<xAOD::TruthEventBaseContainer>(), 1., 0. ) ); + rawMatchInfoDecor( *vxit ) = rawMatchinfo; + continue; + } + + ATH_MSG_DEBUG("Matching new vertex at (" << vxit->x() << ", " << vxit->y() << ", " << vxit->z() << ")" << " with " << ntracks << " tracks:"); + + float totalWeight = 0.; + float totalFake = 0.; + + //loop element link to track particle + for ( size_t t = 0; t < ntracks; ++t ) { + const xAOD::TrackParticle & trk = **trkParts[t]; + + totalWeight += trkWeights[t]; + trk_recoVtx(trk) = ElementLink<xAOD::VertexContainer>(vxContainer, vxEntry - 1); + trk_wtVtx(trk) = trkWeights[t]; + + const ElementLink<xAOD::TruthParticleContainer> & truthPartLink = trk_truthPartAcc( trk ); + float prob = trk_truthProbAcc( trk ); + + if (truthPartLink.isValid() && prob > m_trkMatchProb) { + const xAOD::TruthParticle & truthPart = **truthPartLink; + //check if the truth particle is "good" + if ( pass( truthPart) ) { + ElementLink<xAOD::TruthEventBaseContainer> match = backLinkDecor( truthPart ); + //check we have an actual link + if ( match.isValid() ) { + size_t matchIdx = indexOfMatchInfo( matchinfo, match ); + std::get<1>(matchinfo[matchIdx]) += trkWeights[t]; + std::get<2>(matchinfo[matchIdx]) += (trk.pt()/1000.) * (trk.pt()/1000.) * trkWeights[t]; + matchIdx = indexOfMatchInfo( rawMatchinfo, match ); + std::get<1>(rawMatchinfo[matchIdx]) += trkWeights[t]; + std::get<2>(rawMatchinfo[matchIdx]) += (trk.pt()/1000.) * (trk.pt()/1000.) * trkWeights[t]; + } else { + totalFake += trkWeights[t]; + } + + } else { + //truth particle failed cuts -> add to fakes + totalFake += trkWeights[t]; + } + } else { + //not valid or low matching probability -> add to fakes + totalFake += trkWeights[t]; + } + }//end loop over tracks in vertex + + //finalize the match info vector + if ( totalWeight < 1e-12 ) { // in case we don't have any passing tracks we want to make sure labeled fake + ATH_MSG_DEBUG(" Declaring vertex fully fake (no passing tracks included)"); + totalWeight = 1.; + totalFake = 1.; + } + if ( totalFake > 0. ) + { + matchinfo.push_back( std::make_tuple( ElementLink<xAOD::TruthEventBaseContainer>(), totalFake, 0. ) ); + rawMatchinfo.push_back( std::make_tuple( ElementLink<xAOD::TruthEventBaseContainer>(), totalFake, 0. ) ); + } + + for ( auto & mit : matchinfo ) { + std::get<1>(mit) /= totalWeight; + } + std::sort( matchinfo.begin(), matchinfo.end(), compareMatchPair ); + std::sort( rawMatchinfo.begin(), rawMatchinfo.end(), compareMatchPair ); + matchInfoDecor( *vxit ) = matchinfo; + rawMatchInfoDecor( *vxit ) = rawMatchinfo; + } + + //After first loop, all vertices have been decorated with their vector of match info (link to TruthEvent paired with weight) + //now we want to use that information from the whole collection to assign types + + //keep track of whether a type is assigned + //useful since looking for splits involves a double loop, and then setting types ahead in the collection + std::vector<bool> assignedType( vxContainer.size(), false ); + + for ( size_t i = 0; i < vxContainer.size(); ++i ) { + + if ( assignedType[i] ) continue; // make sure we don't reclassify vertices already found in the split loop below + + std::vector<VertexTruthMatchInfo> & info = matchInfoDecor( *vxContainer[i] ); + if (info.size() == 0) { + matchTypeDecor( *vxContainer[i] ) = DUMMY; + } else if ( !std::get<0>(info[0]).isValid() ) { + matchTypeDecor( *vxContainer[i] ) = FAKE; + } else if ( std::get<1>(info[0]) > m_vxMatchWeight ) { + matchTypeDecor( *vxContainer[i] ) = MATCHED; + } else { + matchTypeDecor( *vxContainer[i] ) = MERGED; + } + + //check for splitting + if ( matchTypeDecor( *vxContainer[i] ) == MATCHED || matchTypeDecor( *vxContainer[i] ) == MERGED ) { + std::vector<size_t> foundSplits; + for ( size_t j = i + 1; j < vxContainer.size(); ++j ) { + std::vector<VertexTruthMatchInfo> & info2 = matchInfoDecor( *vxContainer[j] ); + //check second vertex is not dummy or fake, and that it has same elementlink as first vertex + //equality test is in code but doesnt seem to work for ElementLinks that I have? + //so i am just checking that the contianer key hash and the index are the same + if (matchTypeDecor( *vxContainer[j] ) == FAKE || matchTypeDecor( *vxContainer[j] ) == DUMMY) continue; + if (info2.size() > 0 && std::get<0>(info2[0]).isValid() && std::get<0>(info[0]).key() == std::get<0>(info2[0]).key() && std::get<0>(info[0]).index() == std::get<0>(info2[0]).index() ) { + //add split links; first between first one found and newest one + splitPartnerDecor( *vxContainer[i] ).push_back( ElementLink<xAOD::VertexContainer>( vxContainer, j ) ); + splitPartnerDecor( *vxContainer[j] ).push_back( ElementLink<xAOD::VertexContainer>( vxContainer, i ) ); + //then between any others we found along the way + for ( auto k : foundSplits ) { //k is a size_t in the vector of splits + splitPartnerDecor( *vxContainer[k] ).push_back( ElementLink<xAOD::VertexContainer>( vxContainer, j ) ); + splitPartnerDecor( *vxContainer[j] ).push_back( ElementLink<xAOD::VertexContainer>( vxContainer, k ) ); + } + //then keep track that we found this one + foundSplits.push_back(j); + } //if the two vertices match to same TruthEvent + }//inner loop over vertices + + // Correct labelling of split vertices - keep highest sumpt2 vertex labelled as matched/merged + float maxSumpT2 = std::get<2>( matchInfoDecor( *vxContainer[i] )[0] ); + size_t indexOfMax = i; + for ( auto l : foundSplits ) { + if ( std::get<2>( matchInfoDecor( *vxContainer[l] )[0] ) > maxSumpT2 ){ + maxSumpT2 = std::get<2>( matchInfoDecor( *vxContainer[l] )[0] ); + indexOfMax = l; + } else { + matchTypeDecor( *vxContainer[l] ) = SPLIT; + assignedType[l] = true; + } + } + if ( indexOfMax!=i ) matchTypeDecor( *vxContainer[i] ) = SPLIT; + } //if matched or merged + } //outer loop + + //DEBUG MATCHING + if (msgLvl(MSG::DEBUG)) { + for (const auto &vxit : vxContainer.stdcont() ) { + ATH_MSG_DEBUG("Matched vertex (index " << (*vxit).index() << ") to type " << matchTypeDecor(*vxit) << " with following info of size " << matchInfoDecor(*vxit).size() << ":"); + for (const auto &vit : matchInfoDecor(*vxit) ) { + if ( std::get<0>(vit).isValid() ) { + ATH_MSG_DEBUG(" GenEvent type " << (* std::get<0>(vit))->type() << ", index " << std::get<0>(vit).index() << " with relative weight " << std::get<1>(vit) ); + } else { + ATH_MSG_DEBUG(" Fakes with relative weight " << std::get<1>(vit) ); + } + } + if (matchTypeDecor(*vxit) == SPLIT) { + ATH_MSG_DEBUG(" Split partners are:"); + for (const auto &split : splitPartnerDecor( *vxit ) ) { + if ( split.isValid() ) + ATH_MSG_DEBUG(" Vertex " << split.index()); + else + ATH_MSG_DEBUG(" ERROR"); + } + } + } + } + + return StatusCode::SUCCESS; + +} + + +//Set up any cuts on either the tracks or truth particles to allow here +//A failing track is removed from consideration entirely +//If a passing track matches to a failing truth particle it will be considered "fake" + +bool InDetVertexTruthMatchTool::pass( const xAOD::TruthParticle & truthPart ) const { + + //remove the registered secondaries + if ( truthPart.barcode() > 200000 ) return false; + + return true; + +} + +/* +bool InDetVertexTruthMatchTool::pass( const xAOD::TrackParticle & trackPart ) { + + if( trackPart.pt() < m_trkPtCut ) return false; + + return true; + +} +*/ diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/InDetVertexTruthMatchUtils.cxx b/InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/InDetVertexTruthMatchUtils.cxx new file mode 100644 index 00000000000..91f5fc1bfe1 --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/InDetVertexTruthMatchUtils.cxx @@ -0,0 +1,128 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#include "InDetTruthVertexValidation/InDetVertexTruthMatchUtils.h" +#include "xAODTracking/VertexContainer.h" + +namespace InDetVertexTruthMatchUtils { + +namespace { + +bool isHardScatterEvent( const ElementLink<xAOD::TruthEventBaseContainer> evlink ) { + //good link of type "TruthEvent" (not truthpileupevent) and the first one in the collection + return ( evlink.isValid() && (*evlink)->type() == xAOD::Type::TruthEvent && evlink.index() == 0 ); +} + +} + +//find highest weight match to the hard scatter interaction +//in the case of splitting user can take care to check this is really "best" +// --> example: +// vertex 0 is 90% hard scatter with many tracks, and 10% another vertex +// vertex 1 is 100% hard scatter with few tracks. +// this algorithm will pick vertex 1, but user may want to use vertex 0 (accessible from splitting link decoration) +const xAOD::Vertex * bestHardScatterMatch( const xAOD::VertexContainer & vxContainer ) { + //accessors for decorations + xAOD::Vertex::Decorator<std::vector<VertexTruthMatchInfo> > matchInfoDecor("TruthEventMatchingInfos"); + + std::vector<std::pair<const xAOD::Vertex*, size_t> > allMatches = hardScatterMatches( vxContainer ); + + //look for the highest weight + float bestw = 0.; + const xAOD::Vertex * best = nullptr; + for ( auto it : allMatches ) { + std::vector<VertexTruthMatchInfo> & info = matchInfoDecor( *(it.first) ); + //go to the index of the HS match in the info vector, and check the weight + if ( std::get<1>(info[ it.second ]) > bestw ) { + bestw = std::get<1>(info[ it.second ]); + best = it.first; + } + } + + //if didn't find any matches will return 0 + return best; +} + +//Find all hard scatter matches +const std::vector<std::pair<const xAOD::Vertex*, size_t> > hardScatterMatches( const xAOD::VertexContainer & vxContainer ) { + //accessors for decorations + xAOD::Vertex::Decorator<std::vector<VertexTruthMatchInfo> > matchInfoDecor("TruthEventMatchingInfos"); + + //return vector + std::vector<std::pair<const xAOD::Vertex*, size_t> > result; + + //loop and look + for ( auto vxit : vxContainer ) { + const std::vector<VertexTruthMatchInfo> & info = matchInfoDecor( *vxit ); + for ( size_t i = 0; i < info.size(); ++i ) { + if ( isHardScatterEvent( std::get<0>(info[i]) ) ) { + result.push_back( std::make_pair(vxit, i) ); + break; + } + } + + } + return result; +} + +HardScatterType classifyHardScatter( const xAOD::VertexContainer & vxContainer ) { + + // return a vector of reco vertices with contributions from the hard-scatter + // if the second element in the pair is zero, it means tracks from the hard-scatter + // contribute more weight to that reco vertex than any other interaction + std::vector<std::pair<const xAOD::Vertex*, size_t> > matches = hardScatterMatches( vxContainer ); + + // information indicating whether a given reco vertex is: + // MATCHED, MERGED, SPLIT or FAKE + xAOD::Vertex::Decorator<VertexMatchType> matchTypeDecor("VertexMatchType"); + + if ( matches.size() == 0 ) { + // No reco vertices with tracks from hard-scatter + return NONE; + } else if ( matches.size() == 1 ) { + // A single reco vertex has tracks from hard-scatter + const VertexMatchType & type = matchTypeDecor( *(matches[0].first) ); + //check if the index in the matching info for HS is first, then can assign clean/lowpu based on match/merge + if ( matches[0].second == 0 && type == MATCHED ) { + // HS made largest contribution and vertex matched + return CLEAN; + } else if ( matches[0].second == 0 && type == MERGED ) { + // HS made largest contribution and vertex merged + return LOWPU; + } else { + // HS did not make largest contribution or vertex is fake or vertex is part of non-HS split pair + return HIGHPU; + } + + } else { + // multiple reco vertices have tracks from hard-scatter + // count how many have hard-scatter tracks as largest contribution + int num_main = 0; + const xAOD::Vertex* mainVtx = nullptr; + for ( auto it : matches ) { + if ( it.second == 0 ) // is hard-scatter the largest contribution? + { + num_main++; + mainVtx = it.first; + } + } + if (num_main == 0 ) { + return HIGHPU; + } else if (num_main == 1 ) { + const VertexMatchType& type = matchTypeDecor(*mainVtx); + if (type == MATCHED) + return CLEAN; + else if (type == MERGED) + return LOWPU; + else + return HIGHPU; + } else { + return HSSPLIT; + } + } + + return NONE; +} + +} diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/LinkDef.h b/InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/LinkDef.h new file mode 100644 index 00000000000..6477846377b --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/Root/LinkDef.h @@ -0,0 +1,23 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef INDETRUTHVERTEXVALIDATION_LINKDEF_H +#define INDETRUTHVERTEXVALIDATION_LINKDEF_H + +#include "InDetTruthVertexValidation/InDetVertexTruthMatchUtils.h" +#include "InDetTruthVertexValidation/InDetVertexTruthMatchTool.h" + +#ifdef __CINT__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; +#pragma link C++ nestedclass; + +#pragma link C++ class InDetVertexTruthMatchTool; +#pragma link C++ class InDetVertexTruthMatchUtils; + +#endif + +#endif \ No newline at end of file diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/share/VertexTruthMatch_jobOptions.py b/InnerDetector/InDetValidation/InDetTruthVertexValidation/share/VertexTruthMatch_jobOptions.py new file mode 100644 index 00000000000..4e54cdd4ea3 --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/share/VertexTruthMatch_jobOptions.py @@ -0,0 +1,27 @@ +# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration + +# Set up the file reading: +FNAME = "/afs/cern.ch/atlas/project/PAT/xAODs/r5591/mc14_8TeV.117050.PowhegPythia_P2011C_ttbar.recon.AOD.e1727_s1933_s1911_r5591/AOD.01494882._111853.pool.root.1" + +import AthenaPoolCnvSvc.ReadAthenaPool +ServiceMgr.EventSelector.InputCollections = [ FNAME ] + +# Access the algorithm sequence: +from AthenaCommon.AlgSequence import AlgSequence +theJob = AlgSequence() + +from InDetTruthVertexValidation.InDetTruthVertexValidationConf import InDetVertexTruthMatchTool +tool = InDetVertexTruthMatchTool() +tool.OutputLevel=DEBUG +ToolSvc += tool + +# Add the test algorithm: +from InDetTruthVertexValidation.InDetTruthVertexValidationConf import InDetVertexTruthMatchAlgorithm +alg = InDetVertexTruthMatchAlgorithm() +theJob += alg + +# Do some additional tweaking: +from AthenaCommon.AppMgr import theApp +theApp.EvtMax = 100 +ServiceMgr.MessageSvc.OutputLevel = INFO +ServiceMgr.MessageSvc.defaultLimit = 1000000 diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/InDetVertexTruthMatchAlgorithm.cxx b/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/InDetVertexTruthMatchAlgorithm.cxx new file mode 100644 index 00000000000..1784403e25d --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/InDetVertexTruthMatchAlgorithm.cxx @@ -0,0 +1,43 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#include "InDetVertexTruthMatchAlgorithm.h" + +#include "xAODTracking/VertexContainer.h" + + +InDetVertexTruthMatchAlgorithm::InDetVertexTruthMatchAlgorithm( const std::string& name, ISvcLocator* svcLoc ) + : AthAlgorithm( name, svcLoc ), + m_matchTool( "InDetVertexTruthMatchTool/InDetVertexTruthMatchTool", this ) { + + declareProperty( "SGKey", m_sgKey = "PrimaryVertices" ); + + declareProperty( "VertexTruthMatchTool", m_matchTool ); +} + +StatusCode InDetVertexTruthMatchAlgorithm::initialize() { + + // Greet the user: + ATH_MSG_INFO( "Initialising - Package version: " << PACKAGE_VERSION ); + ATH_MSG_DEBUG( "SGKey = " << m_sgKey ); + + // Retrieve the tools: + ATH_CHECK( m_matchTool.retrieve() ); + + // Return gracefully: + return StatusCode::SUCCESS; +} + +StatusCode InDetVertexTruthMatchAlgorithm::execute() { + + //Retrieve the vertices: + const xAOD::VertexContainer * vxContainer = 0; + ATH_CHECK( evtStore()->retrieve( vxContainer, m_sgKey ) ); + + //pass to the tool for decoration: + ATH_CHECK( m_matchTool->matchVertices( *vxContainer ) ); + + return StatusCode::SUCCESS; + +} diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/InDetVertexTruthMatchAlgorithm.h b/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/InDetVertexTruthMatchAlgorithm.h new file mode 100644 index 00000000000..2d0e7e98a9e --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/InDetVertexTruthMatchAlgorithm.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#ifndef INDETVERTEXTRUTHMATCHALGORITHM_H +#define INDETVERTEXTRUTHMATCHALGORITHM_H + +// Gaudi/Athena include(s): +#include "AthenaBaseComps/AthAlgorithm.h" +#include "AsgTools/ToolHandle.h" + +// Local include(s): +#include "InDetTruthVertexValidation/IInDetVertexTruthMatchTool.h" + +class InDetVertexTruthMatchAlgorithm : public AthAlgorithm { + + public: + /// Regular Algorithm constructor + InDetVertexTruthMatchAlgorithm( const std::string& name, ISvcLocator* svcLoc ); + + /// Function initialising the algorithm + virtual StatusCode initialize() override final; + /// Function executing the algorithm + virtual StatusCode execute() override final; + + private: + /// StoreGate key for the muon container to investigate + std::string m_sgKey; + + ToolHandle<IInDetVertexTruthMatchTool> m_matchTool; + +}; + +#endif diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/components/InDetTruthVertexValidation_entries.cxx b/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/components/InDetTruthVertexValidation_entries.cxx new file mode 100644 index 00000000000..140e6664726 --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/components/InDetTruthVertexValidation_entries.cxx @@ -0,0 +1,13 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +// Gaudi/Athena include(s): +//#include "GaudiKernel/DeclareFactoryEntries.h" + +// Local include(s): +#include "InDetTruthVertexValidation/InDetVertexTruthMatchTool.h" +#include "../InDetVertexTruthMatchAlgorithm.h" + +DECLARE_COMPONENT( InDetVertexTruthMatchTool ) +DECLARE_COMPONENT( InDetVertexTruthMatchAlgorithm ) diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/components/InDetTruthVertexValidation_load.cxx b/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/components/InDetTruthVertexValidation_load.cxx new file mode 100644 index 00000000000..b1a3b84230d --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/src/components/InDetTruthVertexValidation_load.cxx @@ -0,0 +1,7 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +#include "GaudiKernel/LoadFactoryEntries.h" + +LOAD_FACTORY_ENTRIES(InDetTruthVertexValidation) diff --git a/InnerDetector/InDetValidation/InDetTruthVertexValidation/util/VertexTruthMatchTest.cxx b/InnerDetector/InDetValidation/InDetTruthVertexValidation/util/VertexTruthMatchTest.cxx new file mode 100644 index 00000000000..0daa864fa20 --- /dev/null +++ b/InnerDetector/InDetValidation/InDetTruthVertexValidation/util/VertexTruthMatchTest.cxx @@ -0,0 +1,145 @@ +/* + Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +*/ + +//ROOT +#include <TFile.h> +#include <TH1.h> + +#ifdef ROOTCORE +#include "xAODRootAccess/Init.h" +#include "xAODRootAccess/TEvent.h" +#include "xAODRootAccess/TStore.h" +#endif + +#include "xAODEventInfo/EventInfo.h" +#include "xAODTracking/VertexContainer.h" +#include "xAODTracking/TrackParticleContainer.h" + +#include "InDetTruthVertexValidation/InDetVertexTruthMatchTool.h" +#include "InDetTruthVertexValidation/InDetVertexTruthMatchUtils.h" + +int main( int argc, char* argv[] ) { + + const char * APP_NAME = argv[0]; + + //check for filename + if( argc < 2 ) { + Error( APP_NAME, "No file name argument" ); + Error( APP_NAME, " Usage: %s xAOD_file_name [nEntries]",APP_NAME ); + return 1; + } + + //init app + bool result = xAOD::Init( APP_NAME ); + if(!result) { + Error( APP_NAME, "Failed to init"); + return 1; + } + + //open file + const char * fileName = argv[1]; + Info(APP_NAME, "Opening file: %s", fileName ); + TFile * file = new TFile(fileName,"READ"); + + xAOD::TEvent event( xAOD::TEvent::kClassAccess ); + result = event.readFrom( file ); + if(!result) { + Error( APP_NAME, "Failed to have TEvent read file"); + return 1; + } + + //create transient object store + xAOD::TStore store; + + Long64_t entries = event.getEntries(); + if( argc > 2 ) { + const Long64_t e = atoll( argv[2] ); + if( e < entries ) + entries = e; + } + + //Tool to test + InDetVertexTruthMatchTool matchTool("VertexTruthMatchTool"); + + //config + matchTool.msg().setLevel( MSG::DEBUG ); + matchTool.setProperty( "trackMatchProb", 0.7 ); + matchTool.setProperty( "vertexMatchWeight", 0.7 ); + matchTool.initialize(); + + TFile fout("output.root","RECREATE"); + fout.cd(); + + //some inclusive test plots + TH1F * h_cat = new TH1F("vertexMatchTypes","Number of vertices of each type",4,-0.5,3.5); + h_cat->GetXaxis()->SetBinLabel(1, "Matched"); + h_cat->GetXaxis()->SetBinLabel(2, "Merged"); + h_cat->GetXaxis()->SetBinLabel(3, "Split"); + h_cat->GetXaxis()->SetBinLabel(4, "Fake"); + + + //plot some things for the best reco match to hard-scatter event + TH1F * h_cat_hs = new TH1F("vertexTypes_hardScatter","Number of events of each type",5,-0.5,4.5); + h_cat_hs->GetXaxis()->SetBinLabel(1, "Clean"); + h_cat_hs->GetXaxis()->SetBinLabel(2, "Low PU"); + h_cat_hs->GetXaxis()->SetBinLabel(3, "High PU"); + h_cat_hs->GetXaxis()->SetBinLabel(4, "Split"); + h_cat_hs->GetXaxis()->SetBinLabel(5, "No match"); + + //Loop + for( Long64_t entry = 0; entry < entries; ++entry ) { + + event.getEntry( entry ); + + const xAOD::EventInfo * ei = nullptr; + result = event.retrieve( ei, "EventInfo" ); + if(!result) { + Error( APP_NAME, "Failed to retrieve EventInfo on entry %i", static_cast<int>(entry)); + return 1; + } + + if( entry % 100 == 0 ) { + Info( APP_NAME, + "===Start event %i, run %i; %i events processed so far===", + static_cast<int>( ei->eventNumber() ), + static_cast<int>( ei->runNumber() ), + static_cast<int>( entry ) ); + } + + //get vertices + const xAOD::VertexContainer * vxContainer = nullptr; + result = event.retrieve( vxContainer, "PrimaryVertices" ); + if(!result) { + Error( APP_NAME, "Failed to retrieve PrimaryVertices on entry %i", static_cast<int>(entry)); + return 1; + } + + int status = matchTool.matchVertices( *vxContainer ); + if(!status) { + Error( APP_NAME, "Bad status from matching tool on entry %i", static_cast<int>(entry)); + continue; + } + + //accessor for the matching type + xAOD::Vertex::Decorator<InDetVertexTruthMatchUtils::VertexMatchType> matchTypeDecor("VertexMatchType"); + + //fill the category histogram for all vertices + for( auto vxit : *vxContainer ) { + h_cat->Fill( matchTypeDecor( *vxit ) ); + } + + //get the matching type for hard scatter and fill + h_cat_hs->Fill( InDetVertexTruthMatchUtils::classifyHardScatter( *vxContainer ) ); + + //get the best match for the hard scatter + //const xAOD::Vertex * hsMatch = InDetVertexTruthMatchUtils::bestHardScatterMatch( *vxContainer ); + + } + + h_cat->Write(); + h_cat_hs->Write(); + fout.Close(); + + return 0; +} -- GitLab