Exercise with McTruth in AOD

*NOTE* for up-to-date exercizes, go to McAodTutorial


In this section, we will customise the UserAnalysis algorithm to exercise how to :

  • retrieve the HepMC::GenEvent
  • build the Mc Z invariant mass
  • build a custom GenEvent (filled with Z->e+e-)
  • build a TruthParticle from the later container *create and fill histograms :
  • yet another Z invariant mass
  • energy distributions of each of the electrons

Now it's up to you...

Packages retrieval

# cd ~janedoe/Tutorial/9.0.4
# cmt co -r TruthParticleAlgs-00-04-20-01 PhysicsAnalysis/AnalysisCommon/TruthParticleAlgs
# cmt co -r AnalysisUtils-00-00-26 PhysicsAnalysis/AnalysisCommon/AnalysisUtils

Due to a bug in the 9.0.4 version of a filter of AnalysisUtils (my fault but it will be fixed in 10.0.0), do :

# cp ~binet/public/Athena/Tutorial/bugfix/AnalysisUtils/src/*.cxx ~janedoe/Tutorial/9.0.4/PhysicsAnalysis/AnalysisCommon/AnalysisUtils/*/src/.
(Sorry for that)

Then recompile the whole thing:

# cd ~janedoe/Tutorial/9.0.4/PhysicsAnalysis/AnalysisCommon/UserAnalysis/*/cmt
# cmt broadcast gmake

Filter a GenEvent

In this section we will modify the AnalysisSkeleton algorithm to create a custom GenEvent from the ESD default one.

So the first step is to modify its header in order to use the Mc Truth tools :

  • Add a pointer to a McVtxFilterTool as a data member of AnalysisSkeleton : this is the AlgTool which will allow us to select our Monte-Carlo Z bosons.
  • Add a histogram to plot the Mc Z invariant mass.
  • Add a string property for the input location of the McEventCollection we will filter on
  • Add a string property for the output location of the McEventCollection (the one after filtering)
  • Add a new method
    StatusCode doMcZee();
    to be called at

Now edit the

jobOption file :
  • Add the needed POOL converter to be able to read back the McEventCollection
include( "GeneratorObjectsAthenaPool/GeneratorObjectsAthenaPool_joboptions.py" )
  • Add the decay pattern we are looking for:
# Mc filtering, selects the decay vertices based on this collection of strings
AnalysisSkeleton.McVtxFilterTool.DecayPatterns = [ "23 -> -11 + 11" ]

Get a hand on the AnalysisSkeleton source file (.cxx).

  • include the needed header files for the McVtxFilterTool and the McEventCollection, so now AnalysisSkeleton knows how to handle these classes (ie: what methods it can call onto these classes, which type are they, what data members they carry on, etc...) :
#include "TruthParticleAlgs/McVtxFilterTool.h"
#include "GeneratorObjects/McEventCollection.h"
  • declare the property for the input McEventCollection as well as the one for the output (filtered) one
  • in
    retrieve a private instance of the McVtxFilterTool. This code snipplet makes AnalysisSkeleton asks the framework (Athena) for an instance of McVtxFilterTool. The
    statement tells that the instance of the AlgTool will be owned only AnalysisSkeleton and won't be shared with other Algorithms (so the modifications we apply on this AlgTool won't propagate to other Algorithms which by chance use it :
