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
18using namespace Belle2;
19
20REG_MODULE(V0Finder);
21
23{
24 setDescription("This is a simple V0 finder for X = Ks, Lambda and converted photons "
25 "which matches all positive tracks with all negative tracks, "
26 "fitting a vertex for each pair. "
27 "Depending on the outcome of each fit, a corresponding "
28 "Belle2::V0 is stored or not.\n\n"
29 "A loose cut on the invariant mass (``massRangeX``) is applied before the fit (not considering material effects), "
30 "then a vertex fit is performed and only pairs passing a chi^2 (``vertexChi2CutOutside``) "
31 "and a second cut on the invariant mass (``invMassRangeX``) are stored as Belle2::V0. \n\n"
32 "No V0s with vertex inside the beam pipe "
33 "are saved as they can be recovered at analysis level. ");
34
36
37 //input tracks
38 addParam("RecoTracks", m_arrayNameRecoTrack,
39 "RecoTrack StoreArray name (input)", std::string(""));
40 addParam("CopiedRecoTracks", m_arrayNameCopiedRecoTrack,
41 "RecoTrack StoreArray name (used for track refitting)", std::string("CopiedRecoTracks"));
42 addParam("TrackFitResults", m_arrayNameTFResult,
43 "Belle2::TrackFitResult StoreArray name (in- and output).\n"
44 "Note that the V0s use pointers indices into these arrays, so all hell may break loose, "
45 "if you change this.", std::string(""));
46 addParam("Tracks", m_arrayNameTrack,
47 "Belle2::Track StoreArray name (input).\n"
48 "Note that the V0s use pointers indices into these arrays, so all hell may break loose, "
49 "if you change this.", std::string(""));
50
51 // output: V0s
52 addParam("V0s", m_arrayNameV0, "V0 StoreArry name (output).", std::string(""));
53 addParam("Validation", m_useValidation, "Create output for validation.", bool(false));
54 addParam("V0ValidationVertices", m_arrayNameV0ValidationVertex, "V0ValidationVertex StoreArray name (optional output)",
55 std::string(""));
56
57 addParam("beamPipeRadius", m_beamPipeRadius,
58 "Radius at which we switch between the two classes of cuts. "
59 "The default is a little inside the beam pipe to allow some tolerance.",
60 1.);
61
62 addParam("vertexChi2CutOutside", m_vertexChi2CutOutside,
63 "Maximum chi^2 for the vertex fit (NDF = 1)", 10000.);
64
65 addParam("invMassRangeKshort", m_invMassRangeKshort,
66 "mass range in GeV for reconstructed Kshort after removing material effects and inner hits", m_invMassRangeKshort);
67
68 addParam("invMassRangeLambda", m_invMassRangeLambda,
69 "mass range in GeV for reconstructed Lambda after removing material effects and inner hits", m_invMassRangeLambda);
70
71 addParam("invMassRangePhoton", m_invMassRangePhoton,
72 "mass range in GeV for reconstructed Photon after removing material effects and inner hits", m_invMassRangePhoton);
73
74 addParam("v0FitterMode", m_v0FitterMode,
75 "designate which fitAndStore function is called in V0Fitter.\n"
76 " 0: store V0 at the first vertex fit, regardless of inner hits; \n"
77 " 1: remove hits inside the V0 vertex position;\n"
78 " 2: mode 1 + don't use SVD hits if there is only one available SVD hit-pair",
79 1);
80
81 addParam("massRangeKshort", m_preFilterMassRangeKshort,
82 "mass range in GeV for reconstructed Kshort used for pre-selection of candidates"
83 " (to be chosen loosely as used momenta ignore material effects)", m_preFilterMassRangeKshort);
84 addParam("massRangeLambda", m_preFilterMassRangeLambda,
85 "mass range in GeV for reconstructed Lambda used for pre-selection of candidates"
86 " (to be chosen loosely as used momenta ignore material effects)", m_preFilterMassRangeLambda);
87 addParam("precutRho", m_precutRho, "preselection cut on the transverse radius of the point-of-closest-approach of two tracks. "
88 "Set value to 0 to accept all.", 0.5);
89 addParam("precutCosAlpha", m_precutCosAlpha, "preselection cut on the cosine of opening angle between two tracks. "
90 "Those above this cut are always accepted.", 0.9);
91 addParam("useNewV0Fitter", m_useNewV0Fitter, "on true use new V0 fitter, otherwise use the old one", false);
92}
93
94
96{
97 m_tracks.isRequired(m_arrayNameTrack);
99 m_tracks.requireRelationTo(recoTracks);
100 //All the other required StoreArrays are checked in the Constructor of the V0Fitter.
101
102 if (m_useNewV0Fitter) {
103 m_newV0Fitter = std::make_unique<NewV0Fitter>(m_arrayNameTFResult, m_arrayNameV0,
108 m_newV0Fitter->setFitterMode(m_v0FitterMode);
109 } else {
110 m_v0Fitter = std::make_unique<V0Fitter>(m_arrayNameTFResult, m_arrayNameV0,
115 m_v0Fitter->setFitterMode(m_v0FitterMode);
116 }
117
118 // safeguard for users that try to break the code
119 if (std::get<0>(m_preFilterMassRangeKshort) > std::get<1>(m_preFilterMassRangeKshort)) {
120 B2FATAL("The minimum has to be smaller than the maximum of the Kshort mass range! min = " << std::get<0>
121 (m_preFilterMassRangeKshort) << " max = " << std::get<1>(m_preFilterMassRangeKshort));
122 }
123 if (std::get<0>(m_preFilterMassRangeLambda) > std::get<1>(m_preFilterMassRangeLambda)) {
124 B2FATAL("The minimum has to be smaller than the maximum of the Lambda mass range! min = " << std::get<0>
125 (m_preFilterMassRangeLambda) << " max = " << std::get<1>(m_preFilterMassRangeLambda));
126 }
127
128 // Precalculate the mass range squared
129 m_mKshortMin2 = std::get<0>(m_preFilterMassRangeKshort) < 0 ? -std::get<0>(m_preFilterMassRangeKshort) * std::get<0>
130 (m_preFilterMassRangeKshort) : std::get<0>
132 m_mKshortMax2 = std::get<1>(m_preFilterMassRangeKshort) < 0 ? -std::get<1>(m_preFilterMassRangeKshort) * std::get<1>
133 (m_preFilterMassRangeKshort) : std::get<1>
135 m_mLambdaMin2 = std::get<0>(m_preFilterMassRangeLambda) < 0 ? -std::get<0>(m_preFilterMassRangeLambda) * std::get<0>
136 (m_preFilterMassRangeLambda) : std::get<0>
138 m_mLambdaMax2 = std::get<1>(m_preFilterMassRangeLambda) < 0 ? -std::get<1>(m_preFilterMassRangeLambda) * std::get<1>
139 (m_preFilterMassRangeLambda) : std::get<1>
141
142}
143
144
146{
147 B2DEBUG(29, m_tracks.getEntries() << " tracks in event.");
148
149 // Group tracks into positive and negative tracks.
150 std::vector<const Track*> tracksPlus;
151 tracksPlus.reserve(m_tracks.getEntries());
152
153 std::vector<const Track*> tracksMinus;
154 tracksMinus.reserve(m_tracks.getEntries());
155
156 for (const auto& track : m_tracks) {
157 const TrackFitResult* fitResult = track.getTrackFitResultWithClosestMass(Const::pion);
158 B2ASSERT("No TrackFitResult available for given Track.", fitResult);
159
160 if (fitResult->getChargeSign() > 0) {
161 tracksPlus.push_back(&track);
162 }
163 if (fitResult->getChargeSign() < 0) {
164 tracksMinus.push_back(&track);
165 }
166
167 } // End of Track loop
168
169 // Reject boring events.
170 if (tracksPlus.empty() or tracksMinus.empty()) {
171 B2DEBUG(29, "No interesting track pairs. tracksPlus " << tracksPlus.size() << ", tracksMinus " << tracksMinus.size());
172 return;
173 }
174
175 // Pair up each positive track with each negative track.
176 for (auto& trackPlus : tracksPlus) {
177 for (auto& trackMinus : tracksMinus) {
178 if (not isTrackPairSelected(trackPlus, trackMinus)) continue;
179
180 if (preFilterTracks(trackPlus, trackMinus, Const::Kshort)) fitAndStore(trackPlus, trackMinus, Const::Kshort);
181 if (preFilterTracks(trackPlus, trackMinus, Const::Lambda)) fitAndStore(trackPlus, trackMinus, Const::Lambda);
182 if (preFilterTracks(trackPlus, trackMinus, Const::antiLambda)) fitAndStore(trackPlus, trackMinus, Const::antiLambda);
183 // the pre-filter is not able to reject photons, so no need to apply pre filter for photons
184 fitAndStore(trackPlus, trackMinus, Const::photon);
185 }
186 }
187
188}
189
190
192{
193 B2INFO("===V0Finder summary=============================================================");
194 B2INFO("In total " << m_nHitRemoved + m_nForceStored << " of " << m_allStored << " saved V0s have inner hits.");
195 B2INFO("- Inner hits successfully removed in " << m_nHitRemoved << " V0s.");
196 B2INFO("- The hit removal failed in " << m_nForceStored << " V0s, instead V0s before removing inner hits saved.");
197}
198
199bool
200V0FinderModule::preFilterTracks(const Track* trackPlus, const Track* trackMinus, const Const::ParticleType& v0Hypothesis)
201{
202 const double* range_m2_min = nullptr;
203 const double* range_m2_max = nullptr;
204 if (v0Hypothesis == Const::Kshort) {
205 range_m2_min = &m_mKshortMin2;
206 range_m2_max = &m_mKshortMax2;
207 } else if (v0Hypothesis == Const::Lambda or v0Hypothesis == Const::antiLambda) {
208 range_m2_min = &m_mLambdaMin2;
209 range_m2_max = &m_mLambdaMax2;
210 } else {
211 // this case is not covered so accept everything
212 return true;
213 }
214
215 const auto trackHypotheses = m_newV0Fitter ? m_newV0Fitter->getTrackHypotheses(v0Hypothesis) : m_v0Fitter->getTrackHypotheses(
216 v0Hypothesis);
217
218 // first track should always be the positive one
219 double m_plus = trackHypotheses.first.getMass();
220 double p_plus = trackPlus->getTrackFitResultWithClosestMass(trackHypotheses.first)->getMomentum().R();
221 double E_plus = sqrt(m_plus * m_plus + p_plus * p_plus);
222
223 // second track is the negative
224 double m_minus = trackHypotheses.second.getMass();
225 double p_minus = trackMinus->getTrackFitResultWithClosestMass(trackHypotheses.second)->getMomentum().R();
226 double E_minus = sqrt(m_minus * m_minus + p_minus * p_minus);
227
228 // now do the adding of the 4momenta
229 double sum_E2 = (E_minus + E_plus) * (E_minus + E_plus);
230
231 // the minimal/maximal allowed mass for these 4momenta is given if the 3momenta are aligned ( cos(angle)= +/- 1 )
232 double candmass_min2 = sum_E2 - (p_plus + p_minus) * (p_plus + p_minus);
233 double candmass_max2 = sum_E2 - (p_plus - p_minus) * (p_plus - p_minus);
234
235 // if true possible candidate mass overlaps with the user specified range
236 bool in_range = candmass_max2 > *range_m2_min and candmass_min2 < *range_m2_max;
237
238 return in_range;
239}
240
241
242bool V0FinderModule::isTrackPairSelected(const Track* track1, const Track* track2)
243{
244 if (m_precutRho <= 0) return true;
245
246 auto* fit1 = track1->getTrackFitResultWithClosestMass(Belle2::Const::pion);
247 if (not fit1) return false;
248 auto r1 = fit1->getPosition(); // point on the straight line
249 auto k1 = fit1->getMomentum().Unit(); // direction of the line
250
251 auto* fit2 = track2->getTrackFitResultWithClosestMass(Belle2::Const::pion);
252 if (not fit2) return false;
253 auto r2 = fit2->getPosition(); // point on the straight line
254 auto k2 = fit2->getMomentum().Unit(); // direction of the line
255
256 double cosAlpha = k1.Dot(k2); // cosine of opening angle between two tracks
257 if (cosAlpha > m_precutCosAlpha) return true;
258
259 // Find points, p1 and p2, on the straight lines that are closest to each other, i.e.
260 // (p2 - p1).Dot(k1) = 0 and (p2 - p1).Dot(k2) = 0,
261 // where p1 = r1 + k1 * lam1 and p2 = r2 + k2 * lam2,
262 // and lam1 and lam2 are running parameters - the unknowns of the equations.
263 //
264 // After rearrangement the system of equations reads:
265 //
266 // lam1 - cosAlpha * lam2 = b1, b1 = (r2 - r1).Dot(k1),
267 // cosAlpha * lam1 - lam2 = b2, b2 = (r2 - r1).Dot(k2)
268
269 double D = cosAlpha * cosAlpha - 1; // determinant of the system of two equations
270 if (D == 0) return true; // tracks are parallel
271
272 auto dr = r2 - r1;
273 double b1 = dr.Dot(k1);
274 double b2 = dr.Dot(k2);
275 double lam1 = (-b1 + b2 * cosAlpha) / D; // solution for the first straight line
276 double lam2 = (b2 - b1 * cosAlpha) / D; // solution for the second straight line
277 auto p1 = r1 + k1 * lam1; // point on the first line closest to the second line
278 auto p2 = r2 + k2 * lam2; // point on the second line closest to the first line
279 auto poca = (p1 + p2) / 2; // POCA of two straight lines, an approximation for the vertex
280
281 return poca.Rho() > m_precutRho;
282}
283
284
285void V0FinderModule::fitAndStore(const Track* trackPlus, const Track* trackMinus, const Const::ParticleType& v0Hypothesis)
286{
287 try {
288 bool isForceStored = false, isHitRemoved = false;
289 if (m_newV0Fitter) {
290 bool ok = m_newV0Fitter->fitAndStore(trackPlus, trackMinus, v0Hypothesis, isForceStored, isHitRemoved);
291 if (ok) m_allStored++;
292 } else {
293 bool ok = m_v0Fitter->fitAndStore(trackPlus, trackMinus, v0Hypothesis, isForceStored, isHitRemoved);
294 if (ok) m_allStored++;
295 }
296 m_nForceStored += isForceStored;
297 m_nHitRemoved += isHitRemoved;
298 } catch (const genfit::Exception& e) {
299 // genfit exception raised, skip this track pair for this hypothesis
300 B2WARNING("Genfit exception caught. Skipping this track pair"
301 << LogVar("V0 hypothesis PDG", v0Hypothesis.getPDGCode())
302 << LogVar("Genfit exception:", e.what()));
303 }
304}
305
The ParticleType class for identifying different particle types.
Definition: Const.h:408
int getPDGCode() const
PDG code.
Definition: Const.h:473
static const ParticleType Lambda
Lambda particle.
Definition: Const.h:679
static const ChargedStable pion
charged pion particle
Definition: Const.h:661
static const ParticleType antiLambda
Anti-Lambda particle.
Definition: Const.h:680
static const ParticleType Kshort
K^0_S particle.
Definition: Const.h:677
static const ParticleType photon
photon particle
Definition: Const.h:673
Base class for Modules.
Definition: Module.h:72
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
@ 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 a 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).
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
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:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.