Belle II Software  light-2205-abys
Variables.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/Variables.h>
11 
12 // include VariableManager
13 #include <analysis/VariableManager/Manager.h>
14 
15 #include <analysis/utility/PCmsLabTransform.h>
16 #include <analysis/utility/ReferenceFrame.h>
17 #include <analysis/utility/MCMatching.h>
18 #include <analysis/ClusterUtility/ClusterUtils.h>
19 
20 // framework - DataStore
21 #include <framework/datastore/StoreArray.h>
22 #include <framework/datastore/StoreObjPtr.h>
23 
24 // dataobjects
25 #include <analysis/dataobjects/Particle.h>
26 #include <analysis/dataobjects/EventExtraInfo.h>
27 #include <analysis/dataobjects/EventShapeContainer.h>
28 
29 #include <mdst/dataobjects/MCParticle.h>
30 #include <mdst/dataobjects/Track.h>
31 #include <mdst/dataobjects/ECLCluster.h>
32 #include <mdst/dataobjects/V0.h>
33 
34 #include <mdst/dbobjects/BeamSpot.h>
35 
36 // framework aux
37 #include <framework/logging/Logger.h>
38 #include <framework/geometry/B2Vector3.h>
39 #include <framework/geometry/BFieldManager.h>
40 #include <framework/gearbox/Const.h>
41 
42 #include <Math/Vector4D.h>
43 #include <TRandom.h>
44 #include <TVectorF.h>
45 
46 #include <iostream>
47 #include <cmath>
48 
49 using namespace std;
50 
51 namespace Belle2 {
56  namespace Variable {
57 
58 // momentum -------------------------------------------
59 
60  double particleP(const Particle* part)
61  {
62  const auto& frame = ReferenceFrame::GetCurrent();
63  return frame.getMomentum(part).P();
64  }
65 
66  double particleE(const Particle* part)
67  {
68  const auto& frame = ReferenceFrame::GetCurrent();
69  return frame.getMomentum(part).E();
70  }
71 
72  double particleClusterEUncertainty(const Particle* part)
73  {
74  const ECLCluster* cluster = part->getECLCluster();
75  if (cluster) {
76  const auto EPhiThetaCov = cluster->getCovarianceMatrix3x3();
77  return std::sqrt(EPhiThetaCov[0][0]);
78  }
79  return std::numeric_limits<double>::quiet_NaN();
80  }
81 
82  double particlePx(const Particle* part)
83  {
84  const auto& frame = ReferenceFrame::GetCurrent();
85  return frame.getMomentum(part).Px();
86  }
87 
88  double particlePy(const Particle* part)
89  {
90  const auto& frame = ReferenceFrame::GetCurrent();
91  return frame.getMomentum(part).Py();
92  }
93 
94  double particlePz(const Particle* part)
95  {
96  const auto& frame = ReferenceFrame::GetCurrent();
97  return frame.getMomentum(part).Pz();
98  }
99 
100  double particlePt(const Particle* part)
101  {
102  const auto& frame = ReferenceFrame::GetCurrent();
103  return frame.getMomentum(part).Pt();
104  }
105 
106  double covMatrixElement(const Particle* part, const std::vector<double>& element)
107  {
108  int elementI = int(std::lround(element[0]));
109  int elementJ = int(std::lround(element[1]));
110 
111  if (elementI < 0 || elementI > 6) {
112  B2WARNING("Requested particle's momentumVertex covariance matrix element is out of boundaries [0 - 6]:" << LogVar("i", elementI));
113  return std::numeric_limits<double>::quiet_NaN();
114  }
115  if (elementJ < 0 || elementJ > 6) {
116  B2WARNING("Requested particle's momentumVertex covariance matrix element is out of boundaries [0 - 6]:" << LogVar("j", elementJ));
117  return std::numeric_limits<double>::quiet_NaN();
118  }
119 
120  return part->getMomentumVertexErrorMatrix()(elementI, elementJ);
121  }
122 
123  double particleEUncertainty(const Particle* part)
124  {
125  const auto& frame = ReferenceFrame::GetCurrent();
126 
127  double errorSquared = frame.getMomentumErrorMatrix(part)(3, 3);
128 
129  if (errorSquared >= 0.0)
130  return sqrt(errorSquared);
131  else
132  return std::numeric_limits<double>::quiet_NaN();
133  }
134 
135  double particlePErr(const Particle* part)
136  {
137  TMatrixD jacobianRot(3, 3);
138  jacobianRot.Zero();
139 
140  double cosPhi = cos(particlePhi(part));
141  double sinPhi = sin(particlePhi(part));
142  double cosTheta = particleCosTheta(part);
143  double sinTheta = sin(acos(cosTheta));
144  double p = particleP(part);
145 
146  jacobianRot(0, 0) = sinTheta * cosPhi;
147  jacobianRot(0, 1) = sinTheta * sinPhi;
148  jacobianRot(1, 0) = cosTheta * cosPhi / p;
149  jacobianRot(1, 1) = cosTheta * sinPhi / p;
150  jacobianRot(0, 2) = cosTheta;
151  jacobianRot(2, 0) = -sinPhi / sinTheta / p;
152  jacobianRot(1, 2) = -sinTheta / p;
153  jacobianRot(2, 1) = cosPhi / sinTheta / p;
154 
155  const auto& frame = ReferenceFrame::GetCurrent();
156 
157  double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2, " ").Similarity(jacobianRot)(0, 0);
158 
159  if (errorSquared >= 0.0)
160  return sqrt(errorSquared);
161  else
162  return std::numeric_limits<double>::quiet_NaN();
163  }
164 
165  double particlePxErr(const Particle* part)
166  {
167  const auto& frame = ReferenceFrame::GetCurrent();
168 
169  double errorSquared = frame.getMomentumErrorMatrix(part)(0, 0);
170 
171  if (errorSquared >= 0.0)
172  return sqrt(errorSquared);
173  else
174  return std::numeric_limits<double>::quiet_NaN();
175  }
176 
177  double particlePyErr(const Particle* part)
178  {
179  const auto& frame = ReferenceFrame::GetCurrent();
180  double errorSquared = frame.getMomentumErrorMatrix(part)(1, 1);
181 
182  if (errorSquared >= 0.0)
183  return sqrt(errorSquared);
184  else
185  return std::numeric_limits<double>::quiet_NaN();
186  }
187 
188  double particlePzErr(const Particle* part)
189  {
190  const auto& frame = ReferenceFrame::GetCurrent();
191  double errorSquared = frame.getMomentumErrorMatrix(part)(2, 2);
192 
193  if (errorSquared >= 0.0)
194  return sqrt(errorSquared);
195  else
196  return std::numeric_limits<double>::quiet_NaN();
197  }
198 
199  double particlePtErr(const Particle* part)
200  {
201  TMatrixD jacobianRot(3, 3);
202  jacobianRot.Zero();
203 
204  double px = particlePx(part);
205  double py = particlePy(part);
206  double pt = particlePt(part);
207 
208  jacobianRot(0, 0) = px / pt;
209  jacobianRot(0, 1) = py / pt;
210  jacobianRot(1, 0) = -py / (pt * pt);
211  jacobianRot(1, 1) = px / (pt * pt);
212  jacobianRot(2, 2) = 1;
213 
214  const auto& frame = ReferenceFrame::GetCurrent();
215  double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2, " ").Similarity(jacobianRot)(0, 0);
216 
217  if (errorSquared >= 0.0)
218  return sqrt(errorSquared);
219  else
220  return std::numeric_limits<double>::quiet_NaN();
221  }
222 
223  double momentumDeviationChi2(const Particle* part)
224  {
225  double result = std::numeric_limits<double>::quiet_NaN();
226 
227  // check if error matrix is set
228  if (part->getPValue() < 0.0)
229  return result;
230 
231  // check if mc match exists
232  const MCParticle* mcp = part->getMCParticle();
233  if (mcp == nullptr)
234  return result;
235 
236  result = 0.0;
237  result += TMath::Power(part->getPx() - mcp->getMomentum().Px(), 2.0) / part->getMomentumVertexErrorMatrix()(0, 0);
238  result += TMath::Power(part->getPy() - mcp->getMomentum().Py(), 2.0) / part->getMomentumVertexErrorMatrix()(1, 1);
239  result += TMath::Power(part->getPz() - mcp->getMomentum().Pz(), 2.0) / part->getMomentumVertexErrorMatrix()(2, 2);
240 
241  return result;
242  }
243 
244  double particleTheta(const Particle* part)
245  {
246  const auto& frame = ReferenceFrame::GetCurrent();
247  return frame.getMomentum(part).Theta();
248  }
249 
250  double particleThetaErr(const Particle* part)
251  {
252  TMatrixD jacobianRot(3, 3);
253  jacobianRot.Zero();
254 
255  double cosPhi = cos(particlePhi(part));
256  double sinPhi = sin(particlePhi(part));
257  double cosTheta = particleCosTheta(part);
258  double sinTheta = sin(acos(cosTheta));
259  double p = particleP(part);
260 
261  jacobianRot(0, 0) = sinTheta * cosPhi;
262  jacobianRot(0, 1) = sinTheta * sinPhi;
263  jacobianRot(1, 0) = cosTheta * cosPhi / p;
264  jacobianRot(1, 1) = cosTheta * sinPhi / p;
265  jacobianRot(0, 2) = cosTheta;
266  jacobianRot(2, 0) = -sinPhi / sinTheta / p;
267  jacobianRot(1, 2) = -sinTheta / p;
268  jacobianRot(2, 1) = cosPhi / sinTheta / p;
269 
270  const auto& frame = ReferenceFrame::GetCurrent();
271  double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2, " ").Similarity(jacobianRot)(1, 1);
272 
273  if (errorSquared >= 0.0)
274  return sqrt(errorSquared);
275  else
276  return std::numeric_limits<double>::quiet_NaN();
277  }
278 
279  double particleCosTheta(const Particle* part)
280  {
281  const auto& frame = ReferenceFrame::GetCurrent();
282  return cos(frame.getMomentum(part).Theta());
283  }
284 
285  double particleCosThetaErr(const Particle* part)
286  {
287  return fabs(particleThetaErr(part) * sin(particleTheta(part)));
288  }
289 
290  double particlePhi(const Particle* part)
291  {
292  const auto& frame = ReferenceFrame::GetCurrent();
293  return frame.getMomentum(part).Phi();
294  }
295 
296  double particlePhiErr(const Particle* part)
297  {
298  TMatrixD jacobianRot(3, 3);
299  jacobianRot.Zero();
300 
301  double px = particlePx(part);
302  double py = particlePy(part);
303  double pt = particlePt(part);
304 
305  jacobianRot(0, 0) = px / pt;
306  jacobianRot(0, 1) = py / pt;
307  jacobianRot(1, 0) = -py / (pt * pt);
308  jacobianRot(1, 1) = px / (pt * pt);
309  jacobianRot(2, 2) = 1;
310 
311  const auto& frame = ReferenceFrame::GetCurrent();
312  double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2, " ").Similarity(jacobianRot)(1, 1);
313 
314  if (errorSquared >= 0.0)
315  return sqrt(errorSquared);
316  else
317  return std::numeric_limits<double>::quiet_NaN();
318  }
319 
320  double particleXp(const Particle* part)
321  {
322  PCmsLabTransform T;
323  ROOT::Math::PxPyPzEVector p4 = part -> get4Vector();
324  ROOT::Math::PxPyPzEVector p4CMS = T.rotateLabToCms() * p4;
325  float s = T.getCMSEnergy();
326  float M = part->getMass();
327  return p4CMS.P() / TMath::Sqrt(s * s / 4 - M * M);
328  }
329 
330  int particlePDGCode(const Particle* part)
331  {
332  return part->getPDGCode();
333  }
334 
335  double cosAngleBetweenMomentumAndVertexVectorInXYPlane(const Particle* part)
336  {
337  static DBObjPtr<BeamSpot> beamSpotDB;
338  double px = part->getPx();
339  double py = part->getPy();
340 
341  double xV = part->getX();
342  double yV = part->getY();
343 
344  double xIP = (beamSpotDB->getIPPosition()).X();
345  double yIP = (beamSpotDB->getIPPosition()).Y();
346 
347  double x = xV - xIP;
348  double y = yV - yIP;
349 
350  double cosangle = (px * x + py * y) / (sqrt(px * px + py * py) * sqrt(x * x + y * y));
351  return cosangle;
352  }
353 
354  double cosAngleBetweenMomentumAndVertexVector(const Particle* part)
355  {
356  static DBObjPtr<BeamSpot> beamSpotDB;
357  return cos((B2Vector3D(part->getVertex()) - beamSpotDB->getIPPosition()).Angle(B2Vector3D(part->getMomentum())));
358  }
359 
360  double cosThetaBetweenParticleAndNominalB(const Particle* part)
361  {
362 
363  int particlePDG = abs(part->getPDGCode());
364  if (particlePDG != 511 and particlePDG != 521)
365  B2FATAL("The Variables cosThetaBetweenParticleAndNominalB is only meant to be used on B mesons!");
366 
367  PCmsLabTransform T;
368  double e_Beam = T.getCMSEnergy() / 2.0; // GeV
369  double m_B = part->getPDGMass();
370  // if this is a continuum run, use an approximate Y(4S) CMS energy
371  if (e_Beam * e_Beam - m_B * m_B < 0) {
372  e_Beam = 1.0579400E+1 / 2.0; // GeV
373  }
374  double p_B = std::sqrt(e_Beam * e_Beam - m_B * m_B);
375 
376  ROOT::Math::PxPyPzEVector p = T.rotateLabToCms() * part->get4Vector();
377  double e_d = p.E();
378  double m_d = p.M();
379  double p_d = p.P();
380 
381  double theta_BY = (2 * e_Beam * e_d - m_B * m_B - m_d * m_d)
382  / (2 * p_B * p_d);
383  return theta_BY;
384  }
385 
386  double cosToThrustOfEvent(const Particle* part)
387  {
388  StoreObjPtr<EventShapeContainer> evtShape;
389  if (!evtShape) {
390  B2WARNING("Cannot find thrust of event information, did you forget to load the event shape calculation?");
391  return std::numeric_limits<float>::quiet_NaN();
392  }
393  PCmsLabTransform T;
394  B2Vector3D th = evtShape->getThrustAxis();
395  B2Vector3D particleMomentum = (T.rotateLabToCms() * part -> get4Vector()).Vect();
396  return std::cos(th.Angle(particleMomentum));
397  }
398 
399  double ImpactXY(const Particle* particle)
400  {
401  static DBObjPtr<BeamSpot> beamSpotDB;
402 
403  B2Vector3D mom = particle->getMomentum();
404 
405  B2Vector3D r = B2Vector3D(particle->getVertex()) - beamSpotDB->getIPPosition();
406 
407  B2Vector3D Bfield = BFieldManager::getInstance().getFieldInTesla(beamSpotDB->getIPPosition());
408 
409  B2Vector3D curvature = - Bfield * Const::speedOfLight * particle->getCharge(); //Curvature of the track
410  double T = TMath::Sqrt(mom.Perp2() - 2.0 * curvature * r.Cross(mom) + curvature.Mag2() * r.Perp2());
411 
412  return TMath::Abs((-2 * r.Cross(mom).z() + curvature.Mag() * r.Perp2()) / (T + mom.Perp()));
413  }
414 
415  double ArmenterosLongitudinalMomentumAsymmetry(const Particle* part)
416  {
417  const auto& frame = ReferenceFrame::GetCurrent();
418  int nDaughters = part -> getNDaughters();
419  if (nDaughters != 2)
420  B2FATAL("You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters");
421 
422  const auto& daughters = part -> getDaughters();
423  B2Vector3D motherMomentum = frame.getMomentum(part).Vect();
424  B2Vector3D daughter1Momentum = frame.getMomentum(daughters[0]).Vect();
425  B2Vector3D daughter2Momentum = frame.getMomentum(daughters[1]).Vect();
426 
427  int daughter1Charge = daughters[0] -> getCharge();
428  int daughter2Charge = daughters[1] -> getCharge();
429  double daughter1Ql = daughter1Momentum.Dot(motherMomentum) / motherMomentum.Mag();
430  double daughter2Ql = daughter2Momentum.Dot(motherMomentum) / motherMomentum.Mag();
431 
432  double Arm_alpha;
433  if (daughter2Charge > daughter1Charge)
434  Arm_alpha = (daughter2Ql - daughter1Ql) / (daughter2Ql + daughter1Ql);
435  else
436  Arm_alpha = (daughter1Ql - daughter2Ql) / (daughter1Ql + daughter2Ql);
437 
438  return Arm_alpha;
439  }
440 
441  double ArmenterosDaughter1Qt(const Particle* part)
442  {
443  const auto& frame = ReferenceFrame::GetCurrent();
444  int nDaughters = part -> getNDaughters();
445  if (nDaughters != 2)
446  B2FATAL("You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters.");
447 
448  const auto& daughters = part -> getDaughters();
449  B2Vector3D motherMomentum = frame.getMomentum(part).Vect();
450  B2Vector3D daughter1Momentum = frame.getMomentum(daughters[0]).Vect();
451  double qt = daughter1Momentum.Perp(motherMomentum);
452 
453  return qt;
454  }
455 
456  double ArmenterosDaughter2Qt(const Particle* part)
457  {
458  const auto& frame = ReferenceFrame::GetCurrent();
459  int nDaughters = part -> getNDaughters();
460  if (nDaughters != 2)
461  B2FATAL("You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters.");
462 
463  const auto& daughters = part -> getDaughters();
464  B2Vector3D motherMomentum = frame.getMomentum(part).Vect();
465  B2Vector3D daughter2Momentum = frame.getMomentum(daughters[1]).Vect();
466  double qt = daughter2Momentum.Perp(motherMomentum);
467 
468  return qt;
469  }
470 
471 
472 // mass ------------------------------------------------------------
473 
474  double particleMass(const Particle* part)
475  {
476  return part->getMass();
477  }
478 
479  double particleDMass(const Particle* part)
480  {
481  return part->getMass() - part->getPDGMass();
482  }
483 
484  double particleInvariantMassFromDaughters(const Particle* part)
485  {
486  const std::vector<Particle*> daughters = part->getDaughters();
487  if (daughters.size() > 0) {
488  ROOT::Math::PxPyPzEVector sum;
489  for (auto daughter : daughters)
490  sum += daughter->get4Vector();
491 
492  return sum.M();
493  } else {
494  return part->getMass(); // !
495  }
496  }
497 
498  double particleInvariantMassFromDaughtersDisplaced(const Particle* part)
499  {
500  B2Vector3D vertex = part->getVertex();
501  if (part->getParticleSource() != Particle::EParticleSourceObject::c_V0
502  && vertex.Perp() < 0.5) return particleInvariantMassFromDaughters(part);
503 
504  const std::vector<Particle*> daughters = part->getDaughters();
505  if (daughters.size() == 0) return particleInvariantMassFromDaughters(part);
506 
507  const double bField = BFieldManager::getFieldInTesla(vertex).Z();
508  ROOT::Math::PxPyPzMVector sum;
509  for (auto daughter : daughters) {
510  const TrackFitResult* tfr = daughter->getTrackFitResult();
511  if (!tfr) {
512  sum += daughter->get4Vector();
513  continue;
514  }
515  Helix helix = tfr->getHelix();
516  helix.passiveMoveBy(vertex);
517  double scalingFactor = daughter->getEffectiveMomentumScale();
518  double momX = scalingFactor * helix.getMomentumX(bField);
519  double momY = scalingFactor * helix.getMomentumY(bField);
520  double momZ = scalingFactor * helix.getMomentumZ(bField);
521  float mPDG = daughter->getPDGMass();
522  sum += ROOT::Math::PxPyPzMVector(momX, momY, momZ, mPDG);
523  }
524  return sum.M();
525  }
526 
527  double particleInvariantMassLambda(const Particle* part)
528  {
529  const std::vector<Particle*> daughters = part->getDaughters();
530  if (daughters.size() == 2) {
531  ROOT::Math::PxPyPzEVector dt1;
532  ROOT::Math::PxPyPzEVector dt2;
533  ROOT::Math::PxPyPzEVector dtsum;
534  double mpi = Const::pionMass;
535  double mpr = Const::protonMass;
536  dt1 = daughters[0]->get4Vector();
537  dt2 = daughters[1]->get4Vector();
538  double E1 = hypot(mpi, dt1.P());
539  double E2 = hypot(mpr, dt2.P());
540  dtsum = dt1 + dt2;
541  return sqrt((E1 + E2) * (E1 + E2) - dtsum.P() * dtsum.P());
542 
543  } else {
544  return part->getMass();
545  }
546  }
547 
548  double particleInvariantMassError(const Particle* part)
549  {
550  float invMass = part->getMass();
551  TMatrixFSym covarianceMatrix = part->getMomentumErrorMatrix();
552 
553  TVectorF jacobian(Particle::c_DimMomentum);
554  jacobian[0] = -1.0 * part->getPx() / invMass;
555  jacobian[1] = -1.0 * part->getPy() / invMass;
556  jacobian[2] = -1.0 * part->getPz() / invMass;
557  jacobian[3] = 1.0 * part->getEnergy() / invMass;
558 
559  double result = jacobian * (covarianceMatrix * jacobian);
560 
561  if (result < 0.0)
562  return std::numeric_limits<double>::quiet_NaN();
563 
564  return TMath::Sqrt(result);
565  }
566 
567  double particleInvariantMassSignificance(const Particle* part)
568  {
569  return particleDMass(part) / particleInvariantMassError(part);
570  }
571 
572  double particleMassSquared(const Particle* part)
573  {
574  ROOT::Math::PxPyPzEVector p4 = part->get4Vector();
575  return p4.M2();
576  }
577 
578  double b2bTheta(const Particle* part)
579  {
580  PCmsLabTransform T;
581  ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * part->get4Vector();
582  ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
583  ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
584  return b2blab.Theta();
585  }
586 
587  double b2bPhi(const Particle* part)
588  {
589  PCmsLabTransform T;
590  ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * part->get4Vector();
591  ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
592  ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
593  return b2blab.Phi();
594  }
595 
596  double b2bClusterTheta(const Particle* part)
597  {
598  // get associated ECLCluster
599  const ECLCluster* cluster = part->getECLCluster();
600  if (!cluster) return std::numeric_limits<float>::quiet_NaN();
601  const ECLCluster::EHypothesisBit clusterHypothesis = part->getECLClusterEHypothesisBit();
602 
603  // get 4 momentum from cluster
604  ClusterUtils clutls;
605  ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, clusterHypothesis);
606 
607  // find the vector that balances this in the CMS
608  PCmsLabTransform T;
609  ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * p4Cluster;
610  ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
611  ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
612  return b2blab.Theta();
613  }
614 
615  double b2bClusterPhi(const Particle* part)
616  {
617  // get associated ECLCluster
618  const ECLCluster* cluster = part->getECLCluster();
619  if (!cluster) return std::numeric_limits<float>::quiet_NaN();
620  const ECLCluster::EHypothesisBit clusterHypothesis = part->getECLClusterEHypothesisBit();
621 
622  // get 4 momentum from cluster
623  ClusterUtils clutls;
624  ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, clusterHypothesis);
625 
626  // find the vector that balances this in the CMS
627  PCmsLabTransform T;
628  ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * p4Cluster;
629  ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
630  ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
631  return b2blab.Phi();
632  }
633 
634 
635 // released energy --------------------------------------------------
636 
637  double particleQ(const Particle* part)
638  {
639  float m = part->getMass();
640  for (unsigned i = 0; i < part->getNDaughters(); i++) {
641  const Particle* child = part->getDaughter(i);
642  if (child)
643  m -= child->getMass();
644  }
645  return m;
646  }
647 
648  double particleDQ(const Particle* part)
649  {
650  float m = part->getMass() - part->getPDGMass();
651  for (unsigned i = 0; i < part->getNDaughters(); i++) {
652  const Particle* child = part->getDaughter(i);
653  if (child)
654  m -= (child->getMass() - child->getPDGMass());
655  }
656  return m;
657  }
658 
659 // Mbc and deltaE
660 
661  double particleMbc(const Particle* part)
662  {
663  PCmsLabTransform T;
664  ROOT::Math::PxPyPzEVector vec = T.rotateLabToCms() * part->get4Vector();
665  double E = T.getCMSEnergy() / 2;
666  double m2 = E * E - vec.P2();
667  double mbc = m2 >= 0 ? sqrt(m2) : std::numeric_limits<double>::quiet_NaN();
668  return mbc;
669  }
670 
671  double particleDeltaE(const Particle* part)
672  {
673  PCmsLabTransform T;
674  ROOT::Math::PxPyPzEVector vec = T.rotateLabToCms() * part->get4Vector();
675  return vec.E() - T.getCMSEnergy() / 2;
676  }
677 
678 // other ------------------------------------------------------------
679 
680 
681  void printParticleInternal(const Particle* p, int depth)
682  {
683  stringstream s("");
684  for (int i = 0; i < depth; i++) {
685  s << " ";
686  }
687  s << p->getPDGCode();
688  const MCParticle* mcp = p->getMCParticle();
689  if (mcp) {
690  unsigned int flags = MCMatching::getMCErrors(p, mcp);
691  s << " -> MC: " << mcp->getPDG() << ", mcErrors: " << flags << " ("
692  << MCMatching::explainFlags(flags) << ")";
693  s << ", mc-index " << mcp->getIndex();
694  } else {
695  s << " (no MC match)";
696  }
697  s << ", mdst-source " << p->getMdstSource();
698  B2INFO(s.str());
699  for (const auto* daughter : p->getDaughters()) {
700  printParticleInternal(daughter, depth + 1);
701  }
702  }
703 
704  bool printParticle(const Particle* p)
705  {
706  printParticleInternal(p, 0);
707  return 0;
708  }
709 
710 
711  double particleMCMomentumTransfer2(const Particle* part)
712  {
713  // for B meson MC particles only
714  const MCParticle* mcB = part->getMCParticle();
715 
716  if (!mcB)
717  return std::numeric_limits<double>::quiet_NaN();
718 
719  ROOT::Math::PxPyPzEVector pB = mcB->get4Vector();
720 
721  std::vector<MCParticle*> mcDaug = mcB->getDaughters();
722 
723  if (mcDaug.empty())
724  return std::numeric_limits<double>::quiet_NaN();
725 
726  // B -> X l nu
727  // q = pB - pX
728  ROOT::Math::PxPyPzEVector pX;
729 
730  for (auto mcTemp : mcDaug) {
731  if (abs(mcTemp->getPDG()) <= 16)
732  continue;
733 
734  pX += mcTemp->get4Vector();
735  }
736 
737  ROOT::Math::PxPyPzEVector q = pB - pX;
738 
739  return q.M2();
740  }
741 
742 // Recoil Kinematics related ---------------------------------------------
743  double recoilPx(const Particle* particle)
744  {
745  PCmsLabTransform T;
746 
747  // Initial state (e+e- momentum in LAB)
748  ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
749 
750  // Use requested frame for final calculation
751  const auto& frame = ReferenceFrame::GetCurrent();
752  return frame.getMomentum(pIN - particle->get4Vector()).Px();
753  }
754 
755  double recoilPy(const Particle* particle)
756  {
757  PCmsLabTransform T;
758 
759  // Initial state (e+e- momentum in LAB)
760  ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
761 
762  // Use requested frame for final calculation
763  const auto& frame = ReferenceFrame::GetCurrent();
764  return frame.getMomentum(pIN - particle->get4Vector()).Py();
765  }
766 
767  double recoilPz(const Particle* particle)
768  {
769  PCmsLabTransform T;
770 
771  // Initial state (e+e- momentum in LAB)
772  ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
773 
774  // Use requested frame for final calculation
775  const auto& frame = ReferenceFrame::GetCurrent();
776  return frame.getMomentum(pIN - particle->get4Vector()).Pz();
777  }
778 
779  double recoilMomentum(const Particle* particle)
780  {
781  PCmsLabTransform T;
782 
783  // Initial state (e+e- momentum in LAB)
784  ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
785 
786  // Use requested frame for final calculation
787  const auto& frame = ReferenceFrame::GetCurrent();
788  return frame.getMomentum(pIN - particle->get4Vector()).P();
789  }
790 
791  double recoilMomentumTheta(const Particle* particle)
792  {
793  PCmsLabTransform T;
794 
795  // Initial state (e+e- momentum in LAB)
796  ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
797 
798  // Use requested frame for final calculation
799  const auto& frame = ReferenceFrame::GetCurrent();
800  return frame.getMomentum(pIN - particle->get4Vector()).Theta();
801  }
802 
803  double recoilMomentumPhi(const Particle* particle)
804  {
805  PCmsLabTransform T;
806 
807  // Initial state (e+e- momentum in LAB)
808  ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
809 
810  // Use requested frame for final calculation
811  const auto& frame = ReferenceFrame::GetCurrent();
812  return frame.getMomentum(pIN - particle->get4Vector()).Phi();
813  }
814 
815  double recoilEnergy(const Particle* particle)
816  {
817  PCmsLabTransform T;
818 
819  // Initial state (e+e- momentum in LAB)
820  ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
821 
822  // Use requested frame for final calculation
823  const auto& frame = ReferenceFrame::GetCurrent();
824  return frame.getMomentum(pIN - particle->get4Vector()).E();
825  }
826 
827  double recoilMass(const Particle* particle)
828  {
829  PCmsLabTransform T;
830 
831  // Initial state (e+e- momentum in LAB)
832  ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
833 
834  // Use requested frame for final calculation
835  const auto& frame = ReferenceFrame::GetCurrent();
836  return frame.getMomentum(pIN - particle->get4Vector()).M();
837  }
838 
839  double recoilMassSquared(const Particle* particle)
840  {
841  PCmsLabTransform T;
842 
843  // Initial state (e+e- momentum in LAB)
844  ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
845 
846  // Use requested frame for final calculation
847  const auto& frame = ReferenceFrame::GetCurrent();
848  return frame.getMomentum(pIN - particle->get4Vector()).M2();
849  }
850 
851  double m2RecoilSignalSide(const Particle* part)
852  {
853  PCmsLabTransform T;
854  double beamEnergy = T.getCMSEnergy() / 2.;
855  if (part->getNDaughters() != 2) return std::numeric_limits<double>::quiet_NaN();
856  ROOT::Math::PxPyPzEVector tagVec = T.rotateLabToCms() * part->getDaughter(0)->get4Vector();
857  ROOT::Math::PxPyPzEVector sigVec = T.rotateLabToCms() * part->getDaughter(1)->get4Vector();
858  tagVec.SetE(-beamEnergy);
859  return (-tagVec - sigVec).M2();
860  }
861 
862  double recoilMCDecayType(const Particle* particle)
863  {
864  auto* mcp = particle->getMCParticle();
865 
866  if (!mcp)
867  return std::numeric_limits<double>::quiet_NaN();
868 
869  MCParticle* mcMother = mcp->getMother();
870 
871  if (!mcMother)
872  return std::numeric_limits<double>::quiet_NaN();
873 
874  std::vector<MCParticle*> daughters = mcMother->getDaughters();
875 
876  if (daughters.size() != 2)
877  return std::numeric_limits<double>::quiet_NaN();
878 
879  MCParticle* recoilMC = nullptr;
880  if (daughters[0]->getArrayIndex() == mcp->getArrayIndex())
881  recoilMC = daughters[1];
882  else
883  recoilMC = daughters[0];
884 
885  if (!recoilMC->hasStatus(MCParticle::c_PrimaryParticle))
886  return std::numeric_limits<double>::quiet_NaN();
887 
888  int decayType = 0;
889  checkMCParticleDecay(recoilMC, decayType, false);
890 
891  if (decayType == 0)
892  checkMCParticleDecay(recoilMC, decayType, true);
893 
894  return decayType;
895  }
896 
897  void checkMCParticleDecay(MCParticle* mcp, int& decayType, bool recursive)
898  {
899  int nHadronicParticles = 0;
900  int nPrimaryParticleDaughters = 0;
901  std::vector<MCParticle*> daughters = mcp->getDaughters();
902 
903  // Are any of the daughters primary particles? How many of them are hadrons?
904  for (auto& daughter : daughters) {
905  if (!daughter->hasStatus(MCParticle::c_PrimaryParticle))
906  continue;
907 
908  nPrimaryParticleDaughters++;
909  if (abs(daughter->getPDG()) > Const::photon.getPDGCode())
910  nHadronicParticles++;
911  }
912 
913  if (nPrimaryParticleDaughters > 1) {
914  for (auto& daughter : daughters) {
915  if (!daughter->hasStatus(MCParticle::c_PrimaryParticle))
916  continue;
917 
918  if (abs(daughter->getPDG()) == 12 or abs(daughter->getPDG()) == 14 or abs(daughter->getPDG()) == 16) {
919  if (!recursive) {
920  if (nHadronicParticles == 0) {
921  decayType = 1.0;
922  break;
923  } else {
924  decayType = 2.0;
925  break;
926  }
927  } else {
928  decayType = 3.0;
929  break;
930  }
931  }
932 
933  else if (recursive)
934  checkMCParticleDecay(daughter, decayType, recursive);
935  }
936  }
937  }
938 
939  int nRemainingTracksInEvent(const Particle* particle)
940  {
941 
942  StoreArray<Track> tracks;
943  int event_tracks = tracks.getEntries();
944 
945  int par_tracks = 0;
946  const auto& daughters = particle->getFinalStateDaughters();
947  for (const auto& daughter : daughters) {
948  int pdg = abs(daughter->getPDGCode());
949  if (pdg == Const::electron.getPDGCode() or pdg == Const::muon.getPDGCode() or pdg == Const::pion.getPDGCode()
950  or pdg == Const::kaon.getPDGCode() or pdg == Const::proton.getPDGCode())
951  par_tracks++;
952  }
953  return event_tracks - par_tracks;
954  }
955 
956  double trackMatchType(const Particle* particle)
957  {
958  // Particle does not contain a ECL Cluster
959  double result = std::numeric_limits<double>::quiet_NaN();
960 
961  const ECLCluster* cluster = particle->getECLCluster();
962  if (cluster) {
963  // No associated track is default
964  result = 0;
965  if (cluster->isTrack()) {
966  // There is a track match
967  result = 1.0;
968  }
969  }
970  return result;
971  }
972 
973 
974  bool False(const Particle*)
975  {
976  return 0;
977  }
978 
979  bool True(const Particle*)
980  {
981  return 1;
982  }
983 
984  double infinity(const Particle*)
985  {
986  double inf = std::numeric_limits<double>::infinity();
987  return inf;
988  }
989 
990  double random(const Particle*)
991  {
992  return gRandom->Uniform(0, 1);
993  }
994 
995  double eventRandom(const Particle*)
996  {
997  std::string key = "__eventRandom";
998  StoreObjPtr<EventExtraInfo> eventExtraInfo;
999  if (not eventExtraInfo.isValid())
1000  eventExtraInfo.create();
1001  if (eventExtraInfo->hasExtraInfo(key)) {
1002  return eventExtraInfo->getExtraInfo(key);
1003  } else {
1004  double value = gRandom->Uniform(0, 1);
1005  eventExtraInfo->addExtraInfo(key, value);
1006  return value;
1007  }
1008  }
1009 
1010  VARIABLE_GROUP("Kinematics");
1011  REGISTER_VARIABLE("p", particleP, "momentum magnitude", "GeV/c");
1012  REGISTER_VARIABLE("E", particleE, "energy", "GeV");
1013 
1014  REGISTER_VARIABLE("E_uncertainty", particleEUncertainty, R"DOC(energy uncertainty (:math:`\sqrt{\sigma^2}`))DOC", "GeV");
1015  REGISTER_VARIABLE("ECLClusterE_uncertainty", particleClusterEUncertainty,
1016  "energy uncertainty as given by the underlying ECL cluster", "GeV");
1017  REGISTER_VARIABLE("px", particlePx, "momentum component x", "GeV/c");
1018  REGISTER_VARIABLE("py", particlePy, "momentum component y", "GeV/c");
1019  REGISTER_VARIABLE("pz", particlePz, "momentum component z", "GeV/c");
1020  REGISTER_VARIABLE("pt", particlePt, "transverse momentum", "GeV/c");
1021  REGISTER_VARIABLE("xp", particleXp,
1022  "scaled momentum: the momentum of the particle in the CMS as a fraction of its maximum available momentum in the collision");
1023  REGISTER_VARIABLE("pErr", particlePErr, "error of momentum magnitude", "GeV/c");
1024  REGISTER_VARIABLE("pxErr", particlePxErr, "error of momentum component x", "GeV/c");
1025  REGISTER_VARIABLE("pyErr", particlePyErr, "error of momentum component y", "GeV/c");
1026  REGISTER_VARIABLE("pzErr", particlePzErr, "error of momentum component z", "GeV/c");
1027  REGISTER_VARIABLE("ptErr", particlePtErr, "error of transverse momentum", "GeV/c");
1028  REGISTER_VARIABLE("momVertCovM(i,j)", covMatrixElement,
1029  "returns the (i,j)-th element of the MomentumVertex Covariance Matrix (7x7).\n"
1030  "Order of elements in the covariance matrix is: px, py, pz, E, x, y, z.", "GeV/c, GeV/c, GeV/c, GeV, cm, cm, cm");
1031  REGISTER_VARIABLE("momDevChi2", momentumDeviationChi2, R"DOC(
1032 momentum deviation :math:`\chi^2` value calculated as :math:`\chi^2 = \sum_i (p_i - mc(p_i))^2/\sigma(p_i)^2`,
1033 where :math:`\sum` runs over i = px, py, pz and :math:`mc(p_i)` is the mc truth value and :math:`\sigma(p_i)` is the estimated error of i-th component of momentum vector
1034 )DOC");
1035  REGISTER_VARIABLE("theta", particleTheta, "polar angle", "rad");
1036  REGISTER_VARIABLE("thetaErr", particleThetaErr, "error of polar angle", "rad");
1037  REGISTER_VARIABLE("cosTheta", particleCosTheta, "momentum cosine of polar angle");
1038  REGISTER_VARIABLE("cosThetaErr", particleCosThetaErr, "error of momentum cosine of polar angle");
1039  REGISTER_VARIABLE("phi", particlePhi, "momentum azimuthal angle", "rad");
1040  REGISTER_VARIABLE("phiErr", particlePhiErr, "error of momentum azimuthal angle", "rad");
1041  REGISTER_VARIABLE("PDG", particlePDGCode, "PDG code");
1042 
1043  REGISTER_VARIABLE("cosAngleBetweenMomentumAndVertexVectorInXYPlane",
1044  cosAngleBetweenMomentumAndVertexVectorInXYPlane,
1045  "cosine of the angle between momentum and vertex vector (vector connecting ip and fitted vertex) of this particle in xy-plane");
1046  REGISTER_VARIABLE("cosAngleBetweenMomentumAndVertexVector",
1047  cosAngleBetweenMomentumAndVertexVector,
1048  "cosine of the angle between momentum and vertex vector (vector connecting ip and fitted vertex) of this particle");
1049  REGISTER_VARIABLE("cosThetaBetweenParticleAndNominalB",
1050  cosThetaBetweenParticleAndNominalB,
1051  "cosine of the angle in CMS between momentum the particle and a nominal B particle. It is somewhere between -1 and 1 if only a massless particle like a neutrino is missing in the reconstruction.");
1052  REGISTER_VARIABLE("cosToThrustOfEvent", cosToThrustOfEvent,
1053  "Returns the cosine of the angle between the particle and the thrust axis of the event, as calculate by the EventShapeCalculator module. buildEventShape() must be run before calling this variable");
1054 
1055  REGISTER_VARIABLE("ImpactXY" , ImpactXY , "The impact parameter of the given particle in the xy plane", "cm");
1056 
1057  REGISTER_VARIABLE("M", particleMass, R"DOC(
1058 The particle's mass.
1059 
1060 Note that this is context-dependent variable and can take different values depending on the situation. This should be the "best" value possible with the information provided.
1061 
1062 - If this particle is track- or cluster- based, then this is the value of the mass hypothesis.
1063 - If this particle is an MC particle then this is the mass of that particle.
1064 - If this particle is composite, then *initially* this takes the value of the invariant mass of the daughters.
1065 - If this particle is composite and a *mass or vertex fit* has been performed then this may be updated by the fit.
1066 
1067  * You will see a difference between this mass and the :b2:var:`InvM`.
1068  )DOC", "GeV/:math:`\\text{c}^2`");
1069  REGISTER_VARIABLE("dM", particleDMass, "mass minus nominal mass", "GeV/:math:`\\text{c}^2`");
1070  REGISTER_VARIABLE("Q", particleQ, "energy released in decay", "GeV");
1071  REGISTER_VARIABLE("dQ", particleDQ, ":b2:var:`Q` minus nominal energy released in decay", "GeV");
1072  REGISTER_VARIABLE("Mbc", particleMbc, "beam constrained mass", "GeV/:math:`\\text{c}^2`");
1073  REGISTER_VARIABLE("deltaE", particleDeltaE, "difference between :b2:var:`E` and half the center of mass energy", "GeV");
1074  REGISTER_VARIABLE("M2", particleMassSquared, "The particle's mass squared.", ":math:`[\\text{GeV}/\\text{c}^2]^2`");
1075 
1076  REGISTER_VARIABLE("InvM", particleInvariantMassFromDaughtersDisplaced,
1077  "invariant mass (determined from particle's daughter 4-momentum vectors). If this particle is V0 or decays at rho > 5 mm, its daughter 4-momentum vectors at fitted vertex are taken.\n"
1078  "If this particle has no daughters, defaults to :b2:var:`M`.", "GeV/:math:`\\text{c}^2`");
1079  REGISTER_VARIABLE("InvMLambda", particleInvariantMassLambda,
1080  "Invariant mass (determined from particle's daughter 4-momentum vectors), assuming the first daughter is a pion and the second daughter is a proton.\n"
1081  "If the particle has not 2 daughters, it returns just the mass value.", "GeV/:math:`\\text{c}^2`");
1082 
1083  REGISTER_VARIABLE("ErrM", particleInvariantMassError,
1084  "uncertainty of invariant mass", "GeV/:math:`\\text{c}^2`");
1085  REGISTER_VARIABLE("SigM", particleInvariantMassSignificance,
1086  "signed deviation of particle's invariant mass from its nominal mass in units of the uncertainty on the invariant mass (:b2:var:`dM`/:b2:var:`ErrM`)");
1087 
1088  REGISTER_VARIABLE("pxRecoil", recoilPx,
1089  "component x of 3-momentum recoiling against given Particle", "GeV/c");
1090  REGISTER_VARIABLE("pyRecoil", recoilPy,
1091  "component y of 3-momentum recoiling against given Particle", "GeV/c");
1092  REGISTER_VARIABLE("pzRecoil", recoilPz,
1093  "component z of 3-momentum recoiling against given Particle", "GeV/c");
1094 
1095  REGISTER_VARIABLE("pRecoil", recoilMomentum,
1096  "magnitude of 3 - momentum recoiling against given Particle", "GeV/c");
1097  REGISTER_VARIABLE("pRecoilTheta", recoilMomentumTheta,
1098  "Polar angle of a particle's missing momentum", "rad");
1099  REGISTER_VARIABLE("pRecoilPhi", recoilMomentumPhi,
1100  "Azimuthal angle of a particle's missing momentum", "rad");
1101  REGISTER_VARIABLE("eRecoil", recoilEnergy,
1102  "energy recoiling against given Particle", "GeV");
1103  REGISTER_VARIABLE("mRecoil", recoilMass,
1104  "Invariant mass of the system recoiling against given Particle", "GeV/:math:`\\text{c}^2`");
1105  REGISTER_VARIABLE("m2Recoil", recoilMassSquared,
1106  "invariant mass squared of the system recoiling against given Particle", ":math:`[\\text{GeV}/\\text{c}^2]^2`");
1107  REGISTER_VARIABLE("m2RecoilSignalSide", m2RecoilSignalSide,
1108  "Squared recoil mass of the signal side which is calculated in the CMS frame under the assumption that the signal and tag side are produced back to back and the tag side energy equals the beam energy. The variable must be applied to the Upsilon and the tag side must be the first, the signal side the second daughter",
1109  ":math:`[\\text{GeV}/\\text{c}^2]^2`");
1110 
1111  REGISTER_VARIABLE("b2bTheta", b2bTheta,
1112  "Polar angle in the lab system that is back-to-back to the particle in the CMS. Useful for low multiplicity studies.", "rad");
1113  REGISTER_VARIABLE("b2bPhi", b2bPhi,
1114  "Azimuthal angle in the lab system that is back-to-back to the particle in the CMS. Useful for low multiplicity studies.", "rad");
1115  REGISTER_VARIABLE("b2bClusterTheta", b2bClusterTheta,
1116  "Polar angle in the lab system that is back-to-back to the particle's associated ECLCluster in the CMS. Returns NAN if no cluster is found. Useful for low multiplicity studies.",
1117  "rad");
1118  REGISTER_VARIABLE("b2bClusterPhi", b2bClusterPhi,
1119  "Azimuthal angle in the lab system that is back-to-back to the particle's associated ECLCluster in the CMS. Returns NAN if no cluster is found. Useful for low multiplicity studies.",
1120  "rad");
1121  REGISTER_VARIABLE("ArmenterosLongitudinalMomentumAsymmetry", ArmenterosLongitudinalMomentumAsymmetry,
1122  "Longitudinal momentum asymmetry of V0's daughters.\n"
1123  "The mother (V0) is required to have exactly two daughters");
1124  REGISTER_VARIABLE("ArmenterosDaughter1Qt", ArmenterosDaughter1Qt,
1125  "Transverse momentum of the first daughter with respect to the V0 mother.\n"
1126  "The mother is required to have exactly two daughters", "GeV/c");
1127  REGISTER_VARIABLE("ArmenterosDaughter2Qt", ArmenterosDaughter2Qt,
1128  "Transverse momentum of the second daughter with respect to the V0 mother.\n"
1129  "The mother is required to have exactly two daughters", "GeV/c");
1130 
1131  VARIABLE_GROUP("Miscellaneous");
1132  REGISTER_VARIABLE("nRemainingTracksInEvent", nRemainingTracksInEvent,
1133  "Number of tracks in the event - Number of tracks( = charged FSPs) of particle.");
1134  REGISTER_VARIABLE("trackMatchType", trackMatchType, R"DOC(
1135 
1136  * -1 particle has no ECL cluster
1137  * 0 particle has no associated track
1138  * 1 there is a matched track called connected - region(CR) track match
1139  )DOC");
1140  MAKE_DEPRECATED("trackMatchType", true, "light-2012-minos", R"DOC(
1141  Use better variables like `trackNECLClusters`, `clusterTrackMatch`, and `nECLClusterTrackMatches`.)DOC");
1142 
1143  REGISTER_VARIABLE("decayTypeRecoil", recoilMCDecayType,
1144  "type of the particle decay(no related mcparticle = -1, hadronic = 0, direct leptonic = 1, direct semileptonic = 2,"
1145  "lower level leptonic = 3.");
1146 
1147  REGISTER_VARIABLE("printParticle", printParticle,
1148  "For debugging, print Particle and daughter PDG codes, plus MC match. Returns 0.");
1149  REGISTER_VARIABLE("mcMomTransfer2", particleMCMomentumTransfer2,
1150  "Return the true momentum transfer to lepton pair in a B(semi -) leptonic B meson decay.", "GeV/c");
1151  REGISTER_VARIABLE("False", False,
1152  "returns always 0, used for testing and debugging.");
1153  REGISTER_VARIABLE("True", True,
1154  "returns always 1, used for testing and debugging.");
1155  REGISTER_VARIABLE("infinity", infinity,
1156  "returns std::numeric_limits<double>::infinity()");
1157  REGISTER_VARIABLE("random", random,
1158  "return a random number between 0 and 1 for each candidate. Can be used, e.g. for picking a random"
1159  "candidate in the best candidate selection.");
1160  REGISTER_VARIABLE("eventRandom", eventRandom,
1161  "[Eventbased] Returns a random number between 0 and 1 for this event. Can be used, e.g. for applying an event prescale.");
1162 
1163  }
1165 }
DataType Perp() const
The transverse component (R in cylindrical coordinate system).
Definition: B2Vector3.h:194
const MCParticle * getMCParticle() const
Returns the pointer to the MCParticle object that was used to create this Particle (ParticleType == c...
Definition: Particle.cc:934
Class to store variables with their name which were sent to the logging service.
#define MAKE_DEPRECATED(name, make_fatal, version, description)
Registers a variable as deprecated.
Definition: Manager.h:438
B2Vector3< double > B2Vector3D
typedef for common usage with double
Definition: B2Vector3.h:502
Abstract base class for different kinds of events.
Definition: ClusterUtils.h:23