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/ParticleList.h>
27#include <framework/dataobjects/EventExtraInfo.h>
28#include <analysis/dataobjects/EventShapeContainer.h>
30#include <mdst/dataobjects/MCParticle.h>
31#include <mdst/dataobjects/Track.h>
32#include <mdst/dataobjects/ECLCluster.h>
34#include <mdst/dbobjects/BeamSpot.h>
37#include <framework/logging/Logger.h>
38#include <framework/geometry/BFieldManager.h>
39#include <framework/gearbox/Const.h>
40#include <framework/utilities/Conversion.h>
42#include <Math/Vector4D.h>
43#include <Math/VectorUtil.h>
48#include <boost/algorithm/string.hpp>
62 double particleP(
const Particle* part)
65 return frame.getMomentum(part).P();
68 double particleE(
const Particle* part)
71 return frame.getMomentum(part).E();
74 double particleClusterEUncertainty(
const Particle* part)
76 const ECLCluster* cluster = part->getECLCluster();
79 const auto EPhiThetaCov = clutls.GetCovarianceMatrix3x3FromCluster(cluster);
80 return sqrt(fabs(EPhiThetaCov[0][0]));
85 double particlePx(
const Particle* part)
88 return frame.getMomentum(part).Px();
91 double particlePy(
const Particle* part)
94 return frame.getMomentum(part).Py();
97 double particlePz(
const Particle* part)
100 return frame.getMomentum(part).Pz();
103 double particlePt(
const Particle* part)
106 return frame.getMomentum(part).Pt();
109 double covMatrixElement(
const Particle* part,
const std::vector<double>& element)
111 int elementI = int(std::lround(element[0]));
112 int elementJ = int(std::lround(element[1]));
114 if (elementI < 0 || elementI > 6) {
115 B2WARNING(
"Requested particle's momentumVertex covariance matrix element is out of boundaries [0 - 6]:" << LogVar(
"i", elementI));
118 if (elementJ < 0 || elementJ > 6) {
119 B2WARNING(
"Requested particle's momentumVertex covariance matrix element is out of boundaries [0 - 6]:" << LogVar(
"j", elementJ));
123 return part->getMomentumVertexErrorMatrix()(elementI, elementJ);
126 double particleEUncertainty(
const Particle* part)
130 double errorSquared = frame.getMomentumErrorMatrix(part)(3, 3);
132 if (errorSquared >= 0.0)
133 return sqrt(errorSquared);
138 double particlePErr(
const Particle* part)
140 TMatrixD jacobianRot(3, 3);
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);
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;
160 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2,
" ").Similarity(jacobianRot)(0, 0);
162 if (errorSquared >= 0.0)
163 return sqrt(errorSquared);
168 double particlePxErr(
const Particle* part)
172 double errorSquared = frame.getMomentumErrorMatrix(part)(0, 0);
174 if (errorSquared >= 0.0)
175 return sqrt(errorSquared);
180 double particlePyErr(
const Particle* part)
183 double errorSquared = frame.getMomentumErrorMatrix(part)(1, 1);
185 if (errorSquared >= 0.0)
186 return sqrt(errorSquared);
191 double particlePzErr(
const Particle* part)
194 double errorSquared = frame.getMomentumErrorMatrix(part)(2, 2);
196 if (errorSquared >= 0.0)
197 return sqrt(errorSquared);
202 double particlePtErr(
const Particle* part)
204 TMatrixD jacobianRot(3, 3);
207 double px = particlePx(part);
208 double py = particlePy(part);
209 double pt = particlePt(part);
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;
218 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2,
" ").Similarity(jacobianRot)(0, 0);
220 if (errorSquared >= 0.0)
221 return sqrt(errorSquared);
226 double momentumDeviationChi2(
const Particle* part)
231 if (part->getPValue() < 0.0)
235 const MCParticle* mcp = part->getMCParticle();
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);
247 double particleTheta(
const Particle* part)
250 return frame.getMomentum(part).Theta();
253 double particleThetaErr(
const Particle* part)
255 TMatrixD jacobianRot(3, 3);
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);
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;
274 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2,
" ").Similarity(jacobianRot)(1, 1);
276 if (errorSquared >= 0.0)
277 return sqrt(errorSquared);
282 double particleCosTheta(
const Particle* part)
285 return cos(frame.getMomentum(part).Theta());
288 double particleCosThetaErr(
const Particle* part)
290 return fabs(particleThetaErr(part) * sin(particleTheta(part)));
293 double particlePhi(
const Particle* part)
296 return frame.getMomentum(part).Phi();
299 double particlePhiErr(
const Particle* part)
301 TMatrixD jacobianRot(3, 3);
304 double px = particlePx(part);
305 double py = particlePy(part);
306 double pt = particlePt(part);
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;
315 double errorSquared = frame.getMomentumErrorMatrix(part).GetSub(0, 2, 0, 2,
" ").Similarity(jacobianRot)(1, 1);
317 if (errorSquared >= 0.0)
318 return sqrt(errorSquared);
323 double particleXp(
const Particle* part)
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);
333 int particlePDGCode(
const Particle* part)
335 return part->getPDGCode();
338 double cosAngleBetweenMomentumAndVertexVectorInXYPlane(
const Particle* part)
340 static DBObjPtr<BeamSpot> beamSpotDB;
341 if (!beamSpotDB.isValid())
344 double px = part->getPx();
345 double py = part->getPy();
347 double xV = part->getX();
348 double yV = part->getY();
350 double xIP = (beamSpotDB->getIPPosition()).X();
351 double yIP = (beamSpotDB->getIPPosition()).Y();
356 double cosangle = (px * x + py * y) / (
sqrt(px * px + py * py) *
sqrt(x * x + y * y));
360 double cosAngleBetweenMomentumAndVertexVector(
const Particle* part)
362 static DBObjPtr<BeamSpot> beamSpotDB;
363 if (!beamSpotDB.isValid())
365 return ROOT::Math::VectorUtil::CosTheta(part->getVertex() - beamSpotDB->getIPPosition(), part->getMomentum());
368 double cosThetaBetweenParticleAndNominalB(
const Particle* part)
371 int particlePDG = abs(part->getPDGCode());
372 if (particlePDG != 511 and particlePDG != 521)
373 B2FATAL(
"The Variables cosThetaBetweenParticleAndNominalB is only meant to be used on B mesons!");
376 double e_Beam = T.getCMSEnergy() / 2.0;
377 double m_B = part->getPDGMass();
379 if (e_Beam * e_Beam - m_B * m_B < 0) {
380 e_Beam = 1.0579400E+1 / 2.0;
382 double p_B = std::sqrt(e_Beam * e_Beam - m_B * m_B);
384 ROOT::Math::PxPyPzEVector p = T.rotateLabToCms() * part->get4Vector();
389 double theta_BY = (2 * e_Beam * e_d - m_B * m_B - m_d * m_d)
394 double cosToThrustOfEvent(
const Particle* part)
396 StoreObjPtr<EventShapeContainer> evtShape;
398 B2WARNING(
"Cannot find thrust of event information, did you forget to load the event shape calculation?");
402 ROOT::Math::XYZVector th = evtShape->getThrustAxis();
403 ROOT::Math::PxPyPzEVector particleMomentum = T.rotateLabToCms() * part->get4Vector();
404 return ROOT::Math::VectorUtil::CosTheta(th, particleMomentum);
407 double ImpactXY(
const Particle* particle)
409 static DBObjPtr<BeamSpot> beamSpotDB;
410 if (!beamSpotDB.isValid())
413 ROOT::Math::XYZVector mom = particle->getMomentum();
415 ROOT::Math::XYZVector r = particle->getVertex() - beamSpotDB->getIPPosition();
420 double T = TMath::Sqrt(mom.Perp2() - 2.0 * curvature.Dot(r.Cross(mom)) + curvature.Mag2() * r.Perp2());
422 return TMath::Abs((-2 * r.Cross(mom).Z() + curvature.R() * r.Perp2()) / (T + mom.Rho()));
425 double ArmenterosLongitudinalMomentumAsymmetry(
const Particle* part)
428 int nDaughters = part -> getNDaughters();
430 B2FATAL(
"You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters");
432 const auto& daughters = part -> getDaughters();
433 ROOT::Math::XYZVector motherMomentum = frame.getMomentum(part).Vect();
434 ROOT::Math::XYZVector daughter1Momentum = frame.getMomentum(daughters[0]).Vect();
435 ROOT::Math::XYZVector daughter2Momentum = frame.getMomentum(daughters[1]).Vect();
437 int daughter1Charge = daughters[0] -> getCharge();
438 int daughter2Charge = daughters[1] -> getCharge();
439 double daughter1Ql = daughter1Momentum.Dot(motherMomentum) / motherMomentum.R();
440 double daughter2Ql = daughter2Momentum.Dot(motherMomentum) / motherMomentum.R();
443 if (daughter2Charge > daughter1Charge)
444 Arm_alpha = (daughter2Ql - daughter1Ql) / (daughter2Ql + daughter1Ql);
446 Arm_alpha = (daughter1Ql - daughter2Ql) / (daughter1Ql + daughter2Ql);
451 double ArmenterosDaughter1Qt(
const Particle* part)
454 int nDaughters = part -> getNDaughters();
456 B2FATAL(
"You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters.");
458 const auto& daughters = part -> getDaughters();
459 ROOT::Math::XYZVector motherMomentum = frame.getMomentum(part).Vect().Unit();
460 ROOT::Math::XYZVector daughter1Momentum = frame.getMomentum(daughters[0]).Vect();
461 double qt = std::sqrt(daughter1Momentum.Mag2() - daughter1Momentum.Dot(motherMomentum) * daughter1Momentum.Dot(motherMomentum));
466 double ArmenterosDaughter2Qt(
const Particle* part)
469 int nDaughters = part -> getNDaughters();
471 B2FATAL(
"You are trying to use an Armenteros variable. The mother particle is required to have exactly two daughters.");
473 const auto& daughters = part -> getDaughters();
474 ROOT::Math::XYZVector motherMomentum = frame.getMomentum(part).Vect().Unit();
475 ROOT::Math::XYZVector daughter2Momentum = frame.getMomentum(daughters[1]).Vect();
476 double qt = std::sqrt(daughter2Momentum.Mag2() - daughter2Momentum.Dot(motherMomentum) * daughter2Momentum.Dot(motherMomentum));
484 double particleMass(
const Particle* part)
486 return part->getMass();
489 double particleDMass(
const Particle* part)
491 return part->getMass() - part->getPDGMass();
494 double particleInvariantMassFromDaughters(
const Particle* part)
496 const std::vector<Particle*> daughters = part->getDaughters();
497 if (daughters.size() > 0) {
498 ROOT::Math::PxPyPzEVector sum;
499 for (
auto daughter : daughters)
500 sum += daughter->get4Vector();
504 return part->getMass();
508 double particleInvariantMassFromDaughtersDisplaced(
const Particle* part)
510 ROOT::Math::XYZVector vertex = part->getVertex();
511 if (part->getParticleSource() != Particle::EParticleSourceObject::c_V0
512 && vertex.Rho() < 0.5)
return particleInvariantMassFromDaughters(part);
514 const std::vector<Particle*> daughters = part->getDaughters();
515 if (daughters.size() == 0)
return particleInvariantMassFromDaughters(part);
518 ROOT::Math::PxPyPzMVector sum;
519 for (
auto daughter : daughters) {
520 const TrackFitResult* tfr = daughter->getTrackFitResult();
522 sum += daughter->get4Vector();
525 Helix helix = tfr->getHelix();
526 helix.passiveMoveBy(vertex);
527 double scalingFactor = daughter->getEffectiveMomentumScale();
528 double momX = scalingFactor * helix.getMomentumX(bField);
529 double momY = scalingFactor * helix.getMomentumY(bField);
530 double momZ = scalingFactor * helix.getMomentumZ(bField);
531 float mPDG = daughter->getPDGMass();
532 sum += ROOT::Math::PxPyPzMVector(momX, momY, momZ, mPDG);
537 double particleInvariantMassLambda(
const Particle* part)
539 const std::vector<Particle*> daughters = part->getDaughters();
540 if (daughters.size() == 2) {
541 ROOT::Math::PxPyPzEVector dt1;
542 ROOT::Math::PxPyPzEVector dt2;
543 ROOT::Math::PxPyPzEVector dtsum;
546 dt1 = daughters[0]->get4Vector();
547 dt2 = daughters[1]->get4Vector();
548 double E1 = hypot(mpi, dt1.P());
549 double E2 = hypot(mpr, dt2.P());
551 return sqrt((E1 + E2) * (E1 + E2) - dtsum.P() * dtsum.P());
554 return part->getMass();
558 double particleInvariantMassError(
const Particle* part)
560 float invMass = part->getMass();
561 TMatrixFSym covarianceMatrix = part->getMomentumErrorMatrix();
563 TVectorF jacobian(Particle::c_DimMomentum);
564 jacobian[0] = -1.0 * part->getPx() / invMass;
565 jacobian[1] = -1.0 * part->getPy() / invMass;
566 jacobian[2] = -1.0 * part->getPz() / invMass;
567 jacobian[3] = 1.0 * part->getEnergy() / invMass;
569 double result = jacobian * (covarianceMatrix * jacobian);
574 return TMath::Sqrt(result);
577 double particleInvariantMassSignificance(
const Particle* part)
579 return particleDMass(part) / particleInvariantMassError(part);
582 double particleMassSquared(
const Particle* part)
584 ROOT::Math::PxPyPzEVector p4 = part->get4Vector();
588 double b2bTheta(
const Particle* part)
591 ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * part->get4Vector();
592 ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
593 ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
594 return b2blab.Theta();
597 double b2bPhi(
const Particle* part)
600 ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * part->get4Vector();
601 ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
602 ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
606 double b2bClusterTheta(
const Particle* part)
609 const ECLCluster* cluster = part->getECLCluster();
615 ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, clusterHypothesis);
619 ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * p4Cluster;
620 ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
621 ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
622 return b2blab.Theta();
625 double b2bClusterPhi(
const Particle* part)
628 const ECLCluster* cluster = part->getECLCluster();
634 ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, clusterHypothesis);
638 ROOT::Math::PxPyPzEVector pcms = T.rotateLabToCms() * p4Cluster;
639 ROOT::Math::PxPyPzEVector b2bcms(-pcms.Px(), -pcms.Py(), -pcms.Pz(), pcms.E());
640 ROOT::Math::PxPyPzEVector b2blab = T.rotateCmsToLab() * b2bcms;
647 double particleQ(
const Particle* part)
649 float m = part->getMass();
650 for (
unsigned i = 0; i < part->getNDaughters(); i++) {
651 const Particle* child = part->getDaughter(i);
653 m -= child->getMass();
658 double particleDQ(
const Particle* part)
660 float m = part->getMass() - part->getPDGMass();
661 for (
unsigned i = 0; i < part->getNDaughters(); i++) {
662 const Particle* child = part->getDaughter(i);
664 m -= (child->getMass() - child->getPDGMass());
671 double particleMbc(
const Particle* part)
674 ROOT::Math::PxPyPzEVector vec = T.rotateLabToCms() * part->get4Vector();
675 double E = T.getCMSEnergy() / 2;
676 double m2 =
E *
E - vec.P2();
677 double mbc = m2 >= 0 ?
sqrt(m2) : Const::doubleNaN;
681 double particleDeltaE(
const Particle* part)
684 ROOT::Math::PxPyPzEVector vec = T.rotateLabToCms() * part->get4Vector();
685 return vec.E() - T.getCMSEnergy() / 2;
691 void printParticleInternal(
const Particle* p,
int depth)
694 for (
int i = 0; i < depth; i++) {
697 s << p->getPDGCode();
698 const MCParticle* mcp = p->getMCParticle();
701 s <<
" -> MC: " << mcp->getPDG() <<
", mcErrors: " << flags <<
" ("
703 s <<
", mc-index " << mcp->getIndex();
705 s <<
" (no MC match)";
707 s <<
", mdst-source " << p->getMdstSource();
709 for (
const auto* daughter : p->getDaughters()) {
710 printParticleInternal(daughter, depth + 1);
714 bool printParticle(
const Particle* p)
716 printParticleInternal(p, 0);
721 double particleMCMomentumTransfer2(
const Particle* part)
724 const MCParticle* mcB = part->getMCParticle();
729 ROOT::Math::PxPyPzEVector pB = mcB->get4Vector();
731 std::vector<MCParticle*> mcDaug = mcB->getDaughters();
738 ROOT::Math::PxPyPzEVector pX;
740 for (
auto mcTemp : mcDaug) {
741 if (abs(mcTemp->getPDG()) <= 16)
744 pX += mcTemp->get4Vector();
747 ROOT::Math::PxPyPzEVector q = pB - pX;
753 double recoilPx(
const Particle* particle)
758 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
762 return frame.getMomentum(pIN - particle->get4Vector()).Px();
765 double recoilPy(
const Particle* particle)
770 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
774 return frame.getMomentum(pIN - particle->get4Vector()).Py();
777 double recoilPz(
const Particle* particle)
782 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
786 return frame.getMomentum(pIN - particle->get4Vector()).Pz();
789 double recoilMomentum(
const Particle* particle)
794 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
798 return frame.getMomentum(pIN - particle->get4Vector()).P();
801 double recoilMomentumTheta(
const Particle* particle)
806 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
810 return frame.getMomentum(pIN - particle->get4Vector()).Theta();
813 double recoilMomentumPhi(
const Particle* particle)
818 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
822 return frame.getMomentum(pIN - particle->get4Vector()).Phi();
825 double recoilEnergy(
const Particle* particle)
830 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
834 return frame.getMomentum(pIN - particle->get4Vector()).E();
837 double recoilMass(
const Particle* particle)
842 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
846 return frame.getMomentum(pIN - particle->get4Vector()).M();
849 double recoilMassSquared(
const Particle* particle)
854 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
858 return frame.getMomentum(pIN - particle->get4Vector()).M2();
861 double m2RecoilSignalSide(
const Particle* part)
864 double beamEnergy = T.getCMSEnergy() / 2.;
866 ROOT::Math::PxPyPzEVector tagVec = T.rotateLabToCms() * part->getDaughter(0)->get4Vector();
867 ROOT::Math::PxPyPzEVector sigVec = T.rotateLabToCms() * part->getDaughter(1)->get4Vector();
868 tagVec.SetE(-beamEnergy);
869 return (-tagVec - sigVec).M2();
872 double recoilMassDiff(
const Particle* particle,
const std::vector<double>& daughters)
875 if (daughters.size() != 1) B2FATAL(
"recoilMassDiff: currently only one daughter is supported");
876 if (daughters[0] >= particle->getNDaughters()) {
877 B2WARNING(
"recoilMassDiff: daughter index out of range");
882 ROOT::Math::PxPyPzEVector pIN = T.getBeamFourMomentum();
885 ROOT::Math::PxPyPzEVector particle4Mom = particle->get4Vector();
886 double mRecoil = frame.getMomentum(pIN - particle4Mom).M();
887 double mRecoil_wDaughter = frame.getMomentum(pIN + particle->getDaughter(daughters[0])->get4Vector() - particle4Mom).M();
888 return mRecoil_wDaughter - mRecoil;
891 double recoilMCDecayType(
const Particle* particle)
893 auto* mcp = particle->getMCParticle();
898 MCParticle* mcMother = mcp->getMother();
903 std::vector<MCParticle*> daughters = mcMother->getDaughters();
905 if (daughters.size() != 2)
908 MCParticle* recoilMC =
nullptr;
909 if (daughters[0]->getArrayIndex() == mcp->getArrayIndex())
910 recoilMC = daughters[1];
912 recoilMC = daughters[0];
918 checkMCParticleDecay(recoilMC, decayType,
false);
921 checkMCParticleDecay(recoilMC, decayType,
true);
926 void checkMCParticleDecay(MCParticle* mcp,
int& decayType,
bool recursive)
928 int nHadronicParticles = 0;
929 int nPrimaryParticleDaughters = 0;
930 std::vector<MCParticle*> daughters = mcp->getDaughters();
933 for (
auto& daughter : daughters) {
937 nPrimaryParticleDaughters++;
939 nHadronicParticles++;
942 if (nPrimaryParticleDaughters > 1) {
943 for (
auto& daughter : daughters) {
947 if (abs(daughter->getPDG()) == 12 or abs(daughter->getPDG()) == 14 or abs(daughter->getPDG()) == 16) {
949 if (nHadronicParticles == 0) {
963 checkMCParticleDecay(daughter, decayType, recursive);
968 int nRemainingTracksInEvent(
const Particle* particle)
971 StoreArray<Track> tracks;
972 int event_tracks = tracks.getEntries();
975 const auto& daughters = particle->getFinalStateDaughters();
976 for (
const auto& daughter : daughters) {
977 int pdg = abs(daughter->getPDGCode());
982 return event_tracks - par_tracks;
985 bool False(
const Particle*)
990 bool True(
const Particle*)
995 double infinity(
const Particle*)
997 double inf = std::numeric_limits<double>::infinity();
1001 double random(
const Particle*)
1003 return gRandom->Uniform(0, 1);
1006 double eventRandom(
const Particle*)
1008 std::string key =
"__eventRandom";
1009 StoreObjPtr<EventExtraInfo> eventExtraInfo;
1010 if (not eventExtraInfo.isValid())
1011 eventExtraInfo.create();
1012 if (eventExtraInfo->hasExtraInfo(key)) {
1013 return eventExtraInfo->getExtraInfo(key);
1015 double value = gRandom->Uniform(0, 1);
1016 eventExtraInfo->addExtraInfo(key, value);
1023 if (arguments.size() != 3 && arguments.size() != 4) {
1024 B2ERROR(
"Wrong number of arguments (3 or 4 required) for meta variable minET2ETDist");
1027 bool useHighestProbMassForExt(
true);
1028 if (arguments.size() == 4) {
1031 }
catch (std::invalid_argument& e) {
1032 B2ERROR(
"Fourth (optional) argument of minET2ETDist must be an integer flag.");
1037 std::string detName = arguments[0];
1038 std::string detLayer = arguments[1];
1039 std::string referenceListName = arguments[2];
1040 std::string extraSuffix = (useHighestProbMassForExt) ?
"__useHighestProbMassForExt" :
"";
1042 std::string extraInfo =
"distToClosestTrkAt" + detName + detLayer +
"_VS_" + referenceListName + extraSuffix;
1044 auto func = [ = ](
const Particle * part) ->
double {
1045 auto dist = (part->hasExtraInfo(extraInfo)) ? part->getExtraInfo(extraInfo) :
Const::doubleNaN;
1056 if (arguments.size() != 4) {
1057 B2ERROR(
"Wrong number of arguments (4 required) for meta variable minET2ETDistVar");
1061 std::string detName = arguments[0];
1062 std::string detLayer = arguments[1];
1063 std::string referenceListName = arguments[2];
1064 std::string variableName = arguments[3];
1066 std::string extraInfo =
"idxOfClosestPartAt" + detName + detLayer +
"In_" + referenceListName;
1068 auto func = [ = ](
const Particle * part) ->
double {
1070 StoreObjPtr<ParticleList> refPartList(referenceListName);
1071 if (!refPartList.isValid())
1073 B2FATAL(
"Invalid Listname " << referenceListName <<
" given to minET2ETDistVar!");
1076 if (!part->hasExtraInfo(extraInfo))
1082 auto refPart = refPartList->getParticleWithMdstSource(part->getExtraInfo(extraInfo));
1084 return std::get<double>(var->function(refPart));
1094 if (arguments.size() < 3) {
1095 B2ERROR(
"Wrong number of arguments (at least 3 required) for meta variable minET2ETIsoScore");
1099 std::string referenceListName = arguments[0];
1100 bool useHighestProbMassForExt;
1103 }
catch (std::invalid_argument& e) {
1104 B2ERROR(
"Second argument must be an integer flag.");
1107 std::string extraSuffix = (useHighestProbMassForExt) ?
"__useHighestProbMassForExt" :
"";
1109 std::vector<std::string> detectorNames(arguments.begin() + 2, arguments.end());
1111 std::string detNamesConcat(
"");
1112 for (
auto& detName : detectorNames) {
1113 boost::to_upper(detName);
1114 detNamesConcat +=
"_" + detName;
1117 std::string extraInfo =
"trkIsoScore" + detNamesConcat +
"_VS_" + referenceListName + extraSuffix;
1119 auto func = [ = ](
const Particle * part) ->
double {
1121 StoreObjPtr<ParticleList> refPartList(referenceListName);
1122 if (!refPartList.isValid())
1124 B2FATAL(
"Invalid Listname " << referenceListName <<
" given to minET2ETIsoScore!");
1127 if (!part->hasExtraInfo(extraInfo))
1131 auto scoreDet = part->getExtraInfo(extraInfo);
1132 if (std::isnan(scoreDet))
1145 Manager::FunctionPtr particleExtTrkIsoScoreVarAsWeightedAvg(
const std::vector<std::string>& arguments)
1148 if (arguments.size() < 3) {
1149 B2ERROR(
"Wrong number of arguments (at least 3 required) for meta variable minET2ETIsoScoreAsWeightedAvg");
1153 std::string referenceListName = arguments[0];
1154 bool useHighestProbMassForExt;
1157 }
catch (std::invalid_argument& e) {
1158 B2ERROR(
"Second argument must be an integer flag.");
1161 std::string extraSuffix = (useHighestProbMassForExt) ?
"__useHighestProbMassForExt" :
"";
1163 std::vector<std::string> detectorNames(arguments.begin() + 2, arguments.end());
1165 std::string detNamesConcat(
"");
1166 for (
auto& detName : detectorNames) {
1167 boost::to_upper(detName);
1168 detNamesConcat +=
"_" + detName;
1171 std::string extraInfo =
"trkIsoScoreAsWeightedAvg" + detNamesConcat +
"_VS_" + referenceListName + extraSuffix;
1173 auto func = [ = ](
const Particle * part) ->
double {
1175 StoreObjPtr<ParticleList> refPartList(referenceListName);
1176 if (!refPartList.isValid())
1178 B2FATAL(
"Invalid Listname " << referenceListName <<
" given to minET2ETIsoScoreAsWeightedAvg!");
1181 if (!part->hasExtraInfo(extraInfo))
1185 auto scoreDet = part->getExtraInfo(extraInfo);
1186 if (std::isnan(scoreDet))
1198 VARIABLE_GROUP(
"Kinematics");
1199 REGISTER_VARIABLE(
"p", particleP,
"momentum magnitude\n\n",
"GeV/c");
1200 REGISTER_VARIABLE(
"E", particleE,
"energy\n\n",
"GeV");
1202 REGISTER_VARIABLE(
"E_uncertainty", particleEUncertainty, R
"DOC(
1203 energy uncertainty (:math:`\sqrt{\sigma^2}`)
1206 REGISTER_VARIABLE(
"ECLClusterE_uncertainty", particleClusterEUncertainty,
1207 "energy uncertainty as given by the underlying ECL cluster\n\n",
"GeV");
1208 REGISTER_VARIABLE(
"px", particlePx,
"momentum component x\n\n",
"GeV/c");
1209 REGISTER_VARIABLE(
"py", particlePy,
"momentum component y\n\n",
"GeV/c");
1210 REGISTER_VARIABLE(
"pz", particlePz,
"momentum component z\n\n",
"GeV/c");
1211 REGISTER_VARIABLE(
"pt", particlePt,
"transverse momentum\n\n",
"GeV/c");
1212 REGISTER_VARIABLE(
"xp", particleXp,
1213 "scaled momentum: the momentum of the particle in the CMS as a fraction of its maximum available momentum in the collision");
1214 REGISTER_VARIABLE(
"pErr", particlePErr,
"error of momentum magnitude\n\n",
"GeV/c");
1215 REGISTER_VARIABLE(
"pxErr", particlePxErr,
"error of momentum component x\n\n",
"GeV/c");
1216 REGISTER_VARIABLE(
"pyErr", particlePyErr,
"error of momentum component y\n\n",
"GeV/c");
1217 REGISTER_VARIABLE(
"pzErr", particlePzErr,
"error of momentum component z\n\n",
"GeV/c");
1218 REGISTER_VARIABLE(
"ptErr", particlePtErr,
"error of transverse momentum\n\n",
"GeV/c");
1219 REGISTER_VARIABLE(
"momVertCovM(i,j)", covMatrixElement,
1220 "returns the (i,j)-th element of the MomentumVertex Covariance Matrix (7x7).\n"
1221 "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");
1222 REGISTER_VARIABLE(
"momDevChi2", momentumDeviationChi2, R
"DOC(
1223momentum deviation :math:`\chi^2` value calculated as :math:`\chi^2 = \sum_i (p_i - mc(p_i))^2/\sigma(p_i)^2`,
1224where :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
1226 REGISTER_VARIABLE("theta", particleTheta,
"polar angle\n\n",
"rad");
1227 REGISTER_VARIABLE(
"thetaErr", particleThetaErr,
"error of polar angle\n\n",
"rad");
1228 REGISTER_VARIABLE(
"cosTheta", particleCosTheta,
"momentum cosine of polar angle");
1229 REGISTER_VARIABLE(
"cosThetaErr", particleCosThetaErr,
"error of momentum cosine of polar angle");
1230 REGISTER_VARIABLE(
"phi", particlePhi,
"momentum azimuthal angle\n\n",
"rad");
1231 REGISTER_VARIABLE(
"phiErr", particlePhiErr,
"error of momentum azimuthal angle\n\n",
"rad");
1232 REGISTER_VARIABLE(
"PDG", particlePDGCode,
"PDG code");
1233 REGISTER_VARIABLE(
"cosAngleBetweenMomentumAndVertexVectorInXYPlane",
1234 cosAngleBetweenMomentumAndVertexVectorInXYPlane,
1235 "cosine of the angle between momentum and vertex vector (vector connecting ip and fitted vertex) of this particle in xy-plane");
1236 REGISTER_VARIABLE(
"cosAngleBetweenMomentumAndVertexVector",
1237 cosAngleBetweenMomentumAndVertexVector,
1238 "cosine of the angle between momentum and vertex vector (vector connecting ip and fitted vertex) of this particle");
1239 REGISTER_VARIABLE(
"cosThetaBetweenParticleAndNominalB",
1240 cosThetaBetweenParticleAndNominalB,
1241 "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.");
1242 REGISTER_VARIABLE(
"cosToThrustOfEvent", cosToThrustOfEvent,
1243 "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");
1245 REGISTER_VARIABLE(
"ImpactXY" , ImpactXY ,
"The impact parameter of the given particle in the xy plane\n\n",
"cm");
1247 REGISTER_VARIABLE(
"M", particleMass, R
"DOC(
1250Note that this is context-dependent variable and can take different values depending on the situation. This should be the "best"
1251value possible with the information provided.
1253- If this particle is track- or cluster- based, then this is the value of the mass hypothesis.
1254- If this particle is an MC particle then this is the mass of that particle.
1255- If this particle is composite, then *initially* this takes the value of the invariant mass of the daughters.
1256- If this particle is composite and a *mass or vertex fit* has been performed then this may be updated by the fit.
1258* You will see a difference between this mass and the :b2:var:`InvM`.
1260)DOC", "GeV/:math:`\\text{c}^2`");
1261 REGISTER_VARIABLE(
"dM", particleDMass,
"mass minus nominal mass\n\n",
"GeV/:math:`\\text{c}^2`");
1262 REGISTER_VARIABLE(
"Q", particleQ,
"energy released in decay\n\n",
"GeV");
1263 REGISTER_VARIABLE(
"dQ", particleDQ,
":b2:var:`Q` minus nominal energy released in decay\n\n",
"GeV");
1264 REGISTER_VARIABLE(
"Mbc", particleMbc,
"beam constrained mass\n\n",
"GeV/:math:`\\text{c}^2`");
1265 REGISTER_VARIABLE(
"deltaE", particleDeltaE,
"difference between :b2:var:`E` and half the center of mass energy\n\n",
"GeV");
1266 REGISTER_VARIABLE(
"M2", particleMassSquared,
"The particle's mass squared.\n\n",
":math:`[\\text{GeV}/\\text{c}^2]^2`");
1268 REGISTER_VARIABLE(
"InvM", particleInvariantMassFromDaughtersDisplaced,
1269 "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"
1270 "If this particle has no daughters, defaults to :b2:var:`M`.\n\n",
"GeV/:math:`\\text{c}^2`");
1271 REGISTER_VARIABLE(
"InvMLambda", particleInvariantMassLambda,
1272 "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"
1273 "If the particle has not 2 daughters, it returns just the mass value.\n\n",
"GeV/:math:`\\text{c}^2`");
1275 REGISTER_VARIABLE(
"ErrM", particleInvariantMassError,
1276 "uncertainty of invariant mass\n\n",
"GeV/:math:`\\text{c}^2`");
1277 REGISTER_VARIABLE(
"SigM", particleInvariantMassSignificance,
1278 "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`)");
1280 REGISTER_VARIABLE(
"pxRecoil", recoilPx,
1281 "component x of 3-momentum recoiling against given Particle\n\n",
"GeV/c");
1282 REGISTER_VARIABLE(
"pyRecoil", recoilPy,
1283 "component y of 3-momentum recoiling against given Particle\n\n",
"GeV/c");
1284 REGISTER_VARIABLE(
"pzRecoil", recoilPz,
1285 "component z of 3-momentum recoiling against given Particle\n\n",
"GeV/c");
1287 REGISTER_VARIABLE(
"pRecoil", recoilMomentum,
1288 "magnitude of 3 - momentum recoiling against given Particle\n\n",
"GeV/c");
1289 REGISTER_VARIABLE(
"pRecoilTheta", recoilMomentumTheta,
1290 "Polar angle of a particle's missing momentum\n\n",
"rad");
1291 REGISTER_VARIABLE(
"pRecoilPhi", recoilMomentumPhi,
1292 "Azimuthal angle of a particle's missing momentum\n\n",
"rad");
1293 REGISTER_VARIABLE(
"eRecoil", recoilEnergy,
1294 "energy recoiling against given Particle\n\n",
"GeV");
1295 REGISTER_VARIABLE(
"mRecoil", recoilMass,
1296 "Invariant mass of the system recoiling against given Particle\n\n",
"GeV/:math:`\\text{c}^2`");
1297 REGISTER_VARIABLE(
"m2Recoil", recoilMassSquared,
1298 "invariant mass squared of the system recoiling against given Particle\n\n",
":math:`[\\text{GeV}/\\text{c}^2]^2`");
1299 REGISTER_VARIABLE(
"m2RecoilSignalSide", m2RecoilSignalSide, R
"DOC(
1300 Squared recoil mass of the signal side which is calculated in the CMS frame under the assumption that the
1301 signal and tag side are produced back to back and the tag side energy equals the beam energy. The variable
1302 must be applied to the Upsilon and the tag side must be the first, the signal side the second daughter
1304 )DOC", ":math:`[\\text{GeV}/\\text{c}^2]^2`");
1305 REGISTER_VARIABLE(
"massDiffRecoil(i)", recoilMassDiff, R
"DOC(
1306 mass difference M(Recoil + i-th daughter) - M(Recoil)
1307 between recoil for a given Particle without a specific daughter and recoil of the Particle.
1309 This variable is useful for ccbarFEI training where you tag a Lambda_c+ in the recoil,
1310 and on the tag side you can absorb a pion coming from a Sigma_c.
1312 Note: This is used like massDiffRecoil(2) when in ccbarFEI you reconstruct eg. Lambda_c+:tag -> D+ p+ pi-
1313 and you want to calculate the mass difference between the recoil (which is the Lambda_c-)
1314 and the recoil with the pi- which could be coming from Sigma_c--.
1316 )DOC", "GeV/:math:`\\text{c}^2`");
1318 REGISTER_VARIABLE(
"b2bTheta", b2bTheta,
1319 "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");
1320 REGISTER_VARIABLE(
"b2bPhi", b2bPhi,
1321 "Azimuthal angle in the lab system that is back-to-back to the particle in the CMS. Useful for low multiplicity studies.\n\n",
1323 REGISTER_VARIABLE(
"b2bClusterTheta", b2bClusterTheta,
1324 "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",
1326 REGISTER_VARIABLE(
"b2bClusterPhi", b2bClusterPhi,
1327 "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",
1329 REGISTER_VARIABLE(
"ArmenterosLongitudinalMomentumAsymmetry", ArmenterosLongitudinalMomentumAsymmetry,
1330 "Longitudinal momentum asymmetry of V0's daughters.\n"
1331 "The mother (V0) is required to have exactly two daughters");
1332 REGISTER_VARIABLE(
"ArmenterosDaughter1Qt", ArmenterosDaughter1Qt, R
"DOC(
1333 Transverse momentum of the first daughter with respect to the V0 mother.
1334 The mother is required to have exactly two daughters
1337 REGISTER_VARIABLE(
"ArmenterosDaughter2Qt", ArmenterosDaughter2Qt, R
"DOC(
1338 Transverse momentum of the second daughter with respect to the V0 mother.
1339 The mother is required to have exactly two daughters
1343 VARIABLE_GROUP(
"Miscellaneous");
1344 REGISTER_VARIABLE(
"nRemainingTracksInEvent", nRemainingTracksInEvent,
1345 "Number of tracks in the event - Number of tracks( = charged FSPs) of particle.");
1346 REGISTER_VARIABLE(
"decayTypeRecoil", recoilMCDecayType,
1347 "type of the particle decay(no related mcparticle = -1, hadronic = 0, direct leptonic = 1, direct semileptonic = 2,"
1348 "lower level leptonic = 3.");
1350 REGISTER_VARIABLE(
"printParticle", printParticle,
1351 "For debugging, print Particle and daughter PDG codes, plus MC match. Returns 0.");
1352 REGISTER_VARIABLE(
"mcMomTransfer2", particleMCMomentumTransfer2,
1353 "Return the true momentum transfer to lepton pair in a B(semi -) leptonic B meson decay.\n\n",
"GeV/c");
1354 REGISTER_VARIABLE(
"False", False,
1355 "returns always 0, used for testing and debugging.");
1356 REGISTER_VARIABLE(
"True", True,
1357 "returns always 1, used for testing and debugging.");
1358 REGISTER_VARIABLE(
"infinity", infinity,
1359 "returns std::numeric_limits<double>::infinity()");
1360 REGISTER_VARIABLE(
"random", random,
1361 "return a random number between 0 and 1 for each candidate. Can be used, e.g. for picking a random"
1362 "candidate in the best candidate selection.");
1363 REGISTER_VARIABLE(
"eventRandom", eventRandom,
1364 "[Eventbased] Returns a random number between 0 and 1 for this event. Can be used, e.g. for applying an event prescale.");
1365 REGISTER_METAVARIABLE(
"minET2ETDist(detName, detLayer, referenceListName, useHighestProbMassForExt=1)", particleDistToClosestExtTrk,
1366 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.
1367The definition is based on the track helices extrapolation.
1369* The first argument is the name of the detector to consider.
1370* The second argument is the detector layer on whose surface we search for the nearest neighbour.
1371* The third argument is the reference particle list name used to search for the nearest neighbour.
1372* 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;
1373 if 0, it is assumed the mass hypothesis matching the particle lists' PDG was used.
1376 This variable requires to run the ``TrackIsoCalculator`` module first.
1377 Note that the choice of input parameters of this metafunction must correspond to the settings used to configure the module!
1379 Manager::VariableDataType::c_double);
1381 REGISTER_METAVARIABLE("minET2ETDistVar(detName, detLayer, referenceListName, variableName)", particleDistToClosestExtTrkVar,
1382 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
1383, according to the distance definition of `minET2ETDist`.
1385* The first argument is the name of the detector to consider.
1386* The second argument is the detector layer on whose surface we search for the nearest neighbour.
1387* The third argument is the reference particle list name used to search for the nearest neighbour.
1388* The fourth argument is a variable name, e.g. `nCDCHits`.
1391 This variable requires to run the ``TrackIsoCalculator`` module first.
1392 Note that the choice of input parameters of this metafunction must correspond to the settings used to configure the module!
1394 Manager::VariableDataType::c_double);
1396 REGISTER_METAVARIABLE("minET2ETIsoScore(referenceListName, useHighestProbMassForExt, detectorList)", particleExtTrkIsoScoreVar,
1397 R
"DOC(Returns a particle's isolation score :math:`s` defined as:
1404 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), \\
1408 0 & d_{\mathrm{i}} > D_{\mathrm{det}}^{\mathrm{thresh}} \\
1409 1 & d_{\mathrm{i}} <= D_{\mathrm{det}}^{\mathrm{thresh}}, \\
1414where :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
1415number 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,
1416and :math:`w_{\mathrm{det}}` are (negative) weights associated to the detector's impact on PID for this particle type, read from a CDB payload.
1418The score is normalised in [0, 1], where values closer to 1 indicates a well-isolated particle.
1420* The first argument is the reference particle list name used to search for the nearest neighbour.
1421* 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;
1422 if 0, it is assumed the mass hypothesis matching the particle lists' PDG was used.
1423* The remaining arguments are a comma-separated list of detector names, which must correspond to the one given to the `TrackIsoCalculator` module.
1426 The PID detector weights :math:`w_{\mathrm{det}}` are non-trivial only if ``excludePIDDetWeights=false`` in the ``TrackIsoCalculator`` module configuration.
1427 Otherwise :math:`w_{\mathrm{det}} = -1`.
1430 This variable requires to run the `TrackIsoCalculator` module first.
1431 Note that the choice of input parameters of this metafunction must correspond to the settings used to configure the module!
1434 Manager::VariableDataType::c_double);
1436 REGISTER_METAVARIABLE("minET2ETIsoScoreAsWeightedAvg(referenceListName, useHighestProbMassForExt, detectorList)", particleExtTrkIsoScoreVarAsWeightedAvg,
1437 R
"DOC(Returns a particle's isolation score :math:`s` based on the weighted average:
1441 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}}},
1443where :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
1444number 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,
1445and :math:`w_{\mathrm{det}}` are (negative) weights associated to the detector's impact on PID for this particle type, read from a CDB payload.
1447The score is normalised in [0, 1], where values closer to 1 indicates a well-isolated particle.
1449* The first argument is the reference particle list name used to search for the nearest neighbour.
1450* 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;
1451 if 0, it is assumed the mass hypothesis matching the particle lists' PDG was used.
1452* The remaining arguments are a comma-separated list of detector names, which must correspond to the one given to the `TrackIsoCalculator` module.
1455 The PID detector weights :math:`w_{\mathrm{det}}` are non-trivial only if ``excludePIDDetWeights=false`` in the ``TrackIsoCalculator`` module configuration.
1456 Otherwise :math:`\lvert w_{\mathrm{det}} \rvert = 1`.
1459 This variable requires to run the `TrackIsoCalculator` module first.
1460 Note that the choice of input parameters of this metafunction must correspond to the settings used to configure the module!
1463 Manager::VariableDataType::c_double);
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.
int getPDGCode() const
PDG code.
static const ChargedStable muon
muon particle
static const ChargedStable pion
charged pion particle
static const double pionMass
charged pion mass
static const double speedOfLight
[cm/ns]
static const ChargedStable proton
proton particle
static const double protonMass
proton mass
static const double doubleNaN
quiet_NaN
static const ChargedStable kaon
charged kaon particle
static const ParticleType photon
photon particle
static const ChargedStable electron
electron particle
EHypothesisBit
The hypothesis bits for this ECLCluster (Connected region (CR) is split using this hypothesis.
@ c_PrimaryParticle
bit 0: Particle is primary particle.
static const ReferenceFrame & GetCurrent()
Get current rest frame.
std::function< VarVariant(const Particle *)> FunctionPtr
functions stored take a const Particle* and return VarVariant.
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
static Manager & Instance()
get singleton instance.
T convertString(const std::string &str)
Converts a string to type T (one of float, double, long double, int, long int, unsigned long int).
double sqrt(double a)
sqrt for double
Abstract base class for different kinds of events.
static std::string explainFlags(unsigned int flags)
Return string with all human-readable flags, e.g.
static int getMCErrors(const Particle *particle, const MCParticle *mcParticle=nullptr)
Returns quality indicator of the match as a bit pattern where the individual bits indicate the the ty...