Belle II Software development
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 header.
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/ParticleList.h>
27#include <framework/dataobjects/EventExtraInfo.h>
28#include <analysis/dataobjects/EventShapeContainer.h>
29
30#include <mdst/dataobjects/MCParticle.h>
31#include <mdst/dataobjects/Track.h>
32#include <mdst/dataobjects/ECLCluster.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#include <framework/utilities/Conversion.h>
42
43#include <Math/Vector4D.h>
44#include <TRandom.h>
45#include <TVectorF.h>
46
47#include <cmath>
48#include <boost/algorithm/string.hpp>
49
50
51using namespace std;
52
53namespace Belle2 {
58 namespace Variable {
59
60// momentum -------------------------------------------
61
62 double particleP(const Particle* part)
63 {
64 const auto& frame = ReferenceFrame::GetCurrent();
65 return frame.getMomentum(part).P();
66 }
67
68 double particleE(const Particle* part)
69 {
70 const auto& frame = ReferenceFrame::GetCurrent();
71 return frame.getMomentum(part).E();
72 }
73
74 double particleClusterEUncertainty(const Particle* part)
75 {
76 const ECLCluster* cluster = part->getECLCluster();
77 if (cluster) {
78 ClusterUtils clutls;
79 const auto EPhiThetaCov = clutls.GetCovarianceMatrix3x3FromCluster(cluster);
80 return sqrt(fabs(EPhiThetaCov[0][0]));
81 }
82 return Const::doubleNaN;
83 }
84
85 double particlePx(const Particle* part)
86 {
87 const auto& frame = ReferenceFrame::GetCurrent();
88 return frame.getMomentum(part).Px();
89 }
90
91 double particlePy(const Particle* part)
92 {
93 const auto& frame = ReferenceFrame::GetCurrent();
94 return frame.getMomentum(part).Py();
95 }
96
97 double particlePz(const Particle* part)
98 {
99 const auto& frame = ReferenceFrame::GetCurrent();
100 return frame.getMomentum(part).Pz();
101 }
102
103 double particlePt(const Particle* part)
104 {
105 const auto& frame = ReferenceFrame::GetCurrent();
106 return frame.getMomentum(part).Pt();
107 }
108
109 double covMatrixElement(const Particle* part, const std::vector<double>& element)
110 {
111 int elementI = int(std::lround(element[0]));
112 int elementJ = int(std::lround(element[1]));
113
114 if (elementI < 0 || elementI > 6) {
115 B2WARNING("Requested particle's momentumVertex covariance matrix element is out of boundaries [0 - 6]:" << LogVar("i", elementI));
116 return Const::doubleNaN;
117 }
118 if (elementJ < 0 || elementJ > 6) {
119 B2WARNING("Requested particle's momentumVertex covariance matrix element is out of boundaries [0 - 6]:" << LogVar("j", elementJ));
120 return Const::doubleNaN;
121 }
122
123 return part->getMomentumVertexErrorMatrix()(elementI, elementJ);
124 }
125
126 double particleEUncertainty(const Particle* part)
127 {
128 const auto& frame = ReferenceFrame::GetCurrent();
129
130 double errorSquared = frame.getMomentumErrorMatrix(part)(3, 3);
131
132 if (errorSquared >= 0.0)
133 return sqrt(errorSquared);
134 else
135 return Const::doubleNaN;
136 }
137
138 double particlePErr(const Particle* part)
139 {
140 TMatrixD jacobianRot(3, 3);
141 jacobianRot.Zero();
142
143 double cosPhi = cos(particlePhi(part));
144 double sinPhi = sin(particlePhi(part));
145 double cosTheta = particleCosTheta(part);
146 double sinTheta = sin(acos(cosTheta));
147 double p = particleP(part);
148
149 jacobianRot(0, 0) = sinTheta * cosPhi;
150 jacobianRot(0, 1) = sinTheta * sinPhi;
151 jacobianRot(1, 0) = cosTheta * cosPhi / p;
152 jacobianRot(1, 1) = cosTheta * sinPhi / p;
153 jacobianRot(0, 2) = cosTheta;
154 jacobianRot(2, 0) = -sinPhi / sinTheta / p;
155 jacobianRot(1, 2) = -sinTheta / p;
156 jacobianRot(2, 1) = cosPhi / sinTheta / p;
157
158 const auto& frame = ReferenceFrame::GetCurrent();
159
160 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2, " ").Similarity(jacobianRot)(0, 0);
161
162 if (errorSquared >= 0.0)
163 return sqrt(errorSquared);
164 else
165 return Const::doubleNaN;
166 }
167
168 double particlePxErr(const Particle* part)
169 {
170 const auto& frame = ReferenceFrame::GetCurrent();
171
172 double errorSquared = frame.getMomentumErrorMatrix(part)(0, 0);
173
174 if (errorSquared >= 0.0)
175 return sqrt(errorSquared);
176 else
177 return Const::doubleNaN;
178 }
179
180 double particlePyErr(const Particle* part)
181 {
182 const auto& frame = ReferenceFrame::GetCurrent();
183 double errorSquared = frame.getMomentumErrorMatrix(part)(1, 1);
184
185 if (errorSquared >= 0.0)
186 return sqrt(errorSquared);
187 else
188 return Const::doubleNaN;
189 }
190
191 double particlePzErr(const Particle* part)
192 {
193 const auto& frame = ReferenceFrame::GetCurrent();
194 double errorSquared = frame.getMomentumErrorMatrix(part)(2, 2);
195
196 if (errorSquared >= 0.0)
197 return sqrt(errorSquared);
198 else
199 return Const::doubleNaN;
200 }
201
202 double particlePtErr(const Particle* part)
203 {
204 TMatrixD jacobianRot(3, 3);
205 jacobianRot.Zero();
206
207 double px = particlePx(part);
208 double py = particlePy(part);
209 double pt = particlePt(part);
210
211 jacobianRot(0, 0) = px / pt;
212 jacobianRot(0, 1) = py / pt;
213 jacobianRot(1, 0) = -py / (pt * pt);
214 jacobianRot(1, 1) = px / (pt * pt);
215 jacobianRot(2, 2) = 1;
216
217 const auto& frame = ReferenceFrame::GetCurrent();
218 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2, " ").Similarity(jacobianRot)(0, 0);
219
220 if (errorSquared >= 0.0)
221 return sqrt(errorSquared);
222 else
223 return Const::doubleNaN;
224 }
225
226 double momentumDeviationChi2(const Particle* part)
227 {
228 double result = Const::doubleNaN;
229
230 // check if error matrix is set
231 if (part->getPValue() < 0.0)
232 return result;
233
234 // check if mc match exists
235 const MCParticle* mcp = part->getMCParticle();
236 if (mcp == nullptr)
237 return result;
238
239 result = 0.0;
240 result += TMath::Power(part->getPx() - mcp->getMomentum().X(), 2.0) / part->getMomentumVertexErrorMatrix()(0, 0);
241 result += TMath::Power(part->getPy() - mcp->getMomentum().Y(), 2.0) / part->getMomentumVertexErrorMatrix()(1, 1);
242 result += TMath::Power(part->getPz() - mcp->getMomentum().Z(), 2.0) / part->getMomentumVertexErrorMatrix()(2, 2);
243
244 return result;
245 }
246
247 double particleTheta(const Particle* part)
248 {
249 const auto& frame = ReferenceFrame::GetCurrent();
250 return frame.getMomentum(part).Theta();
251 }
252
253 double particleThetaErr(const Particle* part)
254 {
255 TMatrixD jacobianRot(3, 3);
256 jacobianRot.Zero();
257
258 double cosPhi = cos(particlePhi(part));
259 double sinPhi = sin(particlePhi(part));
260 double cosTheta = particleCosTheta(part);
261 double sinTheta = sin(acos(cosTheta));
262 double p = particleP(part);
263
264 jacobianRot(0, 0) = sinTheta * cosPhi;
265 jacobianRot(0, 1) = sinTheta * sinPhi;
266 jacobianRot(1, 0) = cosTheta * cosPhi / p;
267 jacobianRot(1, 1) = cosTheta * sinPhi / p;
268 jacobianRot(0, 2) = cosTheta;
269 jacobianRot(2, 0) = -sinPhi / sinTheta / p;
270 jacobianRot(1, 2) = -sinTheta / p;
271 jacobianRot(2, 1) = cosPhi / sinTheta / p;
272
273 const auto& frame = ReferenceFrame::GetCurrent();
274 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2, " ").Similarity(jacobianRot)(1, 1);
275
276 if (errorSquared >= 0.0)
277 return sqrt(errorSquared);
278 else
279 return Const::doubleNaN;
280 }
281
282 double particleCosTheta(const Particle* part)
283 {
284 const auto& frame = ReferenceFrame::GetCurrent();
285 return cos(frame.getMomentum(part).Theta());
286 }
287
288 double particleCosThetaErr(const Particle* part)
289 {
290 return fabs(particleThetaErr(part) * sin(particleTheta(part)));
291 }
292
293 double particlePhi(const Particle* part)
294 {
295 const auto& frame = ReferenceFrame::GetCurrent();
296 return frame.getMomentum(part).Phi();
297 }
298
299 double particlePhiErr(const Particle* part)
300 {
301 TMatrixD jacobianRot(3, 3);
302 jacobianRot.Zero();
303
304 double px = particlePx(part);
305 double py = particlePy(part);
306 double pt = particlePt(part);
307
308 jacobianRot(0, 0) = px / pt;
309 jacobianRot(0, 1) = py / pt;
310 jacobianRot(1, 0) = -py / (pt * pt);
311 jacobianRot(1, 1) = px / (pt * pt);
312 jacobianRot(2, 2) = 1;
313
314 const auto& frame = ReferenceFrame::GetCurrent();
315 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2, " ").Similarity(jacobianRot)(1, 1);
316
317 if (errorSquared >= 0.0)
318 return sqrt(errorSquared);
319 else
320 return Const::doubleNaN;
321 }
322
323 double particleXp(const Particle* part)
324 {
325 PCmsLabTransform T;
326 ROOT::Math::PxPyPzEVector p4 = part -> get4Vector();
327 ROOT::Math::PxPyPzEVector p4CMS = T.rotateLabToCms() * p4;
328 float s = T.getCMSEnergy();
329 float M = part->getMass();
330 return p4CMS.P() / TMath::Sqrt(s * s / 4 - M * M);
331 }
332
333 int particlePDGCode(const Particle* part)
334 {
335 return part->getPDGCode();
336 }
337
338 double cosAngleBetweenMomentumAndVertexVectorInXYPlane(const Particle* part)
339 {
340 static DBObjPtr<BeamSpot> beamSpotDB;
341 double px = part->getPx();
342 double py = part->getPy();
343
344 double xV = part->getX();
345 double yV = part->getY();
346
347 double xIP = (beamSpotDB->getIPPosition()).X();
348 double yIP = (beamSpotDB->getIPPosition()).Y();
349
350 double x = xV - xIP;
351 double y = yV - yIP;
352
353 double cosangle = (px * x + py * y) / (sqrt(px * px + py * py) * sqrt(x * x + y * y));
354 return cosangle;
355 }
356
357 double cosAngleBetweenMomentumAndVertexVector(const Particle* part)
358 {
359 static DBObjPtr<BeamSpot> beamSpotDB;
360 return cos((B2Vector3D(part->getVertex()) - beamSpotDB->getIPPosition()).Angle(B2Vector3D(part->getMomentum())));
361 }
362
363 double cosThetaBetweenParticleAndNominalB(const Particle* part)
364 {
365
366 int particlePDG = abs(part->getPDGCode());
367 if (particlePDG != 511 and particlePDG != 521)
368 B2FATAL("The Variables cosThetaBetweenParticleAndNominalB is only meant to be used on B mesons!");
369
370 PCmsLabTransform T;
371 double e_Beam = T.getCMSEnergy() / 2.0; // GeV
372 double m_B = part->getPDGMass();
373 // if this is a continuum run, use an approximate Y(4S) CMS energy
374 if (e_Beam * e_Beam - m_B * m_B < 0) {
375 e_Beam = 1.0579400E+1 / 2.0; // GeV
376 }
377 double p_B = std::sqrt(e_Beam * e_Beam - m_B * m_B);
378
379 ROOT::Math::PxPyPzEVector p = T.rotateLabToCms() * part->get4Vector();
380 double e_d = p.E();
381 double m_d = p.M();
382 double p_d = p.P();
383
384 double theta_BY = (2 * e_Beam * e_d - m_B * m_B - m_d * m_d)
385 / (2 * p_B * p_d);
386 return theta_BY;
387 }
388
389 double cosToThrustOfEvent(const Particle* part)
390 {
391 StoreObjPtr<EventShapeContainer> evtShape;
392 if (!evtShape) {
393 B2WARNING("Cannot find thrust of event information, did you forget to load the event shape calculation?");
394 return Const::doubleNaN;
395 }
396 PCmsLabTransform T;
397 B2Vector3D th = evtShape->getThrustAxis();
398 B2Vector3D particleMomentum = (T.rotateLabToCms() * part -> get4Vector()).Vect();
399 return std::cos(th.Angle(particleMomentum));
400 }
401
402 double ImpactXY(const Particle* particle)
403 {
404 static DBObjPtr<BeamSpot> beamSpotDB;
405
406 ROOT::Math::XYZVector mom = particle->getMomentum();
407
408 ROOT::Math::XYZVector r = particle->getVertex() - ROOT::Math::XYZVector(beamSpotDB->getIPPosition());
409
410 ROOT::Math::XYZVector Bfield = BFieldManager::getInstance().getFieldInTesla(ROOT::Math::XYZVector(beamSpotDB->getIPPosition()));
411
412 ROOT::Math::XYZVector curvature = - Bfield * Const::speedOfLight * particle->getCharge(); //Curvature of the track
413 double T = TMath::Sqrt(mom.Perp2() - 2.0 * curvature.Dot(r.Cross(mom)) + curvature.Mag2() * r.Perp2());
414
415 return TMath::Abs((-2 * r.Cross(mom).Z() + curvature.R() * r.Perp2()) / (T + mom.Rho()));
416 }
417
418 double ArmenterosLongitudinalMomentumAsymmetry(const Particle* part)
419 {
420 const auto& frame = ReferenceFrame::GetCurrent();
421 int nDaughters = part -> getNDaughters();
422 if (nDaughters != 2)
423 B2FATAL("You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters");
424
425 const auto& daughters = part -> getDaughters();
426 B2Vector3D motherMomentum = frame.getMomentum(part).Vect();
427 B2Vector3D daughter1Momentum = frame.getMomentum(daughters[0]).Vect();
428 B2Vector3D daughter2Momentum = frame.getMomentum(daughters[1]).Vect();
429
430 int daughter1Charge = daughters[0] -> getCharge();
431 int daughter2Charge = daughters[1] -> getCharge();
432 double daughter1Ql = daughter1Momentum.Dot(motherMomentum) / motherMomentum.Mag();
433 double daughter2Ql = daughter2Momentum.Dot(motherMomentum) / motherMomentum.Mag();
434
435 double Arm_alpha;
436 if (daughter2Charge > daughter1Charge)
437 Arm_alpha = (daughter2Ql - daughter1Ql) / (daughter2Ql + daughter1Ql);
438 else
439 Arm_alpha = (daughter1Ql - daughter2Ql) / (daughter1Ql + daughter2Ql);
440
441 return Arm_alpha;
442 }
443
444 double ArmenterosDaughter1Qt(const Particle* part)
445 {
446 const auto& frame = ReferenceFrame::GetCurrent();
447 int nDaughters = part -> getNDaughters();
448 if (nDaughters != 2)
449 B2FATAL("You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters.");
450
451 const auto& daughters = part -> getDaughters();
452 B2Vector3D motherMomentum = frame.getMomentum(part).Vect();
453 B2Vector3D daughter1Momentum = frame.getMomentum(daughters[0]).Vect();
454 double qt = daughter1Momentum.Perp(motherMomentum);
455
456 return qt;
457 }
458
459 double ArmenterosDaughter2Qt(const Particle* part)
460 {
461 const auto& frame = ReferenceFrame::GetCurrent();
462 int nDaughters = part -> getNDaughters();
463 if (nDaughters != 2)
464 B2FATAL("You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters.");
465
466 const auto& daughters = part -> getDaughters();
467 B2Vector3D motherMomentum = frame.getMomentum(part).Vect();
468 B2Vector3D daughter2Momentum = frame.getMomentum(daughters[1]).Vect();
469 double qt = daughter2Momentum.Perp(motherMomentum);
470
471 return qt;
472 }
473
474
475// mass ------------------------------------------------------------
476
477 double particleMass(const Particle* part)
478 {
479 return part->getMass();
480 }
481
482 double particleDMass(const Particle* part)
483 {
484 return part->getMass() - part->getPDGMass();
485 }
486
487 double particleInvariantMassFromDaughters(const Particle* part)
488 {
489 const std::vector<Particle*> daughters = part->getDaughters();
490 if (daughters.size() > 0) {
491 ROOT::Math::PxPyPzEVector sum;
492 for (auto daughter : daughters)
493 sum += daughter->get4Vector();
494
495 return sum.M();
496 } else {
497 return part->getMass(); // !
498 }
499 }
500
501 double particleInvariantMassFromDaughtersDisplaced(const Particle* part)
502 {
503 ROOT::Math::XYZVector vertex = part->getVertex();
504 if (part->getParticleSource() != Particle::EParticleSourceObject::c_V0
505 && vertex.Rho() < 0.5) return particleInvariantMassFromDaughters(part);
506
507 const std::vector<Particle*> daughters = part->getDaughters();
508 if (daughters.size() == 0) return particleInvariantMassFromDaughters(part);
509
510 const double bField = BFieldManager::getFieldInTesla(vertex).Z();
511 ROOT::Math::PxPyPzMVector sum;
512 for (auto daughter : daughters) {
513 const TrackFitResult* tfr = daughter->getTrackFitResult();
514 if (!tfr) {
515 sum += daughter->get4Vector();
516 continue;
517 }
518 Helix helix = tfr->getHelix();
519 helix.passiveMoveBy(vertex);
520 double scalingFactor = daughter->getEffectiveMomentumScale();
521 double momX = scalingFactor * helix.getMomentumX(bField);
522 double momY = scalingFactor * helix.getMomentumY(bField);
523 double momZ = scalingFactor * helix.getMomentumZ(bField);
524 float mPDG = daughter->getPDGMass();
525 sum += ROOT::Math::PxPyPzMVector(momX, momY, momZ, mPDG);
526 }
527 return sum.M();
528 }
529
530 double particleInvariantMassLambda(const Particle* part)
531 {
532 const std::vector<Particle*> daughters = part->getDaughters();
533 if (daughters.size() == 2) {
534 ROOT::Math::PxPyPzEVector dt1;
535 ROOT::Math::PxPyPzEVector dt2;
536 ROOT::Math::PxPyPzEVector dtsum;
537 double mpi = Const::pionMass;
538 double mpr = Const::protonMass;
539 dt1 = daughters[0]->get4Vector();
540 dt2 = daughters[1]->get4Vector();
541 double E1 = hypot(mpi, dt1.P());
542 double E2 = hypot(mpr, dt2.P());
543 dtsum = dt1 + dt2;
544 return sqrt((E1 + E2) * (E1 + E2) - dtsum.P() * dtsum.P());
545
546 } else {
547 return part->getMass();
548 }
549 }
550
551 double particleInvariantMassError(const Particle* part)
552 {
553 float invMass = part->getMass();
554 TMatrixFSym covarianceMatrix = part->getMomentumErrorMatrix();
555
556 TVectorF jacobian(Particle::c_DimMomentum);
557 jacobian[0] = -1.0 * part->getPx() / invMass;
558 jacobian[1] = -1.0 * part->getPy() / invMass;
559 jacobian[2] = -1.0 * part->getPz() / invMass;
560 jacobian[3] = 1.0 * part->getEnergy() / invMass;
561
562 double result = jacobian * (covarianceMatrix * jacobian);
563
564 if (result < 0.0)
565 return Const::doubleNaN;
566
567 return TMath::Sqrt(result);
568 }
569
570 double particleInvariantMassSignificance(const Particle* part)
571 {
572 return particleDMass(part) / particleInvariantMassError(part);
573 }
574
575 double particleMassSquared(const Particle* part)
576 {
577 ROOT::Math::PxPyPzEVector p4 = part->get4Vector();
578 return p4.M2();
579 }
580
581 double b2bTheta(const Particle* part)
582 {
583 PCmsLabTransform T;
584 ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * part->get4Vector();
585 ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
586 ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
587 return b2blab.Theta();
588 }
589
590 double b2bPhi(const Particle* part)
591 {
592 PCmsLabTransform T;
593 ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * part->get4Vector();
594 ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
595 ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
596 return b2blab.Phi();
597 }
598
599 double b2bClusterTheta(const Particle* part)
600 {
601 // get associated ECLCluster
602 const ECLCluster* cluster = part->getECLCluster();
603 if (!cluster) return Const::doubleNaN;
604 const ECLCluster::EHypothesisBit clusterHypothesis = part->getECLClusterEHypothesisBit();
605
606 // get 4 momentum from cluster
607 ClusterUtils clutls;
608 ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, clusterHypothesis);
609
610 // find the vector that balances this in the CMS
611 PCmsLabTransform T;
612 ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * p4Cluster;
613 ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
614 ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
615 return b2blab.Theta();
616 }
617
618 double b2bClusterPhi(const Particle* part)
619 {
620 // get associated ECLCluster
621 const ECLCluster* cluster = part->getECLCluster();
622 if (!cluster) return Const::doubleNaN;
623 const ECLCluster::EHypothesisBit clusterHypothesis = part->getECLClusterEHypothesisBit();
624
625 // get 4 momentum from cluster
626 ClusterUtils clutls;
627 ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, clusterHypothesis);
628
629 // find the vector that balances this in the CMS
630 PCmsLabTransform T;
631 ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * p4Cluster;
632 ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
633 ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
634 return b2blab.Phi();
635 }
636
637
638// released energy --------------------------------------------------
639
640 double particleQ(const Particle* part)
641 {
642 float m = part->getMass();
643 for (unsigned i = 0; i < part->getNDaughters(); i++) {
644 const Particle* child = part->getDaughter(i);
645 if (child)
646 m -= child->getMass();
647 }
648 return m;
649 }
650
651 double particleDQ(const Particle* part)
652 {
653 float m = part->getMass() - part->getPDGMass();
654 for (unsigned i = 0; i < part->getNDaughters(); i++) {
655 const Particle* child = part->getDaughter(i);
656 if (child)
657 m -= (child->getMass() - child->getPDGMass());
658 }
659 return m;
660 }
661
662// Mbc and deltaE
663
664 double particleMbc(const Particle* part)
665 {
666 PCmsLabTransform T;
667 ROOT::Math::PxPyPzEVector vec = T.rotateLabToCms() * part->get4Vector();
668 double E = T.getCMSEnergy() / 2;
669 double m2 = E * E - vec.P2();
670 double mbc = m2 >= 0 ? sqrt(m2) : Const::doubleNaN;
671 return mbc;
672 }
673
674 double particleDeltaE(const Particle* part)
675 {
676 PCmsLabTransform T;
677 ROOT::Math::PxPyPzEVector vec = T.rotateLabToCms() * part->get4Vector();
678 return vec.E() - T.getCMSEnergy() / 2;
679 }
680
681// other ------------------------------------------------------------
682
683
684 void printParticleInternal(const Particle* p, int depth)
685 {
686 stringstream s("");
687 for (int i = 0; i < depth; i++) {
688 s << " ";
689 }
690 s << p->getPDGCode();
691 const MCParticle* mcp = p->getMCParticle();
692 if (mcp) {
693 unsigned int flags = MCMatching::getMCErrors(p, mcp);
694 s << " -> MC: " << mcp->getPDG() << ", mcErrors: " << flags << " ("
695 << MCMatching::explainFlags(flags) << ")";
696 s << ", mc-index " << mcp->getIndex();
697 } else {
698 s << " (no MC match)";
699 }
700 s << ", mdst-source " << p->getMdstSource();
701 B2INFO(s.str());
702 for (const auto* daughter : p->getDaughters()) {
703 printParticleInternal(daughter, depth + 1);
704 }
705 }
706
707 bool printParticle(const Particle* p)
708 {
709 printParticleInternal(p, 0);
710 return 0;
711 }
712
713
714 double particleMCMomentumTransfer2(const Particle* part)
715 {
716 // for B meson MC particles only
717 const MCParticle* mcB = part->getMCParticle();
718
719 if (!mcB)
720 return Const::doubleNaN;
721
722 ROOT::Math::PxPyPzEVector pB = mcB->get4Vector();
723
724 std::vector<MCParticle*> mcDaug = mcB->getDaughters();
725
726 if (mcDaug.empty())
727 return Const::doubleNaN;
728
729 // B -> X l nu
730 // q = pB - pX
731 ROOT::Math::PxPyPzEVector pX;
732
733 for (auto mcTemp : mcDaug) {
734 if (abs(mcTemp->getPDG()) <= 16)
735 continue;
736
737 pX += mcTemp->get4Vector();
738 }
739
740 ROOT::Math::PxPyPzEVector q = pB - pX;
741
742 return q.M2();
743 }
744
745// Recoil Kinematics related ---------------------------------------------
746 double recoilPx(const Particle* particle)
747 {
748 PCmsLabTransform T;
749
750 // Initial state (e+e- momentum in LAB)
751 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
752
753 // Use requested frame for final calculation
754 const auto& frame = ReferenceFrame::GetCurrent();
755 return frame.getMomentum(pIN - particle->get4Vector()).Px();
756 }
757
758 double recoilPy(const Particle* particle)
759 {
760 PCmsLabTransform T;
761
762 // Initial state (e+e- momentum in LAB)
763 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
764
765 // Use requested frame for final calculation
766 const auto& frame = ReferenceFrame::GetCurrent();
767 return frame.getMomentum(pIN - particle->get4Vector()).Py();
768 }
769
770 double recoilPz(const Particle* particle)
771 {
772 PCmsLabTransform T;
773
774 // Initial state (e+e- momentum in LAB)
775 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
776
777 // Use requested frame for final calculation
778 const auto& frame = ReferenceFrame::GetCurrent();
779 return frame.getMomentum(pIN - particle->get4Vector()).Pz();
780 }
781
782 double recoilMomentum(const Particle* particle)
783 {
784 PCmsLabTransform T;
785
786 // Initial state (e+e- momentum in LAB)
787 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
788
789 // Use requested frame for final calculation
790 const auto& frame = ReferenceFrame::GetCurrent();
791 return frame.getMomentum(pIN - particle->get4Vector()).P();
792 }
793
794 double recoilMomentumTheta(const Particle* particle)
795 {
796 PCmsLabTransform T;
797
798 // Initial state (e+e- momentum in LAB)
799 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
800
801 // Use requested frame for final calculation
802 const auto& frame = ReferenceFrame::GetCurrent();
803 return frame.getMomentum(pIN - particle->get4Vector()).Theta();
804 }
805
806 double recoilMomentumPhi(const Particle* particle)
807 {
808 PCmsLabTransform T;
809
810 // Initial state (e+e- momentum in LAB)
811 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
812
813 // Use requested frame for final calculation
814 const auto& frame = ReferenceFrame::GetCurrent();
815 return frame.getMomentum(pIN - particle->get4Vector()).Phi();
816 }
817
818 double recoilEnergy(const Particle* particle)
819 {
820 PCmsLabTransform T;
821
822 // Initial state (e+e- momentum in LAB)
823 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
824
825 // Use requested frame for final calculation
826 const auto& frame = ReferenceFrame::GetCurrent();
827 return frame.getMomentum(pIN - particle->get4Vector()).E();
828 }
829
830 double recoilMass(const Particle* particle)
831 {
832 PCmsLabTransform T;
833
834 // Initial state (e+e- momentum in LAB)
835 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
836
837 // Use requested frame for final calculation
838 const auto& frame = ReferenceFrame::GetCurrent();
839 return frame.getMomentum(pIN - particle->get4Vector()).M();
840 }
841
842 double recoilMassSquared(const Particle* particle)
843 {
844 PCmsLabTransform T;
845
846 // Initial state (e+e- momentum in LAB)
847 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
848
849 // Use requested frame for final calculation
850 const auto& frame = ReferenceFrame::GetCurrent();
851 return frame.getMomentum(pIN - particle->get4Vector()).M2();
852 }
853
854 double m2RecoilSignalSide(const Particle* part)
855 {
856 PCmsLabTransform T;
857 double beamEnergy = T.getCMSEnergy() / 2.;
858 if (part->getNDaughters() != 2) return Const::doubleNaN;
859 ROOT::Math::PxPyPzEVector tagVec = T.rotateLabToCms() * part->getDaughter(0)->get4Vector();
860 ROOT::Math::PxPyPzEVector sigVec = T.rotateLabToCms() * part->getDaughter(1)->get4Vector();
861 tagVec.SetE(-beamEnergy);
862 return (-tagVec - sigVec).M2();
863 }
864
865 double recoilMCDecayType(const Particle* particle)
866 {
867 auto* mcp = particle->getMCParticle();
868
869 if (!mcp)
870 return Const::doubleNaN;
871
872 MCParticle* mcMother = mcp->getMother();
873
874 if (!mcMother)
875 return Const::doubleNaN;
876
877 std::vector<MCParticle*> daughters = mcMother->getDaughters();
878
879 if (daughters.size() != 2)
880 return Const::doubleNaN;
881
882 MCParticle* recoilMC = nullptr;
883 if (daughters[0]->getArrayIndex() == mcp->getArrayIndex())
884 recoilMC = daughters[1];
885 else
886 recoilMC = daughters[0];
887
888 if (!recoilMC->hasStatus(MCParticle::c_PrimaryParticle))
889 return Const::doubleNaN;
890
891 int decayType = 0;
892 checkMCParticleDecay(recoilMC, decayType, false);
893
894 if (decayType == 0)
895 checkMCParticleDecay(recoilMC, decayType, true);
896
897 return decayType;
898 }
899
900 void checkMCParticleDecay(MCParticle* mcp, int& decayType, bool recursive)
901 {
902 int nHadronicParticles = 0;
903 int nPrimaryParticleDaughters = 0;
904 std::vector<MCParticle*> daughters = mcp->getDaughters();
905
906 // Are any of the daughters primary particles? How many of them are hadrons?
907 for (auto& daughter : daughters) {
908 if (!daughter->hasStatus(MCParticle::c_PrimaryParticle))
909 continue;
910
911 nPrimaryParticleDaughters++;
912 if (abs(daughter->getPDG()) > Const::photon.getPDGCode())
913 nHadronicParticles++;
914 }
915
916 if (nPrimaryParticleDaughters > 1) {
917 for (auto& daughter : daughters) {
918 if (!daughter->hasStatus(MCParticle::c_PrimaryParticle))
919 continue;
920
921 if (abs(daughter->getPDG()) == 12 or abs(daughter->getPDG()) == 14 or abs(daughter->getPDG()) == 16) {
922 if (!recursive) {
923 if (nHadronicParticles == 0) {
924 decayType = 1.0;
925 break;
926 } else {
927 decayType = 2.0;
928 break;
929 }
930 } else {
931 decayType = 3.0;
932 break;
933 }
934 }
935
936 else if (recursive)
937 checkMCParticleDecay(daughter, decayType, recursive);
938 }
939 }
940 }
941
942 int nRemainingTracksInEvent(const Particle* particle)
943 {
944
945 StoreArray<Track> tracks;
946 int event_tracks = tracks.getEntries();
947
948 int par_tracks = 0;
949 const auto& daughters = particle->getFinalStateDaughters();
950 for (const auto& daughter : daughters) {
951 int pdg = abs(daughter->getPDGCode());
952 if (pdg == Const::electron.getPDGCode() or pdg == Const::muon.getPDGCode() or pdg == Const::pion.getPDGCode()
953 or pdg == Const::kaon.getPDGCode() or pdg == Const::proton.getPDGCode())
954 par_tracks++;
955 }
956 return event_tracks - par_tracks;
957 }
958
959 bool False(const Particle*)
960 {
961 return 0;
962 }
963
964 bool True(const Particle*)
965 {
966 return 1;
967 }
968
969 double infinity(const Particle*)
970 {
971 double inf = std::numeric_limits<double>::infinity();
972 return inf;
973 }
974
975 double random(const Particle*)
976 {
977 return gRandom->Uniform(0, 1);
978 }
979
980 double eventRandom(const Particle*)
981 {
982 std::string key = "__eventRandom";
983 StoreObjPtr<EventExtraInfo> eventExtraInfo;
984 if (not eventExtraInfo.isValid())
985 eventExtraInfo.create();
986 if (eventExtraInfo->hasExtraInfo(key)) {
987 return eventExtraInfo->getExtraInfo(key);
988 } else {
989 double value = gRandom->Uniform(0, 1);
990 eventExtraInfo->addExtraInfo(key, value);
991 return value;
992 }
993 }
994
995 Manager::FunctionPtr particleDistToClosestExtTrk(const std::vector<std::string>& arguments)
996 {
997 if (arguments.size() != 3 && arguments.size() != 4) {
998 B2ERROR("Wrong number of arguments (3 or 4 required) for meta variable minET2ETDist");
999 return nullptr;
1000 }
1001 bool useHighestProbMassForExt(true);
1002 if (arguments.size() == 4) {
1003 try {
1004 useHighestProbMassForExt = static_cast<bool>(Belle2::convertString<int>(arguments[3]));
1005 } catch (std::invalid_argument& e) {
1006 B2ERROR("Fourth (optional) argument of minET2ETDist must be an integer flag.");
1007 return nullptr;
1008 }
1009 }
1010
1011 std::string detName = arguments[0];
1012 std::string detLayer = arguments[1];
1013 std::string referenceListName = arguments[2];
1014 std::string extraSuffix = (useHighestProbMassForExt) ? "__useHighestProbMassForExt" : "";
1015 // Distance to closets neighbour at this detector layer.
1016 std::string extraInfo = "distToClosestTrkAt" + detName + detLayer + "_VS_" + referenceListName + extraSuffix;
1017
1018 auto func = [ = ](const Particle * part) -> double {
1019 auto dist = (part->hasExtraInfo(extraInfo)) ? part->getExtraInfo(extraInfo) : Const::doubleNaN;
1020 return dist;
1021 };
1022
1023 return func;
1024 }
1025
1026// Track helix extrapolation-based isolation --------------------------------------------------
1027
1028 Manager::FunctionPtr particleDistToClosestExtTrkVar(const std::vector<std::string>& arguments)
1029 {
1030 if (arguments.size() != 4) {
1031 B2ERROR("Wrong number of arguments (4 required) for meta variable minET2ETDistVar");
1032 return nullptr;
1033 }
1034
1035 std::string detName = arguments[0];
1036 std::string detLayer = arguments[1];
1037 std::string referenceListName = arguments[2];
1038 std::string variableName = arguments[3];
1039 // Mdst array index of the particle that is closest to the particle in question.
1040 std::string extraInfo = "idxOfClosestPartAt" + detName + detLayer + "In_" + referenceListName;
1041
1042 auto func = [ = ](const Particle * part) -> double {
1043
1044 StoreObjPtr<ParticleList> refPartList(referenceListName);
1045 if (!refPartList.isValid())
1046 {
1047 B2FATAL("Invalid Listname " << referenceListName << " given to minET2ETDistVar!");
1048 }
1049
1050 if (!part->hasExtraInfo(extraInfo))
1051 {
1052 return Const::doubleNaN;
1053 }
1054
1055 const Variable::Manager::Var* var = Manager::Instance().getVariable(variableName);
1056 auto refPart = refPartList->getParticleWithMdstSource(part->getExtraInfo(extraInfo));
1057
1058 return std::get<double>(var->function(refPart));
1059 };
1060
1061 return func;
1062 }
1063
1064
1065 Manager::FunctionPtr particleExtTrkIsoScoreVar(const std::vector<std::string>& arguments)
1066 {
1067
1068 if (arguments.size() < 3) {
1069 B2ERROR("Wrong number of arguments (at least 3 required) for meta variable minET2ETIsoScore");
1070 return nullptr;
1071 }
1072
1073 std::string referenceListName = arguments[0];
1074 bool useHighestProbMassForExt;
1075 try {
1076 useHighestProbMassForExt = static_cast<bool>(Belle2::convertString<int>(arguments[1]));
1077 } catch (std::invalid_argument& e) {
1078 B2ERROR("Second argument must be an integer flag.");
1079 return nullptr;
1080 }
1081 std::string extraSuffix = (useHighestProbMassForExt) ? "__useHighestProbMassForExt" : "";
1082
1083 std::vector<std::string> detectorNames(arguments.begin() + 2, arguments.end());
1084
1085 std::string detNamesConcat("");
1086 for (auto& detName : detectorNames) {
1087 boost::to_upper(detName);
1088 detNamesConcat += "_" + detName;
1089 }
1090
1091 std::string extraInfo = "trkIsoScore" + detNamesConcat + "_VS_" + referenceListName + extraSuffix;
1092
1093 auto func = [ = ](const Particle * part) -> double {
1094
1095 StoreObjPtr<ParticleList> refPartList(referenceListName);
1096 if (!refPartList.isValid())
1097 {
1098 B2FATAL("Invalid Listname " << referenceListName << " given to minET2ETIsoScore!");
1099 }
1100
1101 if (!part->hasExtraInfo(extraInfo))
1102 {
1103 return Const::doubleNaN;
1104 }
1105 auto scoreDet = part->getExtraInfo(extraInfo);
1106 if (std::isnan(scoreDet))
1107 {
1108 return Const::doubleNaN;
1109 }
1110
1111 return scoreDet;
1112
1113 };
1114
1115 return func;
1116 }
1117
1118
1119 Manager::FunctionPtr particleExtTrkIsoScoreVarAsWeightedAvg(const std::vector<std::string>& arguments)
1120 {
1121
1122 if (arguments.size() < 3) {
1123 B2ERROR("Wrong number of arguments (at least 3 required) for meta variable minET2ETIsoScoreAsWeightedAvg");
1124 return nullptr;
1125 }
1126
1127 std::string referenceListName = arguments[0];
1128 bool useHighestProbMassForExt;
1129 try {
1130 useHighestProbMassForExt = static_cast<bool>(Belle2::convertString<int>(arguments[1]));
1131 } catch (std::invalid_argument& e) {
1132 B2ERROR("Second argument must be an integer flag.");
1133 return nullptr;
1134 }
1135 std::string extraSuffix = (useHighestProbMassForExt) ? "__useHighestProbMassForExt" : "";
1136
1137 std::vector<std::string> detectorNames(arguments.begin() + 2, arguments.end());
1138
1139 std::string detNamesConcat("");
1140 for (auto& detName : detectorNames) {
1141 boost::to_upper(detName);
1142 detNamesConcat += "_" + detName;
1143 }
1144
1145 std::string extraInfo = "trkIsoScoreAsWeightedAvg" + detNamesConcat + "_VS_" + referenceListName + extraSuffix;
1146
1147 auto func = [ = ](const Particle * part) -> double {
1148
1149 StoreObjPtr<ParticleList> refPartList(referenceListName);
1150 if (!refPartList.isValid())
1151 {
1152 B2FATAL("Invalid Listname " << referenceListName << " given to minET2ETIsoScoreAsWeightedAvg!");
1153 }
1154
1155 if (!part->hasExtraInfo(extraInfo))
1156 {
1157 return Const::doubleNaN;
1158 }
1159 auto scoreDet = part->getExtraInfo(extraInfo);
1160 if (std::isnan(scoreDet))
1161 {
1162 return Const::doubleNaN;
1163 }
1164
1165 return scoreDet;
1166
1167 };
1168
1169 return func;
1170 }
1171
1172 VARIABLE_GROUP("Kinematics");
1173 REGISTER_VARIABLE("p", particleP, "momentum magnitude\n\n", "GeV/c");
1174 REGISTER_VARIABLE("E", particleE, "energy\n\n", "GeV");
1175
1176 REGISTER_VARIABLE("E_uncertainty", particleEUncertainty, R"DOC(
1177 energy uncertainty (:math:`\sqrt{\sigma^2}`)
1178
1179 )DOC", "GeV");
1180 REGISTER_VARIABLE("ECLClusterE_uncertainty", particleClusterEUncertainty,
1181 "energy uncertainty as given by the underlying ECL cluster\n\n", "GeV");
1182 REGISTER_VARIABLE("px", particlePx, "momentum component x\n\n", "GeV/c");
1183 REGISTER_VARIABLE("py", particlePy, "momentum component y\n\n", "GeV/c");
1184 REGISTER_VARIABLE("pz", particlePz, "momentum component z\n\n", "GeV/c");
1185 REGISTER_VARIABLE("pt", particlePt, "transverse momentum\n\n", "GeV/c");
1186 REGISTER_VARIABLE("xp", particleXp,
1187 "scaled momentum: the momentum of the particle in the CMS as a fraction of its maximum available momentum in the collision");
1188 REGISTER_VARIABLE("pErr", particlePErr, "error of momentum magnitude\n\n", "GeV/c");
1189 REGISTER_VARIABLE("pxErr", particlePxErr, "error of momentum component x\n\n", "GeV/c");
1190 REGISTER_VARIABLE("pyErr", particlePyErr, "error of momentum component y\n\n", "GeV/c");
1191 REGISTER_VARIABLE("pzErr", particlePzErr, "error of momentum component z\n\n", "GeV/c");
1192 REGISTER_VARIABLE("ptErr", particlePtErr, "error of transverse momentum\n\n", "GeV/c");
1193 REGISTER_VARIABLE("momVertCovM(i,j)", covMatrixElement,
1194 "returns the (i,j)-th element of the MomentumVertex Covariance Matrix (7x7).\n"
1195 "Order of elements in the covariance matrix is: px, py, pz, E, x, y, z.\n\n", "GeV/c, GeV/c, GeV/c, GeV, cm, cm, cm");
1196 REGISTER_VARIABLE("momDevChi2", momentumDeviationChi2, R"DOC(
1197momentum deviation :math:`\chi^2` value calculated as :math:`\chi^2 = \sum_i (p_i - mc(p_i))^2/\sigma(p_i)^2`,
1198where :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
1199)DOC");
1200 REGISTER_VARIABLE("theta", particleTheta, "polar angle\n\n", "rad");
1201 REGISTER_VARIABLE("thetaErr", particleThetaErr, "error of polar angle\n\n", "rad");
1202 REGISTER_VARIABLE("cosTheta", particleCosTheta, "momentum cosine of polar angle");
1203 REGISTER_VARIABLE("cosThetaErr", particleCosThetaErr, "error of momentum cosine of polar angle");
1204 REGISTER_VARIABLE("phi", particlePhi, "momentum azimuthal angle\n\n", "rad");
1205 REGISTER_VARIABLE("phiErr", particlePhiErr, "error of momentum azimuthal angle\n\n", "rad");
1206 REGISTER_VARIABLE("PDG", particlePDGCode, "PDG code");
1207 REGISTER_VARIABLE("cosAngleBetweenMomentumAndVertexVectorInXYPlane",
1208 cosAngleBetweenMomentumAndVertexVectorInXYPlane,
1209 "cosine of the angle between momentum and vertex vector (vector connecting ip and fitted vertex) of this particle in xy-plane");
1210 REGISTER_VARIABLE("cosAngleBetweenMomentumAndVertexVector",
1211 cosAngleBetweenMomentumAndVertexVector,
1212 "cosine of the angle between momentum and vertex vector (vector connecting ip and fitted vertex) of this particle");
1213 REGISTER_VARIABLE("cosThetaBetweenParticleAndNominalB",
1214 cosThetaBetweenParticleAndNominalB,
1215 "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.");
1216 REGISTER_VARIABLE("cosToThrustOfEvent", cosToThrustOfEvent,
1217 "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");
1218
1219 REGISTER_VARIABLE("ImpactXY" , ImpactXY , "The impact parameter of the given particle in the xy plane\n\n", "cm");
1220
1221 REGISTER_VARIABLE("M", particleMass, R"DOC(
1222The particle's mass.
1223
1224Note that this is context-dependent variable and can take different values depending on the situation. This should be the "best"
1225value possible with the information provided.
1226
1227- If this particle is track- or cluster- based, then this is the value of the mass hypothesis.
1228- If this particle is an MC particle then this is the mass of that particle.
1229- If this particle is composite, then *initially* this takes the value of the invariant mass of the daughters.
1230- If this particle is composite and a *mass or vertex fit* has been performed then this may be updated by the fit.
1231
1232* You will see a difference between this mass and the :b2:var:`InvM`.
1233
1234)DOC", "GeV/:math:`\\text{c}^2`");
1235 REGISTER_VARIABLE("dM", particleDMass, "mass minus nominal mass\n\n", "GeV/:math:`\\text{c}^2`");
1236 REGISTER_VARIABLE("Q", particleQ, "energy released in decay\n\n", "GeV");
1237 REGISTER_VARIABLE("dQ", particleDQ, ":b2:var:`Q` minus nominal energy released in decay\n\n", "GeV");
1238 REGISTER_VARIABLE("Mbc", particleMbc, "beam constrained mass\n\n", "GeV/:math:`\\text{c}^2`");
1239 REGISTER_VARIABLE("deltaE", particleDeltaE, "difference between :b2:var:`E` and half the center of mass energy\n\n", "GeV");
1240 REGISTER_VARIABLE("M2", particleMassSquared, "The particle's mass squared.\n\n", ":math:`[\\text{GeV}/\\text{c}^2]^2`");
1241
1242 REGISTER_VARIABLE("InvM", particleInvariantMassFromDaughtersDisplaced,
1243 "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"
1244 "If this particle has no daughters, defaults to :b2:var:`M`.\n\n", "GeV/:math:`\\text{c}^2`");
1245 REGISTER_VARIABLE("InvMLambda", particleInvariantMassLambda,
1246 "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"
1247 "If the particle has not 2 daughters, it returns just the mass value.\n\n", "GeV/:math:`\\text{c}^2`");
1248
1249 REGISTER_VARIABLE("ErrM", particleInvariantMassError,
1250 "uncertainty of invariant mass\n\n", "GeV/:math:`\\text{c}^2`");
1251 REGISTER_VARIABLE("SigM", particleInvariantMassSignificance,
1252 "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`)");
1253
1254 REGISTER_VARIABLE("pxRecoil", recoilPx,
1255 "component x of 3-momentum recoiling against given Particle\n\n", "GeV/c");
1256 REGISTER_VARIABLE("pyRecoil", recoilPy,
1257 "component y of 3-momentum recoiling against given Particle\n\n", "GeV/c");
1258 REGISTER_VARIABLE("pzRecoil", recoilPz,
1259 "component z of 3-momentum recoiling against given Particle\n\n", "GeV/c");
1260
1261 REGISTER_VARIABLE("pRecoil", recoilMomentum,
1262 "magnitude of 3 - momentum recoiling against given Particle\n\n", "GeV/c");
1263 REGISTER_VARIABLE("pRecoilTheta", recoilMomentumTheta,
1264 "Polar angle of a particle's missing momentum\n\n", "rad");
1265 REGISTER_VARIABLE("pRecoilPhi", recoilMomentumPhi,
1266 "Azimuthal angle of a particle's missing momentum\n\n", "rad");
1267 REGISTER_VARIABLE("eRecoil", recoilEnergy,
1268 "energy recoiling against given Particle\n\n", "GeV");
1269 REGISTER_VARIABLE("mRecoil", recoilMass,
1270 "Invariant mass of the system recoiling against given Particle\n\n", "GeV/:math:`\\text{c}^2`");
1271 REGISTER_VARIABLE("m2Recoil", recoilMassSquared,
1272 "invariant mass squared of the system recoiling against given Particle\n\n", ":math:`[\\text{GeV}/\\text{c}^2]^2`");
1273 REGISTER_VARIABLE("m2RecoilSignalSide", m2RecoilSignalSide, R"DOC(
1274 Squared recoil mass of the signal side which is calculated in the CMS frame under the assumption that the
1275 signal and tag side are produced back to back and the tag side energy equals the beam energy. The variable
1276 must be applied to the Upsilon and the tag side must be the first, the signal side the second daughter
1277
1278 )DOC", ":math:`[\\text{GeV}/\\text{c}^2]^2`");
1279
1280 REGISTER_VARIABLE("b2bTheta", b2bTheta,
1281 "Polar angle in the lab system that is back-to-back to the particle in the CMS. Useful for low multiplicity studies.\n\n", "rad");
1282 REGISTER_VARIABLE("b2bPhi", b2bPhi,
1283 "Azimuthal angle in the lab system that is back-to-back to the particle in the CMS. Useful for low multiplicity studies.\n\n",
1284 "rad");
1285 REGISTER_VARIABLE("b2bClusterTheta", b2bClusterTheta,
1286 "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.\n\n",
1287 "rad");
1288 REGISTER_VARIABLE("b2bClusterPhi", b2bClusterPhi,
1289 "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.\n\n",
1290 "rad");
1291 REGISTER_VARIABLE("ArmenterosLongitudinalMomentumAsymmetry", ArmenterosLongitudinalMomentumAsymmetry,
1292 "Longitudinal momentum asymmetry of V0's daughters.\n"
1293 "The mother (V0) is required to have exactly two daughters");
1294 REGISTER_VARIABLE("ArmenterosDaughter1Qt", ArmenterosDaughter1Qt, R"DOC(
1295 Transverse momentum of the first daughter with respect to the V0 mother.
1296 The mother is required to have exactly two daughters
1297
1298 )DOC", "GeV/c");
1299 REGISTER_VARIABLE("ArmenterosDaughter2Qt", ArmenterosDaughter2Qt, R"DOC(
1300 Transverse momentum of the second daughter with respect to the V0 mother.
1301 The mother is required to have exactly two daughters
1302
1303 )DOC", "GeV/c");
1304
1305 VARIABLE_GROUP("Miscellaneous");
1306 REGISTER_VARIABLE("nRemainingTracksInEvent", nRemainingTracksInEvent,
1307 "Number of tracks in the event - Number of tracks( = charged FSPs) of particle.");
1308 REGISTER_VARIABLE("decayTypeRecoil", recoilMCDecayType,
1309 "type of the particle decay(no related mcparticle = -1, hadronic = 0, direct leptonic = 1, direct semileptonic = 2,"
1310 "lower level leptonic = 3.");
1311
1312 REGISTER_VARIABLE("printParticle", printParticle,
1313 "For debugging, print Particle and daughter PDG codes, plus MC match. Returns 0.");
1314 REGISTER_VARIABLE("mcMomTransfer2", particleMCMomentumTransfer2,
1315 "Return the true momentum transfer to lepton pair in a B(semi -) leptonic B meson decay.\n\n", "GeV/c");
1316 REGISTER_VARIABLE("False", False,
1317 "returns always 0, used for testing and debugging.");
1318 REGISTER_VARIABLE("True", True,
1319 "returns always 1, used for testing and debugging.");
1320 REGISTER_VARIABLE("infinity", infinity,
1321 "returns std::numeric_limits<double>::infinity()");
1322 REGISTER_VARIABLE("random", random,
1323 "return a random number between 0 and 1 for each candidate. Can be used, e.g. for picking a random"
1324 "candidate in the best candidate selection.");
1325 REGISTER_VARIABLE("eventRandom", eventRandom,
1326 "[Eventbased] Returns a random number between 0 and 1 for this event. Can be used, e.g. for applying an event prescale.");
1327 REGISTER_METAVARIABLE("minET2ETDist(detName, detLayer, referenceListName, useHighestProbMassForExt=1)", particleDistToClosestExtTrk,
1328 R"DOC(Returns the distance :math:`d_{\mathrm{i}}` in [cm] between the particle and the nearest particle in the reference list at the given detector :math:`i`-th layer surface.
1329The definition is based on the track helices extrapolation.
1330
1331* The first argument is the name of the detector to consider.
1332* The second argument is the detector layer on whose surface we search for the nearest neighbour.
1333* The third argument is the reference particle list name used to search for the nearest neighbour.
1334* The fourth (optional) argument is an integer ("boolean") flag: if 1 (the default, if nothing is set), it is assumed the extrapolation was done with the most probable mass hypothesis for the track fit;
1335 if 0, it is assumed the mass hypothesis matching the particle lists' PDG was used.
1336
1337.. note::
1338 This variable requires to run the ``TrackIsoCalculator`` module first.
1339 Note that the choice of input parameters of this metafunction must correspond to the settings used to configure the module!
1340)DOC",
1341 Manager::VariableDataType::c_double);
1342
1343 REGISTER_METAVARIABLE("minET2ETDistVar(detName, detLayer, referenceListName, variableName)", particleDistToClosestExtTrkVar,
1344 R"DOC(Returns the value of the variable for the nearest neighbour to this particle as taken from the reference list at the given detector :math:`i`-th layer surface
1345, according to the distance definition of `minET2ETDist`.
1346
1347* The first argument is the name of the detector to consider.
1348* The second argument is the detector layer on whose surface we search for the nearest neighbour.
1349* The third argument is the reference particle list name used to search for the nearest neighbour.
1350* The fourth argument is a variable name, e.g. `nCDCHits`.
1351
1352.. note::
1353 This variable requires to run the ``TrackIsoCalculator`` module first.
1354 Note that the choice of input parameters of this metafunction must correspond to the settings used to configure the module!
1355)DOC",
1356 Manager::VariableDataType::c_double);
1357
1358 REGISTER_METAVARIABLE("minET2ETIsoScore(referenceListName, useHighestProbMassForExt, detectorList)", particleExtTrkIsoScoreVar,
1359 R"DOC(Returns a particle's isolation score :math:`s` defined as:
1360
1361.. math::
1362 :nowrap:
1363
1364 \begin{split}
1365
1366 s &= \sum_{\mathrm{det}} 1 - \left(-w_{\mathrm{det}} \cdot \frac{\sum_{i}^{N_{\mathrm{det}}^{\mathrm{layers}}} H(i)}{N_{\mathrm{det}}^{\mathrm{layers}}}\right), \\
1367
1368 H(i) &=
1369 \begin{cases}
1370 0 & d_{\mathrm{i}} > D_{\mathrm{det}}^{\mathrm{thresh}} \\
1371 1 & d_{\mathrm{i}} <= D_{\mathrm{det}}^{\mathrm{thresh}}, \\
1372 \end{cases}
1373
1374 \end{split}
1375
1376where :math:`d_{\mathrm{i}}` is the distance to the closest neighbour at the :math:`i`-th layer of the given detector (c.f., `minET2ETDist`), :math:`N_{\mathrm{det}}^{\mathrm{layers}}` is the
1377number of layers of the detector, :math:`D_{\mathrm{det}}^{\mathrm{thresh}}` is a threshold length related to the detector's granularity defined in the ``TrackIsoCalculator`` module,
1378and :math:`w_{\mathrm{det}}` are (negative) weights associated to the detector's impact on PID for this particle type, read from a CDB payload.
1379
1380The score is normalised in [0, 1], where values closer to 1 indicates a well-isolated particle.
1381
1382* The first argument is the reference particle list name used to search for the nearest neighbour.
1383* The second argument is an integer ("boolean") flag: if 1, it is assumed the extrapolation was done with the most probable mass hypothesis for the track fit;
1384 if 0, it is assumed the mass hypothesis matching the particle lists' PDG was used.
1385* The remaining arguments are a comma-separated list of detector names, which must correspond to the one given to the `TrackIsoCalculator` module.
1386
1387.. note::
1388 The PID detector weights :math:`w_{\mathrm{det}}` are non-trivial only if ``excludePIDDetWeights=false`` in the ``TrackIsoCalculator`` module configuration.
1389 Otherwise :math:`w_{\mathrm{det}} = -1`.
1390
1391.. note::
1392 This variable requires to run the `TrackIsoCalculator` module first.
1393 Note that the choice of input parameters of this metafunction must correspond to the settings used to configure the module!
1394
1395)DOC",
1396 Manager::VariableDataType::c_double);
1397
1398 REGISTER_METAVARIABLE("minET2ETIsoScoreAsWeightedAvg(referenceListName, useHighestProbMassForExt, detectorList)", particleExtTrkIsoScoreVarAsWeightedAvg,
1399 R"DOC(Returns a particle's isolation score :math:`s` based on the weighted average:
1400
1401.. math::
1402
1403 s = 1 - \frac{\sum_{\mathrm{det}} \sum_{i}^{N_{\mathrm{det}}^{\mathrm{layers}}} w_{\mathrm{det}} \cdot \frac{D_{\mathrm{det}}^{\mathrm{thresh}}}{d_{\mathrm{i}}} }{ \sum_{\mathrm{det}} w_{\mathrm{det}}},
1404
1405where :math:`d_{\mathrm{i}}` is the distance to the closest neighbour at the :math:`i`-th layer of the given detector (c.f., `minET2ETDist`), :math:`N_{\mathrm{det}}^{\mathrm{layers}}` is the
1406number of layers of the detector, :math:`D_{\mathrm{det}}^{\mathrm{thresh}}` is a threshold length related to the detector's granularity defined in the ``TrackIsoCalculator`` module,
1407and :math:`w_{\mathrm{det}}` are (negative) weights associated to the detector's impact on PID for this particle type, read from a CDB payload.
1408
1409The score is normalised in [0, 1], where values closer to 1 indicates a well-isolated particle.
1410
1411* The first argument is the reference particle list name used to search for the nearest neighbour.
1412* The second argument is an integer ("boolean") flag: if 1, it is assumed the extrapolation was done with the most probable mass hypothesis for the track fit;
1413 if 0, it is assumed the mass hypothesis matching the particle lists' PDG was used.
1414* The remaining arguments are a comma-separated list of detector names, which must correspond to the one given to the `TrackIsoCalculator` module.
1415
1416.. note::
1417 The PID detector weights :math:`w_{\mathrm{det}}` are non-trivial only if ``excludePIDDetWeights=false`` in the ``TrackIsoCalculator`` module configuration.
1418 Otherwise :math:`\lvert w_{\mathrm{det}} \rvert = 1`.
1419
1420.. note::
1421 This variable requires to run the `TrackIsoCalculator` module first.
1422 Note that the choice of input parameters of this metafunction must correspond to the settings used to configure the module!
1423
1424)DOC",
1425 Manager::VariableDataType::c_double);
1426
1427 }
1429}
R E
internal precision of FFTW codelets
DataType Perp() const
The transverse component (R in cylindrical coordinate system).
Definition: B2Vector3.h:200
static BFieldManager & getInstance()
Return the instance of the magnetic field manager.
static ROOT::Math::XYZVector getFieldInTesla(const ROOT::Math::XYZVector &pos)
return the magnetic field at a given position in Tesla.
Definition: BFieldManager.h:60
int getPDGCode() const
PDG code.
Definition: Const.h:473
static const ChargedStable muon
muon particle
Definition: Const.h:660
static const ChargedStable pion
charged pion particle
Definition: Const.h:661
static const double pionMass
charged pion mass
Definition: Const.h:687
static const double speedOfLight
[cm/ns]
Definition: Const.h:695
static const ChargedStable proton
proton particle
Definition: Const.h:663
static const double protonMass
proton mass
Definition: Const.h:689
static const double doubleNaN
quiet_NaN
Definition: Const.h:703
static const ChargedStable kaon
charged kaon particle
Definition: Const.h:662
static const ParticleType photon
photon particle
Definition: Const.h:673
static const ChargedStable electron
electron particle
Definition: Const.h:659
EHypothesisBit
The hypothesis bits for this ECLCluster (Connected region (CR) is split using this hypothesis.
Definition: ECLCluster.h:31
@ c_PrimaryParticle
bit 0: Particle is primary particle.
Definition: MCParticle.h:47
const MCParticle * getMCParticle() const
Returns the pointer to the MCParticle object that was used to create this Particle (ParticleType == c...
Definition: Particle.cc:1027
static const ReferenceFrame & GetCurrent()
Get current rest frame.
std::function< VarVariant(const Particle *)> FunctionPtr
functions stored take a const Particle* and return VarVariant.
Definition: Manager.h:112
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
Definition: Manager.cc:58
static Manager & Instance()
get singleton instance.
Definition: Manager.cc:26
Class to store variables with their name which were sent to the logging service.
B2Vector3< double > B2Vector3D
typedef for common usage with double
Definition: B2Vector3.h:516
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.
STL namespace.
static std::string explainFlags(unsigned int flags)
Return string with all human-readable flags, e.g.
Definition: MCMatching.cc:26
static int getMCErrors(const Belle2::Particle *particle, const Belle2::MCParticle *mcParticle=nullptr)
Returns quality indicator of the match as a bit pattern where the individual bits indicate the the ty...
Definition: MCMatching.cc:282