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