Belle II Software  light-2212-foldex
FlightInfoVariables.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 
9 // Own include
10 #include <analysis/variables/FlightInfoVariables.h>
11 
12 // include VariableManager
13 #include <analysis/VariableManager/Manager.h>
14 
15 #include <framework/database/DBObjPtr.h>
16 #include <framework/logging/Logger.h>
17 
18 #include <analysis/dataobjects/Particle.h>
19 #include <mdst/dataobjects/MCParticle.h>
20 #include <mdst/dbobjects/BeamSpot.h>
21 
22 #include <TMatrixFSym.h>
23 
24 #include <boost/algorithm/string.hpp>
25 
26 namespace Belle2 {
32  namespace Variable {
33 
34  //Function to check if a beam constrained rave fit has been performed
35  bool hasRAVEBeamConstrainedProductionVertex(const Particle* particle)
36  {
37  bool hasRAVEProdVertex = true;
38  std::vector<std::string> directions = {"x", "y", "z"};
39  for (auto ielement : directions) {
40  std::string prodVertPositionElement = boost::str(boost::format("prodVert%s") % boost::to_upper_copy(ielement));
41  hasRAVEProdVertex &= particle -> hasExtraInfo(prodVertPositionElement);
42  for (auto jelement : directions) {
43  std::string prodVertCovarianceElement = boost::str(boost::format("prodVertS%s%s") % ielement % jelement);
44  hasRAVEProdVertex &= particle -> hasExtraInfo(prodVertCovarianceElement);
45  }
46  }
47  return hasRAVEProdVertex;
48  }
49 
50  // Helper function for flight distance and its uncertainty (provided as it is)
51  inline double getFlightInfoBtw(const Particle* particle, const Particle* daughter, double& outErr, const std::string& mode,
52  const bool motherToGranddaughter = false)
53  {
54  if (!particle || !daughter) {
55  outErr = std::numeric_limits<float>::quiet_NaN();
56  return std::numeric_limits<float>::quiet_NaN();
57  }
58  // check if the particle source is a composite particle
59  if (!(particle->getParticleSource() == Particle::EParticleSourceObject::c_Composite) ||
60  !(daughter->getParticleSource() == Particle::EParticleSourceObject::c_Composite)) {
61  // check if the particle source is a V0
62  if (!(particle->getParticleSource() == Particle::EParticleSourceObject::c_V0) ||
63  !(daughter->getParticleSource() == Particle::EParticleSourceObject::c_V0)) {
64  B2WARNING("Attempting to calculate flight " << mode << " for neither composite particle nor V0");
65  outErr = std::numeric_limits<float>::quiet_NaN();
66  return std::numeric_limits<float>::quiet_NaN();
67  }
68  }
69  if (!(mode == "distance") && !(mode == "time")) {
70  B2WARNING("FlightInfo helper function called with mode '" << mode
71  << "'. Only 'distance' and 'time' are available.");
72  outErr = std::numeric_limits<float>::quiet_NaN();
73  return std::numeric_limits<float>::quiet_NaN();
74  }
75  // get TreeFitter values if they exist.
76  // Bypass this in case the variables are requested for the granddaughter with respect to the mother as
77  // TreeFitter will return the values of the granddaughter with respect to the daughter
78  if (!motherToGranddaughter) {
79  if (mode == "distance" &&
80  daughter->hasExtraInfo("decayLength") &&
81  daughter->hasExtraInfo("decayLengthErr")) {
82  outErr = daughter -> getExtraInfo("decayLengthErr");
83  return daughter -> getExtraInfo("decayLength");
84  }
85  if (mode == "time" &&
86  daughter->hasExtraInfo("lifeTime") &&
87  daughter->hasExtraInfo("lifeTimeErr")) {
88  outErr = daughter -> getExtraInfo("lifeTimeErr");
89  return daughter -> getExtraInfo("lifeTime");
90  }
91  }
92 
93 
94  double mumvtxX = particle->getX();
95  double mumvtxY = particle->getY();
96  double mumvtxZ = particle->getZ();
97  if (particle == daughter) {
98  if (hasRAVEBeamConstrainedProductionVertex(particle)) {
99  mumvtxX = particle->getExtraInfo("prodVertX");
100  mumvtxY = particle->getExtraInfo("prodVertY");
101  mumvtxZ = particle->getExtraInfo("prodVertZ");
102  } else {
103  //if no production vertex assume the particle originated at the ip
104  static DBObjPtr<BeamSpot> beamSpotDB;
105  mumvtxX = (beamSpotDB->getIPPosition()).X();
106  mumvtxY = (beamSpotDB->getIPPosition()).Y();
107  mumvtxZ = (beamSpotDB->getIPPosition()).Z();
108  }
109  }
110  //daughter vertex
111  double vtxX = daughter->getX();
112  double vtxY = daughter->getY();
113  double vtxZ = daughter->getZ();
114  // daughter MOMENTUM
115  double p = daughter->getP();
116  double pX = daughter->getPx();
117  double pY = daughter->getPy();
118  double pZ = daughter->getPz();
119 
120  //versor of the daughter momentum
121  double nX = pX / p;
122  double nY = pY / p;
123  double nZ = pZ / p;
124  //mother vertex
125  double lX = vtxX - mumvtxX;
126  double lY = vtxY - mumvtxY;
127  double lZ = vtxZ - mumvtxZ;
128 
129  //flight distance
130  double fD = lX * nX + lY * nY + lZ * nZ;
131  //flight time
132  double fT = daughter->getPDGMass() / Const::speedOfLight * fD / p;
133 
134  //covariance matrix of momentum and vertex for the Dz
135  //ORDER = px,py,pz,E,x,y,z
136  TMatrixFSym dauCov = daughter->getMomentumVertexErrorMatrix();
137  TMatrixFSym mumCov = particle->getVertexErrorMatrix(); //order: x,y,z
138  if (particle == daughter) {
139  if (hasRAVEBeamConstrainedProductionVertex(particle)) {
140  std::vector<std::string> directions = {"x", "y", "z"};
141  for (unsigned int i = 0; i < directions.size(); i++) {
142  for (unsigned int j = 0; j < directions.size(); j++) {
143  mumCov[i][j] = particle->getExtraInfo(boost::str(boost::format("prodVertS%s%s") % directions[i] % directions[j]));
144  }
145  }
146  } else {
147  static DBObjPtr<BeamSpot> beamSpotDB;
148  mumCov = beamSpotDB->getCovVertex();
149  }
150  }
151  //compute total covariance matrix
152  //ORDER = px dau, py dau, pz dau, E dau, x dau, y dau, z dau, x mum, y mum, z mum
153 
154  TMatrixFSym Cov(10);
155  for (int i = 0; i < 10; i++)
156  for (int j = 0; j < 10; j++)
157  if (i < 7 && j < 7)
158  Cov[i][j] = dauCov[i][j];
159  else if (i > 6 && j > 6)
160  Cov[i][j] = mumCov[i - 7][j - 7];
161  else
162  Cov[i][j] = 0;
163 
164  if (mode == "distance") {
165  TMatrixF deriv(10, 1);
166  deriv[0][0] = (lX - nX * fD) / p; //px Daughter
167  deriv[1][0] = (lY - nY * fD) / p; //py Daughter
168  deriv[2][0] = (lZ - nZ * fD) / p; //pz Daughter
169  deriv[3][0] = 0; //E Daughter
170  deriv[4][0] = nX; //vtxX Daughter
171  deriv[5][0] = nY; //vtxY Daughter
172  deriv[6][0] = nZ; //vtxZ Daughter
173  deriv[7][0] = - nX; //vtxX Mother
174  deriv[8][0] = - nY; //vtxY Mother
175  deriv[9][0] = - nZ; //vtxZ Mother
176 
177 
178  TMatrixF tmp(10, 1);
179  tmp.Mult(Cov, deriv);
180 
181  TMatrixF result(1, 1);
182  result.Mult(deriv.T(), tmp);
183 
184  outErr = sqrt(result[0][0]);
185  return fD;
186  }
187  if (mode == "time") {
188  TMatrixF deriv(10, 1);
189  deriv[0][0] = (daughter->getPDGMass() / Const::speedOfLight * lX - 2 * pX * fT) / p / p; //px Daughter
190  deriv[1][0] = (daughter->getPDGMass() / Const::speedOfLight * lY - 2 * pY * fT) / p / p; //py Daughter
191  deriv[2][0] = (daughter->getPDGMass() / Const::speedOfLight * lZ - 2 * pZ * fT) / p / p; //pz Daughter
192  deriv[3][0] = 0; //E Daughter
193  deriv[4][0] = daughter->getPDGMass() / Const::speedOfLight * pX / p / p; //vtxX Daughter
194  deriv[5][0] = daughter->getPDGMass() / Const::speedOfLight * pY / p / p; //vtxY Daughter
195  deriv[6][0] = daughter->getPDGMass() / Const::speedOfLight * pZ / p / p; //vtxZ Daughter
196  deriv[7][0] = - daughter->getPDGMass() / Const::speedOfLight * pX / p / p; //vtxX Mother
197  deriv[8][0] = - daughter->getPDGMass() / Const::speedOfLight * pY / p / p; //vtxY Mother
198  deriv[9][0] = - daughter->getPDGMass() / Const::speedOfLight * pZ / p / p; //vtxZ Mother
199 
200 
201  TMatrixF tmp(10, 1);
202  tmp.Mult(Cov, deriv);
203 
204  TMatrixF result(1, 1);
205  result.Mult(deriv.T(), tmp);
206  outErr = sqrt(result[0][0]);
207  return fT;
208  }
209  outErr = std::numeric_limits<float>::quiet_NaN();
210  return std::numeric_limits<float>::quiet_NaN();
211  }
212 
213  // Helper function for MC flight time and distance
214  inline double getMCFlightInfoBtw(const MCParticle* mcparticle, const std::string& mode)
215  {
216 
217  if (mcparticle == nullptr)
218  return std::numeric_limits<float>::quiet_NaN();
219 
220 
221  if (mode == "distance") {
222  ROOT::Math::XYZVector deltaVtx = mcparticle->getDecayVertex() - mcparticle->getProductionVertex();
223  double distance = deltaVtx.R();
224  if (distance < 0)
225  B2WARNING("Negative true flight distance, it's forbidden -> something went wrong.");
226 
227  return distance;
228  }
229 
230  if (mode == "time") {
231  double lifetime = mcparticle->getLifetime();
232  double mass = mcparticle->getMass();
233  double time = std::numeric_limits<float>::quiet_NaN();
234  if (mass == 0)
235  B2WARNING("you are asking for the proper time of a massless particle which is not allowed, returning -99.");
236  else {
237  double energy = mcparticle->getEnergy();
238  time = lifetime / energy * mass;
239  }
240 
241  if (time < 0)
242  B2WARNING("Negative true proper time, it's forbidden -> something went wrong.");
243 
244  return time;
245 
246  }
247  B2WARNING("MCFlightInfo helper function called with mode '" << mode
248  << "'. Only 'distance' and 'time' are available.");
249  return std::numeric_limits<float>::quiet_NaN();
250 
251  }
252 
253  double flightDistance(const Particle* part)
254  {
255  double flightDistanceError = std::numeric_limits<float>::quiet_NaN();
256  return getFlightInfoBtw(part, part, flightDistanceError, "distance");
257  }
258 
259  double flightTime(const Particle* part)
260  {
261  double flightTimeError = std::numeric_limits<float>::quiet_NaN();
262  return getFlightInfoBtw(part, part, flightTimeError, "time");
263  }
264 
265  double flightDistanceErr(const Particle* part)
266  {
267  double flightDistanceError = std::numeric_limits<float>::quiet_NaN();
268  getFlightInfoBtw(part, part, flightDistanceError, "distance");
269  return flightDistanceError;
270  }
271 
272  double flightTimeErr(const Particle* part)
273  {
274  double flightTimeError = std::numeric_limits<float>::quiet_NaN();
275  getFlightInfoBtw(part, part, flightTimeError, "time");
276  return flightTimeError;
277  }
278 
279  inline double getVertexDistance(const Particle* particle, const Particle* daughter, double& vertexDistanceErr,
280  bool prodVertIsIP = false)
281  {
282  if (!particle || !daughter) {
283  vertexDistanceErr = std::numeric_limits<float>::quiet_NaN();
284  return std::numeric_limits<float>::quiet_NaN();
285  }
286 
287  // production vertex
288  double prodVtxX = particle->getX();
289  double prodVtxY = particle->getY();
290  double prodVtxZ = particle->getZ();
291  if (particle == daughter || prodVertIsIP) {
292  if (particle->hasExtraInfo("prodVertX")) prodVtxX = particle->getExtraInfo("prodVertX");
293  if (particle->hasExtraInfo("prodVertY")) prodVtxY = particle->getExtraInfo("prodVertY");
294  if (particle->hasExtraInfo("prodVertZ")) prodVtxZ = particle->getExtraInfo("prodVertZ");
295  }
296 
297  // decay vertex
298  double vtxX = daughter->getX();
299  double vtxY = daughter->getY();
300  double vtxZ = daughter->getZ();
301 
302  // difference between vertices
303  double lX = vtxX - prodVtxX;
304  double lY = vtxY - prodVtxY;
305  double lZ = vtxZ - prodVtxZ;
306 
307  // vertex distance
308  double lD = sqrt(lX * lX + lY * lY + lZ * lZ);
309 
310  // covariance matrix of both vertices
311  TMatrixFSym decCov = daughter->getVertexErrorMatrix();
312  TMatrixFSym prodCov = particle->getVertexErrorMatrix();
313  if (particle == daughter || prodVertIsIP) {
314  if (particle->hasExtraInfo("prodVertSxx")) prodCov[0][0] = particle->getExtraInfo("prodVertSxx");
315  if (particle->hasExtraInfo("prodVertSxy")) prodCov[0][1] = particle->getExtraInfo("prodVertSxy");
316  if (particle->hasExtraInfo("prodVertSxz")) prodCov[0][2] = particle->getExtraInfo("prodVertSxz");
317  if (particle->hasExtraInfo("prodVertSyx")) prodCov[1][0] = particle->getExtraInfo("prodVertSyx");
318  if (particle->hasExtraInfo("prodVertSyy")) prodCov[1][1] = particle->getExtraInfo("prodVertSyy");
319  if (particle->hasExtraInfo("prodVertSyz")) prodCov[1][2] = particle->getExtraInfo("prodVertSyz");
320  if (particle->hasExtraInfo("prodVertSzx")) prodCov[2][0] = particle->getExtraInfo("prodVertSzx");
321  if (particle->hasExtraInfo("prodVertSzy")) prodCov[2][1] = particle->getExtraInfo("prodVertSzy");
322  if (particle->hasExtraInfo("prodVertSzz")) prodCov[2][2] = particle->getExtraInfo("prodVertSzz");
323  }
324 
325  // compute total covariance matrix
326  // ORDER = prod x, prod y, prod z, decay x, decay y, decay z
327 
328  TMatrixFSym Cov(6);
329  for (int i = 0; i < 6; i++)
330  for (int j = 0; j < 6; j++)
331  if (i < 3 && j < 3)
332  Cov[i][j] = prodCov[i][j];
333  else if (i > 2 && j > 2)
334  Cov[i][j] = decCov[i - 3][j - 3];
335  else
336  Cov[i][j] = 0;
337 
338  TMatrixF deriv(6, 1);
339  deriv[0][0] = - lX / lD; // prodVtxX
340  deriv[1][0] = - lY / lD; // prodVtxY
341  deriv[2][0] = - lZ / lD; // prodVtxZ
342  deriv[3][0] = lX / lD; // vtxX
343  deriv[4][0] = lY / lD; // vtxY
344  deriv[5][0] = lZ / lD; // vtxZ
345 
346 
347  TMatrixF tmp(6, 1);
348  tmp.Mult(Cov, deriv);
349 
350  TMatrixF result(1, 1);
351  result.Mult(deriv.T(), tmp);
352 
353  vertexDistanceErr = sqrt(result[0][0]);
354  return lD;
355  }
356 
357  double vertexDistance(const Particle* part)
358  {
359  double vertexDistanceError = std::numeric_limits<float>::quiet_NaN();
360  if (!part->hasExtraInfo("prodVertX") || !part->hasExtraInfo("prodVertY") || !part->hasExtraInfo("prodVertZ")) {
361  return std::numeric_limits<float>::quiet_NaN();
362  }
363  return getVertexDistance(part, part, vertexDistanceError);
364  }
365 
366  double vertexDistanceErr(const Particle* part)
367  {
368  double vertexDistanceError = std::numeric_limits<float>::quiet_NaN();
369  if (!part->hasExtraInfo("prodVertX") || !part->hasExtraInfo("prodVertY") || !part->hasExtraInfo("prodVertZ")) {
370  return std::numeric_limits<float>::quiet_NaN();
371  }
372  getVertexDistance(part, part, vertexDistanceError);
373  return vertexDistanceError;
374  }
375 
376  double vertexDistanceSignificance(const Particle* part)
377  {
378  double vertexDistanceError = std::numeric_limits<float>::quiet_NaN();
379  if (!part->hasExtraInfo("prodVertX") || !part->hasExtraInfo("prodVertY") || !part->hasExtraInfo("prodVertZ")) {
380  return std::numeric_limits<float>::quiet_NaN();
381  }
382  return getVertexDistance(part, part, vertexDistanceError) / vertexDistanceError;
383  }
384 
385  double flightTimeOfDaughter(const Particle* particle, const std::vector<double>& daughters)
386  {
387  if (!particle)
388  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
389 
390  long daughterNumber = -1;
391  if (daughters.size() > 0) {
392  daughterNumber = std::lround(daughters[0]);
393  } else {
394  B2ERROR("At least one integer, the index of the daughter, must be provided to flightTimeOfDaughter!");
395  return std::numeric_limits<float>::quiet_NaN();
396  }
397  int nDaughters = static_cast<int>(particle->getNDaughters());
398  if (daughterNumber >= nDaughters) {
399  B2ERROR("The daughter index provided to flightTimeOfDaughter is larger than the number of daughters of this particle!");
400  return std::numeric_limits<float>::quiet_NaN();
401  }
402 
403  long grandDaughterNumber = -1;
404  if (daughters.size() == 2) {
405  grandDaughterNumber = std::lround(daughters[1]);
406  }
407 
408  const Particle* daughter = particle->getDaughter(daughterNumber);
409  double flightTimeError;
410  if (grandDaughterNumber > -1) {
411  if (grandDaughterNumber < (int)daughter->getNDaughters()) {
412  return getFlightInfoBtw(particle, daughter->getDaughter(grandDaughterNumber), flightTimeError, "time", true);
413  } else {
414  B2ERROR("The granddaughter index provided to flightTimeOfDaughter is too large!");
415  return std::numeric_limits<float>::quiet_NaN();
416  }
417  } else {
418  return getFlightInfoBtw(particle, daughter, flightTimeError, "time");
419  }
420  }
421 
422  // Flight time uncertainty
423  double flightTimeOfDaughterErr(const Particle* particle, const std::vector<double>& daughters)
424  {
425  if (!particle)
426  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
427 
428  long daughterNumber = -1;
429  if (daughters.size() > 0) {
430  daughterNumber = std::lround(daughters[0]);
431  } else {
432  B2ERROR("At least one integer, the index of the daughter, must be provided to flightTimeOfDaughterErr!");
433  return std::numeric_limits<float>::quiet_NaN();
434  }
435  int nDaughters = static_cast<int>(particle->getNDaughters());
436  if (daughterNumber >= nDaughters) {
437  B2ERROR("The daughter index provided to flightTimeOfDaughterErr is larger than the number of daughters of this particle!");
438  return std::numeric_limits<float>::quiet_NaN();
439  }
440 
441  long grandDaughterNumber = -1;
442  if (daughters.size() == 2) {
443  grandDaughterNumber = std::lround(daughters[1]);
444  }
445 
446  const Particle* daughter = particle->getDaughter(daughterNumber);
447  double flightTimeError = std::numeric_limits<float>::quiet_NaN();;
448  if (grandDaughterNumber > -1) {
449  if (grandDaughterNumber < (int)daughter->getNDaughters()) {
450  getFlightInfoBtw(particle, daughter->getDaughter(grandDaughterNumber), flightTimeError, "time", true);
451  } else {
452  B2ERROR("The granddaughter index provided to flightTimeOfDaughterErr is too large!");
453  }
454  } else {
455  getFlightInfoBtw(particle, daughter, flightTimeError, "time");
456  }
457  return flightTimeError;
458  }
459 
460  double flightDistanceOfDaughter(const Particle* particle, const std::vector<double>& daughters)
461  {
462  if (!particle)
463  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
464 
465  long daughterNumber = -1;
466  if (daughters.size() > 0) {
467  daughterNumber = std::lround(daughters[0]);
468  } else {
469  B2ERROR("At least one integer, the index of the daughter, must be provided to flightDistanceOfDaughter!");
470  return std::numeric_limits<float>::quiet_NaN();
471  }
472  int nDaughters = static_cast<int>(particle->getNDaughters());
473  if (daughterNumber >= nDaughters) {
474  B2ERROR("The daughter index provided to flightDistanceOfDaughter is larger than the number of daughters of this particle!");
475  return std::numeric_limits<float>::quiet_NaN();
476  }
477 
478  long grandDaughterNumber = -1;
479  if (daughters.size() == 2) {
480  grandDaughterNumber = std::lround(daughters[1]);
481  }
482 
483  const Particle* daughter = particle->getDaughter(daughterNumber);
484  double flightDistanceError;
485  if (grandDaughterNumber > -1) {
486  if (grandDaughterNumber < (int)daughter->getNDaughters()) {
487  return getFlightInfoBtw(particle, daughter->getDaughter(grandDaughterNumber), flightDistanceError, "distance", true);
488  } else {
489  B2ERROR("The granddaughter index provided to flightDistanceOfDaughter is too large!");
490  return std::numeric_limits<float>::quiet_NaN();
491  }
492  } else {
493  return getFlightInfoBtw(particle, daughter, flightDistanceError, "distance");
494  }
495  }
496 
497  // Flight distance uncertainty
498  double flightDistanceOfDaughterErr(const Particle* particle, const std::vector<double>& daughters)
499  {
500  if (!particle)
501  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
502 
503  long daughterNumber = -1;
504  if (daughters.size() > 0) {
505  daughterNumber = std::lround(daughters[0]);
506  } else {
507  B2ERROR("At least one integer, the index of the daughter, must be provided to flightDistanceOfDaughterErr!");
508  return std::numeric_limits<float>::quiet_NaN();
509  }
510  int nDaughters = static_cast<int>(particle->getNDaughters());
511  if (daughterNumber >= nDaughters) {
512  B2ERROR("The daughter index provided to flightDistanceOfDaughterErr is larger than the number of daughters of this particle!");
513  return std::numeric_limits<float>::quiet_NaN();
514  }
515 
516  long grandDaughterNumber = -1;
517  if (daughters.size() == 2) {
518  grandDaughterNumber = std::lround(daughters[1]);
519  }
520 
521  const Particle* daughter = particle->getDaughter(daughterNumber);
522  double flightDistanceError = std::numeric_limits<float>::quiet_NaN();
523  if (grandDaughterNumber > -1) {
524  if (grandDaughterNumber < (int)daughter->getNDaughters()) {
525  getFlightInfoBtw(particle, daughter->getDaughter(grandDaughterNumber), flightDistanceError, "distance", true);
526  } else {
527  B2ERROR("The granddaughter index provided to flightDistanceOfDaughterErr is too large!");
528  }
529  } else {
530  getFlightInfoBtw(particle, daughter, flightDistanceError, "distance");
531  }
532  return flightDistanceError;
533  }
534 
535  // Distance between mother and daughter vertices
536  double vertexDistanceOfDaughter(const Particle* particle, const std::vector<double>& arguments)
537  {
538  if (!particle)
539  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
540  long daughterNumber = -1;
541  if (arguments.size() > 0) {
542  daughterNumber = std::lround(arguments[0]);
543  } else {
544  B2ERROR("At least one integer, the index of the daughter, must be provided to vertexDistanceOfDaughter!");
545  return std::numeric_limits<float>::quiet_NaN();
546  }
547  int nDaughters = static_cast<int>(particle->getNDaughters());
548  if (daughterNumber >= nDaughters) {
549  B2ERROR("The daughter index provided to vertexDistanceOfDaughter is larger than the number of daughters of this particle!");
550  return std::numeric_limits<float>::quiet_NaN();
551  }
552 
553  bool prodVertIsIP = true;
554  if (arguments.size() == 2) {
555  prodVertIsIP = false;
556  }
557 
558  const Particle* daughter = particle->getDaughter(daughterNumber);
559  double vertexDistanceError;
560  return getVertexDistance(particle, daughter, vertexDistanceError, prodVertIsIP);
561  }
562 
563  // Uncertainty on distance between mother and daughter vertices
564  double vertexDistanceOfDaughterErr(const Particle* particle, const std::vector<double>& arguments)
565  {
566  if (!particle)
567  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
568  long daughterNumber = -1;
569  if (arguments.size() > 0) {
570  daughterNumber = std::lround(arguments[0]);
571  } else {
572  B2ERROR("At least one integer, the index of the daughter, must be provided to vertexDistanceOfDaughterErr!");
573  return std::numeric_limits<float>::quiet_NaN();
574  }
575  int nDaughters = static_cast<int>(particle->getNDaughters());
576  if (daughterNumber >= nDaughters) {
577  B2ERROR("The daughter index provided to vertexDistanceOfDaughterErr is larger than the number of daughters of this particle!");
578  return std::numeric_limits<float>::quiet_NaN();
579  }
580 
581  bool prodVertIsIP = true;
582  if (arguments.size() == 2) {
583  prodVertIsIP = false;
584  }
585 
586  const Particle* daughter = particle->getDaughter(daughterNumber);
587  double vertexDistanceError;
588  getVertexDistance(particle, daughter, vertexDistanceError, prodVertIsIP);
589  return vertexDistanceError;
590  }
591 
592  // Significance of distance between mother and daughter vertices
593  double vertexDistanceOfDaughterSignificance(const Particle* particle, const std::vector<double>& arguments)
594  {
595  if (!particle)
596  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
597  long daughterNumber = -1;
598  if (arguments.size() > 0) {
599  daughterNumber = std::lround(arguments[0]);
600  } else {
601  B2ERROR("At least one integer, the index of the daughter, must be provided to vertexDistanceOfDaughterSignificance!");
602  return std::numeric_limits<float>::quiet_NaN();
603  }
604  int nDaughters = static_cast<int>(particle->getNDaughters());
605  if (daughterNumber >= nDaughters) {
606  B2ERROR("The daughter index provided to vertexDistanceOfDaughterSignificance is larger than the number of daughters of this particle!");
607  return std::numeric_limits<float>::quiet_NaN();
608  }
609 
610  bool prodVertIsIP = true;
611  if (arguments.size() == 2) {
612  prodVertIsIP = false;
613  }
614 
615  const Particle* daughter = particle->getDaughter(daughterNumber);
616  double vertexDistanceError;
617  return getVertexDistance(particle, daughter, vertexDistanceError, prodVertIsIP) / vertexDistanceError;
618  }
619 
620  // MC variables
621 
622  double mcFlightDistance(const Particle* particle)
623  {
624  if (particle == nullptr)
625  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
626 
627  const MCParticle* mcparticle = particle->getMCParticle();
628 
629  if (mcparticle == nullptr)
630  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
631 
632  return getMCFlightInfoBtw(mcparticle, "distance");
633  }
634 
635  double mcFlightTime(const Particle* particle)
636  {
637  if (particle == nullptr)
638  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
639 
640  const MCParticle* mcparticle = particle->getMCParticle();
641 
642  if (mcparticle == nullptr)
643  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
644 
645 
646  return getMCFlightInfoBtw(mcparticle, "time");
647  }
648 
649  double mcFlightDistanceOfDaughter(const Particle* particle, const std::vector<double>& daughters)
650  {
651  if (!particle)
652  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
653 
654  long daughterNumber = -1;
655  if (daughters.size() > 0) {
656  daughterNumber = std::lround(daughters[0]);
657  } else {
658  B2ERROR("At least one integer, the index of the daughter, must be provided to mcFlightDistanceOfDaughter!");
659  return std::numeric_limits<float>::quiet_NaN();
660  }
661  int nDaughters = static_cast<int>(particle->getNDaughters());
662  if (daughterNumber >= nDaughters) {
663  B2ERROR("The daughter index provided to mcFlightDistanceOfDaughter is larger than the number of daughters of this particle!");
664  return std::numeric_limits<float>::quiet_NaN();
665  }
666 
667  long grandDaughterNumber = -1;
668  if (daughters.size() == 2) {
669  grandDaughterNumber = std::lround(daughters[1]);
670  }
671 
672  const Particle* daughterReco = particle->getDaughter(daughterNumber);
673  //get the MC DAUGHTER
674  const MCParticle* daughter = daughterReco->getMCParticle();
675 
676  double flightDistanceMC;
677  if (grandDaughterNumber > -1 && grandDaughterNumber < (int)daughterReco->getNDaughters()) {
678  // Compute value between mother and granddaughter
679  const MCParticle* gdaughter = daughterReco->getDaughter(grandDaughterNumber)->getMCParticle();
680  flightDistanceMC = getMCFlightInfoBtw(gdaughter, "distance");
681  } else {
682  // Compute value between mother and daughter
683  flightDistanceMC = getMCFlightInfoBtw(daughter, "distance");
684  }
685  return flightDistanceMC;
686  }
687 
688  double mcFlightTimeOfDaughter(const Particle* particle, const std::vector<double>& daughters)
689  {
690  if (!particle)
691  return std::numeric_limits<float>::quiet_NaN(); // Initial particle is NULL
692 
693  long daughterNumber = -1;
694  if (daughters.size() > 0) {
695  daughterNumber = std::lround(daughters[0]);
696  } else {
697  B2ERROR("At least one integer, the index of the daughter, must be provided to mcFlightTimeOfDaughter!");
698  return std::numeric_limits<float>::quiet_NaN();
699  }
700  int nDaughters = static_cast<int>(particle->getNDaughters());
701  if (daughterNumber >= nDaughters) {
702  B2ERROR("The daughter index provided to mcFlightTimeOfDaughter is larger than the number of daughters of this particle!");
703  return std::numeric_limits<float>::quiet_NaN();
704  }
705 
706  long grandDaughterNumber = -1;
707  if (daughters.size() == 2) {
708  grandDaughterNumber = std::lround(daughters[1]);
709  }
710 
711  const Particle* daughterReco = particle->getDaughter(daughterNumber);
712  //get the MC DAUGHTER
713  const MCParticle* daughter = daughterReco->getMCParticle();
714 
715  double flightTimeMC;
716  if (grandDaughterNumber > -1 && grandDaughterNumber < (int)daughterReco->getNDaughters()) {
717  // Compute value between mother and granddaughter
718  const MCParticle* gdaughter = daughterReco->getDaughter(grandDaughterNumber)->getMCParticle();
719  flightTimeMC = getMCFlightInfoBtw(gdaughter, "time");
720  } else {
721  flightTimeMC = getMCFlightInfoBtw(daughter, "time");
722  }
723  return flightTimeMC;
724  }
725 
726 
727  VARIABLE_GROUP("Flight Information");
728  REGISTER_VARIABLE("flightTime", flightTime,
729  "Returns the flight time of particle. If a treeFit has been performed the flight time calculated by TreeFitter is returned. Otherwise if a beam constrained rave fit has been performed the production vertex set by rave and the decay vertex are used to calculate the flight time. If neither fit has been performed the i.p. is taken to be the production vertex.",
730  "ns");
731  REGISTER_VARIABLE("flightDistance", flightDistance,
732  "Returns the flight distance of particle. If a treeFit has been performed the flight distance calculated by TreeFitter is returned. Otherwise if a beam constrained rave fit has been performed the production vertex set by rave and the decay vertex are used to calculate the flight distance. If neither fit has been performed the i.p. is taken to be the production vertex.",
733  "cm");
734  REGISTER_VARIABLE("flightTimeErr", flightTimeErr,
735  "Returns the flight time error of particle. If a treeFit has been performed the flight time error calculated by TreeFitter is returned. Otherwise if a beam constrained rave fit has been performed the production vertex set by rave and the decay vertex are used to calculate the flight time error. If neither fit has been performed the i.p. is taken to be the production vertex.",
736  "ns");
737  REGISTER_VARIABLE("flightDistanceErr", flightDistanceErr,
738  "Returns the flight distance error of particle. If a treeFit has been performed the flight distance error calculated by TreeFitter is returned. Otherwise if a beam constrained rave fit has been performed the production vertex set by rave and the decay vertex are used to calculate the flight distance error. If neither fit has been performed the i.p. is taken to be the production vertex.",
739  "cm");
740  // Daughters
741  REGISTER_VARIABLE("flightTimeOfDaughter(daughterN, gdaughterN = -1)", flightTimeOfDaughter,
742  "Returns the flight time between mother and daughter particle with daughterN index. If a treeFit has been performed the value calculated by treeFitter is returned. Otherwise the value is calculated using the decay vertices of the mother and daughter particle. If a second index granddaughterM is given the value is calculated between the mother and the Mth grandaughter (Mth daughter of Nth daughter).",
743  "ns");
744  REGISTER_VARIABLE("flightTimeOfDaughterErr(daughterN, gdaughterN = -1)", flightTimeOfDaughterErr,
745  "Returns the flight time error between mother and daughter particle with daughterN index. If a treeFit has been performed the value calculated by treeFitter is returned. Otherwise the value is calculated using the decay vertices of the mother and daughter particle. If a second index granddaughterM is given the value is calculated between the mother and the Mth grandaughter (Mth daughter of Nth daughter).",
746  "ns");
747  REGISTER_VARIABLE("flightDistanceOfDaughter(daughterN, gdaughterN = -1)", flightDistanceOfDaughter,
748  "Returns the flight distance between mother and daughter particle with daughterN index. If a treeFit has been performed the value calculated by treeFitter is returned. Otherwise the value is calculated using the decay vertices of the mother and daughter particle. If a second index granddaughterM is given the value is calculated between the mother and the Mth grandaughter (Mth daughter of Nth daughter).",
749  "cm");
750  REGISTER_VARIABLE("flightDistanceOfDaughterErr(daughterN, gdaughterN = -1)", flightDistanceOfDaughterErr,
751  "Returns the flight distance error between mother and daughter particle with daughterN index. If a treeFit has been performed the value calculated by treeFitter is returned. Otherwise the value is calculated using the decay vertices of the mother and daughter particle. If a second index granddaughterM is given the value is calculated between the mother and the Mth grandaughter (Mth daughter of Nth daughter).",
752  "cm");
753  // MC Info
754  REGISTER_VARIABLE("mcFlightDistance", mcFlightDistance,
755  "Returns the MC flight distance of the particle", "cm");
756  REGISTER_VARIABLE("mcFlightTime", mcFlightTime,
757  "Returns the MC flight time of the particle", "ns");
758  REGISTER_VARIABLE("mcFlightDistanceOfDaughter(daughterN, gdaughterN = -1)", mcFlightDistanceOfDaughter,
759  "Returns the MC flight distance between mother and daughter particle using generated info", "cm");
760  REGISTER_VARIABLE("mcFlightTimeOfDaughter(daughterN, gdaughterN = -1)", mcFlightTimeOfDaughter,
761  "Returns the MC flight time between mother and daughter particle using generated info", "ns");
762  //Vertex Distance
763  REGISTER_VARIABLE("vertexDistance", vertexDistance,
764  "Returns the distance between the production and decay vertex of a particle. Returns NaN if particle has no production or decay vertex.",
765  "cm");
766  REGISTER_VARIABLE("vertexDistanceErr", vertexDistanceErr,
767  "Returns the uncertainty on the distance between the production and decay vertex of a particle. Returns NaN if particle has no production or decay vertex.",
768  "cm");
769  REGISTER_VARIABLE("vertexDistanceSignificance", vertexDistanceSignificance,
770  "Returns the distance between the production and decay vertex of a particle in units of the uncertainty on this value, i.e. the significance of the vertex separation.");
771  REGISTER_VARIABLE("vertexDistanceOfDaughter(daughterN[, option])", vertexDistanceOfDaughter,
772  "If any integer is provided as second argument it returns the distance between the decay vertices of the particle and of its daughter with index daughterN.\n"
773  "Otherwise, it is assumed that the particle has a production vertex (typically the IP) which is used to calculate the distance to the daughter's decay vertex.\n"
774  "Returns NaN in case anything goes wrong.", "cm");
775  REGISTER_VARIABLE("vertexDistanceOfDaughterErr(daughterN[, option])", vertexDistanceOfDaughterErr,
776  "If any integer is provided as second argument it returns the uncertainty on the distance between the decay vertices of the particle and of its daughter with index daughterN.\n"
777  "Otherwise, it is assumed that the particle has a production vertex (typically the IP) with a corresponding covariance matrix to calculate the uncertainty on the distance to the daughter's decay vertex.\n"
778  "Returns NaN in case anything goes wrong.", "cm");
779  REGISTER_VARIABLE("vertexDistanceOfDaughterSignificance(daughterN[, option)", vertexDistanceOfDaughterSignificance,
780  "If any integer is provided as second argument it returns the distance between the decay vertices of the particle and of its daughter with index daughterN in units of the uncertainty on this value.\n"
781  "Otherwise, it is assumed that the particle has a production vertex (typically the IP) with a corresponding covariance matrix and the significance of the separation to this vertex is calculated.");
782  }
784 } // Belle2 namespace
static const double speedOfLight
[cm/ns]
Definition: Const.h:685
const MCParticle * getMCParticle() const
Returns the pointer to the MCParticle object that was used to create this Particle (ParticleType == c...
Definition: Particle.cc:972
const Particle * getDaughter(unsigned i) const
Returns a pointer to the i-th daughter particle.
Definition: Particle.cc:663
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:23