7.8.2. How to Veto¶
Introduction¶
In many physics analyses one of the (final state) particles originates from a specific decay and is not part of the signal decay chain. Such candidates contribute to the background and need to rejected as effectively as possible. Examples:
in studies of radiative B meson or charm decays, such as \(B^0\to\rho^0\gamma\), the photon candidate, which is used in the reconstruction of the \(B^0\) meson may, in reality, originate from the decay of either \(\pi^0\to\gamma\gamma\) or \(\eta\to\gamma\gamma\).
in studies of semileptonic B meson or charm decays the lepton sometimes originates from the decay of charmonium, \(J/\psi\) for example.
To deal with these backgrounds, we construct a veto in order to suppress the background sources. Vetoing comes in two steps:
calculate or construct some sort of a probability or likelihood that particle \(X\) (used in the reconstruction of the signal decay of interest) in reality originates from some other decay, \(M \to X Y\).
if the calculated probability is larger then some threshold value then we reject X and with it the signal candidate. We veto \(M\).
Any veto (\(\pi^0,\ \eta,\ J/\psi,\ ...\)) can be fully constructed and configured within the python steering file.
Overview of the workflow¶
The analysis of some specific signal side decay with a veto has the following steps. Here we use the worked example of a veto for background photons from a \(\pi^0\to\gamma\gamma\) decay but the procedure generalises.
- Reconstruct signal decay candidates
this includes filling of final-state particle lists, making combinations, performing vertex fits, applying cuts, etc…
Create a Rest Of Event object for each signal candidate
Create new
basf2.Path
to be executed for each Rest Of Event object in the event (one for each signal candidate)Warning
It is important to check if the current Rest Of Event object is related to a Particle from our signal ParticleList. This is a subtlety, but you may find unrelated Rest Of Event objects in the DataStore (from some other decay mode). In this case we simply skip the Rest Of Event by executing a so called “dead end” path.
Fill a ParticleList with all (or selected) photons from the Rest Of Event
Fill a ParticleList with signal photon candidates which is used in the reconstruction of the current signal side candidate (related to current Rest Of Event)
Combine the two lists to form pi0 candidates
Use TMVA or any other method to determine the probability or likelihood that signal photon originates from \(\pi^0\) decay
Select the best \(\pi^0\) candidate
Write the probability (or likelihood value) calculated in step iv for the best \(\pi^0\) candidate as extraInfo to the current \(B^0\) candidate
- Continue with signal side reconstruction
continuum suppression, flavour tagging, tag vertex, etc…
Fill flat ntuple for offline analysis.
All analysis actions coloured in blue are executed once per event and all coloured in green are executed once per each Rest Of Event object in the event. The analysis actions coloured with green together construct a veto.
See also
This is an important usecase of the basf2.Path.for_each
functionality.
Examples¶
\(\pi^0\) veto in \(B^0 \to \rho^0 \gamma\) decays
The code is taken from an existing tutorial: B2A306-B02RhoGamma-withPi0Veto.py
The B0 -> rho0 gamma candidates are reconstructed and collected in the ParticleList with name B0.
Create Rest Of Event objects
import basf2
from modularAnalysis import buildRestOfEvent
mymainpath = basf2.Path()
buildRestOfEvent('B0', path=mymainpath)
Create roe_path in which the veto will be constructed. In addition another dead-end path needs to be created, which will be used in step o)
roe_path = basf2.Path()
deadEndPath = basf2.Path()
In next steps the veto is constructed. In this example the veto works in the following way:
combine photon (gamma) used in the reconstruction of the B0 candidate with all other photons found in the event with energy above 50 MeV to form \(\pi^0\) candidates
find best pi0 candidate with invariant mass closest to \(\pi^0\)’s nominal mass
write value of invariant mass of the best \(\pi^0\) as ‘pi0veto’ extraInfo
check if Rest Of Event is related to any Particle from
B0
list
signalSideParticleFilter('B0', '', roe_path, deadEndPath)
fill ParticleList with all photons that have ‘E>0.050’ from Rest Of Event (using isInRestOfEvent variable)
fillParticleList('gamma:roe', 'isInRestOfEvent == 1 and E > 0.050', path=roe_path)
fill ParticleList with signal photon candidate which is used in the reconstruction of the current signal side candidate (related to current Rest Of Event)
fillSignalSideParticleList('gamma:sig', 'B0 -> rho0 ^gamma', roe_path)
combine the two lists to form \(\pi^0\to\gamma\gamma\) candidates
reconstructDecay('pi0:veto -> gamma:sig gamma:roe', '0.080 < M < 0.200', path=roe_path)
select the best \(\pi^0\) candidate
rankByLowest('pi0:veto', 'abs(dM)', 1, path=roe_path)
write the probability or likelihood value calculated in step iv) for the best pi0 candidate as extraInfo to the current B0 candidate
variableToSignalSideExtraInfo('pi0:veto', {'M': 'pi0veto'}, path=roe_path)
Connect the roe_path with the main path
mymainpath.for_each('RestOfEvent', 'RestOfEvents', roe_path)
Continue with signal side reconstruction. At this point the B0 candidates have extraInfo(pi0veto) attached.
printVariableValues('B0', ['pi0veto'], path=mymainpath)
If the signal photon candidate could not be paired with any other photon candidate from the Rest Of Event to form a \(\pi^0\) candidate, then extraInfo(pi0veto) = NaN
.