10 #include <analysis/variables/FlavorTaggingVariables.h>
12 #include <analysis/variables/MCTruthVariables.h>
13 #include <analysis/variables/KLMClusterVariables.h>
15 #include <analysis/ClusterUtility/ClusterUtils.h>
17 #include <analysis/utility/MCMatching.h>
18 #include <analysis/utility/PCmsLabTransform.h>
21 #include <framework/datastore/StoreObjPtr.h>
24 #include <analysis/dataobjects/Particle.h>
25 #include <analysis/dataobjects/RestOfEvent.h>
26 #include <analysis/dataobjects/ParticleList.h>
27 #include <analysis/dataobjects/FlavorTaggerInfo.h>
28 #include <analysis/ContinuumSuppression/Thrust.h>
30 #include <mdst/dataobjects/MCParticle.h>
31 #include <mdst/dataobjects/Track.h>
32 #include <mdst/dataobjects/ECLCluster.h>
33 #include <mdst/dataobjects/KLMCluster.h>
34 #include <mdst/dataobjects/PIDLikelihood.h>
37 #include <framework/gearbox/Const.h>
38 #include <framework/logging/Logger.h>
40 #include <Math/Vector3D.h>
41 #include <Math/Vector4D.h>
42 #include <framework/geometry/B2Vector3.h>
56 static const double realNaN = std::numeric_limits<double>::quiet_NaN();
61 double momentumMissingTagSide(
const Particle*)
63 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
64 if (!roe.isValid())
return 0;
66 ROOT::Math::PxPyPzEVector roeCMSVec;
68 const auto& roeChargedParticles = roe->getChargedParticles();
69 for (
auto roeChargedParticle : roeChargedParticles) {
70 roeCMSVec += PCmsLabTransform::labToCms(roeChargedParticle->get4Vector());
73 double missMom = -roeCMSVec.P();
77 Manager::FunctionPtr momentumMissingTagSideWithMask(
const std::vector<std::string>& arguments)
80 if (arguments.size() == 0)
81 maskName = RestOfEvent::c_defaultMaskName;
82 else if (arguments.size() == 1)
83 maskName = arguments[0];
85 B2FATAL(
"At most 1 argument (name of mask) accepted.");
87 auto func = [maskName](
const Particle*) ->
double {
88 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
89 if (!roe.isValid())
return 0;
91 ROOT::Math::PxPyPzEVector roeCMSVec;
93 const auto& roeChargedParticles = roe->getChargedParticles(maskName);
94 for (
auto roeChargedParticle : roeChargedParticles)
96 roeCMSVec += PCmsLabTransform::labToCms(roeChargedParticle->get4Vector());
98 double missMom = -roeCMSVec.P();
104 double cosTPTO(
const Particle* part)
106 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
107 if (!roe.isValid())
return 0;
109 std::vector<ROOT::Math::XYZVector> p3_cms_roe;
110 static const double P_MAX(3.2);
114 const auto& roeTracks = roe->getChargedParticles();
115 for (
auto& roeChargedParticle : roeTracks) {
118 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(roeChargedParticle->get4Vector());
119 if (p_cms != p_cms)
continue;
120 if (p_cms.P() > P_MAX)
continue;
121 p3_cms_roe.push_back(p_cms.Vect());
125 const auto& roePhotons = roe->getPhotons();
126 for (
auto& roePhoton : roePhotons) {
127 if (roePhoton->getECLClusterEHypothesisBit() == ECLCluster::EHypothesisBit::c_nPhotons) {
128 ROOT::Math::PxPyPzEVector p_lab = roePhoton->get4Vector();
129 if (p_lab != p_lab)
continue;
130 if (p_lab.P() < 0.05)
continue;
131 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(p_lab);
132 if (p_cms != p_cms)
continue;
133 if (p_cms.P() > P_MAX)
continue;
134 p3_cms_roe.push_back(p_cms.Vect());
138 const auto& roeKlongs = roe->getHadrons();
139 for (
auto& roeKlong : roeKlongs) {
140 if (nKLMClusterTrackMatches(roeKlong) == 0 && !(roeKlong->getKLMCluster()->getAssociatedEclClusterFlag())) {
141 ROOT::Math::PxPyPzEVector p_lab = roeKlong->get4Vector();
142 if (p_lab != p_lab)
continue;
143 if (p_lab.P() < 0.05)
continue;
144 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(p_lab);
145 if (p_cms != p_cms)
continue;
146 if (p_cms.P() > P_MAX)
continue;
147 p3_cms_roe.push_back(p_cms.Vect());
151 const B2Vector3D thrustO = Thrust::calculateThrust(p3_cms_roe);
152 const B2Vector3D pAxis = PCmsLabTransform::labToCms(part->get4Vector()).Vect();
155 if (pAxis == pAxis) result = abs(cos(pAxis.Angle(thrustO)));
160 Manager::FunctionPtr cosTPTOWithMask(
const std::vector<std::string>& arguments)
162 std::string maskName;
163 if (arguments.size() == 0)
164 maskName = RestOfEvent::c_defaultMaskName;
165 else if (arguments.size() == 1)
166 maskName = arguments[0];
168 B2FATAL(
"At most 1 argument (name of mask) accepted.");
170 auto func = [maskName](
const Particle * particle) ->
double {
171 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
172 if (!roe.isValid())
return 0;
174 std::vector<ROOT::Math::XYZVector> p3_cms_roe;
178 const auto& roeTracks = roe->getChargedParticles(maskName);
179 for (
auto& roeChargedParticle : roeTracks)
183 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(roeChargedParticle->get4Vector());
184 if (p_cms != p_cms)
continue;
186 p3_cms_roe.push_back(p_cms.Vect());
190 const auto& roePhotons = roe->getPhotons(maskName);
191 for (
auto& roePhoton : roePhotons)
193 if (roePhoton->getECLClusterEHypothesisBit() == ECLCluster::EHypothesisBit::c_nPhotons) {
194 ROOT::Math::PxPyPzEVector p_lab = roePhoton->get4Vector();
195 if (p_lab != p_lab)
continue;
197 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(p_lab);
198 if (p_cms != p_cms)
continue;
200 p3_cms_roe.push_back(p_cms.Vect());
205 const auto& roeKlongs = roe->getHadrons(maskName);
206 for (
auto& roeKlong : roeKlongs)
208 if (nKLMClusterTrackMatches(roeKlong) == 0 && !(roeKlong->getKLMCluster()->getAssociatedEclClusterFlag())) {
209 ROOT::Math::PxPyPzEVector p_lab = roeKlong->get4Vector();
210 if (p_lab != p_lab)
continue;
212 ROOT::Math::PxPyPzEVector p_cms = PCmsLabTransform::labToCms(p_lab);
213 if (p_cms != p_cms)
continue;
215 p3_cms_roe.push_back(p_cms.Vect());
219 const B2Vector3D thrustO = Thrust::calculateThrust(p3_cms_roe);
220 const B2Vector3D pAxis = PCmsLabTransform::labToCms(particle->get4Vector()).Vect();
224 result = abs(cos(pAxis.Angle(thrustO)));
232 int lambdaFlavor(
const Particle* particle)
234 if (particle->getPDGCode() == Const::Lambda.getPDGCode())
return 1;
235 else if (particle->getPDGCode() == Const::antiLambda.getPDGCode())
return -1;
239 bool isLambda(
const Particle* particle)
242 if (!mcparticle)
return false;
243 return (abs(mcparticle->getPDG()) == Const::Lambda.getPDGCode());
246 double lambdaZError(
const Particle* particle)
250 TMatrixFSym ErrorPositionMatrix = particle->getVertexErrorMatrix();
251 return ErrorPositionMatrix[2][2];
254 double momentumOfSecondDaughter(
const Particle* part)
256 if (!part->getDaughter(1))
return 0.0;
257 return part->getDaughter(1)->getP();
260 double momentumOfSecondDaughterCMS(
const Particle* part)
262 if (!part->getDaughter(1))
return 0.0;
263 ROOT::Math::PxPyPzEVector vec = PCmsLabTransform::labToCms(part->getDaughter(1)->get4Vector());
267 double chargeTimesKaonLiklihood(
const Particle*)
269 StoreObjPtr<ParticleList> KaonList(
"K+:inRoe");
270 if (!KaonList.isValid())
return 0;
272 double maximumKaonid = 0;
273 double maximum_charge = 0;
274 for (
unsigned int i = 0; i < KaonList->getListSize(); ++i) {
275 const Particle* p = KaonList->getParticle(i);
276 double Kid = p->getRelatedTo<PIDLikelihood>()->getProbability(Const::kaon, Const::pion);
277 if (Kid > maximumKaonid) {
279 maximum_charge = p->getCharge();
282 return maximumKaonid * maximum_charge;
285 double transverseMomentumOfChargeTracksInRoe(
const Particle* part)
287 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
288 if (!roe.isValid())
return 0;
292 for (
const auto& track : roe->getChargedParticles()) {
293 if (part->isCopyOf(track,
true))
continue;
294 sum += track->getMomentum().Perp2();
301 Manager::FunctionPtr transverseMomentumOfChargeTracksInRoeWithMask(
const std::vector<std::string>& arguments)
303 std::string maskName;
304 if (arguments.size() == 0)
305 maskName = RestOfEvent::c_defaultMaskName;
306 else if (arguments.size() == 1)
307 maskName = arguments[0];
309 B2FATAL(
"At most 1 argument (name of mask) accepted.");
311 auto func = [maskName](
const Particle * particle) ->
double {
312 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
313 if (!roe.isValid())
return 0;
317 for (
const auto& track : roe->getChargedParticles(maskName))
319 if (particle->isCopyOf(track,
true))
continue;
320 sum += track->getMomentum().Rho();
328 Manager::FunctionPtr transverseMomentumSquaredOfChargeTracksInRoeWithMask(
const std::vector<std::string>& arguments)
330 std::string maskName;
331 if (arguments.size() == 0)
332 maskName = RestOfEvent::c_defaultMaskName;
333 else if (arguments.size() == 1)
334 maskName = arguments[0];
336 B2FATAL(
"At most 1 argument (name of mask) accepted.");
338 auto func = [maskName](
const Particle * particle) ->
double {
339 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
340 if (!roe.isValid())
return 0;
344 for (
const auto& track : roe->getChargedParticles(maskName))
346 if (particle->isCopyOf(track,
true))
continue;
347 sum += track->getMomentum().Perp2();
355 int NumberOfKShortsInRoe(
const Particle* particle)
357 StoreObjPtr<ParticleList> KShortList(
"K_S0:inRoe");
358 if (!KShortList.isValid())
359 B2FATAL(
"NumberOfKShortsInRoe cannot be calculated because the required particleList K_S0:inRoe could not be found or is not valid");
362 for (
unsigned int i = 0; i < KShortList->getListSize(); ++i) {
363 if (!particle->overlapsWith(KShortList->getParticle(i)))
371 bool isInElectronOrMuonCat(
const Particle* particle)
374 StoreObjPtr<ParticleList> MuonList(
"mu+:inRoe");
375 const Track* trackTargetMuon =
nullptr;
376 if (MuonList.isValid()) {
377 double maximumProbMuon = 0;
378 for (
unsigned int i = 0; i < MuonList->getListSize(); ++i) {
379 Particle* pMuon = MuonList->getParticle(i);
380 double probMuon = pMuon->getExtraInfo(
"isRightTrack(Muon)");
381 if (probMuon > maximumProbMuon) {
382 maximumProbMuon = probMuon;
383 trackTargetMuon = pMuon->getTrack();
387 if (particle->getTrack() == trackTargetMuon)
392 StoreObjPtr<ParticleList> ElectronList(
"e+:inRoe");
393 const Track* trackTargetElectron =
nullptr;
394 if (ElectronList.isValid()) {
395 double maximumProbElectron = 0;
396 for (
unsigned int i = 0; i < ElectronList->getListSize(); ++i) {
397 Particle* pElectron = ElectronList->getParticle(i);
398 double probElectron = pElectron->getExtraInfo(
"isRightTrack(Electron)");
399 if (probElectron > maximumProbElectron) {
400 maximumProbElectron = probElectron;
401 trackTargetElectron = pElectron->getTrack();
405 if (particle->getTrack() == trackTargetElectron)
412 static int getB0flavourMC(
const MCParticle* mcParticle)
415 if (mcParticle->getPDG() == 511) {
417 }
else if (mcParticle->getPDG() == -511) {
420 mcParticle = mcParticle->getMother();
427 bool isMajorityInRestOfEventFromB0(
const Particle*)
429 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
430 if (!roe.isValid())
return 0;
433 for (
auto& track : roe->getChargedParticles()) {
434 const MCParticle* mcParticle = track->getMCParticle();
435 vote += getB0flavourMC(mcParticle);
441 Manager::FunctionPtr isMajorityInRestOfEventFromB0WithMask(
const std::vector<std::string>& arguments)
443 std::string maskName;
444 if (arguments.size() == 0)
445 maskName = RestOfEvent::c_defaultMaskName;
446 else if (arguments.size() == 1)
447 maskName = arguments[0];
449 B2FATAL(
"At most 1 argument (name of mask) accepted.");
451 auto func = [maskName](
const Particle*) ->
bool {
452 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
453 if (!roe.isValid())
return 0;
456 for (
auto& track : roe->getChargedParticles(maskName))
458 const MCParticle* mcParticle = track->getMCParticle();
459 vote += getB0flavourMC(mcParticle);
468 bool isMajorityInRestOfEventFromB0bar(
const Particle*)
470 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
471 if (!roe.isValid())
return 0;
474 for (
auto& track : roe->getChargedParticles()) {
475 const MCParticle* mcParticle = track->getMCParticle();
476 vote += getB0flavourMC(mcParticle);
482 Manager::FunctionPtr isMajorityInRestOfEventFromB0barWithMask(
const std::vector<std::string>& arguments)
484 std::string maskName;
485 if (arguments.size() == 0)
486 maskName = RestOfEvent::c_defaultMaskName;
487 else if (arguments.size() == 1)
488 maskName = arguments[0];
490 B2FATAL(
"At most 1 argument (name of mask) accepted.");
492 auto func = [maskName](
const Particle*) ->
bool {
493 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
494 if (!roe.isValid())
return 0;
497 for (
auto& track : roe->getChargedParticles(maskName))
499 const MCParticle* mcParticle = track->getMCParticle();
500 vote += getB0flavourMC(mcParticle);
509 bool hasRestOfEventTracks(
const Particle* part)
511 const RestOfEvent* roe = part->getRelatedTo<RestOfEvent>();
512 return (roe && roe-> getNTracks() > 0);
515 Manager::FunctionPtr hasRestOfEventTracksWithMask(
const std::vector<std::string>& arguments)
517 std::string maskName;
518 if (arguments.size() == 0)
519 maskName = RestOfEvent::c_defaultMaskName;
520 else if (arguments.size() == 1)
521 maskName = arguments[0];
523 B2FATAL(
"At most 1 argument (name of mask) accepted.");
525 auto func = [maskName](
const Particle*) ->
bool {
526 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
527 if (!roe.isValid())
return 0;
529 return roe->getNTracks(maskName) > 0;
534 int isRelatedRestOfEventB0Flavor(
const Particle* particle)
536 const RestOfEvent* roe = particle->getRelatedTo<RestOfEvent>();
540 if (!BcpMC)
return 0;
541 if (Variable::isSignal(particle) <= 0)
return 0;
543 const MCParticle* Y4S = BcpMC->getMother();
549 for (
auto& roeChargedParticle : roe->getChargedParticles()) {
550 const MCParticle* mcParticle = roeChargedParticle->
getMCParticle();
552 if (mcParticle->getMother() == Y4S) {
553 if (mcParticle == BcpMC) {
554 if (mcParticle->getPDG() > 0) BcpFlavor = 2;
556 }
else if (BtagFlavor == 0) {
557 if (abs(mcParticle->getPDG()) == 511 || abs(mcParticle->getPDG()) == 521) {
558 if (mcParticle->getPDG() > 0) BtagFlavor = 1;
559 else BtagFlavor = -1;
560 }
else BtagFlavor = 5;
566 if (BcpFlavor != 0 || BtagFlavor == 5)
break;
570 return (BcpFlavor != 0) ? BcpFlavor : BtagFlavor;
573 Manager::FunctionPtr isRelatedRestOfEventB0FlavorWithMask(
const std::vector<std::string>& arguments)
575 std::string maskName;
576 if (arguments.size() == 0)
577 maskName = RestOfEvent::c_defaultMaskName;
578 else if (arguments.size() == 1)
579 maskName = arguments[0];
581 B2FATAL(
"At most 1 argument (name of mask) accepted.");
583 auto func = [maskName](
const Particle * particle) ->
int {
584 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
585 if (!roe.isValid())
return 0;
588 if (!BcpMC)
return 0;
589 if (Variable::isSignal(particle) <= 0)
return 0;
591 const MCParticle* Y4S = BcpMC->getMother();
597 for (
auto& roeChargedParticle : roe->getChargedParticles(maskName))
599 const MCParticle* mcParticle = roeChargedParticle->
getMCParticle();
601 if (mcParticle->getMother() != Y4S) {
606 if (mcParticle == BcpMC) {
607 if (mcParticle->getPDG() > 0)
611 }
else if (BtagFlavor == 0) {
612 if (abs(mcParticle->getPDG()) == 511 || abs(mcParticle->getPDG()) == 521) {
613 if (mcParticle->getPDG() > 0)
623 if (BcpFlavor != 0 || BtagFlavor == 5)
break;
626 return (BcpFlavor != 0) ? BcpFlavor : BtagFlavor;
632 int isRestOfEventB0Flavor(
const Particle*)
634 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
635 if (!roe.isValid())
return 0;
637 const Particle* Bcp = roe->getRelated<Particle>();
638 return Variable::isRelatedRestOfEventB0Flavor(Bcp);
641 int ancestorHasWhichFlavor(
const Particle* particle)
643 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
644 if (!roe.isValid())
return 0;
646 const MCParticle* BcpMC = roe->
getRelated<Particle>()->getMCParticle();
647 const MCParticle* Y4S = BcpMC->getMother();
650 int outputB0tagQ = 0;
652 if (mcParticle->getMother() == Y4S) {
653 if (mcParticle != BcpMC && abs(mcParticle->getPDG()) == 511) {
654 if (mcParticle->getPDG() == 511) outputB0tagQ = 1;
655 else outputB0tagQ = -1;
656 }
else if (mcParticle == BcpMC) {
657 if (mcParticle->getPDG() == 511) outputB0tagQ = 2;
658 else outputB0tagQ = -2;
659 }
else outputB0tagQ = 5;
668 int B0mcErrors(
const Particle*)
670 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
671 if (!roe.isValid())
return -1;
673 const Particle* Bcp = roe->getRelated<Particle>();
674 const MCParticle* BcpMC = roe->
getRelated<Particle>()->getMCParticle();
675 return MCMatching::getMCErrors(Bcp, BcpMC);
678 int isRelatedRestOfEventMajorityB0Flavor(
const Particle* part)
680 const RestOfEvent* roe = part->getRelatedTo<RestOfEvent>();
685 if (roe->getNTracks() > 0) {
686 for (
auto& track : roe->getChargedParticles()) {
687 const MCParticle* mcParticle = track->getMCParticle();
688 q_MC += getB0flavourMC(mcParticle);
690 }
else if (roe->getNECLClusters() > 0) {
691 for (
auto& cluster : roe->getPhotons()) {
692 if (cluster->getECLClusterEHypothesisBit() != ECLCluster::EHypothesisBit::c_nPhotons)
continue;
693 const MCParticle* mcParticle = cluster->getMCParticle();
694 q_MC += getB0flavourMC(mcParticle);
696 }
else if (roe->getNKLMClusters() > 0) {
697 for (
auto& klmcluster : roe->getHadrons()) {
699 q_MC += getB0flavourMC(mcParticle);
709 Manager::FunctionPtr isRelatedRestOfEventMajorityB0FlavorWithMask(
const std::vector<std::string>& arguments)
711 std::string maskName;
712 if (arguments.size() == 0)
713 maskName = RestOfEvent::c_defaultMaskName;
714 else if (arguments.size() == 1)
715 maskName = arguments[0];
717 B2FATAL(
"At most 1 argument (name of mask) accepted.");
719 auto func = [maskName](
const Particle*) ->
int {
720 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
721 if (!roe.isValid())
return -2;
725 if (roe->getNTracks(maskName) > 0)
727 for (
auto& track : roe->getChargedParticles(maskName)) {
728 const MCParticle* mcParticle = track->getMCParticle();
729 q_MC += getB0flavourMC(mcParticle);
731 }
else if (roe->getNECLClusters(maskName) > 0)
733 for (
auto& cluster : roe->getPhotons(maskName)) {
734 if (cluster->getECLClusterEHypothesisBit() != ECLCluster::EHypothesisBit::c_nPhotons)
continue;
735 const MCParticle* mcParticle = cluster->getMCParticle();
736 q_MC += getB0flavourMC(mcParticle);
738 }
else if (roe->getNKLMClusters(maskName) > 0)
740 for (
auto& klmcluster : roe->getHadrons(maskName)) {
742 q_MC += getB0flavourMC(mcParticle);
749 return int(q_MC > 0);
755 int isRestOfEventMajorityB0Flavor(
const Particle*)
757 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
758 if (!roe.isValid())
return -2;
760 const Particle* Bcp = roe->getRelated<Particle>();
761 return Variable::isRelatedRestOfEventMajorityB0Flavor(Bcp);
764 double mcFlavorOfOtherB(
const Particle* particle)
767 if (std::abs(particle->getPDGCode()) != 511 && std::abs(particle->getPDGCode()) != 521) {
768 B2ERROR(
"MCFlavorOfOtherB: this variable works only for B mesons.\n"
769 "The given particle with PDG code " << particle->getPDGCode() <<
770 " is not a B-meson candidate (PDG code 511 or 521). ");
775 if (!mcParticle)
return realNaN;
777 const MCParticle* mcMother = mcParticle->getMother();
778 if (!mcMother)
return realNaN;
780 if (Variable::isSignal(particle) < 1.0)
return 0;
782 for (
auto& upsilon4SDaughter : mcMother->getDaughters()) {
783 if (upsilon4SDaughter == mcParticle)
continue;
784 return (upsilon4SDaughter->getPDG() > 0) ? 1 : -1;
795 Manager::FunctionPtr BtagToWBosonVariables(
const std::vector<std::string>& arguments)
798 std::string requestedVariable;
799 std::string maskName;
800 if (arguments.size() == 1) {
801 requestedVariable = arguments[0];
802 maskName = RestOfEvent::c_defaultMaskName;
803 }
else if (arguments.size() == 2) {
804 requestedVariable = arguments[0];
805 maskName = arguments[1];
807 B2FATAL(
"Number of arguments must be 1 (requestedVariable) or 2 (requestedVariable, maskName).");
810 const std::vector<string> availableVariables = {
"recoilMass",
817 if (std::find(availableVariables.begin(), availableVariables.end(), requestedVariable) == availableVariables.end()) {
818 B2FATAL(
"Wrong variable " << requestedVariable <<
819 " requested. The possibilities are recoilMass, recoilMassSqrd, pMissCMS, cosThetaMissCMS or EW90");
822 auto func = [requestedVariable, maskName](
const Particle * particle) ->
double {
823 StoreObjPtr<RestOfEvent> roe(
"RestOfEvent");
827 ROOT::Math::PxPyPzEVector momXChargedTracks;
828 const auto& roeChargedParticles = roe->getChargedParticles(maskName);
829 for (
auto& roeChargedParticle : roeChargedParticles)
831 if (roeChargedParticle->isCopyOf(particle,
true))
continue;
832 momXChargedTracks += roeChargedParticle->get4Vector();
835 ROOT::Math::PxPyPzEVector momXNeutralClusters = roe->get4VectorNeutralECLClusters(maskName);
836 const auto& klongs = roe->getHadrons(maskName);
837 for (
auto& klong : klongs)
839 if (nKLMClusterTrackMatches(klong) == 0 && !(klong->getKLMCluster()->getAssociatedEclClusterFlag())) {
840 momXNeutralClusters += klong->get4Vector();
844 ROOT::Math::PxPyPzEVector momX = PCmsLabTransform::labToCms(momXChargedTracks + momXNeutralClusters);
845 ROOT::Math::PxPyPzEVector momTarget = PCmsLabTransform::labToCms(particle->get4Vector());
846 ROOT::Math::PxPyPzEVector momMiss = -(momX + momTarget);
849 if (requestedVariable ==
"recoilMass") output = momX.M();
850 if (requestedVariable ==
"recoilMassSqrd") output = momX.M2();
851 if (requestedVariable ==
"pMissCMS") output = momMiss.P();
852 if (requestedVariable ==
"cosThetaMissCMS") output = momTarget.Vect().Unit().Dot(momMiss.Vect().Unit());
853 if (requestedVariable ==
"EW90")
856 ROOT::Math::PxPyPzEVector momW = momTarget + momMiss;
859 const auto& photons = roe->getPhotons(maskName);
860 for (
auto& photon : photons) {
861 if (PCmsLabTransform::labToCms(photon->get4Vector()).Vect().Dot(momW.Vect()) > 0) {
862 E_W_90 += photon->getECLClusterEnergy();
865 for (
auto& roeChargedParticle : roeChargedParticles) {
866 if (roeChargedParticle->isCopyOf(particle,
true))
869 for (
const ECLCluster& chargedCluster : roeChargedParticle->getTrack()->getRelationsWith<ECLCluster>()) {
871 if (!chargedCluster.hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons))
873 float iEnergy = chargedCluster.getEnergy(ECLCluster::EHypothesisBit::c_nPhotons);
874 if (iEnergy == iEnergy) {
875 if (PCmsLabTransform::labToCms(ClusterUtils().Get4MomentumFromCluster(&chargedCluster,
876 ECLCluster::EHypothesisBit::c_nPhotons)).Vect().Dot(momW.Vect()) > 0)
890 Manager::FunctionPtr KaonPionVariables(
const std::vector<std::string>& arguments)
892 if (arguments.size() != 1)
893 B2FATAL(
"Wrong number of arguments (1 required) for meta function KaonPionVariables");
896 auto requestedVariable = arguments[0];
897 auto func = [requestedVariable](
const Particle * particle) ->
double {
899 StoreObjPtr<ParticleList> SlowPionList(
"pi+:inRoe");
902 if ((requestedVariable !=
"HaveOpositeCharges") && (requestedVariable !=
"cosKaonPion"))
903 B2FATAL(
"Wrong variable " << requestedVariable <<
" requested. The possibilities are cosKaonPion or HaveOpositeCharges");
906 ROOT::Math::PxPyPzEVector momTargetSlowPion;
907 double chargeTargetSlowPion = 0;
908 if (SlowPionList.isValid())
910 double maximumProbSlowPion = 0;
911 for (
unsigned int i = 0; i < SlowPionList->getListSize(); ++i) {
912 Particle* pSlowPion = SlowPionList->getParticle(i);
913 if (!pSlowPion)
continue;
914 if (!pSlowPion->hasExtraInfo(
"isRightCategory(SlowPion)"))
continue;
916 double probSlowPion = pSlowPion->getExtraInfo(
"isRightCategory(SlowPion)");
917 if (probSlowPion > maximumProbSlowPion) {
918 maximumProbSlowPion = probSlowPion;
919 chargeTargetSlowPion = pSlowPion->getCharge();
920 momTargetSlowPion = PCmsLabTransform::labToCms(pSlowPion->get4Vector());
927 double chargeTargetKaon = particle->getCharge();
928 if (requestedVariable ==
"HaveOpositeCharges")
930 if (chargeTargetKaon * chargeTargetSlowPion == -1)
934 else if (requestedVariable ==
"cosKaonPion")
936 ROOT::Math::PxPyPzEVector momTargetKaon = PCmsLabTransform::labToCms(particle->get4Vector());
937 if (momTargetKaon == momTargetKaon && momTargetSlowPion == momTargetSlowPion)
938 output = momTargetKaon.Vect().Unit().Dot(momTargetSlowPion.Vect().Unit());
946 Manager::FunctionPtr FSCVariables(
const std::vector<std::string>& arguments)
948 if (arguments.size() != 1)
949 B2FATAL(
"Wrong number of arguments (1 required) for meta function FSCVariables");
952 auto requestedVariable = arguments[0];
953 auto func = [requestedVariable](
const Particle * particle) ->
double {
954 StoreObjPtr<ParticleList> FastParticleList(
"pi+:inRoe");
955 if (!FastParticleList.isValid())
return 0;
958 if ((requestedVariable !=
"pFastCMS") && (requestedVariable !=
"cosSlowFast") && (requestedVariable !=
"cosTPTOFast") && (requestedVariable !=
"SlowFastHaveOpositeCharges"))
959 B2FATAL(
"Wrong variable " << requestedVariable <<
" requested. The possibilities are pFastCMS, cosSlowFast, cosTPTOFast or SlowFastHaveOpositeCharges");
962 double maximumProbFastest = 0;
963 ROOT::Math::PxPyPzEVector momFastParticle;
964 Particle* TargetFastParticle =
nullptr;
965 for (
unsigned int i = 0; i < FastParticleList->getListSize(); ++i)
967 Particle* particlei = FastParticleList->getParticle(i);
968 if (!particlei)
continue;
970 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
971 if (momParticlei != momParticlei)
continue;
973 double probFastest = momParticlei.P();
974 if (probFastest > maximumProbFastest) {
975 maximumProbFastest = probFastest;
976 TargetFastParticle = particlei;
977 momFastParticle = momParticlei;
982 if (!TargetFastParticle)
return 0;
987 if (requestedVariable ==
"cosTPTOFast")
988 output = std::get<double>(Variable::Manager::Instance().getVariable(
"cosTPTO")->
function(TargetFastParticle));
990 ROOT::Math::PxPyPzEVector momSlowPion = PCmsLabTransform::labToCms(particle->get4Vector());
991 if (momSlowPion == momSlowPion)
993 if (requestedVariable ==
"cosSlowFast") {
994 output = momSlowPion.Vect().Unit().Dot(momFastParticle.Vect().Unit());
995 }
else if (requestedVariable ==
"SlowFastHaveOpositeCharges") {
996 if (particle->getCharge()*TargetFastParticle->getCharge() == -1) {
1000 output = momFastParticle.P();
1013 const std::vector<int> charmMesons = { 411, 421, 10411, 10421, 413, 423, 10413, 10423, 20413, 20423, 415, 425, 431, 10431, 433, 10433, 20433, 435};
1015 const std::vector<int> charmBaryons = { 4122, 4222, 4212, 4112, 4224, 4214, 4114, 4232, 4132, 4322, 4312, 4324, 4314, 4332, 4334, 4412, 4422,
1016 4414, 4424, 4432, 4434, 4444
1019 const std::vector<int> qqbarMesons = {
1020 111, 9000111, 100111, 10111, 200111, 113, 10113, 20113, 9000113, 100113, 9010113, 9020113, 30113, 9030113, 9040113,
1021 115, 10115, 100115, 9000115, 117, 9000117, 9010117, 119,
1023 221, 331, 9000221, 9010221, 100221, 10221, 100331, 9020221, 10331, 200221, 9030221, 9040221, 9050221, 9060221, 9070221, 223, 333, 10223, 20223,
1024 10333, 20333, 100223, 9000223, 9010223, 30223, 100333, 225, 9000225, 335, 9010225, 9020225, 10225, 9030225, 10335, 9040225, 100225, 100335,
1025 9050225, 9060225, 9070225, 227, 337, 229, 9000339, 9000229,
1027 441, 10441, 100441, 443, 10443, 20443, 100443, 30443, 9000443, 9010443, 9020443, 445, 9000445
1030 const std::vector<int> flavorConservingMesons = {
1031 9000211, 100211, 10211, 200211, 213, 10213, 20213, 9000213, 100213, 9010213, 9020213, 30213, 9030213, 9040213,
1032 215, 10215, 100215, 9000215, 217, 9000217, 9010217, 219,
1034 30343, 10311, 10321, 100311, 100321, 200311, 200321, 9000311, 9000321, 313, 323, 10313, 10323, 20313, 20323, 100313, 100323,
1035 9000313, 9000323, 30313, 30323, 315, 325, 9000315, 9000325, 10315, 10325, 20315, 20325, 100315, 100325, 9010315,
1036 9010325, 317, 327, 9010317, 9010327, 319, 329, 9000319, 9000329
1039 const std::vector<std::string> availableForIsRightTrack = {
"Electron",
1040 "IntermediateElectron",
1044 "IntermediateKinLepton",
1052 const std::vector<std::string> availableForIsRightCategory = {
"Electron",
1053 "IntermediateElectron",
1057 "IntermediateKinLepton",
1070 Manager::FunctionPtr isRightTrack(
const std::vector<std::string>& arguments)
1072 if (arguments.size() != 1) {
1073 B2FATAL(
"Wrong number of arguments (1 required) for meta function isRightTrack");
1078 unsigned index = std::find(availableForIsRightTrack.begin(), availableForIsRightTrack.end(), particleName)
1079 - availableForIsRightTrack.begin();
1080 if (index == availableForIsRightTrack.size()) {
1081 B2FATAL(
"isRightTrack: Not available category " << particleName <<
1082 ". The possibilities are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron and Lambda");
1085 auto func = [index](
const Particle * particle) ->
int {
1088 if (!mcParticle)
return -2;
1090 int mcPDG = abs(mcParticle->getPDG());
1093 std::vector<int> mothersPDG;
1094 std::vector<const MCParticle*> mothersPointers;
1096 const MCParticle* mcMother = mcParticle->getMother();
1099 mothersPDG.push_back(abs(mcMother->getPDG()));
1100 mothersPointers.push_back(mcMother);
1101 if (abs(mcMother->getPDG()) == 511)
break;
1102 mcMother = mcMother->getMother();
1105 if (mothersPDG.size() == 0)
return -2;
1108 if (index == 10)
return 1;
1112 bool isCharmedMesonInChain =
false;
1113 for (
auto& iMCMotherPDG : mothersPDG)
1115 if (std::find(charmMesons.begin(), charmMesons.end(), iMCMotherPDG) != charmMesons.end()) {
1116 isCharmedMesonInChain =
true;
1123 bool isCharmedBaryonInChain =
false;
1124 for (
auto& iMCMotherPDG : mothersPDG)
1126 if (std::find(charmBaryons.begin(), charmBaryons.end(), iMCMotherPDG) != charmBaryons.end()) {
1127 isCharmedBaryonInChain =
true;
1134 bool isQQbarMesonInChain =
false;
1135 for (
auto& iMCMotherPDG : mothersPDG)
1137 if (std::find(qqbarMesons.begin(), qqbarMesons.end(), iMCMotherPDG) != qqbarMesons.end()) {
1138 isQQbarMesonInChain =
true;
1145 bool isB0DaughterConservingFlavor =
false;
1146 if (std::find(flavorConservingMesons.begin(), flavorConservingMesons.end(),
1147 mothersPDG.rbegin()[1]) != flavorConservingMesons.end())
1149 isB0DaughterConservingFlavor =
true;
1154 bool isHadronSingleTauDaughter =
false;
1155 if (mothersPDG.size() > 1 && mothersPDG.rbegin()[1] == 15)
1157 int numberOfChargedDaughters = 0;
1158 for (
auto& tauDaughter : mothersPointers.rbegin()[1]->getDaughters()) {
1159 if (tauDaughter->getCharge() != 0)
1160 numberOfChargedDaughters += 1;
1162 if (numberOfChargedDaughters == 1)
1163 isHadronSingleTauDaughter =
true;
1167 && mcPDG == Const::electron.getPDGCode() && mothersPDG[0] == 511)
1170 }
else if (index == 1
1171 && mcPDG == Const::electron.getPDGCode() && mothersPDG.size() > 1 && isQQbarMesonInChain ==
false)
1174 }
else if (index == 2
1175 && mcPDG == Const::muon.getPDGCode() && mothersPDG[0] == 511)
1178 }
else if (index == 3
1179 && mcPDG == Const::muon.getPDGCode() && mothersPDG.size() > 1 && isQQbarMesonInChain ==
false)
1182 }
else if (index == 4
1183 && (mcPDG == Const::muon.getPDGCode() || mcPDG == Const::electron.getPDGCode()) && mothersPDG[0] == 511)
1186 }
else if (index == 5
1187 && (mcPDG == Const::muon.getPDGCode() || mcPDG == Const::electron.getPDGCode()) && mothersPDG.size() > 1
1188 && isQQbarMesonInChain ==
false)
1191 }
else if (index == 6
1192 && mcPDG == Const::kaon.getPDGCode() && isQQbarMesonInChain ==
false
1193 && (isCharmedMesonInChain ==
true || isCharmedBaryonInChain ==
true))
1196 }
else if (index == 7
1197 && mcPDG == Const::pion.getPDGCode() && mothersPDG.size() > 1 && mothersPDG[0] == 413 && mothersPDG[1] == 511)
1200 }
else if (index == 8
1201 && (mcPDG == Const::pion.getPDGCode() || mcPDG == Const::kaon.getPDGCode())
1202 && isQQbarMesonInChain ==
false
1203 && (mothersPDG[0] == 511
1204 || (mothersPDG.rbegin()[0] == 511 && (isB0DaughterConservingFlavor ==
true || isHadronSingleTauDaughter ==
true))))
1207 }
else if (index == 9
1208 && mcPDG == Const::Lambda.getPDGCode() && isCharmedBaryonInChain ==
true)
1219 Manager::FunctionPtr isRightCategory(
const std::vector<std::string>& arguments)
1221 if (arguments.size() != 1) {
1222 B2FATAL(
"Wrong number of arguments (1 required) for meta function isRightCategory");
1227 unsigned index = find(availableForIsRightCategory.begin(), availableForIsRightCategory.end(), particleName)
1228 - availableForIsRightCategory.begin();
1229 if (index == availableForIsRightCategory.size()) {
1230 B2FATAL(
"isRightCategory: Not available category " << particleName <<
1231 ". The possibilities are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
1234 auto func = [index](
const Particle * particle) ->
int {
1236 Particle* nullParticle =
nullptr;
1237 double qTarget = particle->getCharge();
1238 double qMC = Variable::isRestOfEventB0Flavor(nullParticle);
1241 if (!mcParticle)
return -2;
1243 int mcPDG = abs(mcParticle->getPDG());
1246 std::vector<int> mothersPDG;
1247 std::vector<const MCParticle*> mothersPointers;
1249 const MCParticle* mcMother = mcParticle->getMother();
1252 mothersPDG.push_back(abs(mcMother->getPDG()));
1253 mothersPointers.push_back(mcMother);
1254 if (abs(mcMother->getPDG()) == 511)
break;
1255 mcMother = mcMother->getMother();
1258 if (mothersPDG.size() == 0)
return -2;
1260 if (index == 13)
return 1;
1264 bool isCharmedMesonInChain =
false;
1265 for (
auto& iMCMotherPDG : mothersPDG)
1267 if (std::find(charmMesons.begin(), charmMesons.end(), iMCMotherPDG) != charmMesons.end()) {
1268 isCharmedMesonInChain =
true;
1275 bool isCharmedBaryonInChain =
false;
1276 for (
auto& iMCMotherPDG : mothersPDG)
1278 if (std::find(charmBaryons.begin(), charmBaryons.end(), iMCMotherPDG) != charmBaryons.end()) {
1279 isCharmedBaryonInChain =
true;
1286 bool isQQbarMesonInChain =
false;
1287 for (
auto& iMCMotherPDG : mothersPDG)
1289 if (std::find(qqbarMesons.begin(), qqbarMesons.end(), iMCMotherPDG) != qqbarMesons.end()) {
1290 isQQbarMesonInChain =
true;
1297 bool isB0DaughterConservingFlavor =
false;
1298 if (mothersPDG.size() > 1)
1300 if (std::find(flavorConservingMesons.begin(), flavorConservingMesons.end(),
1301 mothersPDG.rbegin()[1]) != flavorConservingMesons.end()) {
1302 isB0DaughterConservingFlavor =
true;
1308 bool isHadronSingleTauDaughter =
false;
1309 if (mothersPDG.size() > 1 && mothersPDG.rbegin()[1] == 15)
1311 int numberOfChargedDaughters = 0;
1312 for (
auto& tauDaughter : mothersPointers.rbegin()[1]->getDaughters()) {
1313 if (tauDaughter->getCharge() != 0)
1314 numberOfChargedDaughters += 1;
1316 if (numberOfChargedDaughters == 1)
1317 isHadronSingleTauDaughter =
true;
1321 bool haveKaonPionSameMother =
false;
1324 const MCParticle* mcSlowPionMother =
nullptr;
1325 StoreObjPtr<ParticleList> SlowPionList(
"pi+:inRoe");
1326 Particle* targetSlowPion =
nullptr;
1327 if (SlowPionList.isValid()) {
1328 double mcProbSlowPion = 0;
1329 for (
unsigned int i = 0; i < SlowPionList->getListSize(); ++i) {
1330 Particle* pSlowPion = SlowPionList->getParticle(i);
1331 if (!pSlowPion)
continue;
1332 if (pSlowPion->hasExtraInfo(
"isRightCategory(SlowPion)")) {
1333 double probSlowPion = pSlowPion->getExtraInfo(
"isRightCategory(SlowPion)");
1334 if (probSlowPion > mcProbSlowPion) {
1335 mcProbSlowPion = probSlowPion;
1336 targetSlowPion = pSlowPion;
1340 if (targetSlowPion !=
nullptr) {
1341 const MCParticle* mcSlowPion = targetSlowPion ->
getMCParticle();
1343 if (mcSlowPion !=
nullptr && mcSlowPion->getMother() !=
nullptr
1344 && abs(mcSlowPion->getPDG()) == Const::pion.getPDGCode() && abs(mcSlowPion->getMother()->getPDG()) == 413) {
1345 mcSlowPionMother = mcSlowPion->
getMother();
1350 if (std::find(mothersPointers.begin(), mothersPointers.end(), mcSlowPionMother) != mothersPointers.end())
1351 haveKaonPionSameMother =
true;
1356 int FastParticlePDGMother = 0;
1360 StoreObjPtr<ParticleList> FastParticleList(
"pi+:inRoe");
1361 Particle* targetFastParticle =
nullptr;
1362 if (FastParticleList.isValid()) {
1363 double mcProbFastest = 0;
1364 for (
unsigned int i = 0; i < FastParticleList->getListSize(); ++i) {
1365 Particle* particlei = FastParticleList->getParticle(i);
1366 if (!particlei)
continue;
1368 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
1369 if (momParticlei == momParticlei) {
1370 double probFastest = momParticlei.P();
1371 if (probFastest > mcProbFastest) {
1372 mcProbFastest = probFastest;
1373 targetFastParticle = particlei;
1377 if (targetFastParticle !=
nullptr) {
1378 const MCParticle* mcFastParticle = targetFastParticle ->
getMCParticle();
1380 if (mcFastParticle !=
nullptr && mcFastParticle->getMother() !=
nullptr) {
1381 FastParticlePDGMother = abs(mcFastParticle->getMother()->getPDG());
1382 qFSC = mcFastParticle->getCharge();
1390 && qTarget == qMC && mcPDG == Const::electron.getPDGCode() && mothersPDG[0] == 511)
1393 }
else if (index == 1
1394 && qTarget != qMC && mcPDG == Const::electron.getPDGCode() && mothersPDG.size() > 1
1395 && isQQbarMesonInChain ==
false)
1398 }
else if (index == 2
1399 && qTarget == qMC && mcPDG == Const::muon.getPDGCode() && mothersPDG[0] == 511)
1402 }
else if (index == 3
1403 && qTarget != qMC && mcPDG == Const::muon.getPDGCode() && mothersPDG.size() > 1
1404 && isQQbarMesonInChain ==
false)
1407 }
else if (index == 4
1409 && (mcPDG == Const::electron.getPDGCode() || mcPDG == Const::muon.getPDGCode()) && mothersPDG[0] == 511)
1412 }
else if (index == 5
1413 && qTarget != qMC && (mcPDG == Const::electron.getPDGCode() || mcPDG == Const::muon.getPDGCode())
1414 && mothersPDG.size() > 1 && isQQbarMesonInChain ==
false)
1417 }
else if (index == 6
1418 && qTarget == qMC && mcPDG == Const::kaon.getPDGCode() && isQQbarMesonInChain ==
false
1419 && (isCharmedMesonInChain ==
true || isCharmedBaryonInChain ==
true))
1422 }
else if (index == 7
1423 && qTarget != qMC && mcPDG == Const::pion.getPDGCode()
1424 && mothersPDG.size() > 1 && mothersPDG[0] == 413 && mothersPDG[1] == 511)
1427 }
else if (index == 8
1428 && qTarget == qMC && (mcPDG == Const::pion.getPDGCode() || mcPDG == Const::kaon.getPDGCode())
1429 && isQQbarMesonInChain ==
false
1430 && (mothersPDG[0] == 511 || (mothersPDG.rbegin()[0] == 511
1431 && (isB0DaughterConservingFlavor ==
true || isHadronSingleTauDaughter ==
true))))
1434 }
else if (index == 9
1435 && qTarget == qMC && mcPDG == Const::kaon.getPDGCode() && haveKaonPionSameMother ==
true)
1438 }
else if (index == 10 && qTarget == qMC)
1441 }
else if (index == 11
1442 && qTarget != qMC && mothersPDG.size() > 1 && qFSC == qMC
1443 && mcPDG == Const::pion.getPDGCode() && FastParticlePDGMother == 511 && isQQbarMesonInChain ==
false)
1446 }
else if (index == 12
1447 && (particle->getPDGCode() / abs(particle->getPDGCode())) != qMC
1448 && mcPDG == Const::Lambda.getPDGCode() && isCharmedBaryonInChain ==
true)
1460 Manager::FunctionPtr hasHighestProbInCat(
const std::vector<std::string>& arguments)
1462 if (arguments.size() != 2) {
1463 B2FATAL(
"Wrong number of arguments (2 required) for meta function hasHighestProbInCat");
1466 auto particleListName = arguments[0];
1467 auto extraInfoName = arguments[1];
1469 bool isAvailable =
false;
1470 for (
const auto& name : availableForIsRightTrack) {
1471 if (extraInfoName ==
"isRightTrack(" + name +
")") {
1476 for (
const auto& name : availableForIsRightCategory) {
1477 if (extraInfoName ==
"isRightCategory(" + name +
")") {
1482 if (extraInfoName ==
"isRightTrack(MaximumPstar)")
1487 string strAvailableForIsRightTrack;
1488 for (
const auto& name : availableForIsRightTrack)
1489 strAvailableForIsRightTrack += name +
" ";
1490 string strAvailableForIsRightCategory;
1491 for (
const auto& name : availableForIsRightCategory)
1492 strAvailableForIsRightCategory += name +
" ";
1494 B2FATAL(
"hasHighestProbInCat: Not available category" << extraInfoName <<
1495 ". The possibilities for isRightTrack() are " << endl << strAvailableForIsRightTrack <<
" MaximumPstar" << endl <<
1496 "The possibilities for isRightCategory() are " << endl << strAvailableForIsRightCategory);
1499 auto func = [particleListName, extraInfoName](
const Particle * particle) ->
bool {
1500 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1501 if (!ListOfParticles.isValid())
return 0;
1503 double maximumProb = 0;
1504 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1506 const Particle* particlei = ListOfParticles->getParticle(i);
1507 if (!particlei)
continue;
1510 if (extraInfoName ==
"isRightTrack(MaximumPstar)") {
1511 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
1512 if (momParticlei == momParticlei) {
1513 prob = momParticlei.P();
1516 if (particlei->hasExtraInfo(extraInfoName)) {
1517 prob = particlei->getExtraInfo(extraInfoName);
1520 if (prob > maximumProb) {
1526 bool output =
false;
1527 if ((extraInfoName ==
"isRightTrack(MaximumPstar)") && (PCmsLabTransform::labToCms(particle->get4Vector()).P() == maximumProb))
1530 }
else if (extraInfoName !=
"isRightTrack(MaximumPstar)" && particle->hasExtraInfo(extraInfoName))
1532 if (particle->getExtraInfo(extraInfoName) == maximumProb) output =
true;
1540 Manager::FunctionPtr HighestProbInCat(
const std::vector<std::string>& arguments)
1542 if (arguments.size() != 2) {
1543 B2FATAL(
"Wrong number of arguments (2 required) for meta function HighestProbInCat");
1546 auto particleListName = arguments[0];
1547 auto extraInfoName = arguments[1];
1549 bool isAvailable =
false;
1550 for (
const auto& name : availableForIsRightTrack) {
1551 if (extraInfoName ==
"isRightTrack(" + name +
")") {
1556 for (
const auto& name : availableForIsRightCategory) {
1557 if (extraInfoName ==
"isRightCategory(" + name +
")") {
1562 if (extraInfoName ==
"isRightTrack(MaximumPstar)")
1567 string strAvailableForIsRightTrack;
1568 for (
const auto& name : availableForIsRightTrack)
1569 strAvailableForIsRightTrack += name +
" ";
1570 string strAvailableForIsRightCategory;
1571 for (
const auto& name : availableForIsRightCategory)
1572 strAvailableForIsRightCategory += name +
" ";
1574 B2FATAL(
"HighestProbInCat: Not available category" << extraInfoName <<
1575 ". The possibilities for isRightTrack() are " << endl << strAvailableForIsRightTrack <<
" MaximumPstar" << endl <<
1576 "The possibilities for isRightCategory() are " << endl << strAvailableForIsRightCategory);
1579 auto func = [particleListName, extraInfoName](
const Particle*) ->
double {
1580 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1581 if (!ListOfParticles.isValid())
return 0;
1583 double maximumProb = 0;
1584 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1586 const Particle* particlei = ListOfParticles->getParticle(i);
1587 if (!particlei)
continue;
1590 if (extraInfoName ==
"isRightTrack(MaximumPstar)") {
1591 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
1592 if (momParticlei == momParticlei) {
1593 prob = momParticlei.P();
1596 if (particlei->hasExtraInfo(extraInfoName)) {
1597 prob = particlei->getExtraInfo(extraInfoName);
1600 maximumProb = max(maximumProb, prob);
1610 std::vector<std::string> availableExtraInfos = {
"isRightTrack(Electron)",
1611 "isRightTrack(IntermediateElectron)",
1612 "isRightTrack(Muon)",
1613 "isRightTrack(IntermediateMuon)",
1614 "isRightTrack(KinLepton)",
1615 "isRightTrack(IntermediateKinLepton)",
1616 "isRightTrack(Kaon)",
1617 "isRightTrack(SlowPion)",
1618 "isRightTrack(FastHadron)",
1619 "isRightTrack(MaximumPstar)",
1620 "isRightTrack(Lambda)",
1621 "isRightCategory(Electron)",
1622 "isRightCategory(IntermediateElectron)",
1623 "isRightCategory(Muon)",
1624 "isRightCategory(IntermediateMuon)",
1625 "isRightCategory(KinLepton)",
1626 "isRightCategory(IntermediateKinLepton)",
1627 "isRightCategory(Kaon)",
1628 "isRightCategory(SlowPion)",
1629 "isRightCategory(FastHadron)",
1630 "isRightCategory(MaximumPstar)",
1631 "isRightCategory(Lambda)",
1632 "isRightCategory(KaonPion)",
1633 "isRightCategory(FSC)",
1636 Manager::FunctionPtr QpOf(
const std::vector<std::string>& arguments)
1638 if (arguments.size() != 3) {
1639 B2FATAL(
"Wrong number of arguments (3 required) for meta function QpOf");
1642 auto particleListName = arguments[0];
1643 auto outputExtraInfo = arguments[1];
1644 auto rankingExtraInfo = arguments[2];
1646 unsigned indexRanking = find(availableExtraInfos.begin(), availableExtraInfos.end(),
1647 rankingExtraInfo) - availableExtraInfos.begin();
1648 unsigned indexOutput = find(availableExtraInfos.begin(), availableExtraInfos.end(),
1649 outputExtraInfo) - availableExtraInfos.begin();
1651 if (indexRanking == availableExtraInfos.size() or indexOutput == availableExtraInfos.size()) {
1652 string strAvailableForIsRightTrack;
1653 for (
const auto& name : availableForIsRightTrack)
1654 strAvailableForIsRightTrack += name +
" ";
1655 string strAvailableForIsRightCategory;
1656 for (
const auto& name : availableForIsRightCategory)
1657 strAvailableForIsRightCategory += name +
" ";
1659 B2FATAL(
"QpOf: Not available category " << rankingExtraInfo <<
1660 ". The possibilities for isRightTrack() are " << endl << strAvailableForIsRightTrack <<
" MaximumPstar" << endl <<
1661 "The possibilities for isRightCategory() are " << endl << strAvailableForIsRightCategory);
1664 auto func = [particleListName, indexOutput, indexRanking](
const Particle*) ->
double {
1665 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1666 if (!ListOfParticles.isValid())
return 0;
1668 Particle* target =
nullptr;
1669 double maximumTargetProb = 0;
1670 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1672 Particle* particlei = ListOfParticles->getParticle(i);
1673 if (!particlei)
continue;
1675 double target_prob = 0;
1676 if (indexRanking == 9 || indexRanking == 20) {
1677 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
1678 if (momParticlei == momParticlei) {
1679 target_prob = momParticlei.P();
1682 if (particlei->hasExtraInfo(availableExtraInfos[indexRanking])) {
1683 target_prob = particlei->getExtraInfo(availableExtraInfos[indexRanking]);
1687 if (target_prob > maximumTargetProb) {
1688 maximumTargetProb = target_prob;
1694 if (!target)
return 0;
1698 if (indexRanking == 10 || indexRanking == 21)
1700 qTarget = (-1) * target->getPDGCode() / abs(target->getPDGCode());
1702 }
else if (indexRanking == 1 || indexRanking == 3 || indexRanking == 5 || indexRanking == 7 ||
1703 indexRanking == 12 || indexRanking == 14 || indexRanking == 16 || indexRanking == 18)
1705 qTarget = (-1) * target->getCharge();
1708 qTarget = target->getCharge();
1712 double prob = target->getExtraInfo(availableExtraInfos[indexOutput]);
1716 return qTarget * prob;
1721 Manager::FunctionPtr weightedQpOf(
const std::vector<std::string>& arguments)
1723 if (arguments.size() != 3) {
1724 B2FATAL(
"Wrong number of arguments (3 required) for meta function weightedQpOf");
1729 auto particleListName = arguments[0];
1730 auto outputExtraInfo = arguments[1];
1731 auto rankingExtraInfo = arguments[2];
1734 unsigned indexRanking = find(availableExtraInfos.begin(), availableExtraInfos.end(),
1735 rankingExtraInfo) - availableExtraInfos.begin();
1736 unsigned indexOutput = find(availableExtraInfos.begin(), availableExtraInfos.end(),
1737 outputExtraInfo) - availableExtraInfos.begin();
1740 if (indexRanking == availableExtraInfos.size() or indexOutput == availableExtraInfos.size()) {
1741 string strAvailableForIsRightTrack;
1742 for (
const auto& name : availableForIsRightTrack)
1743 strAvailableForIsRightTrack += name +
" ";
1744 string strAvailableForIsRightCategory;
1745 for (
const auto& name : availableForIsRightCategory)
1746 strAvailableForIsRightCategory += name +
" ";
1748 B2FATAL(
"weightedQpOf: Not available category " << rankingExtraInfo <<
1749 ". The possibilities for isRightTrack() are " << endl << strAvailableForIsRightTrack <<
" MaximumPstar" << endl <<
1750 "The possibilities for isRightCategory() are " << endl << strAvailableForIsRightCategory);
1754 auto func = [particleListName, indexOutput, indexRanking, rankingExtraInfo](
const Particle*) ->
double {
1756 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1757 if (!ListOfParticles)
return 0;
1758 if (ListOfParticles->getListSize() == 0)
return 0;
1761 auto compare = [rankingExtraInfo](
const Particle * part1,
const Particle * part2)->
bool {
1764 if (part1->hasExtraInfo(rankingExtraInfo)) info1 = part1->getExtraInfo(rankingExtraInfo);
1765 if (part2->hasExtraInfo(rankingExtraInfo)) info2 = part2->getExtraInfo(rankingExtraInfo);
1766 return (info1 > info2);
1769 auto compareMomentum = [rankingExtraInfo](
const Particle * part1,
const Particle * part2)->
bool {
1770 double info1 = PCmsLabTransform::labToCms(part1->get4Vector()).P();
1771 double info2 = PCmsLabTransform::labToCms(part2->get4Vector()).P();
1772 return (info1 > info2);
1775 std::vector<const Particle*> ParticleVector(ListOfParticles->getListSize());
1776 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1778 ParticleVector[i] = ListOfParticles->getParticle(i);
1781 if (indexRanking == 9 || indexRanking == 20)
1782 std::sort(ParticleVector.begin(), ParticleVector.end(), compareMomentum);
1784 std::sort(ParticleVector.begin(), ParticleVector.end(), compare);
1787 double final_value = 0.0;
1788 if (ParticleVector.size() != 0) final_value = 1.0;
1791 int Limit = min(3,
int(ParticleVector.size()));
1794 for (
int i = 0; i < Limit; ++i)
1796 if (ParticleVector[i]->hasExtraInfo(availableExtraInfos[indexOutput])) {
1797 double flavor = 0.0;
1798 if (indexRanking == 10 || indexRanking == 21) {
1799 flavor = - copysign(1, ParticleVector[i]->getPDGCode());
1801 }
else if (indexRanking == 1 || indexRanking == 3 || indexRanking == 5 || indexRanking == 7 ||
1802 indexRanking == 12 || indexRanking == 14 || indexRanking == 16 || indexRanking == 18) {
1803 flavor = - ParticleVector[i]->getCharge();
1805 flavor = + ParticleVector[i]->getCharge();
1808 double p = ParticleVector[i]->getExtraInfo(availableExtraInfos[indexOutput]);
1811 double qp = (flavor * p);
1816 final_value = (val1 - val2) / (val1 + val2);
1823 Manager::FunctionPtr variableOfTarget(
const std::vector<std::string>& arguments)
1826 if (arguments.size() != 3)
1827 B2FATAL(
"Wrong number of arguments (3 required) for meta function variableOfTarget");
1829 std::string particleListName = arguments[0];
1830 std::string inputVariable = arguments[1];
1831 std::string rankingExtraInfo = arguments[2];
1833 int indexRanking = -1;
1835 for (
unsigned i = 0; i < availableExtraInfos.size(); ++i) {
1836 if (rankingExtraInfo == availableExtraInfos[i]) {indexRanking = i;
break;}
1839 if (indexRanking == -1) {
1840 string strAvailableForIsRightTrack;
1841 for (
const auto& name : availableForIsRightTrack)
1842 strAvailableForIsRightTrack += name +
" ";
1843 string strAvailableForIsRightCategory;
1844 for (
const auto& name : availableForIsRightCategory)
1845 strAvailableForIsRightCategory += name +
" ";
1847 B2FATAL(
"variableOfTarget: Not available category " << rankingExtraInfo <<
1848 ". The possibilities for isRightTrack() are " << endl << strAvailableForIsRightTrack <<
" MaximumPstar" << endl <<
1849 "The possibilities for isRightCategory() are " << endl << strAvailableForIsRightCategory);
1852 const Variable::Manager::Var* var = Manager::Instance().getVariable(inputVariable);
1853 auto func = [particleListName, var, indexRanking](
const Particle*) ->
double {
1854 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1855 if (!ListOfParticles.isValid())
return realNaN;
1857 Particle* target =
nullptr;
1859 double maximumTargetProb = 0;
1860 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1862 Particle* particlei = ListOfParticles->getParticle(i);
1863 if (!particlei)
continue;
1865 double target_prob = 0;
1866 if (indexRanking == 9 || indexRanking == 20) {
1867 ROOT::Math::PxPyPzEVector momParticlei = PCmsLabTransform::labToCms(particlei->get4Vector());
1868 if (momParticlei == momParticlei) {
1869 target_prob = momParticlei.P();
1872 if (particlei->hasExtraInfo(availableExtraInfos[indexRanking])) {
1873 target_prob = particlei->getExtraInfo(availableExtraInfos[indexRanking]);
1876 if (target_prob > maximumTargetProb) {
1877 maximumTargetProb = target_prob;
1883 if (!target)
return realNaN;
1885 if (std::holds_alternative<double>(var->function(target)))
1887 return std::get<double>(var->function(target));
1888 }
else if (std::holds_alternative<int>(var->function(target)))
1890 return std::get<int>(var->function(target));
1891 }
else if (std::holds_alternative<bool>(var->function(target)))
1893 return std::get<bool>(var->function(target));
1894 }
else return realNaN;
1899 Manager::FunctionPtr hasTrueTarget(
const std::vector<std::string>& arguments)
1901 if (arguments.size() != 1) {
1902 B2FATAL(
"Wrong number of arguments (1 required) for meta function hasTrueTarget");
1905 auto categoryName = arguments[0];
1907 bool isAvailable =
false;
1908 for (
const auto& name : availableForIsRightCategory) {
1909 if (categoryName == name) {
1914 if (categoryName ==
"mcAssociated")
1915 isAvailable =
false;
1918 string strAvailableForIsRightCategory;
1919 for (
const auto& name : availableForIsRightCategory) {
1920 if (name ==
"mcAssociated")
continue;
1921 strAvailableForIsRightCategory += name +
" ";
1923 B2FATAL(
"hasTrueTarget: Not available category" << categoryName <<
1924 ". The possibilities for the category name are " << endl << strAvailableForIsRightCategory);
1927 auto func = [categoryName](
const Particle*) ->
double {
1928 std::string particleListName;
1929 std::string trackTargetName = categoryName;
1931 if (categoryName ==
"Electron" || categoryName ==
"IntermediateElectron") particleListName =
"e+:inRoe";
1932 else if (categoryName ==
"Muon" || categoryName ==
"IntermediateMuon" || categoryName ==
"KinLepton" || categoryName ==
"IntermediateKinLepton") particleListName =
"mu+:inRoe";
1933 else if (categoryName ==
"Kaon" || categoryName ==
"KaonPion") {particleListName =
"K+:inRoe"; trackTargetName =
"Kaon";}
1934 else if (categoryName ==
"Lambda") particleListName =
"Lambda0:inRoe";
1935 else particleListName =
"pi+:inRoe";
1937 if (categoryName ==
"FSC") trackTargetName =
"SlowPion";
1939 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1940 if (!ListOfParticles.isValid())
return realNaN;
1942 Variable::Manager& manager = Variable::Manager::Instance();
1944 bool particlesHaveMCAssociated =
false;
1946 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
1948 Particle* iParticle = ListOfParticles->getParticle(i);
1949 if (!iParticle)
continue;
1951 if (categoryName ==
"MaximumPstar") {
1952 bool targetFlag = std::get<bool>(manager.getVariable(
"hasHighestProbInCat(pi+:inRoe, isRightTrack(MaximumPstar))")->function(
1955 particlesHaveMCAssociated =
true;
1959 int targetFlag = std::get<int>(manager.getVariable(
"isRightTrack(" + trackTargetName +
")")->function(iParticle));
1960 if (targetFlag != -2) particlesHaveMCAssociated =
true;
1961 if (targetFlag == 1) ++nTargets;
1965 if (!particlesHaveMCAssociated)
return realNaN;
1966 return (nTargets > 0);
1971 Manager::FunctionPtr isTrueCategory(
const std::vector<std::string>& arguments)
1973 if (arguments.size() != 1) {
1974 B2FATAL(
"Wrong number of arguments (1 required) for meta function isTrueCategory");
1976 auto categoryName = arguments[0];
1978 bool isAvailable =
false;
1979 for (
const auto& name : availableForIsRightCategory) {
1980 if (categoryName == name) {
1985 if (categoryName ==
"mcAssociated")
1986 isAvailable =
false;
1989 string strAvailableForIsRightCategory;
1990 for (
const auto& name : availableForIsRightCategory) {
1991 if (name ==
"mcAssociated")
continue;
1992 strAvailableForIsRightCategory += name +
" ";
1994 B2FATAL(
"isTrueCategory: Not available category" << categoryName <<
1995 ". The possibilities for the category name are " << endl << strAvailableForIsRightCategory);
1998 auto func = [categoryName](
const Particle*) ->
double {
1999 std::string particleListName;
2000 std::string trackTargetName = categoryName;
2002 if (categoryName ==
"Electron" || categoryName ==
"IntermediateElectron") particleListName =
"e+:inRoe";
2003 else if (categoryName ==
"Muon" || categoryName ==
"IntermediateMuon" || categoryName ==
"KinLepton" || categoryName ==
"IntermediateKinLepton") particleListName =
"mu+:inRoe";
2004 else if (categoryName ==
"Kaon" || categoryName ==
"KaonPion") {particleListName =
"K+:inRoe"; trackTargetName =
"Kaon";}
2005 else if (categoryName ==
"Lambda") particleListName =
"Lambda0:inRoe";
2006 else particleListName =
"pi+:inRoe";
2008 if (categoryName ==
"FSC") trackTargetName =
"SlowPion";
2010 StoreObjPtr<ParticleList> ListOfParticles(particleListName);
2011 if (!ListOfParticles.isValid())
return realNaN;
2013 std::vector<Particle*> targetParticles;
2014 std::vector<Particle*> targetParticlesCategory;
2015 Variable::Manager& manager = Variable::Manager::Instance();
2020 for (
unsigned int i = 0; i < ListOfParticles->getListSize(); ++i)
2022 Particle* iParticle = ListOfParticles->getParticle(i);
2023 if (!iParticle)
continue;
2025 if (categoryName ==
"MaximumPstar") {
2026 if (std::get<bool>(manager.getVariable(
"hasHighestProbInCat(pi+:inRoe, isRightTrack(MaximumPstar))")->function(iParticle)))
2027 targetParticles.push_back(iParticle);
2028 }
else if (std::get<int>(manager.getVariable(
"isRightTrack(" + trackTargetName +
")")->function(iParticle))) {
2029 targetParticles.push_back(iParticle);
2033 for (
const auto& targetParticle : targetParticles)
2035 int isTargetOfRightCategory = std::get<int>(manager.getVariable(
"isRightCategory(" + categoryName +
")")->function(
2037 if (isTargetOfRightCategory == 1) {
2039 nTargets += 1; targetParticlesCategory.push_back(targetParticle);
2040 }
else if (isTargetOfRightCategory == -2 && output != 1)
2064 Manager::FunctionPtr qrOutput(
const std::vector<std::string>& arguments)
2066 if (arguments.size() != 1)
2067 B2FATAL(
"Wrong number of arguments for meta function qrOutput");
2069 std::string combinerMethod = arguments[0];
2070 auto func = [combinerMethod](
const Particle * particle) ->
double {
2072 double output = realNaN;
2073 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2075 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2076 output = flavorTaggerInfo->getMethodMap(combinerMethod)->getQrCombined();
2083 Manager::FunctionPtr qOutput(
const std::vector<std::string>& arguments)
2085 if (arguments.size() != 1)
2086 B2FATAL(
"Wrong number of arguments for meta function qOutput");
2088 std::string combinerMethod = arguments[0];
2089 auto func = [combinerMethod](
const Particle * particle) ->
double {
2091 double output = realNaN;
2092 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2094 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2095 output = TMath::Sign(1, flavorTaggerInfo->getMethodMap(combinerMethod)->getQrCombined());
2102 Manager::FunctionPtr rBinBelle(
const std::vector<std::string>& arguments)
2104 if (arguments.size() != 1)
2105 B2FATAL(
"Wrong number of arguments for meta function rBinBelle");
2108 std::string combinerMethod = arguments[0];
2109 auto func = [combinerMethod](
const Particle * particle) ->
int {
2112 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2114 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2116 double r = std::abs(flavorTaggerInfo->getMethodMap(combinerMethod)->getQrCombined());
2117 if (r < 0.1) output = 0;
2118 if (r > 0.1 && r < 0.25) output = 1;
2119 if (r > 0.25 && r < 0.5) output = 2;
2120 if (r > 0.5 && r < 0.625) output = 3;
2121 if (r > 0.625 && r < 0.75) output = 4;
2122 if (r > 0.75 && r < 0.875) output = 5;
2123 if (r > 0.875 && r < 1.10) output = 6;
2131 Manager::FunctionPtr qpCategory(
const std::vector<std::string>& arguments)
2133 if (arguments.size() != 1)
2134 B2FATAL(
"Wrong number of arguments for meta function qpCategory");
2136 std::string categoryName = arguments[0];
2137 auto func = [categoryName](
const Particle * particle) ->
double {
2139 double output = realNaN;
2140 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2142 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2144 std::map<std::string, float> iQpCategories = flavorTaggerInfo->getMethodMap(
"FBDT")->getQpCategory();
2145 if (iQpCategories.find(categoryName) != iQpCategories.end()) output = iQpCategories.at(categoryName);
2146 else if (iQpCategories.size() != 0) B2FATAL(
"qpCategory: Category with name " << categoryName
2147 <<
" not found. Check the official category names or if this category is included in the flavor tagger categories list.");
2154 Manager::FunctionPtr isTrueFTCategory(
const std::vector<std::string>& arguments)
2156 if (arguments.size() != 1)
2157 B2FATAL(
"Wrong number of arguments for meta function isTrueFTCategory");
2159 std::string categoryName = arguments[0];
2160 auto func = [categoryName](
const Particle * particle) ->
double {
2162 double output = realNaN;
2163 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2165 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2167 std::map<std::string, float> iIsTrueCategories = flavorTaggerInfo->getMethodMap(
"FBDT")->getIsTrueCategory();
2168 if (iIsTrueCategories.find(categoryName) != iIsTrueCategories.end()) output = iIsTrueCategories.at(categoryName);
2169 else if (iIsTrueCategories.size() != 0) B2FATAL(
"isTrueFTCategory: Category with name " << categoryName
2170 <<
" not found. Check the official category names or if this category is included in the flavor tagger categories list.");
2178 Manager::FunctionPtr hasTrueTargets(
const std::vector<std::string>& arguments)
2180 if (arguments.size() != 1)
2181 B2FATAL(
"Wrong number of arguments for meta function hasTrueTargets");
2183 std::string categoryName = arguments[0];
2184 auto func = [categoryName](
const Particle * particle) ->
double {
2186 double output = realNaN;
2187 auto* flavorTaggerInfo = particle->getRelatedTo<FlavorTaggerInfo>();
2189 if (flavorTaggerInfo && flavorTaggerInfo->getUseModeFlavorTagger() ==
"Expert")
2191 std::map<std::string, float> iHasTrueTargets = flavorTaggerInfo->getMethodMap(
"FBDT")->getHasTrueTarget();
2192 if (iHasTrueTargets.find(categoryName) != iHasTrueTargets.end()) output = iHasTrueTargets.at(categoryName);
2193 else if (iHasTrueTargets.size() != 0) B2FATAL(
"hasTrueTargets: Category with name " << categoryName
2194 <<
" not found. Check the official category names or if this category is included in the flavor tagger categories list.");
2202 VARIABLE_GROUP(
"Flavor Tagger Expert Variables");
2204 REGISTER_VARIABLE(
"pMissTag", momentumMissingTagSide, R
"DOC(
2205 [Expert] Calculates the missing momentum for a given particle on the tag side.
2208 REGISTER_METAVARIABLE("pMissTag(maskName)", momentumMissingTagSideWithMask,
2209 "[Expert] Calculates the missing momentum for a given particle on the tag side. The unit of the missing momentum is ``GeV/c`` ",
2210 Manager::VariableDataType::c_double);
2211 REGISTER_VARIABLE("cosTPTO" , cosTPTO, R"DOC(
2212 [Expert] Returns cosine of angle between thrust axis of given particle and thrust axis of ROE.
2215 REGISTER_METAVARIABLE("cosTPTO(maskName)", cosTPTOWithMask,
2216 "[Expert] Returns cosine of angle between thrust axis of given particle and thrust axis of ROE.",
2217 Manager::VariableDataType::c_double);
2218 REGISTER_VARIABLE(
"lambdaFlavor", lambdaFlavor,
2219 "[Expert] Returns 1.0 if particle is ``Lambda0``, -1.0 in case of ``anti-Lambda0``, 0.0 otherwise.");
2220 REGISTER_VARIABLE(
"isLambda", isLambda,
"[Expert] Returns 1.0 if particle is truth-matched to ``Lambda0``, 0.0 otherwise.");
2221 REGISTER_VARIABLE(
"lambdaZError", lambdaZError,
"[Expert] Returns the variance of the z-component of the decay vertex.",
":math:`\\text{cm}^2`");
2222 REGISTER_VARIABLE(
"momentumOfSecondDaughter", momentumOfSecondDaughter,
2223 "[Expert] Returns the momentum of second daughter if exists, 0. otherwise.",
"GeV/c");
2224 REGISTER_VARIABLE(
"momentumOfSecondDaughterCMS", momentumOfSecondDaughterCMS,
2225 "[Expert] Returns the momentum of the second daughter in the centre-of-mass system, 0. if this daughter doesn't exist.",
"GeV/c");
2226 REGISTER_VARIABLE(
"chargeTimesKaonLiklihood", chargeTimesKaonLiklihood,
2227 "[Expert] Returns ``q*(highest PID_Likelihood for Kaons)``, 0. otherwise.");
2228 REGISTER_VARIABLE(
"ptTracksRoe", transverseMomentumOfChargeTracksInRoe, R
"DOC(
2229 [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.
2232 REGISTER_METAVARIABLE("ptTracksRoe(maskName)", transverseMomentumOfChargeTracksInRoeWithMask,
2233 "[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`` ",
2234 Manager::VariableDataType::c_double);
2235 REGISTER_METAVARIABLE("pt2TracksRoe(maskName)", transverseMomentumSquaredOfChargeTracksInRoeWithMask,
2236 "[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` ",
2237 Manager::VariableDataType::c_double);
2238 REGISTER_VARIABLE("NumberOfKShortsInRoe", NumberOfKShortsInRoe,
2239 "[Expert] Returns the number of ``K_S0`` in the rest of event. The particle list ``K_S0:inRoe`` has to be filled beforehand.");
2241 REGISTER_VARIABLE("isInElectronOrMuonCat", isInElectronOrMuonCat,
2242 "[Expert] Returns 1.0 if the particle has been selected as target in the Muon or Electron Category, 0.0 otherwise.");
2244 REGISTER_VARIABLE("isMajorityInRestOfEventFromB0", isMajorityInRestOfEventFromB0, R"DOC(
2245 [Eventbased][Expert] Checks if the majority of the tracks in the current RestOfEvent are from a ``B0``.
2248 REGISTER_METAVARIABLE("isMajorityInRestOfEventFromB0(maskName)", isMajorityInRestOfEventFromB0WithMask,
2249 "[Eventbased][Expert] Checks if the majority of the tracks in the current RestOfEvent are from a ``B0``.",
2250 Manager::VariableDataType::c_bool);
2251 REGISTER_VARIABLE(
"isMajorityInRestOfEventFromB0bar", isMajorityInRestOfEventFromB0bar, R
"DOC(
2252 [Eventbased][Expert] Check if the majority of the tracks in the current RestOfEvent are from a ``anti-B0``.
2255 REGISTER_METAVARIABLE("isMajorityInRestOfEventFromB0bar(maskName)", isMajorityInRestOfEventFromB0barWithMask,
2256 "[Eventbased][Expert] Check if the majority of the tracks in the current RestOfEvent are from a ``anti-B0``.",
2257 Manager::VariableDataType::c_bool);
2258 REGISTER_VARIABLE(
"hasRestOfEventTracks", hasRestOfEventTracks, R
"DOC(
2259 [Expert] Returns the number of tracks in the RestOfEvent related to the given Particle. -2 if the RestOfEvent is empty.
2262 REGISTER_METAVARIABLE("hasRestOfEventTracks(maskName)", hasRestOfEventTracksWithMask,
2263 "[Expert] Returns the number of tracks in the RestOfEvent related to the given Particle. -2 if the RestOfEvent is empty.",
2264 Manager::VariableDataType::c_bool);
2266 REGISTER_VARIABLE(
"qrCombined", isRestOfEventB0Flavor, R
"DOC(
2267 [Eventbased][Expert] Returns -1 (1) if current RestOfEvent is related to a ``anti-B0`` (``B0``).
2268 The ``MCError`` bit of Breco has to be 0, 1, 2, 16 or 1024.
2269 The output of the variable is 0 otherwise.
2270 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.
2272 REGISTER_VARIABLE("ancestorHasWhichFlavor", ancestorHasWhichFlavor,
2273 "[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.");
2274 REGISTER_VARIABLE(
"B0mcErrors", B0mcErrors,
"[Expert] Returns MC-matching flag, see :b2:var:`mcErrors` for the particle, e.g. ``B0`` .");
2275 REGISTER_VARIABLE(
"isRelatedRestOfEventMajorityB0Flavor", isRelatedRestOfEventMajorityB0Flavor, R
"DOC(
2276 [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``).
2279 REGISTER_METAVARIABLE("isRelatedRestOfEventMajorityB0Flavor(maskName)", isRelatedRestOfEventMajorityB0FlavorWithMask,
2280 "[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``).",
2281 Manager::VariableDataType::c_int);
2282 REGISTER_VARIABLE(
"isRestOfEventMajorityB0Flavor", isRestOfEventMajorityB0Flavor,
2283 "[Expert] Returns 0 (1) if the majority of tracks and clusters of the current RestOfEvent are related to a ``anti-B0`` (``B0``).");
2284 REGISTER_VARIABLE(
"mcFlavorOfOtherB", mcFlavorOfOtherB, R
"DOC(
2285 [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.
2286 In other words, this variable checks the generated flavor of the other generated ``Upsilon(4S)`` daughter.
2290 REGISTER_METAVARIABLE("BtagToWBosonVariables(requestedVariable[, maskName])", BtagToWBosonVariables, R
"DOC(
2291 [Eventbased][Expert] Returns values of FlavorTagging-specific kinematical variables assuming a semileptonic decay with the given particle as target.
2292 The input values of ``requestedVariable`` can be the following: recoilMass in GeV/c^2 , pMissCMS in ``GeV/c``, cosThetaMissCMS and EW90.
2293 )DOC", Manager::VariableDataType::c_double);
2294 REGISTER_METAVARIABLE("KaonPionVariables(requestedVariable)" , KaonPionVariables , R
"DOC(
2295 [Expert] Returns values of FlavorTagging-specific kinematical variables for ``KaonPion`` category.
2296 The input values of ``requestedVariable`` can be the following: cosKaonPion, HaveOpositeCharges.
2297 )DOC", Manager::VariableDataType::c_double);
2298 REGISTER_METAVARIABLE("FSCVariables(requestedVariable)", FSCVariables, R
"DOC(
2299 [Eventbased][Expert] Returns values of FlavorTagging-specific kinematical variables for ``FastSlowCorrelated`` category.
2300 The input values of ``requestedVariable`` can be the following: pFastCMS in ``GeV/c``, cosSlowFast, SlowFastHaveOpositeCharges, or cosTPTOFast.
2301 )DOC", Manager::VariableDataType::c_double);
2302 REGISTER_METAVARIABLE("hasHighestProbInCat(particleListName, extraInfoName)", hasHighestProbInCat, R
"DOC(
2303 [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.
2304 The probability is accessed via ``extraInfoName``, which can have the following input values:
2306 * isRightTrack(Electron),
2307 * isRightTrack(IntermediateElectron),
2308 * isRightTrack(Muon),
2309 * isRightTrack(IntermediateMuon),
2310 * isRightTrack(KinLepton),
2311 * isRightTrack(IntermediateKinLepton),
2312 * isRightTrack(Kaon),
2313 * isRightTrack(SlowPion),
2314 * isRightTrack(FastHadron),
2315 * isRightTrack(MaximumPstar),
2316 * isRightTrack(Lambda),
2317 * isRightCategory(Electron),
2318 * isRightCategory(IntermediateElectron),
2319 * isRightCategory(Muon),
2320 * isRightCategory(IntermediateMuon),
2321 * isRightCategory(KinLepton),
2322 * isRightCategory(IntermediateKinLepton),
2323 * isRightCategory(Kaon),
2324 * isRightCategory(SlowPion),
2325 * isRightCategory(FastHadron),
2326 * isRightCategory(MaximumPstar),
2327 * isRightCategory(Lambda),
2328 * isRightCategory(KaonPion),
2329 * isRightCategory(FSC).
2331 )DOC", Manager::VariableDataType::c_bool);
2332 REGISTER_METAVARIABLE("HighestProbInCat(particleListName, extraInfoName)", HighestProbInCat,
2333 "[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);
2335 REGISTER_METAVARIABLE(
"isRightTrack(particleName)", isRightTrack, R
"DOC(
2336 [Expert] Returns 1.0 if the given particle was really from a B-meson depending on category provided in ``particleName`` argument, 0.0 otherwise.
2337 Allowed input values for ``particleName`` argument in this variable are the following:
2340 * IntermediateElectron,
2344 * IntermediateKinLepton,
2351 )DOC", Manager::VariableDataType::c_int);
2352 REGISTER_METAVARIABLE("isRightCategory(particleName)", isRightCategory, R
"DOC(
2353 [Expert] Returns 1.0 if the class track by ``particleName`` category has the same flavor as the MC target track, 0.0 otherwise.
2354 Allowed input values for ``particleName`` argument in this variable are the following:
2357 * IntermediateElectron,
2361 * IntermediateKinLepton
2371 )DOC", Manager::VariableDataType::c_int);
2372 REGISTER_METAVARIABLE("QpOf(particleListName, outputExtraInfo, rankingExtraInfo)", QpOf, R
"DOC(
2373 [Eventbased][Expert] Returns the :math:`q*p` value for a given particle list provided as the 1st argument,
2374 where :math:`p` is the probability of a category stored as extraInfo, provided as the 2nd argument,
2375 allowed values are same as in :b2:var:`hasHighestProbInCat`.
2376 The particle is selected after ranking according to a flavor tagging extraInfo, provided as the 3rd argument,
2377 allowed values are same as in :b2:var:`hasHighestProbInCat`.
2378 )DOC", Manager::VariableDataType::c_double);
2379 REGISTER_METAVARIABLE("weightedQpOf(particleListName, outputExtraInfo, rankingExtraInfo)", weightedQpOf, R
"DOC(
2380 [Eventbased][Expert] Returns the weighted :math:`q*p` value for a given particle list, provided as the 1st argument,
2381 where :math:`p` is the probability of a category stored as extraInfo, provided in the 2nd argument,
2382 allowed values are same as in :b2:var:`hasHighestProbInCat`.
2383 The particles in the list are ranked according to a flavor tagging extraInfo, provided as the 3rd argument,
2384 allowed values are same as in :b2:var:`hasHighestProbInCat`.
2385 The values for the three top particles is combined into an effective (weighted) output.
2386 )DOC", Manager::VariableDataType::c_double);
2387 REGISTER_METAVARIABLE("variableOfTarget(particleListName, inputVariable, rankingExtraInfo)", variableOfTarget, R
"DOC(
2388 [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.
2389 The particles are ranked according to a flavor tagging extraInfo, provided as the 2nd argument,
2390 allowed values are same as in :b2:var:`hasHighestProbInCat`.
2391 )DOC", Manager::VariableDataType::c_double);
2393 REGISTER_METAVARIABLE("hasTrueTarget(categoryName)", hasTrueTarget,
2394 "[Expert] Returns 1 if the given category has a target, 0 otherwise.", Manager::VariableDataType::c_double);
2395 REGISTER_METAVARIABLE(
"isTrueCategory(categoryName)", isTrueCategory,
2396 "[Expert] Returns 1 if the given category tags the B0 MC flavor correctly, 0 otherwise.", Manager::VariableDataType::c_double);
2398 REGISTER_METAVARIABLE(
"qpCategory(categoryName)", qpCategory, R
"DOC(
2399 [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.
2400 The allowed categories are the official Flavor Tagger Category Names.
2401 )DOC", Manager::VariableDataType::c_double);
2402 REGISTER_METAVARIABLE("isTrueFTCategory(categoryName)", isTrueFTCategory, R
"DOC(
2403 [Expert] Returns 1 if the target particle (checking the decay chain) of the category with the given name is found in the MC particles,
2404 and if it provides the right flavor. The allowed categories are the official Flavor Tagger Category Names.
2405 )DOC", Manager::VariableDataType::c_double);
2406 REGISTER_METAVARIABLE("hasTrueTargets(categoryName)", hasTrueTargets, R
"DOC(
2407 [Expert] Returns 1 if target particles (checking only the decay chain) of the category with the given name is found in the MC particles.
2408 The allowed categories are the official Flavor Tagger Category Names.
2409 )DOC", Manager::VariableDataType::c_double);
2411 VARIABLE_GROUP("Flavor Tagger Analysis Variables")
2413 REGISTER_METAVARIABLE("rBinBelle(combinerMethod)", rBinBelle, R"DOC(
2414 Returns the corresponding :math:`r` (dilution) bin according to the Belle binning for the given ``combinerMethod``.
2415 The available methods are 'FBDT' and 'FANN' (category-based combiners), and 'DNN' (DNN tagger output).
2416 The return values and the corresponding dilution ranges are the following:
2418 * 0: :math:`0.000 < r < 0.100`;
2419 * 1: :math:`0.100 < r < 0.250`;
2420 * 2: :math:`0.250 < r < 0.500`;
2421 * 3: :math:`0.500 < r < 0.625`;
2422 * 4: :math:`0.625 < r < 0.750`;
2423 * 5: :math:`0.750 < r < 0.875`;
2424 * 6: :math:`0.875 < r < 1.000`.
2426 .. warning:: You have to run the Flavor Tagger for this variable to be meaningful.
2427 .. seealso:: :ref:`FlavorTagger` and :func:`flavorTagger.flavorTagger`.
2428 )DOC", Manager::VariableDataType::c_int);
2429 REGISTER_METAVARIABLE("qrOutput(combinerMethod)", qrOutput, R"DOC(
2430 Returns the output of the flavorTagger, flavor tag :math:`q` times the dilution factor :math:`r`, for the given combiner method.
2431 The available methods are 'FBDT' and 'FANN' (category-based combiners), and 'DNN' (DNN tagger output).
2433 .. warning:: You have to run the Flavor Tagger for this variable to be meaningful.
2434 .. seealso:: :ref:`FlavorTagger` and :func:`flavorTagger.flavorTagger`.
2435 )DOC", Manager::VariableDataType::c_double);
2436 REGISTER_METAVARIABLE("qOutput(combinerMethod)", qOutput, R"DOC(
2437 Returns the flavor tag :math:`q` output of the flavorTagger for the given combinerMethod.
2438 The available methods are 'FBDT' and 'FANN' (category-based combiners), and 'DNN' (DNN tagger output).
2440 .. warning:: You have to run the Flavor Tagger for this variable to be meaningful.
2441 .. seealso:: :ref:`FlavorTagger` and :func:`flavorTagger.flavorTagger`.
2442 )DOC", Manager::VariableDataType::c_double);
2443 REGISTER_VARIABLE("isRelatedRestOfEventB0Flavor", isRelatedRestOfEventB0Flavor, R"DOC(
2444 Returns -1 (1) if the RestOfEvent related to the given particle is related to a ``anti-B0`` (``B0``).
2445 The ``MCError`` bit of Breco has to be 0, 1, 2, 16 or 1024.
2446 The output of the variable is 0 otherwise.
2447 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...
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or 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.