Belle II Software development
V0FinderModule.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8#include <tracking/modules/V0Finder/V0FinderModule.h>
9
10#include <framework/gearbox/Const.h>
11#include <framework/logging/Logger.h>
12#include <framework/core/ModuleParam.templateDetails.h> // needed for complicated parameter types
13
14#include <mdst/dataobjects/TrackFitResult.h>
15
16#include <tracking/dataobjects/RecoTrack.h>
17#include <tracking/v0Finding/fitter/V0VertexFitterFactory.h>
18
19using namespace Belle2;
20
21REG_MODULE(V0Finder);
22
24{
25 setDescription("This is a simple V0 finder for X = Ks, Lambda and converted photons "
26 "which matches all positive tracks with all negative tracks, "
27 "fitting a vertex for each pair. "
28 "Depending on the outcome of each fit, a corresponding "
29 "Belle2::V0 is stored or not.\n\n"
30 "A loose cut on the invariant mass (``massRangeX``) is applied before the fit (not considering material effects), "
31 "then a vertex fit is performed and only pairs passing a chi^2 (``vertexChi2CutOutside``) "
32 "and a second cut on the invariant mass (``invMassRangeX``) are stored as Belle2::V0. \n\n"
33 "No V0s with vertex inside the beam pipe "
34 "are saved as they can be recovered at analysis level. ");
35
37
38 //input tracks
39 addParam("RecoTracks", m_arrayNameRecoTrack,
40 "RecoTrack StoreArray name (input)", std::string(""));
41 addParam("CopiedRecoTracks", m_arrayNameCopiedRecoTrack,
42 "RecoTrack StoreArray name (used for track refitting)", std::string("CopiedRecoTracks"));
43 addParam("TrackFitResults", m_arrayNameTFResult,
44 "Belle2::TrackFitResult StoreArray name (in- and output).\n"
45 "Note that the V0s use pointers indices into these arrays, so all hell may break loose, "
46 "if you change this.", std::string(""));
47 addParam("Tracks", m_arrayNameTrack,
48 "Belle2::Track StoreArray name (input).\n"
49 "Note that the V0s use pointers indices into these arrays, so all hell may break loose, "
50 "if you change this.", std::string(""));
51
52 // output: V0s
53 addParam("V0s", m_arrayNameV0, "V0 StoreArry name (output).", std::string(""));
54 addParam("Validation", m_useValidation, "Create output for validation.", bool(false));
55 addParam("V0ValidationVertices", m_arrayNameV0ValidationVertex, "V0ValidationVertex StoreArray name (optional output)",
56 std::string(""));
57
58 addParam("beamPipeRadius", m_beamPipeRadius,
59 "Radius at which we switch between the two classes of cuts. "
60 "The default is a little inside the beam pipe to allow some tolerance.",
61 1.);
62
63 addParam("vertexChi2CutOutside", m_vertexChi2CutOutside,
64 "Maximum chi^2 for the vertex fit (NDF = 1)", 10000.);
65
66 addParam("invMassRangeKshort", m_invMassRangeKshort,
67 "mass range in GeV for reconstructed Kshort after removing material effects and inner hits", m_invMassRangeKshort);
68
69 addParam("invMassRangeLambda", m_invMassRangeLambda,
70 "mass range in GeV for reconstructed Lambda after removing material effects and inner hits", m_invMassRangeLambda);
71
72 addParam("invMassRangePhoton", m_invMassRangePhoton,
73 "mass range in GeV for reconstructed Photon after removing material effects and inner hits", m_invMassRangePhoton);
74
75 addParam("v0FitterMode", m_v0FitterMode,
76 "designate which fitAndStore function is called in V0Fitter.\n"
77 " 0: store V0 at the first vertex fit, regardless of inner hits; \n"
78 " 1: remove hits inside the V0 vertex position;\n"
79 " 2: mode 1 + don't use SVD hits if there is only one available SVD hit-pair",
80 1);
81
82 addParam("massRangeKshort", m_preFilterMassRangeKshort,
83 "mass range in GeV for reconstructed Kshort used for pre-selection of candidates"
84 " (to be chosen loosely as used momenta ignore material effects)", m_preFilterMassRangeKshort);
85 addParam("massRangeLambda", m_preFilterMassRangeLambda,
86 "mass range in GeV for reconstructed Lambda used for pre-selection of candidates"
87 " (to be chosen loosely as used momenta ignore material effects)", m_preFilterMassRangeLambda);
88 addParam("precutRho", m_precutRho, "preselection cut on the transverse radius of the point-of-closest-approach of two tracks. "
89 "Set value to 0 to accept all.", 0.5);
90 addParam("precutCosAlpha", m_precutCosAlpha, "preselection cut on the cosine of opening angle between two tracks. "
91 "Those above this cut are always accepted.", 0.9);
92 addParam("useNewV0Fitter", m_useNewV0Fitter, "on true use new V0 fitter, otherwise use the old one", false);
93 addParam("vertexFitter", m_vertexFitterName,
94 "name of the vertex fitter to be used, one of: " + V0VertexFitterFactory::getNamesAsString(),
95 std::string("Rave"));
96}
97
98
100{
101 m_tracks.isRequired(m_arrayNameTrack);
103 m_tracks.requireRelationTo(recoTracks);
104 //All the other required StoreArrays are checked in the Constructor of the V0Fitter.
105
106 if (m_useNewV0Fitter) {
107 m_newV0Fitter = std::make_unique<NewV0Fitter>(m_arrayNameTFResult, m_arrayNameV0,
112 m_newV0Fitter->setFitterMode(m_v0FitterMode);
114 } else {
115 m_v0Fitter = std::make_unique<V0Fitter>(m_arrayNameTFResult, m_arrayNameV0,
120 m_v0Fitter->setFitterMode(m_v0FitterMode);
122 }
123
124 // safeguard for users that try to break the code
125 if (std::get<0>(m_preFilterMassRangeKshort) > std::get<1>(m_preFilterMassRangeKshort)) {
126 B2FATAL("The minimum has to be smaller than the maximum of the Kshort mass range! min = " << std::get<0>
127 (m_preFilterMassRangeKshort) << " max = " << std::get<1>(m_preFilterMassRangeKshort));
128 }
129 if (std::get<0>(m_preFilterMassRangeLambda) > std::get<1>(m_preFilterMassRangeLambda)) {
130 B2FATAL("The minimum has to be smaller than the maximum of the Lambda mass range! min = " << std::get<0>
131 (m_preFilterMassRangeLambda) << " max = " << std::get<1>(m_preFilterMassRangeLambda));
132 }
133
134 // Precalculate the mass range squared
135 m_mKshortMin2 = std::get<0>(m_preFilterMassRangeKshort) < 0 ? -std::get<0>(m_preFilterMassRangeKshort) * std::get<0>
136 (m_preFilterMassRangeKshort) : std::get<0>
138 m_mKshortMax2 = std::get<1>(m_preFilterMassRangeKshort) < 0 ? -std::get<1>(m_preFilterMassRangeKshort) * std::get<1>
139 (m_preFilterMassRangeKshort) : std::get<1>
141 m_mLambdaMin2 = std::get<0>(m_preFilterMassRangeLambda) < 0 ? -std::get<0>(m_preFilterMassRangeLambda) * std::get<0>
142 (m_preFilterMassRangeLambda) : std::get<0>
144 m_mLambdaMax2 = std::get<1>(m_preFilterMassRangeLambda) < 0 ? -std::get<1>(m_preFilterMassRangeLambda) * std::get<1>
145 (m_preFilterMassRangeLambda) : std::get<1>
147
148}
149
150
152{
153 B2DEBUG(29, m_tracks.getEntries() << " tracks in event.");
154
155 // Group tracks into positive and negative tracks.
156 std::vector<const Track*> tracksPlus;
157 tracksPlus.reserve(m_tracks.getEntries());
158
159 std::vector<const Track*> tracksMinus;
160 tracksMinus.reserve(m_tracks.getEntries());
161
162 for (const auto& track : m_tracks) {
163 const TrackFitResult* fitResult = track.getTrackFitResultWithClosestMass(Const::pion);
164 B2ASSERT("No TrackFitResult available for given Track.", fitResult);
165
166 if (fitResult->getChargeSign() > 0) {
167 tracksPlus.push_back(&track);
168 }
169 if (fitResult->getChargeSign() < 0) {
170 tracksMinus.push_back(&track);
171 }
172
173 } // End of Track loop
174
175 // Reject boring events.
176 if (tracksPlus.empty() or tracksMinus.empty()) {
177 B2DEBUG(29, "No interesting track pairs. tracksPlus " << tracksPlus.size() << ", tracksMinus " << tracksMinus.size());
178 return;
179 }
180
181 // Pair up each positive track with each negative track.
182 for (auto& trackPlus : tracksPlus) {
183 for (auto& trackMinus : tracksMinus) {
184 if (not isTrackPairSelected(trackPlus, trackMinus)) continue;
185
186 if (preFilterTracks(trackPlus, trackMinus, Const::Kshort)) fitAndStore(trackPlus, trackMinus, Const::Kshort);
187 if (preFilterTracks(trackPlus, trackMinus, Const::Lambda)) fitAndStore(trackPlus, trackMinus, Const::Lambda);
188 if (preFilterTracks(trackPlus, trackMinus, Const::antiLambda)) fitAndStore(trackPlus, trackMinus, Const::antiLambda);
189 // the pre-filter is not able to reject photons, so no need to apply pre filter for photons
190 fitAndStore(trackPlus, trackMinus, Const::photon);
191 }
192 }
193
194}
195
196
198{
199 B2INFO("===V0Finder summary=============================================================");
200 B2INFO("In total " << m_nHitRemoved + m_nForceStored << " of " << m_allStored << " saved V0s have inner hits.");
201 B2INFO("- Inner hits successfully removed in " << m_nHitRemoved << " V0s.");
202 B2INFO("- The hit removal failed in " << m_nForceStored << " V0s, instead V0s before removing inner hits saved.");
203}
204
205bool
206V0FinderModule::preFilterTracks(const Track* trackPlus, const Track* trackMinus, const Const::ParticleType& v0Hypothesis)
207{
208 const double* range_m2_min = nullptr;
209 const double* range_m2_max = nullptr;
210 if (v0Hypothesis == Const::Kshort) {
211 range_m2_min = &m_mKshortMin2;
212 range_m2_max = &m_mKshortMax2;
213 } else if (v0Hypothesis == Const::Lambda or v0Hypothesis == Const::antiLambda) {
214 range_m2_min = &m_mLambdaMin2;
215 range_m2_max = &m_mLambdaMax2;
216 } else {
217 // this case is not covered so accept everything
218 return true;
219 }
220
221 const auto trackHypotheses = m_newV0Fitter ? m_newV0Fitter->getTrackHypotheses(v0Hypothesis) : m_v0Fitter->getTrackHypotheses(
222 v0Hypothesis);
223
224 // first track should always be the positive one
225 double m_plus = trackHypotheses.first.getMass();
226 double p_plus = trackPlus->getTrackFitResultWithClosestMass(trackHypotheses.first)->getMomentum().R();
227 double E_plus = sqrt(m_plus * m_plus + p_plus * p_plus);
228
229 // second track is the negative
230 double m_minus = trackHypotheses.second.getMass();
231 double p_minus = trackMinus->getTrackFitResultWithClosestMass(trackHypotheses.second)->getMomentum().R();
232 double E_minus = sqrt(m_minus * m_minus + p_minus * p_minus);
233
234 // now do the adding of the 4momenta
235 double sum_E2 = (E_minus + E_plus) * (E_minus + E_plus);
236
237 // the minimal/maximal allowed mass for these 4momenta is given if the 3momenta are aligned ( cos(angle)= +/- 1 )
238 double candmass_min2 = sum_E2 - (p_plus + p_minus) * (p_plus + p_minus);
239 double candmass_max2 = sum_E2 - (p_plus - p_minus) * (p_plus - p_minus);
240
241 // if true possible candidate mass overlaps with the user specified range
242 bool in_range = candmass_max2 > *range_m2_min and candmass_min2 < *range_m2_max;
243
244 return in_range;
245}
246
247
248bool V0FinderModule::isTrackPairSelected(const Track* track1, const Track* track2)
249{
250 if (m_precutRho <= 0) return true;
251
252 auto* fit1 = track1->getTrackFitResultWithClosestMass(Belle2::Const::pion);
253 if (not fit1) return false;
254 auto r1 = fit1->getPosition(); // point on the straight line
255 auto k1 = fit1->getMomentum().Unit(); // direction of the line
256
257 auto* fit2 = track2->getTrackFitResultWithClosestMass(Belle2::Const::pion);
258 if (not fit2) return false;
259 auto r2 = fit2->getPosition(); // point on the straight line
260 auto k2 = fit2->getMomentum().Unit(); // direction of the line
261
262 double cosAlpha = k1.Dot(k2); // cosine of opening angle between two tracks
263 if (cosAlpha > m_precutCosAlpha) return true;
264
265 // Find points, p1 and p2, on the straight lines that are closest to each other, i.e.
266 // (p2 - p1).Dot(k1) = 0 and (p2 - p1).Dot(k2) = 0,
267 // where p1 = r1 + k1 * lam1 and p2 = r2 + k2 * lam2,
268 // and lam1 and lam2 are running parameters - the unknowns of the equations.
269 //
270 // After rearrangement the system of equations reads:
271 //
272 // lam1 - cosAlpha * lam2 = b1, b1 = (r2 - r1).Dot(k1),
273 // cosAlpha * lam1 - lam2 = b2, b2 = (r2 - r1).Dot(k2)
274
275 double D = cosAlpha * cosAlpha - 1; // determinant of the system of two equations
276 if (D == 0) return true; // tracks are parallel
277
278 auto dr = r2 - r1;
279 double b1 = dr.Dot(k1);
280 double b2 = dr.Dot(k2);
281 double lam1 = (-b1 + b2 * cosAlpha) / D; // solution for the first straight line
282 double lam2 = (b2 - b1 * cosAlpha) / D; // solution for the second straight line
283 auto p1 = r1 + k1 * lam1; // point on the first line closest to the second line
284 auto p2 = r2 + k2 * lam2; // point on the second line closest to the first line
285 auto poca = (p1 + p2) / 2; // POCA of two straight lines, an approximation for the vertex
286
287 return poca.Rho() > m_precutRho;
288}
289
290
291void V0FinderModule::fitAndStore(const Track* trackPlus, const Track* trackMinus, const Const::ParticleType& v0Hypothesis)
292{
293 try {
294 bool isForceStored = false, isHitRemoved = false;
295 if (m_newV0Fitter) {
296 bool ok = m_newV0Fitter->fitAndStore(trackPlus, trackMinus, v0Hypothesis, isForceStored, isHitRemoved);
297 if (ok) m_allStored++;
298 } else {
299 bool ok = m_v0Fitter->fitAndStore(trackPlus, trackMinus, v0Hypothesis, isForceStored, isHitRemoved);
300 if (ok) m_allStored++;
301 }
302 m_nForceStored += isForceStored;
303 m_nHitRemoved += isHitRemoved;
304 } catch (const genfit::Exception& e) {
305 // genfit exception raised, skip this track pair for this hypothesis
306 B2WARNING("Genfit exception caught. Skipping this track pair"
307 << LogVar("V0 hypothesis PDG", v0Hypothesis.getPDGCode())
308 << LogVar("Genfit exception:", e.what()));
309 }
310}
311
The ParticleType class for identifying different particle types.
Definition Const.h:409
int getPDGCode() const
PDG code.
Definition Const.h:474
static const ParticleType Lambda
Lambda particle.
Definition Const.h:680
static const ChargedStable pion
charged pion particle
Definition Const.h:662
static const ParticleType antiLambda
Anti-Lambda particle.
Definition Const.h:681
static const ParticleType Kshort
K^0_S particle.
Definition Const.h:678
static const ParticleType photon
photon particle
Definition Const.h:674
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition Module.cc:208
Module()
Constructor.
Definition Module.cc:30
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition Module.h:80
Accessor to arrays stored in the data store.
Definition StoreArray.h:113
Values of the result of a track fit with a given particle hypothesis.
short getChargeSign() const
Return track charge (1 or -1).
ROOT::Math::XYZVector getMomentum() const
Getter for vector of momentum at closest approach of track in r/phi projection.
Class that bundles various TrackFitResults.
Definition Track.h:25
const TrackFitResult * getTrackFitResultWithClosestMass(const Const::ChargedStable &requestedType) const
Return the track fit for the fit hypothesis with the closest mass.
Definition Track.cc:104
std::tuple< double, double > m_preFilterMassRangeKshort
range for reconstructed Kshort mass used for pre-selection
int m_allStored
counter for all saved V0s
std::string m_arrayNameCopiedRecoTrack
StoreArray name of the RecoTracks.
std::string m_arrayNameV0
StoreArray name of the V0 (Output).
void initialize() override
Registration of StoreArrays, Relations, check proper GenFit setup.
std::tuple< double, double > m_preFilterMassRangeLambda
range for reconstructed Lambda mass used for pre-selection
bool isTrackPairSelected(const Track *track1, const Track *track2)
Track pair preselection based on a point-of-closest-approach of two tracks.
void fitAndStore(const Track *trackPlus, const Track *trackMinus, const Const::ParticleType &v0Hypothesis)
V0 fitting and storing.
void event() override
Creates Belle2::V0s from Belle2::Tracks as described in the class documentation.
int m_nForceStored
counter for saved V0s failing to remove the inner hits
std::string m_arrayNameTFResult
StoreArray name of the TrackFitResults (In- and Output).
double m_mKshortMax2
pre-calculated maximum Kshort mass squared
bool m_useValidation
on true save also fitted vertices in V0ValidationVertex StoreArray
std::string m_arrayNameV0ValidationVertex
StoreArray name of the V0ValidationVertex.
void terminate() override
Prints status summary.
double m_mLambdaMin2
pre-calculated minimum Lambda mass squared
double m_beamPipeRadius
Radius where inside/outside beampipe is defined.
V0FinderModule()
Setting of module description, parameters.
double m_mLambdaMax2
pre-calculated maximum Lambda mass squared
std::tuple< double, double > m_invMassRangePhoton
range for reconstructed Photon mass used after removing material effects and inner hits
double m_precutRho
preselection cut on transverse radius of the track pair POCA
std::unique_ptr< V0Fitter > m_v0Fitter
Object containing the actual algorithm.
StoreArray< Track > m_tracks
Actually array of mdst Tracks.
bool m_useNewV0Fitter
toggle between old (false) and new (true) V0 fitter
int m_nHitRemoved
counter for saved V0s successfully removing the inner hits
double m_vertexChi2CutOutside
Chi2 cut for V0s outside of the beampipe. Applies to all.
std::string m_arrayNameRecoTrack
StoreArray name of the RecoTracks (Input).
std::string m_vertexFitterName
name of the vertex fitter used to fit the V0 vertex
bool preFilterTracks(const Track *trackPlus, const Track *trackMinus, const Const::ParticleType &v0Hypothesis)
Helper function that gets the approximate mass range for the two given tracks and rejects candidates ...
int m_v0FitterMode
fitter mode
std::unique_ptr< NewV0Fitter > m_newV0Fitter
Object containing the actual algorithm.
double m_precutCosAlpha
preselection cut on opening angle of the track pair
std::tuple< double, double > m_invMassRangeKshort
range for reconstructed Kshort mass used after removing material effects and inner hits
std::tuple< double, double > m_invMassRangeLambda
range for reconstructed Lambda mass used after removing material effects and inner hits
std::string m_arrayNameTrack
StoreArray name of the Tracks (Input).
double m_mKshortMin2
pre-calculated minimum Kshort mass squared
static std::string getNamesAsString()
Get the names of all the registered fitters as a single string, for messages and parameter descriptio...
static std::unique_ptr< V0VertexFitter > create(const std::string &name)
Create the fitter registered under the given name.
Class to store variables with their name which were sent to the logging service.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
Abstract base class for different kinds of events.