10 #include <analysis/variables/Variables.h>
13 #include <analysis/VariableManager/Manager.h>
15 #include <analysis/utility/PCmsLabTransform.h>
16 #include <analysis/utility/ReferenceFrame.h>
17 #include <analysis/utility/MCMatching.h>
18 #include <analysis/ClusterUtility/ClusterUtils.h>
21 #include <framework/datastore/StoreArray.h>
22 #include <framework/datastore/StoreObjPtr.h>
25 #include <analysis/dataobjects/Particle.h>
26 #include <analysis/dataobjects/EventExtraInfo.h>
27 #include <analysis/dataobjects/EventShapeContainer.h>
29 #include <mdst/dataobjects/MCParticle.h>
30 #include <mdst/dataobjects/Track.h>
31 #include <mdst/dataobjects/ECLCluster.h>
32 #include <mdst/dataobjects/V0.h>
34 #include <mdst/dbobjects/BeamSpot.h>
37 #include <framework/logging/Logger.h>
38 #include <framework/geometry/B2Vector3.h>
39 #include <framework/geometry/BFieldManager.h>
40 #include <framework/gearbox/Const.h>
42 #include <Math/Vector4D.h>
60 double particleP(
const Particle* part)
62 const auto& frame = ReferenceFrame::GetCurrent();
63 return frame.getMomentum(part).P();
66 double particleE(
const Particle* part)
68 const auto& frame = ReferenceFrame::GetCurrent();
69 return frame.getMomentum(part).E();
72 double particleClusterEUncertainty(
const Particle* part)
74 const ECLCluster* cluster = part->getECLCluster();
76 const auto EPhiThetaCov = cluster->getCovarianceMatrix3x3();
77 return std::sqrt(EPhiThetaCov[0][0]);
79 return std::numeric_limits<double>::quiet_NaN();
82 double particlePx(
const Particle* part)
84 const auto& frame = ReferenceFrame::GetCurrent();
85 return frame.getMomentum(part).Px();
88 double particlePy(
const Particle* part)
90 const auto& frame = ReferenceFrame::GetCurrent();
91 return frame.getMomentum(part).Py();
94 double particlePz(
const Particle* part)
96 const auto& frame = ReferenceFrame::GetCurrent();
97 return frame.getMomentum(part).Pz();
100 double particlePt(
const Particle* part)
102 const auto& frame = ReferenceFrame::GetCurrent();
103 return frame.getMomentum(part).Pt();
106 double covMatrixElement(
const Particle* part,
const std::vector<double>& element)
108 int elementI = int(std::lround(element[0]));
109 int elementJ = int(std::lround(element[1]));
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();
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();
120 return part->getMomentumVertexErrorMatrix()(elementI, elementJ);
123 double particleEUncertainty(
const Particle* part)
125 const auto& frame = ReferenceFrame::GetCurrent();
127 double errorSquared = frame.getMomentumErrorMatrix(part)(3, 3);
129 if (errorSquared >= 0.0)
130 return sqrt(errorSquared);
132 return std::numeric_limits<double>::quiet_NaN();
135 double particlePErr(
const Particle* part)
137 TMatrixD jacobianRot(3, 3);
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);
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;
155 const auto& frame = ReferenceFrame::GetCurrent();
157 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2,
" ").Similarity(jacobianRot)(0, 0);
159 if (errorSquared >= 0.0)
160 return sqrt(errorSquared);
162 return std::numeric_limits<double>::quiet_NaN();
165 double particlePxErr(
const Particle* part)
167 const auto& frame = ReferenceFrame::GetCurrent();
169 double errorSquared = frame.getMomentumErrorMatrix(part)(0, 0);
171 if (errorSquared >= 0.0)
172 return sqrt(errorSquared);
174 return std::numeric_limits<double>::quiet_NaN();
177 double particlePyErr(
const Particle* part)
179 const auto& frame = ReferenceFrame::GetCurrent();
180 double errorSquared = frame.getMomentumErrorMatrix(part)(1, 1);
182 if (errorSquared >= 0.0)
183 return sqrt(errorSquared);
185 return std::numeric_limits<double>::quiet_NaN();
188 double particlePzErr(
const Particle* part)
190 const auto& frame = ReferenceFrame::GetCurrent();
191 double errorSquared = frame.getMomentumErrorMatrix(part)(2, 2);
193 if (errorSquared >= 0.0)
194 return sqrt(errorSquared);
196 return std::numeric_limits<double>::quiet_NaN();
199 double particlePtErr(
const Particle* part)
201 TMatrixD jacobianRot(3, 3);
204 double px = particlePx(part);
205 double py = particlePy(part);
206 double pt = particlePt(part);
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;
214 const auto& frame = ReferenceFrame::GetCurrent();
215 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2,
" ").Similarity(jacobianRot)(0, 0);
217 if (errorSquared >= 0.0)
218 return sqrt(errorSquared);
220 return std::numeric_limits<double>::quiet_NaN();
223 double momentumDeviationChi2(
const Particle* part)
225 double result = std::numeric_limits<double>::quiet_NaN();
228 if (part->getPValue() < 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);
244 double particleTheta(
const Particle* part)
246 const auto& frame = ReferenceFrame::GetCurrent();
247 return frame.getMomentum(part).Theta();
250 double particleThetaErr(
const Particle* part)
252 TMatrixD jacobianRot(3, 3);
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);
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;
270 const auto& frame = ReferenceFrame::GetCurrent();
271 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2,
" ").Similarity(jacobianRot)(1, 1);
273 if (errorSquared >= 0.0)
274 return sqrt(errorSquared);
276 return std::numeric_limits<double>::quiet_NaN();
279 double particleCosTheta(
const Particle* part)
281 const auto& frame = ReferenceFrame::GetCurrent();
282 return cos(frame.getMomentum(part).Theta());
285 double particleCosThetaErr(
const Particle* part)
287 return fabs(particleThetaErr(part) * sin(particleTheta(part)));
290 double particlePhi(
const Particle* part)
292 const auto& frame = ReferenceFrame::GetCurrent();
293 return frame.getMomentum(part).Phi();
296 double particlePhiErr(
const Particle* part)
298 TMatrixD jacobianRot(3, 3);
301 double px = particlePx(part);
302 double py = particlePy(part);
303 double pt = particlePt(part);
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;
311 const auto& frame = ReferenceFrame::GetCurrent();
312 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2,
" ").Similarity(jacobianRot)(1, 1);
314 if (errorSquared >= 0.0)
315 return sqrt(errorSquared);
317 return std::numeric_limits<double>::quiet_NaN();
320 double particleXp(
const Particle* part)
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);
330 int particlePDGCode(
const Particle* part)
332 return part->getPDGCode();
335 double cosAngleBetweenMomentumAndVertexVectorInXYPlane(
const Particle* part)
337 static DBObjPtr<BeamSpot> beamSpotDB;
338 double px = part->getPx();
339 double py = part->getPy();
341 double xV = part->getX();
342 double yV = part->getY();
344 double xIP = (beamSpotDB->getIPPosition()).X();
345 double yIP = (beamSpotDB->getIPPosition()).Y();
350 double cosangle = (px * x + py * y) / (sqrt(px * px + py * py) * sqrt(x * x + y * y));
354 double cosAngleBetweenMomentumAndVertexVector(
const Particle* part)
356 static DBObjPtr<BeamSpot> beamSpotDB;
357 return cos((
B2Vector3D(part->getVertex()) - beamSpotDB->getIPPosition()).Angle(
B2Vector3D(part->getMomentum())));
360 double cosThetaBetweenParticleAndNominalB(
const Particle* part)
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!");
368 double e_Beam = T.getCMSEnergy() / 2.0;
369 double m_B = part->getPDGMass();
371 if (e_Beam * e_Beam - m_B * m_B < 0) {
372 e_Beam = 1.0579400E+1 / 2.0;
374 double p_B = std::sqrt(e_Beam * e_Beam - m_B * m_B);
376 ROOT::Math::PxPyPzEVector p = T.rotateLabToCms() * part->get4Vector();
381 double theta_BY = (2 * e_Beam * e_d - m_B * m_B - m_d * m_d)
386 double cosToThrustOfEvent(
const Particle* part)
388 StoreObjPtr<EventShapeContainer> 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();
395 B2Vector3D particleMomentum = (T.rotateLabToCms() * part -> get4Vector()).Vect();
396 return std::cos(th.Angle(particleMomentum));
399 double ImpactXY(
const Particle* particle)
401 static DBObjPtr<BeamSpot> beamSpotDB;
407 B2Vector3D Bfield = BFieldManager::getInstance().getFieldInTesla(beamSpotDB->getIPPosition());
409 B2Vector3D curvature = - Bfield * Const::speedOfLight * particle->getCharge();
410 double T = TMath::Sqrt(mom.Perp2() - 2.0 * curvature * r.Cross(mom) + curvature.Mag2() * r.Perp2());
412 return TMath::Abs((-2 * r.Cross(mom).z() + curvature.Mag() * r.Perp2()) / (T + mom.Perp()));
415 double ArmenterosLongitudinalMomentumAsymmetry(
const Particle* part)
417 const auto& frame = ReferenceFrame::GetCurrent();
418 int nDaughters = part -> getNDaughters();
420 B2FATAL(
"You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters");
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();
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();
433 if (daughter2Charge > daughter1Charge)
434 Arm_alpha = (daughter2Ql - daughter1Ql) / (daughter2Ql + daughter1Ql);
436 Arm_alpha = (daughter1Ql - daughter2Ql) / (daughter1Ql + daughter2Ql);
441 double ArmenterosDaughter1Qt(
const Particle* part)
443 const auto& frame = ReferenceFrame::GetCurrent();
444 int nDaughters = part -> getNDaughters();
446 B2FATAL(
"You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters.");
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);
456 double ArmenterosDaughter2Qt(
const Particle* part)
458 const auto& frame = ReferenceFrame::GetCurrent();
459 int nDaughters = part -> getNDaughters();
461 B2FATAL(
"You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters.");
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);
474 double particleMass(
const Particle* part)
476 return part->getMass();
479 double particleDMass(
const Particle* part)
481 return part->getMass() - part->getPDGMass();
484 double particleInvariantMassFromDaughters(
const Particle* part)
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();
494 return part->getMass();
498 double particleInvariantMassFromDaughtersDisplaced(
const Particle* part)
501 if (part->getParticleSource() != Particle::EParticleSourceObject::c_V0
502 && vertex.Perp() < 0.5)
return particleInvariantMassFromDaughters(part);
504 const std::vector<Particle*> daughters = part->getDaughters();
505 if (daughters.size() == 0)
return particleInvariantMassFromDaughters(part);
507 const double bField = BFieldManager::getFieldInTesla(vertex).Z();
508 ROOT::Math::PxPyPzMVector sum;
509 for (
auto daughter : daughters) {
510 const TrackFitResult* tfr = daughter->getTrackFitResult();
512 sum += daughter->get4Vector();
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);
527 double particleInvariantMassLambda(
const Particle* part)
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());
541 return sqrt((E1 + E2) * (E1 + E2) - dtsum.P() * dtsum.P());
544 return part->getMass();
548 double particleInvariantMassError(
const Particle* part)
550 float invMass = part->getMass();
551 TMatrixFSym covarianceMatrix = part->getMomentumErrorMatrix();
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;
559 double result = jacobian * (covarianceMatrix * jacobian);
562 return std::numeric_limits<double>::quiet_NaN();
564 return TMath::Sqrt(result);
567 double particleInvariantMassSignificance(
const Particle* part)
569 return particleDMass(part) / particleInvariantMassError(part);
572 double particleMassSquared(
const Particle* part)
574 ROOT::Math::PxPyPzEVector p4 = part->get4Vector();
578 double b2bTheta(
const Particle* part)
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();
587 double b2bPhi(
const Particle* part)
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;
596 double b2bClusterTheta(
const Particle* part)
599 const ECLCluster* cluster = part->getECLCluster();
600 if (!cluster)
return std::numeric_limits<float>::quiet_NaN();
601 const ECLCluster::EHypothesisBit clusterHypothesis = part->getECLClusterEHypothesisBit();
605 ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, clusterHypothesis);
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();
615 double b2bClusterPhi(
const Particle* part)
618 const ECLCluster* cluster = part->getECLCluster();
619 if (!cluster)
return std::numeric_limits<float>::quiet_NaN();
620 const ECLCluster::EHypothesisBit clusterHypothesis = part->getECLClusterEHypothesisBit();
624 ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, clusterHypothesis);
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;
637 double particleQ(
const Particle* part)
639 float m = part->getMass();
640 for (
unsigned i = 0; i < part->getNDaughters(); i++) {
641 const Particle* child = part->getDaughter(i);
643 m -= child->getMass();
648 double particleDQ(
const Particle* part)
650 float m = part->getMass() - part->getPDGMass();
651 for (
unsigned i = 0; i < part->getNDaughters(); i++) {
652 const Particle* child = part->getDaughter(i);
654 m -= (child->getMass() - child->getPDGMass());
661 double particleMbc(
const Particle* part)
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();
671 double particleDeltaE(
const Particle* part)
674 ROOT::Math::PxPyPzEVector vec = T.rotateLabToCms() * part->get4Vector();
675 return vec.E() - T.getCMSEnergy() / 2;
681 void printParticleInternal(
const Particle* p,
int depth)
684 for (
int i = 0; i < depth; i++) {
687 s << p->getPDGCode();
688 const MCParticle* mcp = p->getMCParticle();
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();
695 s <<
" (no MC match)";
697 s <<
", mdst-source " << p->getMdstSource();
699 for (
const auto* daughter : p->getDaughters()) {
700 printParticleInternal(daughter, depth + 1);
704 bool printParticle(
const Particle* p)
706 printParticleInternal(p, 0);
711 double particleMCMomentumTransfer2(
const Particle* part)
717 return std::numeric_limits<double>::quiet_NaN();
719 ROOT::Math::PxPyPzEVector pB = mcB->get4Vector();
721 std::vector<MCParticle*> mcDaug = mcB->getDaughters();
724 return std::numeric_limits<double>::quiet_NaN();
728 ROOT::Math::PxPyPzEVector pX;
730 for (
auto mcTemp : mcDaug) {
731 if (abs(mcTemp->getPDG()) <= 16)
734 pX += mcTemp->get4Vector();
737 ROOT::Math::PxPyPzEVector q = pB - pX;
743 double recoilPx(
const Particle* particle)
748 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
751 const auto& frame = ReferenceFrame::GetCurrent();
752 return frame.getMomentum(pIN - particle->get4Vector()).Px();
755 double recoilPy(
const Particle* particle)
760 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
763 const auto& frame = ReferenceFrame::GetCurrent();
764 return frame.getMomentum(pIN - particle->get4Vector()).Py();
767 double recoilPz(
const Particle* particle)
772 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
775 const auto& frame = ReferenceFrame::GetCurrent();
776 return frame.getMomentum(pIN - particle->get4Vector()).Pz();
779 double recoilMomentum(
const Particle* particle)
784 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
787 const auto& frame = ReferenceFrame::GetCurrent();
788 return frame.getMomentum(pIN - particle->get4Vector()).P();
791 double recoilMomentumTheta(
const Particle* particle)
796 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
799 const auto& frame = ReferenceFrame::GetCurrent();
800 return frame.getMomentum(pIN - particle->get4Vector()).Theta();
803 double recoilMomentumPhi(
const Particle* particle)
808 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
811 const auto& frame = ReferenceFrame::GetCurrent();
812 return frame.getMomentum(pIN - particle->get4Vector()).Phi();
815 double recoilEnergy(
const Particle* particle)
820 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
823 const auto& frame = ReferenceFrame::GetCurrent();
824 return frame.getMomentum(pIN - particle->get4Vector()).E();
827 double recoilMass(
const Particle* particle)
832 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
835 const auto& frame = ReferenceFrame::GetCurrent();
836 return frame.getMomentum(pIN - particle->get4Vector()).M();
839 double recoilMassSquared(
const Particle* particle)
844 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
847 const auto& frame = ReferenceFrame::GetCurrent();
848 return frame.getMomentum(pIN - particle->get4Vector()).M2();
851 double m2RecoilSignalSide(
const Particle* part)
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();
862 double recoilMCDecayType(
const Particle* particle)
864 auto* mcp = particle->getMCParticle();
867 return std::numeric_limits<double>::quiet_NaN();
869 MCParticle* mcMother = mcp->getMother();
872 return std::numeric_limits<double>::quiet_NaN();
874 std::vector<MCParticle*> daughters = mcMother->getDaughters();
876 if (daughters.size() != 2)
877 return std::numeric_limits<double>::quiet_NaN();
879 MCParticle* recoilMC =
nullptr;
880 if (daughters[0]->getArrayIndex() == mcp->getArrayIndex())
881 recoilMC = daughters[1];
883 recoilMC = daughters[0];
885 if (!recoilMC->hasStatus(MCParticle::c_PrimaryParticle))
886 return std::numeric_limits<double>::quiet_NaN();
889 checkMCParticleDecay(recoilMC, decayType,
false);
892 checkMCParticleDecay(recoilMC, decayType,
true);
897 void checkMCParticleDecay(MCParticle* mcp,
int& decayType,
bool recursive)
899 int nHadronicParticles = 0;
900 int nPrimaryParticleDaughters = 0;
901 std::vector<MCParticle*> daughters = mcp->getDaughters();
904 for (
auto& daughter : daughters) {
905 if (!daughter->hasStatus(MCParticle::c_PrimaryParticle))
908 nPrimaryParticleDaughters++;
909 if (abs(daughter->getPDG()) > Const::photon.getPDGCode())
910 nHadronicParticles++;
913 if (nPrimaryParticleDaughters > 1) {
914 for (
auto& daughter : daughters) {
915 if (!daughter->hasStatus(MCParticle::c_PrimaryParticle))
918 if (abs(daughter->getPDG()) == 12 or abs(daughter->getPDG()) == 14 or abs(daughter->getPDG()) == 16) {
920 if (nHadronicParticles == 0) {
934 checkMCParticleDecay(daughter, decayType, recursive);
939 int nRemainingTracksInEvent(
const Particle* particle)
942 StoreArray<Track> tracks;
943 int event_tracks = tracks.getEntries();
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())
953 return event_tracks - par_tracks;
956 double trackMatchType(
const Particle* particle)
959 double result = std::numeric_limits<double>::quiet_NaN();
961 const ECLCluster* cluster = particle->getECLCluster();
965 if (cluster->isTrack()) {
974 bool False(
const Particle*)
979 bool True(
const Particle*)
984 double infinity(
const Particle*)
986 double inf = std::numeric_limits<double>::infinity();
990 double random(
const Particle*)
992 return gRandom->Uniform(0, 1);
995 double eventRandom(
const Particle*)
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);
1004 double value = gRandom->Uniform(0, 1);
1005 eventExtraInfo->addExtraInfo(key, value);
1010 VARIABLE_GROUP(
"Kinematics");
1011 REGISTER_VARIABLE(
"p", particleP,
"momentum magnitude",
"GeV/c");
1012 REGISTER_VARIABLE(
"E", particleE,
"energy",
"GeV");
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
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");
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");
1055 REGISTER_VARIABLE(
"ImpactXY" , ImpactXY ,
"The impact parameter of the given particle in the xy plane",
"cm");
1057 REGISTER_VARIABLE(
"M", particleMass, R
"DOC(
1058 The particle's mass.
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.
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.
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`");
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`");
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`)");
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");
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`");
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.",
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.",
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");
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(
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
1141 Use better variables like `trackNECLClusters`, `clusterTrackMatch`, and `nECLClusterTrackMatches`.)DOC");
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.");
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.");
DataType Perp() const
The transverse component (R in cylindrical coordinate system).
const MCParticle * getMCParticle() const
Returns the pointer to the MCParticle object that was used to create this Particle (ParticleType == c...
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.
B2Vector3< double > B2Vector3D
typedef for common usage with double
Abstract base class for different kinds of events.