Particle -> primary vertex association

The motivation for LHCb::Particle to primary vertex (PV) association is outlined in this note by Patrick Koppenburg. This wiki aims to explain the current implementation of Particle to PV and give examples of the various ways in which this can be achieved.


Particle to PV association has been an integral part of the DVAlgorithm/PhysDesktop software for some time now, where clever and configurable tools have been used to calculate related PVs "on-demand", and store the result in a relations table which is local to the PhysDesktop. The relations consist of a link between a particle and a PV, plus a weight giving the relative strength or "bestness" of the association. The relations for stored particles are saved to the TES at the end of each event, and can be passed on as input to DVAlgorithms that follow in the sequence, such that these relations do not have to be re-calculated each time. Since then, there has been a review of the tool interfaces and the way the configuration is handled, resulting in a de-coupling of PV relating tools from the DVAlgorithm and PhysDesktop. In brief, instead of having highly configurable tools, which apply different criteria to estimate the association weights or to obtain the input information, different tools have been written for each case, such that one tool can only do one thing and the user does not have to keep track of how a tool was configured somewhere in the middle of a sequence, or even in a job that produces a DST or MicroDST. Code duplication has been avoided by use of template programming techniques, and in fact each tool can be defined as a typedef. The DVAlgorithm/PhysDesktop duo now uses these tools and so needs less configuration than before. However, it is also possible to instrument a standard GaudiAlgorithm with the tools in order to run the relation-making independently of a selection, or to make use of them directly in GaudiPython. If you are only interested in how to get the single, "best" primary vertex for a given particle in a DVAlgorithm or a tool ultimately owned by a DVAlgorithm you may skip the following technical sections and go straight to the Using PV association in Analysis section.

Tool Interface

The task of obtaining a set of weighted, sorted primary vertices for a given particle is handled by implementations of the IRelatedPVFinder tool interface. Such a tool takes a Particle and a set of primary vertices (strictly speaking, it accepts containers of LHCb::RecVertex or LHCb::VertexBase pointers) and returns a weighted relations table with relations between the particle and the primary vertices ordered by increasing weight. The calculation of the weight depends on the implementation, with the convention that the larger the weight, the "better" the association to the primary vertex.

Weight estimation logic

At the time of writing, there are two ways of estimating the weights for the Particle to PV associations.
  1. Impact parameter chi2
  2. Impact parameter
Both use the IDistanceCalculator tool to obtain the impact parameter (IP) between a particle and a vertex, and the corresponding chi2. The weights are the inverse of these quantities, such that the best association is that with the smallest IP or chi2.

Tool Implementations

There exist four implementations of IRelatedPVFinder. These are all typedefs since the implementation is a template class. The corresponding string name used by the ToolSvc is also shown.
C++ typedef ToolSvc name (std::string)
P2PVWithIP. "GenericParticle2PVRelator__p2PVWithIP_OfflineDistanceCalculatorName_"
P2PVWithIPChi2 "GenericParticle2PVRelator__p2PVWithIPChi2_OfflineDistanceCalculatorName_"
OnlineP2PVWithIP "GenericParticle2PVRelator__p2PVWithIP_OnlineDistanceCalculatorName_"
OnlineP2PVWithIPChi2 "GenericParticle2PVRelator__p2PVWithIPChi2_OnlineDistanceCalculatorName_"

The difference between them is the weight-calculating logic, which is either IP or IP chi2, the IRelatedPVFinder implementation, which is TrgDistanceCalculator for online and DistanceCalculator for offline.

Using PV association in analysis

Primary vertex relating can be achieved either by direct use of the tools described above, automatically from a DVAlgorithm, or with PVRelatorAlg, an algorithm designed specifically for that purpose. In the first case, the user obtains relations that can be used directly. In the second and third case, relations tables linking the particles to primary vertices are stored on the TES. The relations tables can then be passed on to any DVAlgorithm via it's PhysDesktop's P2PVInputLocations property (see examples below). It is also possible to directly call whatever machinery the parent DVAlgorithm uses to estimate the best PV among a range of weighted relations using the _BestPV functor.

Automatic relating in DVAlgorithm in C++

