10 #include <analysis/variables/FlavorTaggingVariables.h>
11 #include <analysis/variables/ROEVariables.h>
13 #include <analysis/variables/MCTruthVariables.h>
14 #include <analysis/variables/KLMClusterVariables.h>
16 #include <analysis/ClusterUtility/ClusterUtils.h>
18 #include <analysis/utility/MCMatching.h>
19 #include <analysis/utility/PCmsLabTransform.h>
22 #include <framework/datastore/StoreObjPtr.h>
25 #include <analysis/dataobjects/Particle.h>
26 #include <analysis/dataobjects/RestOfEvent.h>
27 #include <analysis/dataobjects/ParticleList.h>
28 #include <analysis/dataobjects/FlavorTaggerInfo.h>
29 #include <analysis/ContinuumSuppression/Thrust.h>
31 #include <mdst/dataobjects/MCParticle.h>
32 #include <mdst/dataobjects/Track.h>
33 #include <mdst/dataobjects/ECLCluster.h>
34 #include <mdst/dataobjects/KLMCluster.h>
35 #include <mdst/dataobjects/PIDLikelihood.h>
38 #include <framework/gearbox/Const.h>
39 #include <framework/logging/Logger.h>
41 #include <Math/Vector3D.h>
42 #include <Math/Vector4D.h>
43 #include <framework/geometry/B2Vector3.h>
57 static const double realNaN = std::numeric_limits<double>::quiet_NaN();
62 double momentumMissingTagSide(
const Particle*)
64 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
65 if (!roe.isValid())
return 0;
67 ROOT::Math::PxPyPzEVector roeCMSVec;
69 const auto& roeChargedParticles = roe->getChargedParticles();
70 for (
auto roeChargedParticle : roeChargedParticles) {
71 roeCMSVec += PCmsLabTransform::labToCms(roeChargedParticle->get4Vector());
74 double missMom = -roeCMSVec.P();
78 Manager::FunctionPtr momentumMissingTagSideWithMask(
const std::vector<std::string>& arguments)
81 if (arguments.size() == 0)
82 maskName = RestOfEvent::c_defaultMaskName;
83 else if (arguments.size() == 1)
84 maskName = arguments[0];
86 B2FATAL(
"At most 1 argument (name of mask) accepted.");
88 auto func = [maskName](
const Particle*) ->
double {
89 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
90 if (!roe.isValid())
return 0;
92 ROOT::Math::PxPyPzEVector roeCMSVec;
94 const auto& roeChargedParticles = roe->getChargedParticles(maskName);
95 for (
auto roeChargedParticle : roeChargedParticles)
97 roeCMSVec += PCmsLabTransform::labToCms(roeChargedParticle->get4Vector());
99 double missMom = -roeCMSVec.P();
105 double cosTPTO(
const Particle* part)
107 StoreObjPtr<RestOfEvent> roeobject(
"RestOfEvent");
108 const RestOfEvent* roe;
109 if (roeobject.isValid()) {
112 roe = getRelatedROEObject(part);
117 std::vector<ROOT::Math::XYZVector> p3_cms_roe;
118 static const double P_MAX(3.2);
122 const auto& roeTracks = roe->getChargedParticles();
123 for (
auto& roeChargedParticle : roeTracks) {
126 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(roeChargedParticle->get4Vector());
127 if (p_cms != p_cms)
continue;
128 if (p_cms.P() > P_MAX)
continue;
129 p3_cms_roe.push_back(p_cms.Vect());
133 const auto& roePhotons = roe->getPhotons();
134 for (
auto& roePhoton : roePhotons) {
135 if (roePhoton->getECLClusterEHypothesisBit() == ECLCluster::EHypothesisBit::c_nPhotons) {
136 ROOT::Math::PxPyPzEVector p_lab = roePhoton->get4Vector();
137 if (p_lab != p_lab)
continue;
138 if (p_lab.P() < 0.05)
continue;
139 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(p_lab);
140 if (p_cms != p_cms)
continue;
141 if (p_cms.P() > P_MAX)
continue;
142 p3_cms_roe.push_back(p_cms.Vect());
146 const auto& roeKlongs = roe->getHadrons();
147 for (
auto& roeKlong : roeKlongs) {
148 if (nKLMClusterTrackMatches(roeKlong) == 0 && !(roeKlong->getKLMCluster()->getAssociatedEclClusterFlag())) {
149 ROOT::Math::PxPyPzEVector p_lab = roeKlong->get4Vector();
150 if (p_lab != p_lab)
continue;
151 if (p_lab.P() < 0.05)
continue;
152 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(p_lab);
153 if (p_cms != p_cms)
continue;
154 if (p_cms.P() > P_MAX)
continue;
155 p3_cms_roe.push_back(p_cms.Vect());
159 const B2Vector3D thrustO = Thrust::calculateThrust(p3_cms_roe);
160 const B2Vector3D pAxis = PCmsLabTransform::labToCms(part->get4Vector()).Vect();
163 if (pAxis == pAxis) result = abs(cos(pAxis.Angle(thrustO)));
168 Manager::FunctionPtr cosTPTOWithMask(
const std::vector<std::string>& arguments)
170 std::string maskName;
171 if (arguments.size() == 0)
172 maskName = RestOfEvent::c_defaultMaskName;
173 else if (arguments.size() == 1)
174 maskName = arguments[0];
176 B2FATAL(
"At most 1 argument (name of mask) accepted.");
178 auto func = [maskName](
const Particle * particle) ->
double {
179 StoreObjPtr<RestOfEvent> roeobject(
"RestOfEvent");
180 const RestOfEvent* roe;
181 if (roeobject.isValid())
186 roe = getRelatedROEObject(particle);
191 std::vector<ROOT::Math::XYZVector> p3_cms_roe;
195 const auto& roeTracks = roe->getChargedParticles(maskName);
196 for (
auto& roeChargedParticle : roeTracks)
200 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(roeChargedParticle->get4Vector());
201 if (p_cms != p_cms)
continue;
203 p3_cms_roe.push_back(p_cms.Vect());
207 const auto& roePhotons = roe->getPhotons(maskName);
208 for (
auto& roePhoton : roePhotons)
210 if (roePhoton->getECLClusterEHypothesisBit() == ECLCluster::EHypothesisBit::c_nPhotons) {
211 ROOT::Math::PxPyPzEVector p_lab = roePhoton->get4Vector();
212 if (p_lab != p_lab)
continue;
214 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(p_lab);
215 if (p_cms != p_cms)
continue;
217 p3_cms_roe.push_back(p_cms.Vect());
222 const auto& roeKlongs = roe->getHadrons(maskName);
223 for (
auto& roeKlong : roeKlongs)
225 if (nKLMClusterTrackMatches(roeKlong) == 0 && !(roeKlong->getKLMCluster()->getAssociatedEclClusterFlag())) {
226 ROOT::Math::PxPyPzEVector p_lab = roeKlong->get4Vector();
227 if (p_lab != p_lab)
continue;
229 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(p_lab);
230 if (p_cms != p_cms)
continue;
232 p3_cms_roe.push_back(p_cms.Vect());
236 const B2Vector3D thrustO = Thrust::calculateThrust(p3_cms_roe);
237 const B2Vector3D pAxis = PCmsLabTransform::labToCms(particle->get4Vector()).Vect();
241 result = abs(cos(pAxis.Angle(thrustO)));
249 int lambdaFlavor(
const Particle* particle)
251 if (particle->getPDGCode() == Const::Lambda.getPDGCode())
return 1;
252 else if (particle->getPDGCode() == Const::antiLambda.getPDGCode())
return -1;
256 bool isLambda(
const Particle* particle)
259 if (!mcparticle)
return false;
260 return (abs(mcparticle->getPDG()) == Const::Lambda.getPDGCode());
263 double lambdaZError(
const Particle* particle)
267 TMatrixFSym ErrorPositionMatrix = particle->getVertexErrorMatrix();
268 return ErrorPositionMatrix[2][2];
271 double momentumOfSecondDaughter(
const Particle* part)
273 if (!part->getDaughter(1))
return 0.0;
274 return part->getDaughter(1)->getP();
277 double momentumOfSecondDaughterCMS(
const Particle* part)
279 if (!part->getDaughter(1))
return 0.0;
280 ROOT::Math::PxPyPzEVector vec = PCmsLabTransform::labToCms(part->getDaughter(1)->get4Vector());
284 double chargeTimesKaonLiklihood(
const Particle*)
286 StoreObjPtr<ParticleList> KaonList(
"K+:inRoe");
287 if (!KaonList.isValid())
return 0;
289 double maximumKaonid = 0;
290 double maximum_charge = 0;
291 for (
unsigned int i = 0; i < KaonList->getListSize(); ++i) {
292 const Particle* p = KaonList->getParticle(i);
293 double Kid = p->getRelatedTo<PIDLikelihood>()->getProbability(Const::kaon, Const::pion);
294 if (Kid > maximumKaonid) {
296 maximum_charge = p->getCharge();
299 return maximumKaonid * maximum_charge;
302 double transverseMomentumOfChargeTracksInRoe(
const Particle* part)
304 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
305 if (!roe.isValid())
return 0;
309 for (
const auto& track : roe->getChargedParticles()) {
310 if (part->isCopyOf(track,
true))
continue;
311 sum += track->getMomentum().Perp2();
318 Manager::FunctionPtr transverseMomentumOfChargeTracksInRoeWithMask(
const std::vector<std::string>& arguments)
320 std::string maskName;
321 if (arguments.size() == 0)
322 maskName = RestOfEvent::c_defaultMaskName;
323 else if (arguments.size() == 1)
324 maskName = arguments[0];
326 B2FATAL(
"At most 1 argument (name of mask) accepted.");
328 auto func = [maskName](
const Particle * particle) ->
double {
329 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
330 if (!roe.isValid())
return 0;
334 for (
const auto& track : roe->getChargedParticles(maskName))
336 if (particle->isCopyOf(track,
true))
continue;
337 sum += track->getMomentum().Rho();
345 Manager::FunctionPtr transverseMomentumSquaredOfChargeTracksInRoeWithMask(
const std::vector<std::string>& arguments)
347 std::string maskName;
348 if (arguments.size() == 0)
349 maskName = RestOfEvent::c_defaultMaskName;
350 else if (arguments.size() == 1)
351 maskName = arguments[0];
353 B2FATAL(
"At most 1 argument (name of mask) accepted.");
355 auto func = [maskName](
const Particle * particle) ->
double {
356 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
357 if (!roe.isValid())
return 0;
361 for (
const auto& track : roe->getChargedParticles(maskName))
363 if (particle->isCopyOf(track,
true))
continue;
364 sum += track->getMomentum().Perp2();
372 int NumberOfKShortsInRoe(
const Particle* particle)
374 StoreObjPtr<ParticleList> KShortList(
"K_S0:inRoe");
375 if (!KShortList.isValid())
376 B2FATAL(
"NumberOfKShortsInRoe cannot be calculated because the required particleList K_S0:inRoe could not be found or is not valid");
379 for (
unsigned int i = 0; i < KShortList->getListSize(); ++i) {
380 if (!particle->overlapsWith(KShortList->getParticle(i)))
388 bool isInElectronOrMuonCat(
const Particle* particle)
391 StoreObjPtr<ParticleList> MuonList(
"mu+:inRoe");
392 const Track* trackTargetMuon =
nullptr;
393 if (MuonList.isValid()) {
394 double maximumProbMuon = 0;
395 for (
unsigned int i = 0; i < MuonList->getListSize(); ++i) {
396 Particle* pMuon = MuonList->getParticle(i);
397 double probMuon = pMuon->getExtraInfo(
"isRightTrack(Muon)");
398 if (probMuon > maximumProbMuon) {
399 maximumProbMuon = probMuon;
400 trackTargetMuon = pMuon->getTrack();
404 if (particle->getTrack() == trackTargetMuon)
409 StoreObjPtr<ParticleList> ElectronList(
"e+:inRoe");
410 const Track* trackTargetElectron =
nullptr;
411 if (ElectronList.isValid()) {
412 double maximumProbElectron = 0;
413 for (
unsigned int i = 0; i < ElectronList->getListSize(); ++i) {
414 Particle* pElectron = ElectronList->getParticle(i);
415 double probElectron = pElectron->getExtraInfo(
"isRightTrack(Electron)");
416 if (probElectron > maximumProbElectron) {
417 maximumProbElectron = probElectron;
418 trackTargetElectron = pElectron->getTrack();
422 if (particle->getTrack() == trackTargetElectron)
429 static int getB0flavourMC(
const MCParticle* mcParticle)
432 if (mcParticle->getPDG() == 511) {
434 }
else if (mcParticle->getPDG() == -511) {
437 mcParticle = mcParticle->getMother();
444 bool isMajorityInRestOfEventFromB0(
const Particle*)
446 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
447 if (!roe.isValid())
return 0;
450 for (
auto& track : roe->getChargedParticles()) {
451 const MCParticle* mcParticle = track->getMCParticle();
452 vote += getB0flavourMC(mcParticle);
458 Manager::FunctionPtr isMajorityInRestOfEventFromB0WithMask(
const std::vector<std::string>& arguments)
460 std::string maskName;
461 if (arguments.size() == 0)
462 maskName = RestOfEvent::c_defaultMaskName;
463 else if (arguments.size() == 1)
464 maskName = arguments[0];
466 B2FATAL(
"At most 1 argument (name of mask) accepted.");
468 auto func = [maskName](
const Particle*) ->
bool {
469 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
470 if (!roe.isValid())
return 0;
473 for (
auto& track : roe->getChargedParticles(maskName))
475 const MCParticle* mcParticle = track->getMCParticle();
476 vote += getB0flavourMC(mcParticle);
485 bool isMajorityInRestOfEventFromB0bar(
const Particle*)
487 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
488 if (!roe.isValid())
return 0;
491 for (
auto& track : roe->getChargedParticles()) {
492 const MCParticle* mcParticle = track->getMCParticle();
493 vote += getB0flavourMC(mcParticle);
499 Manager::FunctionPtr isMajorityInRestOfEventFromB0barWithMask(
const std::vector<std::string>& arguments)
501 std::string maskName;
502 if (arguments.size() == 0)
503 maskName = RestOfEvent::c_defaultMaskName;
504 else if (arguments.size() == 1)
505 maskName = arguments[0];
507 B2FATAL(
"At most 1 argument (name of mask) accepted.");
509 auto func = [maskName](
const Particle*) ->
bool {
510 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
511 if (!roe.isValid())
return 0;
514 for (
auto& track : roe->getChargedParticles(maskName))
516 const MCParticle* mcParticle = track->getMCParticle();
517 vote += getB0flavourMC(mcParticle);
526 bool hasRestOfEventTracks(
const Particle* part)
528 const RestOfEvent* roe = part->getRelatedTo<RestOfEvent>();
529 return (roe && roe-> getNTracks() > 0);
532 Manager::FunctionPtr hasRestOfEventTracksWithMask(
const std::vector<std::string>& arguments)
534 std::string maskName;
535 if (arguments.size() == 0)
536 maskName = RestOfEvent::c_defaultMaskName;
537 else if (arguments.size() == 1)
538 maskName = arguments[0];
540 B2FATAL(
"At most 1 argument (name of mask) accepted.");
542 auto func = [maskName](
const Particle*) ->
bool {
543 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
544 if (!roe.isValid())
return 0;
546 return roe->getNTracks(maskName) > 0;
551 int isRelatedRestOfEventB0Flavor(
const Particle* particle)
553 const RestOfEvent* roe = particle->getRelatedTo<RestOfEvent>();
557 if (!BcpMC)
return 0;
558 if (Variable::isSignal(particle) <= 0)
return 0;
560 const MCParticle* Y4S = BcpMC->getMother();
566 for (
auto& roeChargedParticle : roe->getChargedParticles()) {
567 const MCParticle* mcParticle = roeChargedParticle->
getMCParticle();
569 if (mcParticle->getMother() == Y4S) {
570 if (mcParticle == BcpMC) {
571 if (mcParticle->getPDG() > 0) BcpFlavor = 2;
573 }
else if (BtagFlavor == 0) {
574 if (abs(mcParticle->getPDG()) == 511 || abs(mcParticle->getPDG()) == 521) {
575 if (mcParticle->getPDG() > 0) BtagFlavor = 1;
576 else BtagFlavor = -1;
577 }
else BtagFlavor = 5;
583 if (BcpFlavor != 0 || BtagFlavor == 5)
break;
587 return (BcpFlavor != 0) ? BcpFlavor : BtagFlavor;
590 Manager::FunctionPtr isRelatedRestOfEventB0FlavorWithMask(
const std::vector<std::string>& arguments)
592 std::string maskName;
593 if (arguments.size() == 0)
594 maskName = RestOfEvent::c_defaultMaskName;
595 else if (arguments.size() == 1)
596 maskName = arguments[0];
598 B2FATAL(
"At most 1 argument (name of mask) accepted.");
600 auto func = [maskName](
const Particle * particle) ->
int {
601 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
602 if (!roe.isValid())
return 0;
605 if (!BcpMC)
return 0;
606 if (Variable::isSignal(particle) <= 0)
return 0;
608 const MCParticle* Y4S = BcpMC->getMother();
614 for (
auto& roeChargedParticle : roe->getChargedParticles(maskName))
616 const MCParticle* mcParticle = roeChargedParticle->
getMCParticle();
618 if (mcParticle->getMother() != Y4S) {
623 if (mcParticle == BcpMC) {
624 if (mcParticle->getPDG() > 0)
628 }
else if (BtagFlavor == 0) {
629 if (abs(mcParticle->getPDG()) == 511 || abs(mcParticle->getPDG()) == 521) {
630 if (mcParticle->getPDG() > 0)
640 if (BcpFlavor != 0 || BtagFlavor == 5)
break;
643 return (BcpFlavor != 0) ? BcpFlavor : BtagFlavor;
649 int isRestOfEventB0Flavor(
const Particle*)
651 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
652 if (!roe.isValid())
return 0;
654 const Particle* Bcp = roe->getRelatedFrom<Particle>();
655 return Variable::isRelatedRestOfEventB0Flavor(Bcp);
658 int ancestorHasWhichFlavor(
const Particle* particle)
660 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
661 if (!roe.isValid())
return 0;
663 const MCParticle* BcpMC = roe->
getRelatedFrom<Particle>()->getMCParticle();
664 const MCParticle* Y4S = BcpMC->getMother();
667 int outputB0tagQ = 0;
669 if (mcParticle->getMother() == Y4S) {
670 if (mcParticle != BcpMC && abs(mcParticle->getPDG()) == 511) {
671 if (mcParticle->getPDG() == 511) outputB0tagQ = 1;
672 else outputB0tagQ = -1;
673 }
else if (mcParticle == BcpMC) {
674 if (mcParticle->getPDG() == 511) outputB0tagQ = 2;
675 else outputB0tagQ = -2;
676 }
else outputB0tagQ = 5;
685 int B0mcErrors(
const Particle*)
687 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
688 if (!roe.isValid())
return -1;
690 const Particle* Bcp = roe->getRelatedFrom<Particle>();
691 const MCParticle* BcpMC = roe->
getRelatedFrom<Particle>()->getMCParticle();
692 return MCMatching::getMCErrors(Bcp, BcpMC);
695 int isRelatedRestOfEventMajorityB0Flavor(
const Particle* part)
697 const RestOfEvent* roe = part->getRelatedTo<RestOfEvent>();
702 if (roe->getNTracks() > 0) {
703 for (
auto& track : roe->getChargedParticles()) {
704 const MCParticle* mcParticle = track->getMCParticle();
705 q_MC += getB0flavourMC(mcParticle);
707 }
else if (roe->getNECLClusters() > 0) {
708 for (
auto& cluster : roe->getPhotons()) {
709 if (cluster->getECLClusterEHypothesisBit() != ECLCluster::EHypothesisBit::c_nPhotons)
continue;
710 const MCParticle* mcParticle = cluster->getMCParticle();
711 q_MC += getB0flavourMC(mcParticle);
713 }
else if (roe->getNKLMClusters() > 0) {
714 for (
auto& klmcluster : roe->getHadrons()) {
716 q_MC += getB0flavourMC(mcParticle);
726 Manager::FunctionPtr isRelatedRestOfEventMajorityB0FlavorWithMask(
const std::vector<std::string>& arguments)
728 std::string maskName;
729 if (arguments.size() == 0)
730 maskName = RestOfEvent::c_defaultMaskName;
731 else if (arguments.size() == 1)
732 maskName = arguments[0];
734 B2FATAL(
"At most 1 argument (name of mask) accepted.");
736 auto func = [maskName](
const Particle*) ->
int {
737 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
738 if (!roe.isValid())
return -2;
742 if (roe->getNTracks(maskName) > 0)
744 for (
auto& track : roe->getChargedParticles(maskName)) {
745 const MCParticle* mcParticle = track->getMCParticle();
746 q_MC += getB0flavourMC(mcParticle);
748 }
else if (roe->getNECLClusters(maskName) > 0)
750 for (
auto& cluster : roe->getPhotons(maskName)) {
751 if (cluster->getECLClusterEHypothesisBit() != ECLCluster::EHypothesisBit::c_nPhotons)
continue;
752 const MCParticle* mcParticle = cluster->getMCParticle();
753 q_MC += getB0flavourMC(mcParticle);
755 }
else if (roe->getNKLMClusters(maskName) > 0)
757 for (
auto& klmcluster : roe->getHadrons(maskName)) {
759 q_MC += getB0flavourMC(mcParticle);
766 return int(q_MC > 0);
772 int isRestOfEventMajorityB0Flavor(
const Particle*)
774 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
775 if (!roe.isValid())
return -2;
777 const Particle* Bcp = roe->getRelatedFrom<Particle>();
778 return Variable::isRelatedRestOfEventMajorityB0Flavor(Bcp);
781 double mcFlavorOfOtherB(
const Particle* particle)
784 if (std::abs(particle->getPDGCode()) != 511 && std::abs(particle->getPDGCode()) != 521) {
785 B2ERROR(
"MCFlavorOfOtherB: this variable works only for B mesons.\n"
786 "The given particle with PDG code " << particle->getPDGCode() <<
787 " is not a B-meson candidate (PDG code 511 or 521). ");
792 if (!mcParticle)
return realNaN;
794 const MCParticle* mcMother = mcParticle->getMother();
795 if (!mcMother)
return realNaN;
797 if (Variable::isSignal(particle) < 1.0)
return 0;
799 for (
auto& upsilon4SDaughter : mcMother->getDaughters()) {
800 if (upsilon4SDaughter == mcParticle)
continue;
801 return (upsilon4SDaughter->getPDG() > 0) ? 1 : -1;
812 Manager::FunctionPtr BtagToWBosonVariables(
const std::vector<std::string>& arguments)
815 std::string requestedVariable;
816 std::string maskName;
817 if (arguments.size() == 1) {
818 requestedVariable = arguments[0];
819 maskName = RestOfEvent::c_defaultMaskName;
820 }
else if (arguments.size() == 2) {
821 requestedVariable = arguments[0];
822 maskName = arguments[1];
824 B2FATAL(
"Number of arguments must be 1 (requestedVariable) or 2 (requestedVariable, maskName).");
827 const std::vector<string> availableVariables = {
"recoilMass",
834 if (std::find(availableVariables.begin(), availableVariables.end(), requestedVariable) == availableVariables.end()) {
835 B2FATAL(
"Wrong variable " << requestedVariable <<
836 " requested. The possibilities are recoilMass, recoilMassSqrd, pMissCMS, cosThetaMissCMS or EW90");
839 auto func = [requestedVariable, maskName](
const Particle * particle) ->
double {
840 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
844 ROOT::Math::PxPyPzEVector momXChargedTracks;
845 const auto& roeChargedParticles = roe->getChargedParticles(maskName);
846 for (
auto& roeChargedParticle : roeChargedParticles)
848 if (roeChargedParticle->isCopyOf(particle,
true))
continue;
849 momXChargedTracks += roeChargedParticle->get4Vector();
852 ROOT::Math::PxPyPzEVector momXNeutralClusters = roe->get4VectorNeutralECLClusters(maskName);
853 const auto& klongs = roe->getHadrons(maskName);
854 for (
auto& klong : klongs)
856 if (nKLMClusterTrackMatches(klong) == 0 && !(klong->getKLMCluster()->getAssociatedEclClusterFlag())) {
857 momXNeutralClusters += klong->get4Vector();
861 ROOT::Math::PxPyPzEVector momX = PCmsLabTransform::labToCms(momXChargedTracks + momXNeutralClusters);
862 ROOT::Math::PxPyPzEVector momTarget = PCmsLabTransform::labToCms(particle->get4Vector());
863 ROOT::Math::PxPyPzEVector momMiss = -(momX + momTarget);
866 if (requestedVariable ==
"recoilMass") output = momX.M();
867 if (requestedVariable ==
"recoilMassSqrd") output = momX.M2();
868 if (requestedVariable ==
"pMissCMS") output = momMiss.P();
869 if (requestedVariable ==
"cosThetaMissCMS") output = momTarget.Vect().Unit().Dot(momMiss.Vect().Unit());
870 if (requestedVariable ==
"EW90")
873 ROOT::Math::PxPyPzEVector momW = momTarget + momMiss;
876 const auto& photons = roe->getPhotons(maskName);
877 for (
auto& photon : photons) {
878 if (PCmsLabTransform::labToCms(photon->get4Vector()).Vect().Dot(momW.Vect()) > 0) {
879 E_W_90 += photon->getECLClusterEnergy();
882 for (
auto& roeChargedParticle : roeChargedParticles) {
883 if (roeChargedParticle->isCopyOf(particle,
true))
886 for (
const ECLCluster& chargedCluster : roeChargedParticle->getTrack()->getRelationsWith<ECLCluster>()) {
888 if (!chargedCluster.hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons))
890 float iEnergy = chargedCluster.getEnergy(ECLCluster::EHypothesisBit::c_nPhotons);
891 if (iEnergy == iEnergy) {
892 if (PCmsLabTransform::labToCms(ClusterUtils().Get4MomentumFromCluster(&chargedCluster,
893 ECLCluster::EHypothesisBit::c_nPhotons)).Vect().Dot(momW.Vect()) > 0)
907 Manager::FunctionPtr KaonPionVariables(
const std::vector<std::string>& arguments)
909 if (arguments.size() != 1)
910 B2FATAL(
"Wrong number of arguments (1 required) for meta function KaonPionVariables");
913 auto requestedVariable = arguments[0];
914 auto func = [requestedVariable](
const Particle * particle) ->
double {
916 StoreObjPtr<ParticleList> SlowPionList(
"pi+:inRoe");
919 if ((requestedVariable !=
"HaveOpositeCharges") && (requestedVariable !=
"cosKaonPion"))
920 B2FATAL(
"Wrong variable " << requestedVariable <<
" requested. The possibilities are cosKaonPion or HaveOpositeCharges");
923 ROOT::Math::PxPyPzEVector momTargetSlowPion;
924 double chargeTargetSlowPion = 0;
925 if (SlowPionList.isValid())
927 double maximumProbSlowPion = 0;
928 for (
unsigned int i = 0; i < SlowPionList->getListSize(); ++i) {
929 Particle* pSlowPion = SlowPionList->getParticle(i);
930 if (!pSlowPion)
continue;
931 if (!pSlowPion->hasExtraInfo(
"isRightCategory(SlowPion)"))
continue;
933 double probSlowPion = pSlowPion->getExtraInfo(
"isRightCategory(SlowPion)");
934 if (probSlowPion > maximumProbSlowPion) {
935 maximumProbSlowPion = probSlowPion;
936 chargeTargetSlowPion = pSlowPion->getCharge();
937 momTargetSlowPion = PCmsLabTransform::labToCms(pSlowPion->get4Vector());
944 double chargeTargetKaon = particle->getCharge();
945 if (requestedVariable ==
"HaveOpositeCharges")
947 if (chargeTargetKaon * chargeTargetSlowPion == -1)
951 else if (requestedVariable ==
"cosKaonPion")
953 ROOT::Math::PxPyPzEVector momTargetKaon = PCmsLabTransform::labToCms(particle->get4Vector());
954 if (momTargetKaon == momTargetKaon && momTargetSlowPion == momTargetSlowPion)
955 output = momTargetKaon.Vect().Unit().Dot(momTargetSlowPion.Vect().Unit());
963 Manager::FunctionPtr FSCVariables(
const std::vector<std::string>& arguments)
965 if (arguments.size() != 1)
966 B2FATAL(
"Wrong number of arguments (1 required) for meta function FSCVariables");
969 auto requestedVariable = arguments[0];
970 auto func = [requestedVariable](
const Particle * particle) ->
double {
971 StoreObjPtr<ParticleList> FastParticleList(
"pi+:inRoe");
972 if (!FastParticleList.isValid())
return 0;
975 if ((requestedVariable !=
"pFastCMS") && (requestedVariable !=
"cosSlowFast") && (requestedVariable !=
"cosTPTOFast") && (requestedVariable !=
"SlowFastHaveOpositeCharges"))
976 B2FATAL(
"Wrong variable " << requestedVariable <<
" requested. The possibilities are pFastCMS, cosSlowFast, cosTPTOFast or SlowFastHaveOpositeCharges");
979 double maximumProbFastest = 0;
980 ROOT::Math::PxPyPzEVector momFastParticle;
981 Particle* TargetFastParticle =
nullptr;
982 for (
unsigned int i = 0; i < FastParticleList->getListSize(); ++i)
984 Particle* particlei = FastParticleList->getParticle(i);
985 if (!particlei)
continue;
987 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
988 if (momParticlei != momParticlei)
continue;
990 double probFastest = momParticlei.P();
991 if (probFastest > maximumProbFastest) {
992 maximumProbFastest = probFastest;
993 TargetFastParticle = particlei;
994 momFastParticle = momParticlei;
999 if (!TargetFastParticle)
return 0;
1002 double output = 0.0;
1004 if (requestedVariable ==
"cosTPTOFast")
1005 output = cosTPTO(TargetFastParticle);
1007 ROOT::Math::PxPyPzEVector momSlowPion = PCmsLabTransform::labToCms(particle->get4Vector());
1008 if (momSlowPion == momSlowPion)
1010 if (requestedVariable ==
"cosSlowFast") {
1011 output = momSlowPion.Vect().Unit().Dot(momFastParticle.Vect().Unit());
1012 }
else if (requestedVariable ==
"SlowFastHaveOpositeCharges") {
1013 if (particle->getCharge()*TargetFastParticle->getCharge() == -1) {
1017 output = momFastParticle.P();
1030 const std::vector<int> charmMesons = { 411, 421, 10411, 10421, 413, 423, 10413, 10423, 20413, 20423, 415, 425, 431, 10431, 433, 10433, 20433, 435};
1032 const std::vector<int> charmBaryons = { 4122, 4222, 4212, 4112, 4224, 4214, 4114, 4232, 4132, 4322, 4312, 4324, 4314, 4332, 4334, 4412, 4422,
1033 4414, 4424, 4432, 4434, 4444
1036 const std::vector<int> qqbarMesons = {
1037 111, 9000111, 100111, 10111, 200111, 113, 10113, 20113, 9000113, 100113, 9010113, 9020113, 30113, 9030113, 9040113,
1038 115, 10115, 100115, 9000115, 117, 9000117, 9010117, 119,
1040 221, 331, 9000221, 9010221, 100221, 10221, 100331, 9020221, 10331, 200221, 9030221, 9040221, 9050221, 9060221, 9070221, 223, 333, 10223, 20223,
1041 10333, 20333, 100223, 9000223, 9010223, 30223, 100333, 225, 9000225, 335, 9010225, 9020225, 10225, 9030225, 10335, 9040225, 100225, 100335,
1042 9050225, 9060225, 9070225, 227, 337, 229, 9000339, 9000229,
1044 441, 10441, 100441, 443, 10443, 20443, 100443, 30443, 9000443, 9010443, 9020443, 445, 9000445
1047 const std::vector<int> flavorConservingMesons = {
1048 9000211, 100211, 10211, 200211, 213, 10213, 20213, 9000213, 100213, 9010213, 9020213, 30213, 9030213, 9040213,
1049 215, 10215, 100215, 9000215, 217, 9000217, 9010217, 219,
1051 30343, 10311, 10321, 100311, 100321, 200311, 200321, 9000311, 9000321, 313, 323, 10313, 10323, 20313, 20323, 100313, 100323,
1052 9000313, 9000323, 30313, 30323, 315, 325, 9000315, 9000325, 10315, 10325, 20315, 20325, 100315, 100325, 9010315,
1053 9010325, 317, 327, 9010317, 9010327, 319, 329, 9000319, 9000329
1056 const std::vector<std::string> availableForIsRightTrack = {
"Electron",
1057 "IntermediateElectron",
1061 "IntermediateKinLepton",
1069 const std::vector<std::string> availableForIsRightCategory = {
"Electron",
1070 "IntermediateElectron",
1074 "IntermediateKinLepton",
1087 Manager::FunctionPtr isRightTrack(
const std::vector<std::string>& arguments)
1089 if (arguments.size() != 1) {
1090 B2FATAL(
"Wrong number of arguments (1 required) for meta function isRightTrack");
1095 unsigned index = std::find(availableForIsRightTrack.begin(), availableForIsRightTrack.end(), particleName)
1096 - availableForIsRightTrack.begin();
1097 if (index == availableForIsRightTrack.size()) {
1098 B2FATAL(
"isRightTrack: Not available category " << particleName <<
1099 ". The possibilities are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron and Lambda");
1102 auto func = [index](
const Particle * particle) ->
int {
1105 if (!mcParticle)
return -2;
1107 int mcPDG = abs(mcParticle->getPDG());
1110 std::vector<int> mothersPDG;
1111 std::vector<const MCParticle*> mothersPointers;
1113 const MCParticle* mcMother = mcParticle->getMother();
1116 mothersPDG.push_back(abs(mcMother->getPDG()));
1117 mothersPointers.push_back(mcMother);
1118 if (abs(mcMother->getPDG()) == 511)
break;
1119 mcMother = mcMother->getMother();
1122 if (mothersPDG.size() == 0)
return -2;
1125 if (index == 10)
return 1;
1129 bool isCharmedMesonInChain =
false;
1130 for (
auto& iMCMotherPDG : mothersPDG)
1132 if (std::find(charmMesons.begin(), charmMesons.end(), iMCMotherPDG) != charmMesons.end()) {
1133 isCharmedMesonInChain =
true;
1140 bool isCharmedBaryonInChain =
false;
1141 for (
auto& iMCMotherPDG : mothersPDG)
1143 if (std::find(charmBaryons.begin(), charmBaryons.end(), iMCMotherPDG) != charmBaryons.end()) {
1144 isCharmedBaryonInChain =
true;
1151 bool isQQbarMesonInChain =
false;
1152 for (
auto& iMCMotherPDG : mothersPDG)
1154 if (std::find(qqbarMesons.begin(), qqbarMesons.end(), iMCMotherPDG) != qqbarMesons.end()) {
1155 isQQbarMesonInChain =
true;
1162 bool isB0DaughterConservingFlavor =
false;
1163 if (std::find(flavorConservingMesons.begin(), flavorConservingMesons.end(),
1164 mothersPDG.rbegin()[1]) != flavorConservingMesons.end())
1166 isB0DaughterConservingFlavor =
true;
1171 bool isHadronSingleTauDaughter =
false;
1172 if (mothersPDG.size() > 1 && mothersPDG.rbegin()[1] == 15)
1174 int numberOfChargedDaughters = 0;
1175 for (
auto& tauDaughter : mothersPointers.rbegin()[1]->getDaughters()) {
1176 if (tauDaughter->getCharge() != 0)
1177 numberOfChargedDaughters += 1;
1179 if (numberOfChargedDaughters == 1)
1180 isHadronSingleTauDaughter =
true;
1184 && mcPDG == Const::electron.getPDGCode() && mothersPDG[0] == 511)
1187 }
else if (index == 1
1188 && mcPDG == Const::electron.getPDGCode() && mothersPDG.size() > 1 && isQQbarMesonInChain ==
false)
1191 }
else if (index == 2
1192 && mcPDG == Const::muon.getPDGCode() && mothersPDG[0] == 511)
1195 }
else if (index == 3
1196 && mcPDG == Const::muon.getPDGCode() && mothersPDG.size() > 1 && isQQbarMesonInChain ==
false)
1199 }
else if (index == 4
1200 && (mcPDG == Const::muon.getPDGCode() || mcPDG == Const::electron.getPDGCode()) && mothersPDG[0] == 511)
1203 }
else if (index == 5
1204 && (mcPDG == Const::muon.getPDGCode() || mcPDG == Const::electron.getPDGCode()) && mothersPDG.size() > 1
1205 && isQQbarMesonInChain ==
false)
1208 }
else if (index == 6
1209 && mcPDG == Const::kaon.getPDGCode() && isQQbarMesonInChain ==
false
1210 && (isCharmedMesonInChain ==
true || isCharmedBaryonInChain ==
true))
1213 }
else if (index == 7
1214 && mcPDG == Const::pion.getPDGCode() && mothersPDG.size() > 1 && mothersPDG[0] == 413 && mothersPDG[1] == 511)
1217 }
else if (index == 8
1218 && (mcPDG == Const::pion.getPDGCode() || mcPDG == Const::kaon.getPDGCode())
1219 && isQQbarMesonInChain ==
false
1220 && (mothersPDG[0] == 511
1221 || (mothersPDG.rbegin()[0] == 511 && (isB0DaughterConservingFlavor ==
true || isHadronSingleTauDaughter ==
true))))
1224 }
else if (index == 9
1225 && mcPDG == Const::Lambda.getPDGCode() && isCharmedBaryonInChain ==
true)
1236 Manager::FunctionPtr isRightCategory(
const std::vector<std::string>& arguments)
1238 if (arguments.size() != 1) {
1239 B2FATAL(
"Wrong number of arguments (1 required) for meta function isRightCategory");
1244 unsigned index = find(availableForIsRightCategory.begin(), availableForIsRightCategory.end(), particleName)
1245 - availableForIsRightCategory.begin();
1246 if (index == availableForIsRightCategory.size()) {
1247 B2FATAL(
"isRightCategory: Not available category " << particleName <<
1248 ". The possibilities are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
1251 auto func = [index](
const Particle * particle) ->
int {
1253 Particle* nullParticle =
nullptr;
1254 double qTarget = particle->getCharge();
1255 double qMC = Variable::isRestOfEventB0Flavor(nullParticle);
1258 if (!mcParticle)
return -2;
1260 int mcPDG = abs(mcParticle->getPDG());
1263 std::vector<int> mothersPDG;
1264 std::vector<const MCParticle*> mothersPointers;
1266 const MCParticle* mcMother = mcParticle->getMother();
1269 mothersPDG.push_back(abs(mcMother->getPDG()));
1270 mothersPointers.push_back(mcMother);
1271 if (abs(mcMother->getPDG()) == 511)
break;
1272 mcMother = mcMother->getMother();
1275 if (mothersPDG.size() == 0)
return -2;
1277 if (index == 13)
return 1;
1281 bool isCharmedMesonInChain =
false;
1282 for (
auto& iMCMotherPDG : mothersPDG)
1284 if (std::find(charmMesons.begin(), charmMesons.end(), iMCMotherPDG) != charmMesons.end()) {
1285 isCharmedMesonInChain =
true;
1292 bool isCharmedBaryonInChain =
false;
1293 for (
auto& iMCMotherPDG : mothersPDG)
1295 if (std::find(charmBaryons.begin(), charmBaryons.end(), iMCMotherPDG) != charmBaryons.end()) {
1296 isCharmedBaryonInChain =
true;
1303 bool isQQbarMesonInChain =
false;
1304 for (
auto& iMCMotherPDG : mothersPDG)
1306 if (std::find(qqbarMesons.begin(), qqbarMesons.end(), iMCMotherPDG) != qqbarMesons.end()) {
1307 isQQbarMesonInChain =
true;
1314 bool isB0DaughterConservingFlavor =
false;
1315 if (mothersPDG.size() > 1)
1317 if (std::find(flavorConservingMesons.begin(), flavorConservingMesons.end(),
1318 mothersPDG.rbegin()[1]) != flavorConservingMesons.end()) {
1319 isB0DaughterConservingFlavor =
true;
1325 bool isHadronSingleTauDaughter =
false;
1326 if (mothersPDG.size() > 1 && mothersPDG.rbegin()[1] == 15)
1328 int numberOfChargedDaughters = 0;
1329 for (
auto& tauDaughter : mothersPointers.rbegin()[1]->getDaughters()) {
1330 if (tauDaughter->getCharge() != 0)
1331 numberOfChargedDaughters += 1;
1333 if (numberOfChargedDaughters == 1)
1334 isHadronSingleTauDaughter =
true;
1338 bool haveKaonPionSameMother =
false;
1341 const MCParticle* mcSlowPionMother =
nullptr;
1342 StoreObjPtr<ParticleList> SlowPionList(
"pi+:inRoe");
1343 Particle* targetSlowPion =
nullptr;
1344 if (SlowPionList.isValid()) {
1345 double mcProbSlowPion = 0;
1346 for (
unsigned int i = 0; i < SlowPionList->getListSize(); ++i) {
1347 Particle* pSlowPion = SlowPionList->getParticle(i);
1348 if (!pSlowPion)
continue;
1349 if (pSlowPion->hasExtraInfo(
"isRightCategory(SlowPion)")) {
1350 double probSlowPion = pSlowPion->getExtraInfo(
"isRightCategory(SlowPion)");
1351 if (probSlowPion > mcProbSlowPion) {
1352 mcProbSlowPion = probSlowPion;
1353 targetSlowPion = pSlowPion;
1357 if (targetSlowPion !=
nullptr) {
1358 const MCParticle* mcSlowPion = targetSlowPion ->
getMCParticle();
1360 if (mcSlowPion !=
nullptr && mcSlowPion->getMother() !=
nullptr
1361 && abs(mcSlowPion->getPDG()) == Const::pion.getPDGCode() && abs(mcSlowPion->getMother()->getPDG()) == 413) {
1362 mcSlowPionMother = mcSlowPion->
getMother();
1367 if (std::find(mothersPointers.begin(), mothersPointers.end(), mcSlowPionMother) != mothersPointers.end())
1368 haveKaonPionSameMother =
true;
1373 int FastParticlePDGMother = 0;
1377 StoreObjPtr<ParticleList> FastParticleList(
"pi+:inRoe");
1378 Particle* targetFastParticle =
nullptr;
1379 if (FastParticleList.isValid()) {
1380 double mcProbFastest = 0;
1381 for (
unsigned int i = 0; i < FastParticleList->getListSize(); ++i) {
1382 Particle* particlei = FastParticleList->getParticle(i);
1383 if (!particlei)
continue;
1385 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
1386 if (momParticlei == momParticlei) {
1387 double probFastest = momParticlei.P();
1388 if (probFastest > mcProbFastest) {
1389 mcProbFastest = probFastest;
1390 targetFastParticle = particlei;
1394 if (targetFastParticle !=
nullptr) {
1395 const MCParticle* mcFastParticle = targetFastParticle ->
getMCParticle();
1397 if (mcFastParticle !=
nullptr && mcFastParticle->getMother() !=
nullptr) {
1398 FastParticlePDGMother = abs(mcFastParticle->getMother()->getPDG());
1399 qFSC = mcFastParticle->getCharge();
1407 && qTarget == qMC && mcPDG == Const::electron.getPDGCode() && mothersPDG[0] == 511)
1410 }
else if (index == 1
1411 && qTarget != qMC && mcPDG == Const::electron.getPDGCode() && mothersPDG.size() > 1
1412 && isQQbarMesonInChain ==
false)
1415 }
else if (index == 2
1416 && qTarget == qMC && mcPDG == Const::muon.getPDGCode() && mothersPDG[0] == 511)
1419 }
else if (index == 3
1420 && qTarget != qMC && mcPDG == Const::muon.getPDGCode() && mothersPDG.size() > 1
1421 && isQQbarMesonInChain ==
false)
1424 }
else if (index == 4
1426 && (mcPDG == Const::electron.getPDGCode() || mcPDG == Const::muon.getPDGCode()) && mothersPDG[0] == 511)
1429 }
else if (index == 5
1430 && qTarget != qMC && (mcPDG == Const::electron.getPDGCode() || mcPDG == Const::muon.getPDGCode())
1431 && mothersPDG.size() > 1 && isQQbarMesonInChain ==
false)
1434 }
else if (index == 6
1435 && qTarget == qMC && mcPDG == Const::kaon.getPDGCode() && isQQbarMesonInChain ==
false
1436 && (isCharmedMesonInChain ==
true || isCharmedBaryonInChain ==
true))
1439 }
else if (index == 7
1440 && qTarget != qMC && mcPDG == Const::pion.getPDGCode()
1441 && mothersPDG.size() > 1 && mothersPDG[0] == 413 && mothersPDG[1] == 511)
1444 }
else if (index == 8
1445 && qTarget == qMC && (mcPDG == Const::pion.getPDGCode() || mcPDG == Const::kaon.getPDGCode())
1446 && isQQbarMesonInChain ==
false
1447 && (mothersPDG[0] == 511 || (mothersPDG.rbegin()[0] == 511
1448 && (isB0DaughterConservingFlavor ==
true || isHadronSingleTauDaughter ==
true))))
1451 }
else if (index == 9
1452 && qTarget == qMC && mcPDG == Const::kaon.getPDGCode() && haveKaonPionSameMother ==
true)
1455 }
else if (index == 10 && qTarget == qMC)
1458 }
else if (index == 11
1459 && qTarget != qMC && mothersPDG.size() > 1 && qFSC == qMC
1460 && mcPDG == Const::pion.getPDGCode() && FastParticlePDGMother == 511 && isQQbarMesonInChain ==
false)
1463 }
else if (index == 12
1464 && (particle->getPDGCode() / abs(particle->getPDGCode())) != qMC
1465 && mcPDG == Const::Lambda.getPDGCode() && isCharmedBaryonInChain ==
true)
1477 Manager::FunctionPtr hasHighestProbInCat(
const std::vector<std::string>& arguments)
1479 if (arguments.size() != 2) {
1480 B2FATAL(
"Wrong number of arguments (2 required) for meta function hasHighestProbInCat");
1483 auto particleListName = arguments[0];
1484 auto extraInfoName = arguments[1];
1486 bool isAvailable =
false;
1487 for (
const auto& name : availableForIsRightTrack) {
1488 if (extraInfoName ==
"isRightTrack(" + name +
")") {
1493 for (
const auto& name : availableForIsRightCategory) {
1494 if (extraInfoName ==
"isRightCategory(" + name +
")") {
1499 if (extraInfoName ==
"isRightTrack(MaximumPstar)")
1504 string strAvailableForIsRightTrack;
1505 for (
const auto& name : availableForIsRightTrack)
1506 strAvailableForIsRightTrack += name +
" ";
1507 string strAvailableForIsRightCategory;
1508 for (
const auto& name : availableForIsRightCategory)
1509 strAvailableForIsRightCategory += name +
" ";
1511 B2FATAL(
"hasHighestProbInCat: Not available category" << extraInfoName <<
1512 ". The possibilities for isRightTrack() are " << endl << strAvailableForIsRightTrack <<
" MaximumPstar" << endl <<
1513 "The possibilities for isRightCategory() are " << endl << strAvailableForIsRightCategory);
1516 auto func = [particleListName, extraInfoName](
const Particle * particle) ->
bool {
1517 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1518 if (!ListOfParticles.isValid())
return 0;
1520 double maximumProb = 0;
1521 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1523 const Particle* particlei = ListOfParticles->getParticle(i);
1524 if (!particlei)
continue;
1527 if (extraInfoName ==
"isRightTrack(MaximumPstar)") {
1528 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
1529 if (momParticlei == momParticlei) {
1530 prob = momParticlei.P();
1533 if (particlei->hasExtraInfo(extraInfoName)) {
1534 prob = particlei->getExtraInfo(extraInfoName);
1537 if (prob > maximumProb) {
1543 bool output =
false;
1544 if ((extraInfoName ==
"isRightTrack(MaximumPstar)") && (PCmsLabTransform::labToCms(particle->get4Vector()).P() == maximumProb))
1547 }
else if (extraInfoName !=
"isRightTrack(MaximumPstar)" && particle->hasExtraInfo(extraInfoName))
1549 if (particle->getExtraInfo(extraInfoName) == maximumProb) output =
true;
1557 Manager::FunctionPtr HighestProbInCat(
const std::vector<std::string>& arguments)
1559 if (arguments.size() != 2) {
1560 B2FATAL(
"Wrong number of arguments (2 required) for meta function HighestProbInCat");
1563 auto particleListName = arguments[0];
1564 auto extraInfoName = arguments[1];
1566 bool isAvailable =
false;
1567 for (
const auto& name : availableForIsRightTrack) {
1568 if (extraInfoName ==
"isRightTrack(" + name +
")") {
1573 for (
const auto& name : availableForIsRightCategory) {
1574 if (extraInfoName ==
"isRightCategory(" + name +
")") {
1579 if (extraInfoName ==
"isRightTrack(MaximumPstar)")
1584 string strAvailableForIsRightTrack;
1585 for (
const auto& name : availableForIsRightTrack)
1586 strAvailableForIsRightTrack += name +
" ";
1587 string strAvailableForIsRightCategory;
1588 for (
const auto& name : availableForIsRightCategory)
1589 strAvailableForIsRightCategory += name +
" ";
1591 B2FATAL(
"HighestProbInCat: Not available category" << extraInfoName <<
1592 ". The possibilities for isRightTrack() are " << endl << strAvailableForIsRightTrack <<
" MaximumPstar" << endl <<
1593 "The possibilities for isRightCategory() are " << endl << strAvailableForIsRightCategory);
1596 auto func = [particleListName, extraInfoName](
const Particle*) ->
double {
1597 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1598 if (!ListOfParticles.isValid())
return 0;
1600 double maximumProb = 0;
1601 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1603 const Particle* particlei = ListOfParticles->getParticle(i);
1604 if (!particlei)
continue;
1607 if (extraInfoName ==
"isRightTrack(MaximumPstar)") {
1608 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
1609 if (momParticlei == momParticlei) {
1610 prob = momParticlei.P();
1613 if (particlei->hasExtraInfo(extraInfoName)) {
1614 prob = particlei->getExtraInfo(extraInfoName);
1617 maximumProb = max(maximumProb, prob);
1627 std::vector<std::string> availableExtraInfos = {
"isRightTrack(Electron)",
1628 "isRightTrack(IntermediateElectron)",
1629 "isRightTrack(Muon)",
1630 "isRightTrack(IntermediateMuon)",
1631 "isRightTrack(KinLepton)",
1632 "isRightTrack(IntermediateKinLepton)",
1633 "isRightTrack(Kaon)",
1634 "isRightTrack(SlowPion)",
1635 "isRightTrack(FastHadron)",
1636 "isRightTrack(MaximumPstar)",
1637 "isRightTrack(Lambda)",
1638 "isRightCategory(Electron)",
1639 "isRightCategory(IntermediateElectron)",
1640 "isRightCategory(Muon)",
1641 "isRightCategory(IntermediateMuon)",
1642 "isRightCategory(KinLepton)",
1643 "isRightCategory(IntermediateKinLepton)",
1644 "isRightCategory(Kaon)",
1645 "isRightCategory(SlowPion)",
1646 "isRightCategory(FastHadron)",
1647 "isRightCategory(MaximumPstar)",
1648 "isRightCategory(Lambda)",
1649 "isRightCategory(KaonPion)",
1650 "isRightCategory(FSC)",
1653 Manager::FunctionPtr QpOf(
const std::vector<std::string>& arguments)
1655 if (arguments.size() != 3) {
1656 B2FATAL(
"Wrong number of arguments (3 required) for meta function QpOf");
1659 auto particleListName = arguments[0];
1660 auto outputExtraInfo = arguments[1];
1661 auto rankingExtraInfo = arguments[2];
1663 unsigned indexRanking = find(availableExtraInfos.begin(), availableExtraInfos.end(),
1664 rankingExtraInfo) - availableExtraInfos.begin();
1665 unsigned indexOutput = find(availableExtraInfos.begin(), availableExtraInfos.end(),
1666 outputExtraInfo) - availableExtraInfos.begin();
1668 if (indexRanking == availableExtraInfos.size() or indexOutput == availableExtraInfos.size()) {
1669 string strAvailableForIsRightTrack;
1670 for (
const auto& name : availableForIsRightTrack)
1671 strAvailableForIsRightTrack += name +
" ";
1672 string strAvailableForIsRightCategory;
1673 for (
const auto& name : availableForIsRightCategory)
1674 strAvailableForIsRightCategory += name +
" ";
1676 B2FATAL(
"QpOf: Not available category " << rankingExtraInfo <<
1677 ". The possibilities for isRightTrack() are " << endl << strAvailableForIsRightTrack <<
" MaximumPstar" << endl <<
1678 "The possibilities for isRightCategory() are " << endl << strAvailableForIsRightCategory);
1681 auto func = [particleListName, indexOutput, indexRanking](
const Particle*) ->
double {
1682 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1683 if (!ListOfParticles.isValid())
return 0;
1685 Particle* target =
nullptr;
1686 double maximumTargetProb = 0;
1687 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1689 Particle* particlei = ListOfParticles->getParticle(i);
1690 if (!particlei)
continue;
1692 double target_prob = 0;
1693 if (indexRanking == 9 || indexRanking == 20) {
1694 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
1695 if (momParticlei == momParticlei) {
1696 target_prob = momParticlei.P();
1699 if (particlei->hasExtraInfo(availableExtraInfos[indexRanking])) {
1700 target_prob = particlei->getExtraInfo(availableExtraInfos[indexRanking]);
1704 if (target_prob > maximumTargetProb) {
1705 maximumTargetProb = target_prob;
1711 if (!target)
return 0;
1715 if (indexRanking == 10 || indexRanking == 21)
1717 qTarget = (-1) * target->getPDGCode() / abs(target->getPDGCode());
1719 }
else if (indexRanking == 1 || indexRanking == 3 || indexRanking == 5 || indexRanking == 7 ||
1720 indexRanking == 12 || indexRanking == 14 || indexRanking == 16 || indexRanking == 18)
1722 qTarget = (-1) * target->getCharge();
1725 qTarget = target->getCharge();
1729 double prob = target->getExtraInfo(availableExtraInfos[indexOutput]);
1733 return qTarget * prob;
1738 Manager::FunctionPtr weightedQpOf(
const std::vector<std::string>& arguments)
1740 if (arguments.size() != 3) {
1741 B2FATAL(
"Wrong number of arguments (3 required) for meta function weightedQpOf");
1746 auto particleListName = arguments[0];
1747 auto outputExtraInfo = arguments[1];
1748 auto rankingExtraInfo = arguments[2];
1751 unsigned indexRanking = find(availableExtraInfos.begin(), availableExtraInfos.end(),
1752 rankingExtraInfo) - availableExtraInfos.begin();
1753 unsigned indexOutput = find(availableExtraInfos.begin(), availableExtraInfos.end(),
1754 outputExtraInfo) - availableExtraInfos.begin();
1757 if (indexRanking == availableExtraInfos.size() or indexOutput == availableExtraInfos.size()) {
1758 string strAvailableForIsRightTrack;
1759 for (
const auto& name : availableForIsRightTrack)
1760 strAvailableForIsRightTrack += name +
" ";
1761 string strAvailableForIsRightCategory;
1762 for (
const auto& name : availableForIsRightCategory)
1763 strAvailableForIsRightCategory += name +
" ";
1765 B2FATAL(
"weightedQpOf: Not available category " << rankingExtraInfo <<
1766 ". The possibilities for isRightTrack() are " << endl << strAvailableForIsRightTrack <<
" MaximumPstar" << endl <<
1767 "The possibilities for isRightCategory() are " << endl << strAvailableForIsRightCategory);
1771 auto func = [particleListName, indexOutput, indexRanking, rankingExtraInfo](
const Particle*) ->
double {
1773 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1774 if (!ListOfParticles)
return 0;
1775 if (ListOfParticles->getListSize() == 0)
return 0;
1778 auto compare = [rankingExtraInfo](
const Particle * part1,
const Particle * part2)->
bool {
1781 if (part1->hasExtraInfo(rankingExtraInfo)) info1 = part1->getExtraInfo(rankingExtraInfo);
1782 if (part2->hasExtraInfo(rankingExtraInfo)) info2 = part2->getExtraInfo(rankingExtraInfo);
1783 return (info1 > info2);
1786 auto compareMomentum = [rankingExtraInfo](
const Particle * part1,
const Particle * part2)->
bool {
1787 double info1 = PCmsLabTransform::labToCms(part1->get4Vector()).P();
1788 double info2 = PCmsLabTransform::labToCms(part2->get4Vector()).P();
1789 return (info1 > info2);
1792 std::vector<const Particle*> ParticleVector(ListOfParticles->getListSize());
1793 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1795 ParticleVector[i] = ListOfParticles->getParticle(i);
1798 if (indexRanking == 9 || indexRanking == 20)
1799 std::sort(ParticleVector.begin(), ParticleVector.end(), compareMomentum);
1801 std::sort(ParticleVector.begin(), ParticleVector.end(), compare);
1804 double final_value = 0.0;
1805 if (ParticleVector.size() != 0) final_value = 1.0;
1808 int Limit = min(3,
int(ParticleVector.size()));
1811 for (
int i = 0; i < Limit; ++i)
1813 if (ParticleVector[i]->hasExtraInfo(availableExtraInfos[indexOutput])) {
1814 double flavor = 0.0;
1815 if (indexRanking == 10 || indexRanking == 21) {
1816 flavor = - copysign(1, ParticleVector[i]->getPDGCode());
1818 }
else if (indexRanking == 1 || indexRanking == 3 || indexRanking == 5 || indexRanking == 7 ||
1819 indexRanking == 12 || indexRanking == 14 || indexRanking == 16 || indexRanking == 18) {
1820 flavor = - ParticleVector[i]->getCharge();
1822 flavor = + ParticleVector[i]->getCharge();
1825 double p = ParticleVector[i]->getExtraInfo(availableExtraInfos[indexOutput]);
1828 double qp = (flavor * p);
1833 final_value = (val1 - val2) / (val1 + val2);
1840 Manager::FunctionPtr variableOfTarget(
const std::vector<std::string>& arguments)
1843 if (arguments.size() != 3)
1844 B2FATAL(
"Wrong number of arguments (3 required) for meta function variableOfTarget");
1846 std::string particleListName = arguments[0];
1847 std::string inputVariable = arguments[1];
1848 std::string rankingExtraInfo = arguments[2];
1850 int indexRanking = -1;
1852 for (
unsigned i = 0; i < availableExtraInfos.size(); ++i) {
1853 if (rankingExtraInfo == availableExtraInfos[i]) {indexRanking = i;
break;}
1856 if (indexRanking == -1) {
1857 string strAvailableForIsRightTrack;
1858 for (
const auto& name : availableForIsRightTrack)
1859 strAvailableForIsRightTrack += name +
" ";
1860 string strAvailableForIsRightCategory;
1861 for (
const auto& name : availableForIsRightCategory)
1862 strAvailableForIsRightCategory += name +
" ";
1864 B2FATAL(
"variableOfTarget: Not available category " << rankingExtraInfo <<
1865 ". The possibilities for isRightTrack() are " << endl << strAvailableForIsRightTrack <<
" MaximumPstar" << endl <<
1866 "The possibilities for isRightCategory() are " << endl << strAvailableForIsRightCategory);
1869 const Variable::Manager::Var* var = Manager::Instance().getVariable(inputVariable);
1870 auto func = [particleListName, var, indexRanking](
const Particle*) ->
double {
1871 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1872 if (!ListOfParticles.isValid())
return realNaN;
1874 Particle* target =
nullptr;
1876 double maximumTargetProb = 0;
1877 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1879 Particle* particlei = ListOfParticles->getParticle(i);
1880 if (!particlei)
continue;
1882 double target_prob = 0;
1883 if (indexRanking == 9 || indexRanking == 20) {
1884 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
1885 if (momParticlei == momParticlei) {
1886 target_prob = momParticlei.P();
1889 if (particlei->hasExtraInfo(availableExtraInfos[indexRanking])) {
1890 target_prob = particlei->getExtraInfo(availableExtraInfos[indexRanking]);
1893 if (target_prob > maximumTargetProb) {
1894 maximumTargetProb = target_prob;
1900 if (!target)
return realNaN;
1902 if (std::holds_alternative<double>(var->function(target)))
1904 return std::get<double>(var->function(target));
1905 }
else if (std::holds_alternative<int>(var->function(target)))
1907 return std::get<int>(var->function(target));
1908 }
else if (std::holds_alternative<bool>(var->function(target)))
1910 return std::get<bool>(var->function(target));
1911 }
else return realNaN;
1916 Manager::FunctionPtr hasTrueTarget(
const std::vector<std::string>& arguments)
1918 if (arguments.size() != 1) {
1919 B2FATAL(
"Wrong number of arguments (1 required) for meta function hasTrueTarget");
1922 auto categoryName = arguments[0];
1924 bool isAvailable =
false;
1925 for (
const auto& name : availableForIsRightCategory) {
1926 if (categoryName == name) {
1931 if (categoryName ==
"mcAssociated")
1932 isAvailable =
false;
1935 string strAvailableForIsRightCategory;
1936 for (
const auto& name : availableForIsRightCategory) {
1937 if (name ==
"mcAssociated")
continue;
1938 strAvailableForIsRightCategory += name +
" ";
1940 B2FATAL(
"hasTrueTarget: Not available category" << categoryName <<
1941 ". The possibilities for the category name are " << endl << strAvailableForIsRightCategory);
1944 auto func = [categoryName](
const Particle*) ->
double {
1945 std::string particleListName;
1946 std::string trackTargetName = categoryName;
1948 if (categoryName ==
"Electron" || categoryName ==
"IntermediateElectron") particleListName =
"e+:inRoe";
1949 else if (categoryName ==
"Muon" || categoryName ==
"IntermediateMuon" || categoryName ==
"KinLepton" || categoryName ==
"IntermediateKinLepton") particleListName =
"mu+:inRoe";
1950 else if (categoryName ==
"Kaon" || categoryName ==
"KaonPion") {particleListName =
"K+:inRoe"; trackTargetName =
"Kaon";}
1951 else if (categoryName ==
"Lambda") particleListName =
"Lambda0:inRoe";
1952 else particleListName =
"pi+:inRoe";
1954 if (categoryName ==
"FSC") trackTargetName =
"SlowPion";
1956 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1957 if (!ListOfParticles.isValid())
return realNaN;
1959 Variable::Manager& manager = Variable::Manager::Instance();
1961 bool particlesHaveMCAssociated =
false;
1963 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1965 Particle* iParticle = ListOfParticles->getParticle(i);
1966 if (!iParticle)
continue;
1968 if (categoryName ==
"MaximumPstar") {
1969 static Manager::FunctionPtr selectionFunction =
1970 hasHighestProbInCat({
"pi+:inRoe",
"isRightTrack(MaximumPstar)"});
1971 bool targetFlag = std::get<bool>(selectionFunction(iParticle));
1973 particlesHaveMCAssociated =
true;
1977 int targetFlag = std::get<int>(manager.getVariable(
"isRightTrack(" + trackTargetName +
")")->function(iParticle));
1978 if (targetFlag != -2) particlesHaveMCAssociated =
true;
1979 if (targetFlag == 1) ++nTargets;
1983 if (!particlesHaveMCAssociated)
return realNaN;
1984 return (nTargets > 0);
1989 Manager::FunctionPtr isTrueCategory(
const std::vector<std::string>& arguments)
1991 if (arguments.size() != 1) {
1992 B2FATAL(
"Wrong number of arguments (1 required) for meta function isTrueCategory");
1994 auto categoryName = arguments[0];
1996 bool isAvailable =
false;
1997 for (
const auto& name : availableForIsRightCategory) {
1998 if (categoryName == name) {
2003 if (categoryName ==
"mcAssociated")
2004 isAvailable =
false;
2007 string strAvailableForIsRightCategory;
2008 for (
const auto& name : availableForIsRightCategory) {
2009 if (name ==
"mcAssociated")
continue;
2010 strAvailableForIsRightCategory += name +
" ";
2012 B2FATAL(
"isTrueCategory: Not available category" << categoryName <<
2013 ". The possibilities for the category name are " << endl << strAvailableForIsRightCategory);
2016 auto func = [categoryName](
const Particle*) ->
double {
2017 std::string particleListName;
2018 std::string trackTargetName = categoryName;
2020 if (categoryName ==
"Electron" || categoryName ==
"IntermediateElectron") particleListName =
"e+:inRoe";
2021 else if (categoryName ==
"Muon" || categoryName ==
"IntermediateMuon" || categoryName ==
"KinLepton" || categoryName ==
"IntermediateKinLepton") particleListName =
"mu+:inRoe";
2022 else if (categoryName ==
"Kaon" || categoryName ==
"KaonPion") {particleListName =
"K+:inRoe"; trackTargetName =
"Kaon";}
2023 else if (categoryName ==
"Lambda") particleListName =
"Lambda0:inRoe";
2024 else particleListName =
"pi+:inRoe";
2026 if (categoryName ==
"FSC") trackTargetName =
"SlowPion";
2028 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
2029 if (!ListOfParticles.isValid())
return realNaN;
2031 std::vector<Particle*> targetParticles;
2032 std::vector<Particle*> targetParticlesCategory;
2033 Variable::Manager& manager = Variable::Manager::Instance();
2038 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
2040 Particle* iParticle = ListOfParticles->getParticle(i);
2041 if (!iParticle)
continue;
2043 if (categoryName ==
"MaximumPstar") {
2044 static Manager::FunctionPtr selectionFunction =
2045 hasHighestProbInCat({
"pi+:inRoe",
"isRightTrack(MaximumPstar)"});
2046 if (std::get<bool>(selectionFunction(iParticle)))
2047 targetParticles.push_back(iParticle);
2048 }
else if (std::get<int>(manager.getVariable(
"isRightTrack(" + trackTargetName +
")")->function(iParticle))) {
2049 targetParticles.push_back(iParticle);
2053 for (
const auto& targetParticle : targetParticles)
2055 int isTargetOfRightCategory = std::get<int>(manager.getVariable(
"isRightCategory(" + categoryName +
")")->function(
2057 if (isTargetOfRightCategory == 1) {
2059 nTargets += 1; targetParticlesCategory.push_back(targetParticle);
2060 }
else if (isTargetOfRightCategory == -2 && output != 1)
2084 Manager::FunctionPtr qrOutput(
const std::vector<std::string>& arguments)
2086 if (arguments.size() != 1)
2087 B2FATAL(
"Wrong number of arguments for meta function qrOutput");
2089 std::string combinerMethod = arguments[0];
2090 auto func = [combinerMethod](
const Particle * particle) ->
double {
2092 double output = realNaN;
2093 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2095 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2096 output = flavorTaggerInfo->getMethodMap(combinerMethod)->getQrCombined();
2103 Manager::FunctionPtr qOutput(
const std::vector<std::string>& arguments)
2105 if (arguments.size() != 1)
2106 B2FATAL(
"Wrong number of arguments for meta function qOutput");
2108 std::string combinerMethod = arguments[0];
2109 auto func = [combinerMethod](
const Particle * particle) ->
double {
2111 double output = realNaN;
2112 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2114 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2115 output = TMath::Sign(1, flavorTaggerInfo->getMethodMap(combinerMethod)->getQrCombined());
2122 Manager::FunctionPtr rBinBelle(
const std::vector<std::string>& arguments)
2124 if (arguments.size() != 1)
2125 B2FATAL(
"Wrong number of arguments for meta function rBinBelle");
2128 std::string combinerMethod = arguments[0];
2129 auto func = [combinerMethod](
const Particle * particle) ->
int {
2132 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2134 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2136 double r = std::abs(flavorTaggerInfo->getMethodMap(combinerMethod)->getQrCombined());
2137 if (r < 0.1) output = 0;
2138 if (r > 0.1 && r < 0.25) output = 1;
2139 if (r > 0.25 && r < 0.5) output = 2;
2140 if (r > 0.5 && r < 0.625) output = 3;
2141 if (r > 0.625 && r < 0.75) output = 4;
2142 if (r > 0.75 && r < 0.875) output = 5;
2143 if (r > 0.875 && r < 1.10) output = 6;
2151 Manager::FunctionPtr qpCategory(
const std::vector<std::string>& arguments)
2153 if (arguments.size() != 1)
2154 B2FATAL(
"Wrong number of arguments for meta function qpCategory");
2156 std::string categoryName = arguments[0];
2157 auto func = [categoryName](
const Particle * particle) ->
double {
2159 double output = realNaN;
2160 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2162 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2164 std::map<std::string, float> iQpCategories = flavorTaggerInfo->getMethodMap(
"FBDT")->getQpCategory();
2165 if (iQpCategories.find(categoryName) != iQpCategories.end()) output = iQpCategories.at(categoryName);
2166 else if (iQpCategories.size() != 0) B2FATAL(
"qpCategory: Category with name " << categoryName
2167 <<
" not found. Check the official category names or if this category is included in the flavor tagger categories list.");
2174 Manager::FunctionPtr isTrueFTCategory(
const std::vector<std::string>& arguments)
2176 if (arguments.size() != 1)
2177 B2FATAL(
"Wrong number of arguments for meta function isTrueFTCategory");
2179 std::string categoryName = arguments[0];
2180 auto func = [categoryName](
const Particle * particle) ->
double {
2182 double output = realNaN;
2183 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2185 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2187 std::map<std::string, float> iIsTrueCategories = flavorTaggerInfo->getMethodMap(
"FBDT")->getIsTrueCategory();
2188 if (iIsTrueCategories.find(categoryName) != iIsTrueCategories.end()) output = iIsTrueCategories.at(categoryName);
2189 else if (iIsTrueCategories.size() != 0) B2FATAL(
"isTrueFTCategory: Category with name " << categoryName
2190 <<
" not found. Check the official category names or if this category is included in the flavor tagger categories list.");
2198 Manager::FunctionPtr hasTrueTargets(
const std::vector<std::string>& arguments)
2200 if (arguments.size() != 1)
2201 B2FATAL(
"Wrong number of arguments for meta function hasTrueTargets");
2203 std::string categoryName = arguments[0];
2204 auto func = [categoryName](
const Particle * particle) ->
double {
2206 double output = realNaN;
2207 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2209 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2211 std::map<std::string, float> iHasTrueTargets = flavorTaggerInfo->getMethodMap(
"FBDT")->getHasTrueTarget();
2212 if (iHasTrueTargets.find(categoryName) != iHasTrueTargets.end()) output = iHasTrueTargets.at(categoryName);
2213 else if (iHasTrueTargets.size() != 0) B2FATAL(
"hasTrueTargets: Category with name " << categoryName
2214 <<
" not found. Check the official category names or if this category is included in the flavor tagger categories list.");
2222 VARIABLE_GROUP(
"Flavor Tagger Expert Variables");
2224 REGISTER_VARIABLE(
"pMissTag", momentumMissingTagSide, R
"DOC(
2225 [Expert] Calculates the missing momentum for a given particle on the tag side.
2228 REGISTER_METAVARIABLE("pMissTag(maskName)", momentumMissingTagSideWithMask,
2229 "[Expert] Calculates the missing momentum for a given particle on the tag side. The unit of the missing momentum is ``GeV/c`` ",
2230 Manager::VariableDataType::c_double);
2231 REGISTER_VARIABLE("cosTPTO" , cosTPTO, R"DOC(
2232 [Expert] Returns cosine of angle between thrust axis of given particle and thrust axis of ROE.
2235 REGISTER_METAVARIABLE("cosTPTO(maskName)", cosTPTOWithMask,
2236 "[Expert] Returns cosine of angle between thrust axis of given particle and thrust axis of ROE.",
2237 Manager::VariableDataType::c_double);
2238 REGISTER_VARIABLE(
"lambdaFlavor", lambdaFlavor,
2239 "[Expert] Returns 1.0 if particle is ``Lambda0``, -1.0 in case of ``anti-Lambda0``, 0.0 otherwise.");
2240 REGISTER_VARIABLE(
"isLambda", isLambda,
"[Expert] Returns 1.0 if particle is truth-matched to ``Lambda0``, 0.0 otherwise.");
2241 REGISTER_VARIABLE(
"lambdaZError", lambdaZError,
"[Expert] Returns the variance of the z-component of the decay vertex.",
":math:`\\text{cm}^2`");
2242 REGISTER_VARIABLE(
"momentumOfSecondDaughter", momentumOfSecondDaughter,
2243 "[Expert] Returns the momentum of second daughter if exists, 0. otherwise.",
"GeV/c");
2244 REGISTER_VARIABLE(
"momentumOfSecondDaughterCMS", momentumOfSecondDaughterCMS,
2245 "[Expert] Returns the momentum of the second daughter in the centre-of-mass system, 0. if this daughter doesn't exist.",
"GeV/c");
2246 REGISTER_VARIABLE(
"chargeTimesKaonLiklihood", chargeTimesKaonLiklihood,
2247 "[Expert] Returns ``q*(highest PID_Likelihood for Kaons)``, 0. otherwise.");
2248 REGISTER_VARIABLE(
"ptTracksRoe", transverseMomentumOfChargeTracksInRoe, R
"DOC(
2249 [Expert] Returns the transverse momentum of all charged tracks of the ROE related to the given particle, 0.0 if particle has no related ROE.
2252 REGISTER_METAVARIABLE("ptTracksRoe(maskName)", transverseMomentumOfChargeTracksInRoeWithMask,
2253 "[Expert] Returns the transverse momentum of all charged tracks of the ROE related to the given particle, 0.0 if particle has no related ROE. The unit of the momentum is ``GeV/c`` ",
2254 Manager::VariableDataType::c_double);
2255 REGISTER_METAVARIABLE("pt2TracksRoe(maskName)", transverseMomentumSquaredOfChargeTracksInRoeWithMask,
2256 "[Expert] Returns the transverse momentum squared of all charged tracks of the ROE related to the given particle, 0.0 if particle has no related ROE. The unit of the momentum squared is :math:`[\\text{GeV}/\\text{c}]^2` ",
2257 Manager::VariableDataType::c_double);
2258 REGISTER_VARIABLE("NumberOfKShortsInRoe", NumberOfKShortsInRoe,
2259 "[Expert] Returns the number of ``K_S0`` in the rest of event. The particle list ``K_S0:inRoe`` has to be filled beforehand.");
2261 REGISTER_VARIABLE("isInElectronOrMuonCat", isInElectronOrMuonCat,
2262 "[Expert] Returns 1.0 if the particle has been selected as target in the Muon or Electron Category, 0.0 otherwise.");
2264 REGISTER_VARIABLE("isMajorityInRestOfEventFromB0", isMajorityInRestOfEventFromB0, R"DOC(
2265 [Eventbased][Expert] Checks if the majority of the tracks in the current RestOfEvent are from a ``B0``.
2268 REGISTER_METAVARIABLE("isMajorityInRestOfEventFromB0(maskName)", isMajorityInRestOfEventFromB0WithMask,
2269 "[Eventbased][Expert] Checks if the majority of the tracks in the current RestOfEvent are from a ``B0``.",
2270 Manager::VariableDataType::c_bool);
2271 REGISTER_VARIABLE(
"isMajorityInRestOfEventFromB0bar", isMajorityInRestOfEventFromB0bar, R
"DOC(
2272 [Eventbased][Expert] Check if the majority of the tracks in the current RestOfEvent are from a ``anti-B0``.
2275 REGISTER_METAVARIABLE("isMajorityInRestOfEventFromB0bar(maskName)", isMajorityInRestOfEventFromB0barWithMask,
2276 "[Eventbased][Expert] Check if the majority of the tracks in the current RestOfEvent are from a ``anti-B0``.",
2277 Manager::VariableDataType::c_bool);
2278 REGISTER_VARIABLE(
"hasRestOfEventTracks", hasRestOfEventTracks, R
"DOC(
2279 [Expert] Returns the number of tracks in the RestOfEvent related to the given Particle. -2 if the RestOfEvent is empty.
2282 REGISTER_METAVARIABLE("hasRestOfEventTracks(maskName)", hasRestOfEventTracksWithMask,
2283 "[Expert] Returns the number of tracks in the RestOfEvent related to the given Particle. -2 if the RestOfEvent is empty.",
2284 Manager::VariableDataType::c_bool);
2286 REGISTER_VARIABLE(
"qrCombined", isRestOfEventB0Flavor, R
"DOC(
2287 [Eventbased][Expert] Returns -1 (1) if current RestOfEvent is related to a ``anti-B0`` (``B0``).
2288 The ``MCError`` bit of Breco has to be 0, 1, 2, 16 or 1024.
2289 The output of the variable is 0 otherwise.
2290 If one particle in the RestOfEvent is found to belong to the reconstructed ``B0``, the output is -2(2) for a ``anti-B0`` (``B0``) on the reconstructed side.
2292 REGISTER_VARIABLE("ancestorHasWhichFlavor", ancestorHasWhichFlavor,
2293 "[Expert] Checks the decay chain of the given particle upwards up to the ``Upsilon(4S)`` resonance and outputs 0 (1) if an ancestor is found to be a ``anti-B0`` (``B0``), if not -2.");
2294 REGISTER_VARIABLE(
"B0mcErrors", B0mcErrors,
"[Expert] Returns MC-matching flag, see :b2:var:`mcErrors` for the particle, e.g. ``B0`` .");
2295 REGISTER_VARIABLE(
"isRelatedRestOfEventMajorityB0Flavor", isRelatedRestOfEventMajorityB0Flavor, R
"DOC(
2296 [Expert] Returns 0 (1) if the majority of tracks and clusters of the RestOfEvent related to the given Particle are related to a ``anti-B0`` (``B0``).
2299 REGISTER_METAVARIABLE("isRelatedRestOfEventMajorityB0Flavor(maskName)", isRelatedRestOfEventMajorityB0FlavorWithMask,
2300 "[Expert] Returns 0 (1) if the majority of tracks and clusters of the RestOfEvent related to the given Particle are related to a ``anti-B0`` (``B0``).",
2301 Manager::VariableDataType::c_int);
2302 REGISTER_VARIABLE(
"isRestOfEventMajorityB0Flavor", isRestOfEventMajorityB0Flavor,
2303 "[Expert] Returns 0 (1) if the majority of tracks and clusters of the current RestOfEvent are related to a ``anti-B0`` (``B0``).");
2304 REGISTER_VARIABLE(
"mcFlavorOfOtherB", mcFlavorOfOtherB, R
"DOC(
2305 [Expert] Returns the MC flavor (+1 or -1) of the accompanying tag-side B meson if the given particle is a correctly truth-matched B candidate, 0 otherwise.
2306 In other words, this variable checks the generated flavor of the other generated ``Upsilon(4S)`` daughter.
2310 REGISTER_METAVARIABLE("BtagToWBosonVariables(requestedVariable[, maskName])", BtagToWBosonVariables, R
"DOC(
2311 [Eventbased][Expert] Returns values of FlavorTagging-specific kinematical variables assuming a semileptonic decay with the given particle as target.
2312 The input values of ``requestedVariable`` can be the following: recoilMass in GeV/c^2 , pMissCMS in ``GeV/c``, cosThetaMissCMS and EW90.
2313 )DOC", Manager::VariableDataType::c_double);
2314 REGISTER_METAVARIABLE("KaonPionVariables(requestedVariable)" , KaonPionVariables , R
"DOC(
2315 [Expert] Returns values of FlavorTagging-specific kinematical variables for ``KaonPion`` category.
2316 The input values of ``requestedVariable`` can be the following: cosKaonPion, HaveOpositeCharges.
2317 )DOC", Manager::VariableDataType::c_double);
2318 REGISTER_METAVARIABLE("FSCVariables(requestedVariable)", FSCVariables, R
"DOC(
2319 [Eventbased][Expert] Returns values of FlavorTagging-specific kinematical variables for ``FastSlowCorrelated`` category.
2320 The input values of ``requestedVariable`` can be the following: pFastCMS in ``GeV/c``, cosSlowFast, SlowFastHaveOpositeCharges, or cosTPTOFast.
2321 )DOC", Manager::VariableDataType::c_double);
2322 REGISTER_METAVARIABLE("hasHighestProbInCat(particleListName, extraInfoName)", hasHighestProbInCat, R
"DOC(
2323 [Expert] Returns 1.0 if the given Particle is classified as target track, i.e. if it has the highest target track probability in particleListName.
2324 The probability is accessed via ``extraInfoName``, which can have the following input values:
2326 * isRightTrack(Electron),
2327 * isRightTrack(IntermediateElectron),
2328 * isRightTrack(Muon),
2329 * isRightTrack(IntermediateMuon),
2330 * isRightTrack(KinLepton),
2331 * isRightTrack(IntermediateKinLepton),
2332 * isRightTrack(Kaon),
2333 * isRightTrack(SlowPion),
2334 * isRightTrack(FastHadron),
2335 * isRightTrack(MaximumPstar),
2336 * isRightTrack(Lambda),
2337 * isRightCategory(Electron),
2338 * isRightCategory(IntermediateElectron),
2339 * isRightCategory(Muon),
2340 * isRightCategory(IntermediateMuon),
2341 * isRightCategory(KinLepton),
2342 * isRightCategory(IntermediateKinLepton),
2343 * isRightCategory(Kaon),
2344 * isRightCategory(SlowPion),
2345 * isRightCategory(FastHadron),
2346 * isRightCategory(MaximumPstar),
2347 * isRightCategory(Lambda),
2348 * isRightCategory(KaonPion),
2349 * isRightCategory(FSC).
2351 )DOC", Manager::VariableDataType::c_bool);
2352 REGISTER_METAVARIABLE("HighestProbInCat(particleListName, extraInfoName)", HighestProbInCat,
2353 "[Expert] Returns the highest target track probability value for the given category, for allowed input values for ``extraInfoName`` see :b2:var:`hasHighestProbInCat`.", Manager::VariableDataType::c_double);
2355 REGISTER_METAVARIABLE(
"isRightTrack(particleName)", isRightTrack, R
"DOC(
2356 [Expert] Returns 1.0 if the given particle was really from a B-meson depending on category provided in ``particleName`` argument, 0.0 otherwise.
2357 Allowed input values for ``particleName`` argument in this variable are the following:
2360 * IntermediateElectron,
2364 * IntermediateKinLepton,
2371 )DOC", Manager::VariableDataType::c_int);
2372 REGISTER_METAVARIABLE("isRightCategory(particleName)", isRightCategory, R
"DOC(
2373 [Expert] Returns 1.0 if the class track by ``particleName`` category has the same flavor as the MC target track, 0.0 otherwise.
2374 Allowed input values for ``particleName`` argument in this variable are the following:
2377 * IntermediateElectron,
2381 * IntermediateKinLepton
2391 )DOC", Manager::VariableDataType::c_int);
2392 REGISTER_METAVARIABLE("QpOf(particleListName, outputExtraInfo, rankingExtraInfo)", QpOf, R
"DOC(
2393 [Eventbased][Expert] Returns the :math:`q*p` value for a given particle list provided as the 1st argument,
2394 where :math:`p` is the probability of a category stored as extraInfo, provided as the 2nd argument,
2395 allowed values are same as in :b2:var:`hasHighestProbInCat`.
2396 The particle is selected after ranking according to a flavor tagging extraInfo, provided as the 3rd argument,
2397 allowed values are same as in :b2:var:`hasHighestProbInCat`.
2398 )DOC", Manager::VariableDataType::c_double);
2399 REGISTER_METAVARIABLE("weightedQpOf(particleListName, outputExtraInfo, rankingExtraInfo)", weightedQpOf, R
"DOC(
2400 [Eventbased][Expert] Returns the weighted :math:`q*p` value for a given particle list, provided as the 1st argument,
2401 where :math:`p` is the probability of a category stored as extraInfo, provided in the 2nd argument,
2402 allowed values are same as in :b2:var:`hasHighestProbInCat`.
2403 The particles in the list are ranked according to a flavor tagging extraInfo, provided as the 3rd argument,
2404 allowed values are same as in :b2:var:`hasHighestProbInCat`.
2405 The values for the three top particles is combined into an effective (weighted) output.
2406 )DOC", Manager::VariableDataType::c_double);
2407 REGISTER_METAVARIABLE("variableOfTarget(particleListName, inputVariable, rankingExtraInfo)", variableOfTarget, R
"DOC(
2408 [Eventbased][Expert] Returns the value of an input variable provided as the 2nd argument for a particle selected from the given list provided as the 1st argument.
2409 The particles are ranked according to a flavor tagging extraInfo, provided as the 2nd argument,
2410 allowed values are same as in :b2:var:`hasHighestProbInCat`.
2411 )DOC", Manager::VariableDataType::c_double);
2413 REGISTER_METAVARIABLE("hasTrueTarget(categoryName)", hasTrueTarget,
2414 "[Expert] Returns 1 if the given category has a target, 0 otherwise.", Manager::VariableDataType::c_double);
2415 REGISTER_METAVARIABLE(
"isTrueCategory(categoryName)", isTrueCategory,
2416 "[Expert] Returns 1 if the given category tags the B0 MC flavor correctly, 0 otherwise.", Manager::VariableDataType::c_double);
2418 REGISTER_METAVARIABLE(
"qpCategory(categoryName)", qpCategory, R
"DOC(
2419 [Expert] Returns the output :math:`q` (charge of target track) times :math:`p` (probability that this is the right category) of the category with the given name.
2420 The allowed categories are the official Flavor Tagger Category Names.
2421 )DOC", Manager::VariableDataType::c_double);
2422 REGISTER_METAVARIABLE("isTrueFTCategory(categoryName)", isTrueFTCategory, R
"DOC(
2423 [Expert] Returns 1 if the target particle (checking the decay chain) of the category with the given name is found in the MC particles,
2424 and if it provides the right flavor. The allowed categories are the official Flavor Tagger Category Names.
2425 )DOC", Manager::VariableDataType::c_double);
2426 REGISTER_METAVARIABLE("hasTrueTargets(categoryName)", hasTrueTargets, R
"DOC(
2427 [Expert] Returns 1 if target particles (checking only the decay chain) of the category with the given name is found in the MC particles.
2428 The allowed categories are the official Flavor Tagger Category Names.
2429 )DOC", Manager::VariableDataType::c_double);
2431 VARIABLE_GROUP("Flavor Tagger Analysis Variables")
2433 REGISTER_METAVARIABLE("rBinBelle(combinerMethod)", rBinBelle, R"DOC(
2434 Returns the corresponding :math:`r` (dilution) bin according to the Belle binning for the given ``combinerMethod``.
2435 The available methods are 'FBDT' and 'FANN' (category-based combiners), and 'DNN' (DNN tagger output).
2436 The return values and the corresponding dilution ranges are the following:
2438 * 0: :math:`0.000 < r < 0.100`;
2439 * 1: :math:`0.100 < r < 0.250`;
2440 * 2: :math:`0.250 < r < 0.500`;
2441 * 3: :math:`0.500 < r < 0.625`;
2442 * 4: :math:`0.625 < r < 0.750`;
2443 * 5: :math:`0.750 < r < 0.875`;
2444 * 6: :math:`0.875 < r < 1.000`.
2446 .. warning:: You have to run the Flavor Tagger for this variable to be meaningful.
2447 .. seealso:: :ref:`FlavorTagger` and :func:`flavorTagger.flavorTagger`.
2448 )DOC", Manager::VariableDataType::c_int);
2449 REGISTER_METAVARIABLE("qrOutput(combinerMethod)", qrOutput, R"DOC(
2450 Returns the output of the flavorTagger, flavor tag :math:`q` times the dilution factor :math:`r`, for the given combiner method.
2451 The available methods are 'FBDT' and 'FANN' (category-based combiners), and 'DNN' (DNN tagger output).
2453 .. warning:: You have to run the Flavor Tagger for this variable to be meaningful.
2454 .. seealso:: :ref:`FlavorTagger` and :func:`flavorTagger.flavorTagger`.
2455 )DOC", Manager::VariableDataType::c_double);
2456 REGISTER_METAVARIABLE("qOutput(combinerMethod)", qOutput, R"DOC(
2457 Returns the flavor tag :math:`q` output of the flavorTagger for the given combinerMethod.
2458 The available methods are 'FBDT' and 'FANN' (category-based combiners), and 'DNN' (DNN tagger output).
2460 .. warning:: You have to run the Flavor Tagger for this variable to be meaningful.
2461 .. seealso:: :ref:`FlavorTagger` and :func:`flavorTagger.flavorTagger`.
2462 )DOC", Manager::VariableDataType::c_double);
2463 REGISTER_VARIABLE("isRelatedRestOfEventB0Flavor", isRelatedRestOfEventB0Flavor, R"DOC(
2464 Returns -1 (1) if the RestOfEvent related to the given particle is related to a ``anti-B0`` (``B0``).
2465 The ``MCError`` bit of Breco has to be 0, 1, 2, 16 or 1024.
2466 The output of the variable is 0 otherwise.
2467 If one particle in the RestOfEvent is found to belong to the reconstructed ``B0``, the output is -2(2) for a ``anti-B0`` (``B0``) on the reconstructed side.
const MCParticle * getMCParticle() const
Returns the pointer to the MCParticle object that was used to create this Particle (ParticleType == c...
FROM * getRelatedFrom(const std::string &name="", const std::string &namedRelation="") const
Get the object from which this object has a relation.
B2Vector3< double > B2Vector3D
typedef for common usage with double
MCParticle * getMother() const
Returns a pointer to the mother particle.
std::string particleName(int pdgCode)
Returns the name of a particle with given pdg code.
Abstract base class for different kinds of events.