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