The DVAlgorithm base class automatically relates particles to primary vertices each time the DVAlgorithm::getRelatedPV method is called. In practice, this method is called each time a PV-related cut is applied in the creation or selection of an LHCb::Particle. The results are cached, such that the relating isn't performed for a particle that already has a "best" re-fitted primary vertex. At the end of each event, the DVAlgorithm writes the particles out to TES location "Phys/AlgoName/Particles" and the relations tables to ="Phys/AlgoName/Particle2VertexRelations". The relations tables can be used by following DVAlgorithms such that the same vertices are used in the selection and in following analysis stages. Inside a DVAlgorithm it is possible to either obtain the best PV with or without caching the result for further searches:

Obtaining a previously calculated best PV or triggering the calculation if it hasn't been performed before:

// inside a DVAlgorithm
const LHCb::Particle* particle = ....;
const LHCb::VertexBase* bestPV = this->bestPV(particle);

Obtain the best PV without caching or any side effects:

// inside a DVAlgorithm
const LHCb::Particle* particle = ....;
const LHCb::VertexBase* bestPV = this->calculateRelatedPV(particle);

Accessing the DVAlgorithm relation machinery from a member tool in C++

Make an automatic DaVinci::BestPV and use it directly:

// inside a GaudiTool ultimately owned by a DVAlgorithm
     const DaVinci::BestPV getBestPV(*this);
     const LHCb::Particle* p = ....
     const LHCb::VertexBase* bestPV = getBestPV(p);

It is also possible to avoid the intermediate instance:

     const LHCb::Particle* p = ....;
     const LHCb::VertexBase* bestPV = DaVinci::BestPV(*this)(p);

The DaVinci::BestPV functor searches for the parent DVAlgorithm and calls its getRelatedPV method, therefore if uses caching of the result.

Direct use of PV-relating tool in C++

The following example shows how to get an instance of an IRelatedPVFinder implementation in C++. It assumes access to the ToolSvc via the tool templated method, present in GaudiAlgorithm and GaudiTool.
// The tool service doesn't understand typedefs, so we have to pass this long string
const std::string finderType = "GenericParticle2PVRelator__p2PVWithIPChi2_OfflineDistanceCalculatorName_";

// get it from the tool service.
const IRelatedPVFinder* pFinder = tool<IRelatedPVFinder>(finderType,this);

// get a particle
const LHCb::Particle* particle = ......;
// get some primary vertices
const LHCb::RecVertex::Container* pVertices = ....;
// get the best PV for the particle. See the IRelatedPVFinder doxygen for full interface.
const LHCb::VertexBase* bestPV = pFinder( particle, *pVertices);

Direct use of PV-relating tool in GaudiPython

The following example illustrates how to get an instance of an IRelatedPVFinder implementation and relate particles to primary vertices in a GaudiPython event loop:
from GaudiPython.Bindings import AppMgr
from GaudiConf.Configuration import *
from Configurables import DaVinci
app = DaVinci()
appMgr = AppMgr()
toolSvc = appMgr.toolsvc()
particleLocation = "Phys/.../Particles"
pvLocation = "Rec/Vertex/Primary"
# get the tool here. Since the implementations are templates, the tool names
# are lengthy and mangled. We can use a special module in DaVinciTools. This holds
# strings with the C++ typedefs of the implementations.
from DaVinciTools import Tools as DVTools
relPVFinder = toolSvc.create(DVTools.P2PVWithIPChi2, interface = 'IRelatedPVFinder')
# event loop
from AnalysisPython.Functors import NextEvent
nextEvt = NetxEvent(appMgr)

while (nextEvt() ) :
  particles = evtSvc[particleLocation]
  vertices = evtSvc[pvLocation]
  for particle in particles :
    table = relPVFinder.relatedPVs(particle, vertices)
    relPVs = table.relations(particle)
    print "found ", relPVs.size(), " related PVs"
    for rel in relPVs :
       print "particle related to PV ",, " with weight ", rel.weight()
    bestVertex = relPVs.back().to()

PVRelatorAlg: PV relating independently from particle selection and/or creation