IAlgTool * algTool = 0;
StatusCode sc = toolSvc->retrieveTool( "McVtxFilterTool", algTool, this );
if ( sc.isFailure() ) {
  log << MSG::ERROR
      << "Creation of algTool McVtxFilterTool FAILED !!"
      << endreq;
  return sc;
} else {
  log << MSG::VERBOSE << "Successfully retrieved McVtxFilterTool" << endreq;
  m_mcVtxFilterTool = dynamic_cast<McVtxFilterTool*>( algTool );

Now we have to implement the

method :
  • Retrieve a constant pointer to the ESD GenEvent from StoreGateSvc:
const McEventCollection * mcColl = 0;
StatusCode sc = StatusCode::SUCCESS;
sc = m_storeGate->retrieve( mcColl, m_mcEventsName );

// Test that we have a valid pointer to the McEventCollection
if ( sc.isFailure() || 0 == mcColl ) {
  log << MSG::ERROR
      << "Could not retrieve McEventCollection at : "
      << m_mcEventsName
      << endreq;
  return StatusCode::SUCCESS;

// Get the pointer to GenEvent, the object which holds the collection
// of vertices and particles
const HepMC::GenEvent * evt = *(mcColl->begin());

Now we have a handle on the GenEvent we create the McEventCollection which will receive our custom and filtered GenEvent. This later collection will be filled with the McVtxFilterTool which has been setup at the job option level (remember the

DecayPatterns = [ "23 -> -11 + 11" ]
statement) :
log << MSG::VERBOSE << "Create the filtered McEventCollection" << endreq;
McEventCollection * myMcAOD = new McEventCollection;

// Tell StoreGate to manage the memory for this object, so we don't have to bother anymore with delete statements
// Make this collection available for downstream algorithm (thanks to StoreGate)
sc = m_storeGate->record( myMcAOD, m_mcEventsOutputName, true );

// Tell StoreGate that other algorithms won't be able to change the content of this container
sc = m_storeGate->setConst( myMcAOD );
if ( sc.isSuccess() ) {
  log << MSG::VERBOSE
      << "Recorded and locked the output McEventCollection into StoreGate"
      << endreq;

// Filter the input collection and fill the output one
m_mcVtxFilterTool->filterMcEventCollection( mcColl, myMcAOD );

Mc Z invariant mass

Still in the doMcZee() method, we will loop over the content of our filtered McEventCollection and plot the invariant mass of the Z bosons. As this Mc collection should only contain the Z's with its children, it should be way faster than if we had looped over the whole "TruthEvent" GenEvent.

const HepMC::GenEvent * evtAOD = *(myMcAOD->begin());
for ( HepMC::GenEvent::particle_const_iterator itr = evtAOD->particles_begin();
      itr != evtAOD->particles_end();
      ++itr ) {
   log << MSG::DEBUG
       << "Parti id: " << (*itr)->pdg_id() << endreq
       << "E= "        << (*itr)->momentum().e()
       << "\tpx= "     << (*itr)->momentum().px()
       << endreq;
   // retrieve the decay vertex of the current particle
   const HepMC::GenVertex * decayVtx = (*itr)->end_vertex();

   if ( 23 == (*itr)->pdg_id() && //> select Z bosons
        0  !=  decayVtx        && //> check that we have a valid vtx pointer
        2  <= decayVtx->particles_out_size() ) { //> check we are looking the good Z (shouldn't be necessary, just to exercize the GenVertex interface
     m_mc_zee_mass_hist->fill( (*itr)->momentum().m() );
   }//> Z boson
}//> end loop over particles

Create a TruthParticleContainer

Why do we need to create (yet) another container ?

Indeed, we could stop at this point. But suppose we have written a nice calibration algorithm which can extract the electromagnetic energy scale from the Z invariant mass. Let say that this algorithm has this method :

StatusCode calcEMScale( const IParticle * zBoson,
                        const IParticle * ele1,
                        const IParticle * ele2,
                        CalibrationWeightObject& calib );
If we'd like to test our calibration method onto MonteCarlo data we could not just give the GenParticle Z and GenParticle electrons as arguments. The calcEMScale method expects IParticle objects. We would have to modify it and end up with 2 methods doing essentially the same job. And then we'll have to maintain the consistency between both methods...

But TruthParticles can be seen as IParticles. So it suffice to create a container of these TruthParticles : problem solved !

Back to exercise

Edit the AnalysisSkeleton header file :

  • Add a pointer to ITruthParticleCnvTool as a data member of our Algorithm. It will allow us to :
    • convert McEventCollection to TruthParticleContainer
    • retrieve the TruthParticle children of a TruthParticle
  • Add another histogram to plot the Z invariant mass (but this time it will be filled with TruthParticle Z bosons, and yes, in the end both histograms should have same content)
  • Add 2 histograms to plot the energy of the MonteCarlo electrons
  • Add a string property for the output location of our TruthParticleContainer

Edit the AnalysisSkeleton source file :

  • include the header file for the TruthParticleCnvTool
  • include the header file for the class which can select IParticle
#include "TruthParticleAlgs/TruthParticleCnvTool.h"
#include "AnalysisUtils/IParticleFilter.h"

  • in the constructor, declare the property for the output location of the TruthParticleContainer
  • in the initialize() method, retrieve a private instance of the TruthParticleCnvTool:
sc = toolSvc->retrieveTool( "TruthParticleCnvTool", algTool, this );
if ( sc.isFailure() ) {
  log << MSG::ERROR
      << "Creation of algTool TruthParticleCnvTool FAILED !!"
      << endreq;
  return sc;
} else {
  log << MSG::VERBOSE << "Successfully retrieved TruthParticleCnvTool" << endreq;
  m_truthParticleCnvTool = dynamic_cast<TruthParticleCnvTool*>( algTool );
  • in the doMcZee() method, create a new TruthParticleContainer to be filled from our custom GenEvent (filled with Z bosons and electrons) :
// Create a new container of TruthParticles
TruthParticleContainer * mcParts = new TruthParticleContainer;
// Tell StoreGate to do the memory management for us
sc = m_storeGate->record( mcParts, m_truthParticlesOutputName, true );
sc = m_storeGate->setConst( mcParts );

// Do the conversion
m_truthParticleCnvTool->convert_McEventCollection( myMcAOD, mcParts ); 

At this point, we have a container filled with TruthParticle electrons, TruthParticle Z bosons and TruthParticle photons. Let see how we can further filter this container to get on one hand the Z and on the other hand the electrons.

  • Create the filters :
IParticleFilter zFilter;
zFilter.set_pdgId( PDG::Z0 );

IParticleFilter eleMinFilter;
// tell the filter we want only electrons, not electrons and positrons
eleMinFilter.setPdgId( PDG::e_minus );

IParticleFilter elePlusFilter;
// tell the filter we want only positrons, not electrons and positrons
elePlusFilter.setPdgId( PDG::e_plus );
This is a lot of lines to do a (rather) simple task. But with the IParticleFilter class you can also select particles with 4-momentum cuts (min,max,range) and among multiple PDG-Ids list.

  • Fill the histograms :
for ( TruthParticleContainer::const_iterator itr = mcParts->begin();
      itr != mcParts->end();
      ++itr ) {
   // Get the Z boson
   if ( zFilter.isAccepted( *itr ) ) {
     m_mc_zmc_mass_hist->fill( (*itr)->m() );
     const TruthParticle * child = 0;
     // Loop over the Z boson children
     for ( int iChild = 0; iChild < (*itr)->nDecay(); ++iChild ) {
        // Tell TruthParticleCnvTool to look into the TruthParticleContainer
        // for the iChild-th child of the Z boson
        child = m_truthParticleCnvTool->child( mcParts, *itr, iChild );
        if ( elePlusFilter.isAccepted(child) ) {
          m_mc_elePlus_ene->fill( child->e() );
        } else if ( eleMinFiltern.isAccepted(child) ) {
          m_mc_eleMin_ene->fill( child->e() );
        } else {
          // this is most probably a photon.
          // We are not interested in photons.
     }//> loop over Z0's children 
   }//> is a Z0
}//> end loop over TruthParticles


Here are provided some answers to common errors, mistakes and existential questions...

Can't read back input POOL file

Most probably it is because the catalog file which POOL uses internally to know where to find the file, is incorrectly filled or because the information on where to find the file is simply not provided. By default, POOL looks for a file called PoolFileCatalog.xml where such information about the various POOL files should be stored. If you want to store information about the POOL file you want to process into a different file, just issue the following command :
pool_insertFileToCatalog -u xmlcatalog_file:/path/to/my/catalog/myCatalog.xml /path/to/my/POOL/files/*.pool.root
Usually one has a catalog for ESD files, another one for AOD files and finally a last one for analysis output files.

Then you can tell POOL to look for these particular catalogs (into your job option) :

# Load POOL support
include( "AthenaPoolCnvSvc/ReadAthenaPool_jobOptions.py" )
PoolSvc = Service( "PoolSvc" )
PoolSvc.ReadCatalog = [ "xmlcatalog_file:/afs/cern.ch/user/b/binet/public/ttbar/ana1001/rome.004100.ana.xml",

For a more detailed information about POOL in Athena, see this Wiki page : AthenaPool.

Can't read back input POOL file (cont'd)

Here the event loop is starting but you can't access to data objects. It also happened that you have these error messages :
EventSelector        INFO Initializing EventSelector - package version EventSelectorAthenaPool-00-00-71
EventSelector        INFO Create PoolCollectionConverter -  CollectionType: ImplicitROOT Connection:  InputCollection: AOD.pool.root
DbSession: level[Info]     Open     DbSession    
Domain[ROOT_All]: level[Info] >   Access   DbDomain     READ      [ROOT_All] 
Domain[ROOT_All]: level[Info] ->  Access   DbDatabase   READ      [ROOT_All] AOD.pool.root
RootClassLoader: level[Info] Failed to load dictionary for native class: "Trk::Vertex"
RootClassLoader: level[Info] Failed to load dictionary for native class: "DataVector<Trk::VxCandidate>"
RootClassLoader: level[Info] Failed to load dictionary for native class: "DataProxyStorage<CombinedMuonContainer>"
RootClassLoader: level[Info] Failed to load dictionary for native class: "ForwardIndexingPolicy<CombinedMuonContainer>"

Here it seems you are missing the necessary POOL converters which can load the persistified AOD objects from the POOL file. Rather conveniently the PAT group supplies a single jobOption which loads all the AOD converter libraries (if you seem to miss one just drop an email on the PAT list) :

include( "ParticleEventAthenaPool/AOD_PoolCnv_jobOptions.py")

Something new ?

If you have an error which is not listed here : drop me an email...

-- SebastienBinet - 21 Feb 2005 -- SebastienBinet - 25 Mar 2006

Edit | Attach | Watch | Print version | History: r12 < r11 < r10 < r9 < r8 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r12 - 2011-04-26 - SebastienBinet
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    Main All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright & 2008-2023 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
or Ideas, requests, problems regarding TWiki? use Discourse or Send feedback