The PVRelatorAlg is a GaudiAlgorithm which holds a pointer to a IRelatedPVFinder. It's configuration properties allow the user to set the TES location of primary vertices and LHCb::Particles, and the output TES location of the resulting relations table. It is also possible to provide an input relations table location. In this case, the existing relations for each particle are sorted according to the weights estimated by the IRelatedPVFinder tool. Internally, PVRelatorAlg uses an OnOfflineTool to pick the implementation of the IPVRelator according to context. It is therefore possible to change this implementation through the properties of the OnOfflineTool. The default values will use the IPVRelators used in DVAlgorithm. The PVRelatorAlg approach should typically be used if a different PV relating logic to that used in the DVAlgorithm is required, or if the selection required no estimation of the "best" vertex for candidate particles, in which case, no PV relation logic has been run or stored. In the example below, we create a Particle2Vertex::Table relating LHCb::Particles from "Phys/DC06selBd2Jpsi2MuMu_Kst2KPi/Particles" to default primary vertices and put it in "Phys/DC06selBd2Jpsi2MuMu_Kst2KPi/P2DefaultPVRelations". Then we create another Particle2Vertex::Table relating LHCb::Particles to re-fitted primary vertices starting from a Particle2Vertex::Table in "Phys/DC06selBd2Jpsi2MuMu_Kst2KPi/P2ReFitPVRelations" and put it in "Phys/DC06selBd2Jpsi2MuMu_Kst2KPi/P2ReFitPVSortedRelations"

from Configurables import PVRelatorAlg
 # Default PVs
 p2PV = PVRelatorAlg("P2StandardVertices")
 p2PV.ParticleInputLocation = "Phys/DC06selBd2Jpsi2MuMu_Kst2KPi/Particles"
 p2PV.P2PVRelationsOutputLocation = "Phys/DC06selBd2Jpsi2MuMu_Kst2KPi/P2DefaultPVRelations"
 # re-fitted PVs
 p2RefitPV = PVRelatorAlg("P2ReFitVertices")
 p2RefitPV.ParticleInputLocation = "Phys/DC06selBd2Jpsi2MuMu_Kst2KPi/Particles"
 p2RefitPV.P2PVRelationsInputLocation = "Phys/DC06selBd2Jpsi2MuMu_Kst2KPi/P2ReFitPVRelations"
 p2RefitPV.P2PVRelationsOutputLocation = "Phys/DC06selBd2Jpsi2MuMu_Kst2KPi/P2ReFitPVSortedRelations"
 # Add it to a selection sequence
 seq = GaudiSequencer('SeqDC06selBd2Jpsi2MuMu_Kst2KPi')
 seq.Members += [p2PV, P2RefitPV]

The relations table can be used as input to additional DVAlgorithms:

from Configurables import FilterDesktop # FilterDesktop is a DVAlgorithm
myFilter = FilterDesktop("ParticleFilter")
myFilter.Code = .....
myFilter.PhysDesktop.P2PVInputLocations = "Phys/DC06selBd2Jpsi2MuMu_Kst2KPi/P2ReFitPVSortedRelations"
seq.Members +=[myFilter]

Additional Examples

Direct access to relations table in GaudiPython

Here we illustrate how to access a Particle2Vertex::Table weighted relations table and used the relations directly. This is very similar to the example above, except that we obtain from the TES a relations table that links all particles to all primary vertices, instead of having a table for each particle.

# configuration the same as example above

p2pvLocation = ... # TES location of the Particle->PV relations

# event loop
from AnalysisPython.Functors import NextEvent
nextEvt = NetxEvent(appMgr)

while (nextEvt() ) :
  particles = evtSvc[particleLocation]
  p2pvTable = evtSvc[p2pvLocation]
  for particle in particles :
    relPVs = p2pvTable.relations(particle)
    print "found ", relPVs.size(), " related PVs"
    for rel in relPvs :
       print "particle related to PV ",, " with weight ", rel.weight()
    bestVertex = relPVs.back().to()

-- JuanPalacios - 04 Jun 2009

Edit | Attach | Watch | Print version | History: r13 < r12 < r11 < r10 < r9 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r13 - 2009-11-20 - unknown
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    LHCb All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright & 2008-2021 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