Belle II Software  release-05-01-25
FlavorTaggingVariables.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2010 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Fernando Abudinen, Moritz Gelb *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 // Own include
12 #include <analysis/variables/FlavorTaggingVariables.h>
13 #include <analysis/variables/MCTruthVariables.h>
14 #include <analysis/utility/PCmsLabTransform.h>
15 
16 #include <analysis/ClusterUtility/ClusterUtils.h>
17 
18 #include <analysis/utility/MCMatching.h>
19 
20 // framework - DataStore
21 #include <framework/datastore/StoreObjPtr.h>
22 
23 // dataobjects
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>
29 
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>
35 
36 
37 // framework aux
38 #include <framework/gearbox/Const.h>
39 #include <framework/logging/Logger.h>
40 
41 #include <TLorentzVector.h>
42 #include <TVector3.h>
43 
44 #include <iostream>
45 #include <algorithm>
46 #include <cmath>
47 
48 using namespace std;
49 
50 namespace Belle2 {
55  namespace Variable {
56 
57  // ############################################## FlavorTagger Variables ###############################################
58 
59  // Track Level Variables ---------------------------------------------------------------------------------------------------
60 
61  double momentumMissingTagSide(const Particle*)
62  {
63  TLorentzVector trackiCMSVec;
64  TLorentzVector roeCMSVec;
65  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
66  if (roe.isValid()) {
67  const auto& tracks = roe->getTracks();
68  for (auto track : tracks) {
69  const PIDLikelihood* trackiPidLikelihood = track->getRelated<PIDLikelihood>();
70  const Const::ChargedStable trackiChargedStable = trackiPidLikelihood ? trackiPidLikelihood->getMostLikely() : Const::pion;
71  double trackiMassHypothesis = trackiChargedStable.getMass();
72  const TrackFitResult* tracki = track->getTrackFitResultWithClosestMass(trackiChargedStable);
73  if (tracki == nullptr) continue;
74  double energy = sqrt(trackiMassHypothesis * trackiMassHypothesis + (tracki->getMomentum()).Dot(tracki->getMomentum()));
75  TLorentzVector trackiVec(tracki->getMomentum(), energy);
76  trackiCMSVec = PCmsLabTransform::labToCms(trackiVec);
77  roeCMSVec += trackiCMSVec;
78  }
79  }
80  double missMom = -roeCMSVec.P();
81  return missMom ;
82  }
83 
84  double cosTPTO(const Particle* part)
85  {
86  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
87  PCmsLabTransform T;
88  std::vector<TVector3> p3_cms_roe;
89  TVector3 thrustO;
90  static const double P_MAX(3.2);
91 
92  double result = 0 ;
93 
94  if (roe.isValid()) {
95 
96  // The following calculation of the thrust axis has been copied and modified
97  // from analysis/ContinuumSuppression/src/ContinuumSuppression.cc
98  // At some point this has to be updated!
99 
100  // FIXME the following three loops reimplements the ParticleLoader and should be avoided -- SC
101 
102  // Charged tracks
103  //
104  const auto& roeTracks = roe->getTracks();
105  for (auto& track : roeTracks) {
106  if (track == nullptr) continue;
107  // TODO: Add helix and KVF with IpProfile once available. Port from L163-199 of:
108  // /belle/b20090127_0910/src/anal/ekpcontsuppress/src/ksfwmoments.cc
109  // Create particle from track with most probable hypothesis
110  const PIDLikelihood* iPidLikelihood = track->getRelated<PIDLikelihood>();
111  const Const::ChargedStable charged = iPidLikelihood ? iPidLikelihood->getMostLikely() : Const::pion;
112  // Here we skip tracks with 0 charge
113  if (track->getTrackFitResultWithClosestMass(charged)->getChargeSign() == 0) continue;
114  Particle particle(track, charged);
115  if (particle.getParticleSource() == Particle::c_Track) {
116  TLorentzVector p_cms = T.rotateLabToCms() * particle.get4Vector();
117  if (p_cms != p_cms) continue;
118  if (p_cms.Rho() > P_MAX) continue;
119  p3_cms_roe.push_back(p_cms.Vect());
120  }
121  }
122 
123  // ECLCluster -> Gamma
124  const auto& roeECLClusters = roe->getECLClusters();
125  for (auto& cluster : roeECLClusters) {
126  if (cluster == nullptr) continue;
127  if (not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons)) continue;
128  if (cluster->isNeutral()) {
129  // Create particle from ECLCluster with gamma hypothesis
130  Particle particle(cluster);
131  TLorentzVector p_lab = particle.get4Vector();
132  if (p_lab != p_lab) continue;
133  if (p_lab.Rho() < 0.05) continue;
134  TLorentzVector p_cms = T.rotateLabToCms() * p_lab;
135  if (p_cms != p_cms) continue;
136  if (p_cms.Rho() > P_MAX) continue;
137  p3_cms_roe.push_back(p_cms.Vect());
138  }
139  }
140 
141  const auto& roeKLMClusters = roe->getKLMClusters();
142  for (auto& cluster : roeKLMClusters) {
143  if (cluster == nullptr) continue;
144  if (!(cluster -> getAssociatedTrackFlag()) && !(cluster -> getAssociatedEclClusterFlag())) {
145  // Create particle from KLMCluster with K0_L hypothesis
146  Particle particle(cluster);
147  TLorentzVector p_lab = particle.get4Vector();
148  if (p_lab != p_lab) continue;
149  if (p_lab.Rho() < 0.05) continue;
150  TLorentzVector p_cms = T.rotateLabToCms() * p_lab;
151  if (p_cms != p_cms) continue;
152  if (p_cms.Rho() > P_MAX) continue;
153  p3_cms_roe.push_back(p_cms.Vect());
154  }
155  }
156 
157  thrustO = Thrust::calculateThrust(p3_cms_roe);
158  const TVector3 pAxis = PCmsLabTransform::labToCms(part->get4Vector()).Vect();
159  if (pAxis == pAxis) result = fabs(cos(pAxis.Angle(thrustO)));
160 
161  }
162  return result;
163  }
164 
165  double lambdaFlavor(const Particle* particle)
166  {
167  if (particle->getPDGCode() == 3122) return 1.0; //Lambda0
168  else if (particle->getPDGCode() == -3122) return -1.0; //Anti-Lambda0
169  else return 0.0;
170  }
171 
172  double isLambda(const Particle* particle)
173  {
174  const MCParticle* mcparticle = particle->getRelatedTo<MCParticle>();
175  // if (mcparticle ==nullptr)
176  // return 0.0;
177  if (mcparticle != nullptr) {
178  if (mcparticle->getPDG() == 3122) return 1.0; //Lambda0
179  else if (mcparticle->getPDG() == -3122) return 1.0; //Anti-Lambda0
180  else return 0.0;
181  } else return 0.0;
182  }
183 
184  double lambdaZError(const Particle* particle)
185  {
186  //This is a simplisitc hack. But I see no other way to get that information.
187  //Should be removed if worthless
188  TMatrixFSym ErrorPositionMatrix = particle->getVertexErrorMatrix();
189  double zError = ErrorPositionMatrix[2][2];
190  return zError;
191  }
192 
193  double momentumOfSecondDaughter(const Particle* part)
194  {
195  if (part->getDaughter(1) == nullptr) return 0.0;
196  else {
197  return part->getDaughter(1)->getP();
198  }
199  }
200 
201  double momentumOfSecondDaughterCMS(const Particle* part)
202  {
203  if (part->getDaughter(1) == nullptr) return 0.0;
204  else {
205  PCmsLabTransform T;
206  TLorentzVector vec = T.rotateLabToCms() * part->getDaughter(1)->get4Vector();
207  return vec.P();
208  }
209  }
210 
211  double chargeTimesKaonLiklihood(const Particle*)
212  {
213  double maximumKaonid = 0;
214  double maximum_charge = 0;
215  StoreObjPtr<ParticleList> KaonList("K+:inRoe");
216  if (KaonList.isValid()) {
217  for (unsigned int i = 0; i < KaonList->getListSize(); ++i) {
218  Particle* p = KaonList->getParticle(i);
219  double Kid = p->getRelatedTo<PIDLikelihood>()->getProbability(Const::kaon, Const::pion);
220  if (Kid > maximumKaonid) {
221  maximumKaonid = Kid;
222  maximum_charge = p->getCharge();
223  }
224  }
225  }
226  return maximumKaonid * maximum_charge;
227  }
228 
229  double transverseMomentumOfChargeTracksInRoe(const Particle* part)
230  {
231  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
232 
233  double sum = 0.0;
234 
235  if (roe.isValid()) {
236  for (const auto& track : roe->getTracks()) {
237  if (part->getTrack() == track) continue;
238  if (track == nullptr) continue;
239  const PIDLikelihood* iPidLikelihood = track->getRelated<PIDLikelihood>();
240  const Const::ChargedStable charged = iPidLikelihood ? iPidLikelihood->getMostLikely() : Const::pion;
241  // TODO: this will always return something (so not nullptr) contrary to the previous method
242  // used here. This line can be removed as soon as the multi hypothesis fitting method
243  // has been properly established
244  if (track->getTrackFitResultWithClosestMass(charged) == nullptr) continue;
245  double pt = track->getTrackFitResultWithClosestMass(charged)->getTransverseMomentum();
246  if (pt == pt) sum += sqrt(pt * pt);
247  }
248  }
249  return sum;
250 
251  }
252 
253  double NumberOfKShortsInRoe(const Particle* particle)
254  {
255  int flag = 0;
256  StoreObjPtr<ParticleList> KShortList("K_S0:inRoe");
257  if (KShortList.isValid()) {
258  for (unsigned int i = 0; i < KShortList->getListSize(); i++) {
259  if (particle->overlapsWith(KShortList->getParticle(i))) {continue;}
260  flag++;
261  }
262  } else B2FATAL("NumberOfKShortsInRoe cannot be calculated because the required particleList K_S0:inRoe could not be found or is not valid");
263  return flag;
264  }
265 
266 // Event Level Variables --------------------------------------------------------------------------------------------
267 
268  double isInElectronOrMuonCat(const Particle* particle)
269  {
270 
271  StoreObjPtr<ParticleList> MuonList("mu+:inRoe");
272  StoreObjPtr<ParticleList> ElectronList("e+:inRoe");
273 
274  const Track* trackTargetMuon = nullptr;
275  const Track* trackTargetElectron = nullptr;
276 
277  if (MuonList.isValid()) {
278  double maximumProbMuon = 0;
279  for (unsigned int i = 0; i < MuonList->getListSize(); ++i) {
280  Particle* pMuon = MuonList->getParticle(i);
281  double probMuon = pMuon->getExtraInfo("isRightTrack(Muon)");
282  if (probMuon > maximumProbMuon) {
283  maximumProbMuon = probMuon;
284  trackTargetMuon = pMuon -> getTrack();
285  }
286  }
287  }
288  if (ElectronList.isValid()) {
289  double maximumProbElectron = 0;
290  for (unsigned int i = 0; i < ElectronList->getListSize(); ++i) {
291  Particle* pElectron = ElectronList->getParticle(i);
292  double probElectron = pElectron->getExtraInfo("isRightTrack(Electron)");
293  if (probElectron > maximumProbElectron) {
294  maximumProbElectron = probElectron;
295  trackTargetElectron = pElectron -> getTrack();
296  }
297  }
298  }
299  if (particle->getTrack() == trackTargetMuon || particle->getTrack() == trackTargetElectron) {
300  return 1.0;
301  } else return 0.0;
302  }
303 
304 // Target Variables --------------------------------------------------------------------------------------------------
305 
306  double isMajorityInRestOfEventFromB0(const Particle*)
307  {
308  int vote = 0;
309  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
310  if (roe.isValid()) {
311  for (auto& track : roe->getTracks()) {
312  const MCParticle* mcParticle = track->getRelated<MCParticle>();
313  while (mcParticle != nullptr) {
314  if (mcParticle->getPDG() == 511) {
315  vote++;
316  break;
317  }
318  if (mcParticle->getPDG() == -511) {
319  vote--;
320  break;
321  }
322  mcParticle = mcParticle->getMother();
323  }
324  }
325  }
326  return vote > 0;
327  }
328 
329  double isMajorityInRestOfEventFromB0bar(const Particle*)
330  {
331  int vote = 0;
332  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
333  if (roe.isValid()) {
334  for (auto& track : roe->getTracks()) {
335  const MCParticle* mcParticle = track->getRelated<MCParticle>();
336  while (mcParticle != nullptr) {
337  if (mcParticle->getPDG() == 511) {
338  vote++;
339  }
340  if (mcParticle->getPDG() == -511) {
341  vote--;
342  }
343  mcParticle = mcParticle->getMother();
344  }
345  }
346  }
347  return vote < 0;
348  }
349 
350  double hasRestOfEventTracks(const Particle* part)
351  {
352  const RestOfEvent* roe = part->getRelatedTo<RestOfEvent>();
353  float ObjectsInROE = 0; //Flavor of B
354  if (roe != nullptr) {
355  if (roe-> getNTracks() != 0) {
356  ObjectsInROE++;
357 // } else if (roe-> getNECLClusters() != 0) {
358 // ObjectsInROE++;
359 // } else if (roe-> getNKLMClusters() != 0) {
360 // ObjectsInROE++;
361  }
362  }
363  if (ObjectsInROE > 0) {
364  return 1;
365  } else return 0;
366  }
367 
368  double isRelatedRestOfEventB0Flavor(const Particle* particle)
369  {
370  const RestOfEvent* roe = particle->getRelatedTo<RestOfEvent>();
371 
372  float BtagFlavor = 0;
373  float BcpFlavor = 0;
374 
375  if (roe != nullptr) {
376  const MCParticle* BcpMC = particle->getRelatedTo<MCParticle>();
377 
378  if (Variable::isSignal(particle) > 0 && BcpMC != nullptr) {
379  const MCParticle* Y4S = BcpMC->getMother();
380  if (Y4S != nullptr) {
381  for (auto& iTrack : roe->getTracks()) {
382  const MCParticle* mcParticle = iTrack->getRelated<MCParticle>();
383  while (mcParticle != nullptr) {
384  if (mcParticle->getMother() == Y4S) {
385  if (mcParticle == BcpMC) {
386  if (mcParticle -> getPDG() > 0) BcpFlavor = 2;
387  else BcpFlavor = -2;
388  } else if (BtagFlavor == 0) {
389  if (TMath::Abs(mcParticle -> getPDG()) == 511 || TMath::Abs(mcParticle -> getPDG()) == 521) {
390  if (mcParticle -> getPDG() > 0) BtagFlavor = 1;
391  else BtagFlavor = -1;
392  } else BtagFlavor = 5;
393  }
394  break;
395  }
396  mcParticle = mcParticle->getMother();
397  }
398  if (BcpFlavor != 0 || BtagFlavor == 5) break;
399  }
400  }
401  }
402  }
403  return (BcpFlavor != 0) ? BcpFlavor : BtagFlavor;
404  }
405 
406  double isRestOfEventB0Flavor(const Particle*)
407  {
408  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
409 
410  if (roe.isValid()) {
411  const Particle* Bcp = roe->getRelated<Particle>();
412  return Variable::isRelatedRestOfEventB0Flavor(Bcp);
413  } else return 0;
414 
415  }
416 
417  double ancestorHasWhichFlavor(const Particle* particle)
418  {
419  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
420  (void)particle;
421  float outputB0tagQ = 0;
422  if (roe.isValid()) {
423  const MCParticle* BcpMC = roe->getRelated<Particle>()->getRelatedTo<MCParticle>();
424  const MCParticle* Y4S = BcpMC->getMother();
425  const MCParticle* mcParticle = particle->getRelatedTo<MCParticle>();
426  while (mcParticle != nullptr) {
427  if (mcParticle->getMother() == Y4S) {
428  if (mcParticle != BcpMC && TMath::Abs(mcParticle -> getPDG()) == 511) {
429  if (mcParticle -> getPDG() == 511) outputB0tagQ = 1;
430  else outputB0tagQ = -1;
431  } else if (mcParticle == BcpMC) {
432  if (mcParticle -> getPDG() == 511) outputB0tagQ = 2;
433  else outputB0tagQ = -2;
434  } else outputB0tagQ = 5;
435  break;
436  }
437  mcParticle = mcParticle->getMother();
438  }
439  }
440 
441  return outputB0tagQ;
442  }
443 
444  double B0mcErrors(const Particle* particle)
445  {
446  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
447  (void)particle;
448  int MCMatchingError = -1;
449  if (roe.isValid()) {
450  const Particle* Bcp = roe->getRelated<Particle>();
451  const MCParticle* BcpMC = roe->getRelated<Particle>()->getRelatedTo<MCParticle>();
452 
453  MCMatchingError = MCMatching::getMCErrors(Bcp, BcpMC);
454  }
455  return MCMatchingError;
456  }
457 
458  double isRelatedRestOfEventMajorityB0Flavor(const Particle* part)
459  {
460  const RestOfEvent* roe = part->getRelatedTo<RestOfEvent>();
461 
462  float outputStandard = 0.0;
463 
464  float q_MC = 0; //Flavor of B
465  if (roe != nullptr) {
466  if (roe-> getNTracks() != 0) {
467  for (auto& track : roe->getTracks()) {
468  const MCParticle* mcParticle = track->getRelated<MCParticle>();
469  while (mcParticle != nullptr) {
470  if (mcParticle->getPDG() == 511) {
471  q_MC++;
472  break;
473  }
474  if (mcParticle->getPDG() == -511) {
475  q_MC--;
476  break;
477  }
478  mcParticle = mcParticle->getMother();
479  }
480  }
481  } else if (roe-> getNECLClusters() != 0) {
482  for (auto& cluster : roe-> getECLClusters()) {
483  if (not cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons)) continue;
484  const MCParticle* mcParticle = cluster->getRelated<MCParticle>();
485  while (mcParticle != nullptr) {
486  if (mcParticle->getPDG() == 511) {
487  q_MC++;
488  break;
489  }
490  if (mcParticle->getPDG() == -511) {
491  q_MC--;
492  break;
493  }
494  mcParticle = mcParticle->getMother();
495  }
496  }
497  } else if (roe-> getNKLMClusters() != 0) {
498  for (auto& klmcluster : roe-> getKLMClusters()) {
499  const MCParticle* mcParticle = klmcluster->getRelated<MCParticle>();
500  while (mcParticle != nullptr) {
501  if (mcParticle->getPDG() == 511) {
502  q_MC++;
503  break;
504  }
505  if (mcParticle->getPDG() == -511) {
506  q_MC--;
507  break;
508  }
509  mcParticle = mcParticle->getMother();
510  }
511  }
512  }
513  }
514 
515  if (q_MC > 0) {
516  outputStandard = 1;
517  } else if (q_MC < 0) {
518  outputStandard = 0;
519  } else outputStandard = -2;
520 
521  return outputStandard;
522  }
523 
524  double isRestOfEventMajorityB0Flavor(const Particle*)
525  {
526  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
527 
528  if (roe.isValid()) {
529  const Particle* Bcp = roe->getRelated<Particle>();
530  return Variable::isRelatedRestOfEventMajorityB0Flavor(Bcp);
531  } else return -2;//gRandom->Uniform(0, 1);
532  }
533 
534  double mcFlavorOfOtherB(const Particle* particle)
535  {
536 
537  if (std::abs(particle->getPDGCode()) != 511 && std::abs(particle->getPDGCode()) != 521) {
538  B2ERROR("MCFlavorOfOtherB: this variable works only for B mesons.\n"
539  "The given particle with PDG code " << particle->getPDGCode() <<
540  " is not a B-meson candidate (PDG code 511 or 521). ");
541  return std::numeric_limits<double>::quiet_NaN();
542  }
543 
544  const MCParticle* mcParticle = particle->getRelatedTo<MCParticle>();
545 
546  if (mcParticle == nullptr) return std::numeric_limits<double>::quiet_NaN();
547 
548  const MCParticle* mcMother = mcParticle->getMother();
549 
550  if (mcMother == nullptr) return std::numeric_limits<double>::quiet_NaN();
551 
552  if (Variable::isSignal(particle) < 1.0) return 0;
553 
554  for (auto& upsilon4SDaughter : mcMother -> getDaughters()) {
555  if (upsilon4SDaughter != mcParticle) {
556  if (upsilon4SDaughter -> getPDG() > 0) return 1.0;
557  else return -1.0;
558  }
559  }
560 
561  return 0;
562 
563  };
564 
565 // ######################################### Meta Variables ##############################################
566 
567 // Miscelaneous -------------------------------------------------------------------------------------------
568  Manager::FunctionPtr CheckingVariables(const std::vector<std::string>& arguments)
569  {
570  if (arguments.size() == 2) {
571  auto ListName = arguments[0];
572  auto requestedVariable = arguments[1];
573  auto func = [requestedVariable, ListName](const Particle*) -> double {
574  if (requestedVariable == "getListSize")
575  {
576  StoreObjPtr<ParticleList> ListOfParticles(ListName);
577  if (ListOfParticles.isValid()) return ListOfParticles->getListSize();
578  else return 0;
579  } else {
580  B2FATAL("Wrong requested Variable. Available is getListSize for particle lists");
581  }
582  };
583  return func;
584  } else {
585  B2FATAL("Wrong number of arguments (2 required) for meta function CheckingVariables");
586  }
587  }
588 
589  Manager::FunctionPtr IsDaughterOf(const std::vector<std::string>& arguments)
590  {
591  auto motherlist = arguments[0];
592  auto func = [motherlist](const Particle * particle) -> double {
593 
594  StoreObjPtr<ParticleList> Y(motherlist);
595  std::vector<Particle*> daughters;
596  double result = 0.0;
597  if (!Y.isValid())
598  B2ERROR("Particle List with name " << motherlist << "isn't valid!");
599 
600  for (unsigned int i = 0; i < Y->getListSize(); ++i)
601  {
602  const auto& oParticle = Y->getParticle(i);
603  result = (double)particle->overlapsWith(oParticle);
604  if (result == 1.0)
605  return 1;
606  }
607 
608  return result;
609  };
610  return func;
611  }
612 
613 // Track and Event Level variables ------------------------------------------------------------------------
614 
615  Manager::FunctionPtr BtagToWBosonVariables(const std::vector<std::string>& arguments)
616  {
617  if (arguments.size() == 1) {
618  auto requestedVariable = arguments[0];
619  auto func = [requestedVariable](const Particle * particle) -> double {
620  PCmsLabTransform T;
621  ClusterUtils C;
622  TLorentzVector momXChargedTracks; //Momentum of charged X tracks in CMS-System
623  TLorentzVector momXChargedClusters; //Momentum of charged X clusters in CMS-System
624  TLorentzVector momXNeutralClusters; //Momentum of neutral X clusters in CMS-System
625  TLorentzVector momTarget = T.rotateLabToCms() * particle -> get4Vector(); //Momentum of Mu in CMS-System
626 
627  double output = 0.0;
628 
629  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
630  if (roe.isValid())
631  {
632  const auto& tracks = roe->getTracks();
633  for (auto& track : tracks) {
634  const PIDLikelihood* iPidLikelihood = track->getRelated<PIDLikelihood>();
635  const Const::ChargedStable charged = iPidLikelihood ? iPidLikelihood->getMostLikely() : Const::pion;
636  const TrackFitResult* iTrack = track->getTrackFitResultWithClosestMass(charged);
637  if (iTrack == nullptr) continue;
638  if (track != particle->getTrack()) {
639  TLorentzVector iTrackMom = iTrack->get4Momentum();
640  if (iTrackMom == iTrackMom) momXChargedTracks += iTrackMom;
641  }
642  }
643 
644  momXNeutralClusters = roe->get4VectorNeutralECLClusters();
645 
646  const auto& klm = roe->getKLMClusters();
647  for (auto& x : klm) {
648  if (x == nullptr) continue;
649  TLorentzVector iMomKLMCluster = x -> getMomentum();
650  if (iMomKLMCluster == iMomKLMCluster) {
651  if (!(x -> getAssociatedTrackFlag()) && !(x -> getAssociatedEclClusterFlag())) {
652  momXNeutralClusters += iMomKLMCluster;
653  }
654  }
655  }
656 
657  // TLorentzVector momXcharged(momXchargedtracks.Vect(), momXchargedclusters.E());
658  TLorentzVector momX = T.rotateLabToCms() * (momXChargedTracks +
659  momXNeutralClusters); //Total Momentum of the recoiling X in CMS-System
660  TLorentzVector momMiss = -(momX + momTarget); //Momentum of Anti-v in CMS-System
661 
662  if (requestedVariable == "recoilMass") output = momX.M();
663  else if (requestedVariable == "recoilMassSqrd") output = momX.M2();
664  else if (requestedVariable == "pMissCMS") output = momMiss.Vect().Mag();
665  else if (requestedVariable == "cosThetaMissCMS") output = TMath::Cos(momTarget.Angle(momMiss.Vect()));
666  else if (requestedVariable == "EW90") {
667 
668  TLorentzVector momW = momTarget + momMiss; //Momentum of the W-Boson in CMS
669  float E_W_90 = 0 ; // Energy of all charged and neutral clusters in the hemisphere of the W-Boson
670 
671  const auto& ecl = roe->getECLClusters();
672  for (auto& x : ecl) {
673  if (x == nullptr) continue;
674  float iEnergy = x -> getEnergy(ECLCluster::EHypothesisBit::c_nPhotons);
675  if (x->isNeutral() && iEnergy == iEnergy) {
676  if ((T.rotateLabToCms() * C.Get4MomentumFromCluster(x,
677  ECLCluster::EHypothesisBit::c_nPhotons)).Vect().Dot(momW.Vect()) > 0) E_W_90 += iEnergy;
678  }
679  }
680  for (auto& track : tracks) {
681  if (track != particle->getTrack()) {
682  for (const ECLCluster& chargedCluster : track->getRelationsWith<ECLCluster>()) {
683  // ignore everything except the nPhotons hypothesis
684  if (!chargedCluster.hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons))
685  continue;
686  float iEnergy = chargedCluster.getEnergy(ECLCluster::EHypothesisBit::c_nPhotons);
687  if (iEnergy == iEnergy) {
688  if ((T.rotateLabToCms() * C.Get4MomentumFromCluster(&chargedCluster,
689  ECLCluster::EHypothesisBit::c_nPhotons)).Vect().Dot(momW.Vect()) > 0) E_W_90 += iEnergy;
690  }
691  }
692  }
693  }
694 
695  // for (auto & i : klm) {
696  // if ((T.rotateLabToCms() * i -> getMomentum()).Vect().Dot(momW.Vect()) > 0) E_W_90 +=;
697  // }
698 
699  output = E_W_90;
700  } else {
701  B2FATAL("Wrong variable " << requestedVariable <<
702  " requested. The possibilities are recoilMass, recoilMassSqrd, pMissCMS, cosThetaMissCMS or EW90");
703  }
704  }
705  return output;
706  };
707  return func;
708  } else {
709  B2FATAL("Wrong number of arguments (1 required) for meta function BtagToWBosonVariables");
710  }
711  }
712 
713  Manager::FunctionPtr KaonPionVariables(const std::vector<std::string>& arguments)
714  {
715  if (arguments.size() == 1) {
716  auto requestedVariable = arguments[0];
717  auto func = [requestedVariable](const Particle * particle) -> double {
718 // StoreObjPtr<ParticleList> KaonList("K+:ROE");
719  StoreObjPtr<ParticleList> SlowPionList("pi+:inRoe");
720 
721  PCmsLabTransform T;
722  TLorentzVector momTargetKaon = T.rotateLabToCms() * particle -> get4Vector();
723  TLorentzVector momTargetSlowPion;
724 
725  float chargeTargetKaon = particle -> getCharge();
726 
727  double output = 0.0;
728 
729  if ((requestedVariable == "HaveOpositeCharges") || (requestedVariable == "cosKaonPion"))
730  {
731  float chargeTargetSlowPion = 0;
732  if (SlowPionList.isValid()) {
733  double maximumProbSlowPion = 0;
734  for (unsigned int i = 0; i < SlowPionList->getListSize(); ++i) {
735  Particle* pSlowPion = SlowPionList->getParticle(i);
736  if (pSlowPion != nullptr) {
737  if (pSlowPion -> hasExtraInfo("isRightCategory(SlowPion)")) {
738  double probSlowPion = pSlowPion->getExtraInfo("isRightCategory(SlowPion)");
739  if (probSlowPion > maximumProbSlowPion) {
740  maximumProbSlowPion = probSlowPion;
741  chargeTargetSlowPion = pSlowPion -> getCharge();
742  momTargetSlowPion = T.rotateLabToCms() * pSlowPion -> get4Vector();
743  }
744  }
745  }
746  }
747  }
748  if (requestedVariable == "HaveOpositeCharges") {
749  if (chargeTargetKaon * chargeTargetSlowPion == -1) output = 1;
750  }
751  if (requestedVariable == "cosKaonPion") {
752  if (momTargetKaon == momTargetKaon
753  && momTargetSlowPion == momTargetSlowPion) output = TMath::Cos(momTargetKaon.Angle(momTargetSlowPion.Vect()));
754  }
755 
756  } else {
757  B2FATAL("Wrong variable " << requestedVariable << " requested. The possibilities are cosKaonPion or HaveOpositeCharges");
758  }
759  return output;
760  };
761  return func;
762  } else {
763  B2FATAL("Wrong number of arguments (1 required) for meta function KaonPionVariables");
764  }
765  }
766 
767  Manager::FunctionPtr FSCVariables(const std::vector<std::string>& arguments)
768  {
769  if (arguments.size() == 1) {
770  auto requestedVariable = arguments[0];
771  auto func = [requestedVariable](const Particle * particle) -> double {
772  StoreObjPtr<ParticleList> FastParticleList("pi+:inRoe");
773  PCmsLabTransform T;
774  TLorentzVector momSlowPion = T.rotateLabToCms() * particle -> get4Vector(); //Momentum of Slow Pion in CMS-System
775  TLorentzVector momFastParticle; //Momentum of Fast Pion in CMS-System
776 
777  double output = 0.0;
778 
779  if ((requestedVariable == "pFastCMS") || (requestedVariable == "cosSlowFast") || (requestedVariable == "cosTPTOFast") || (requestedVariable == "SlowFastHaveOpositeCharges"))
780  {
781  if (FastParticleList.isValid()) {
782  double maximumProbFastest = 0;
783  Particle* TargetFastParticle = nullptr;
784  for (unsigned int i = 0; i < FastParticleList->getListSize(); ++i) {
785  Particle* particlei = FastParticleList->getParticle(i);
786  if (particlei != nullptr) {
787  TLorentzVector momParticlei = T.rotateLabToCms() * particlei -> get4Vector();
788  if (momParticlei == momParticlei) {
789  double probFastest = momParticlei.P();
790  if (probFastest > maximumProbFastest) {
791  maximumProbFastest = probFastest;
792  TargetFastParticle = particlei;
793  momFastParticle = momParticlei;
794  }
795  }
796  }
797  }
798  if (TargetFastParticle != nullptr) {
799  if (requestedVariable == "cosTPTOFast") output = Variable::Manager::Instance().getVariable("cosTPTO")->function(
800  TargetFastParticle);
801  if (momSlowPion == momSlowPion) { // FIXME
802  if (requestedVariable == "cosSlowFast") output = TMath::Cos(momSlowPion.Angle(momFastParticle.Vect()));
803  else if (requestedVariable == "SlowFastHaveOpositeCharges") {
804  if (particle->getCharge()*TargetFastParticle->getCharge() == -1) {
805  output = 1;
806  }
807  } else output = momFastParticle.P();
808  }
809  }
810  }
811  } else {
812  B2FATAL("Wrong variable " << requestedVariable << " requested. The possibilities are pFastCMS, cosSlowFast or cosTPTOFast");
813  }
814  return output;
815  };
816  return func;
817  } else {
818  B2FATAL("Wrong number of arguments (1 required) for meta function FSCVariables");
819  }
820  }
821 
822  Manager::FunctionPtr hasHighestProbInCat(const std::vector<std::string>& arguments)
823  {
824  if (arguments.size() == 2) {
825  auto particleListName = arguments[0];
826  auto extraInfoName = arguments[1];
827  auto func = [particleListName, extraInfoName](const Particle * particle) -> double {
828  if (!(extraInfoName == "isRightTrack(Electron)" || extraInfoName == "isRightTrack(IntermediateElectron)" || extraInfoName == "isRightTrack(Muon)" || extraInfoName == "isRightTrack(IntermediateMuon)"
829  || extraInfoName == "isRightTrack(KinLepton)" || extraInfoName == "isRightTrack(IntermediateKinLepton)" || extraInfoName == "isRightTrack(Kaon)"
830  || extraInfoName == "isRightTrack(SlowPion)" || extraInfoName == "isRightTrack(FastHadron)" || extraInfoName == "isRightTrack(MaximumPstar)" || extraInfoName == "isRightTrack(Lambda)"
831  || extraInfoName == "isRightCategory(Electron)" || extraInfoName == "isRightCategory(IntermediateElectron)" || extraInfoName == "isRightCategory(Muon)" || extraInfoName == "isRightCategory(IntermediateMuon)"
832  || extraInfoName == "isRightCategory(KinLepton)" || extraInfoName == "isRightCategory(IntermediateKinLepton)" || extraInfoName == "isRightCategory(Kaon)"
833  || extraInfoName == "isRightCategory(SlowPion)" || extraInfoName == "isRightCategory(FastHadron)" || extraInfoName == "isRightCategory(KaonPion)" || extraInfoName == "isRightCategory(Lambda)"
834  || extraInfoName == "isRightCategory(MaximumPstar)" || extraInfoName == "isRightCategory(FSC)"))
835  {
836  B2FATAL("hasHighestProbInCat: Not available category" << extraInfoName <<
837  ". The possibilities for isRightTrack() are \nElectron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, MaximumPstar, and Lambda."
838  << endl <<
839  "The possibilities for isRightCategory() are \nElectron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
840  return 0.0;
841  }
842 
843  StoreObjPtr<ParticleList> ListOfParticles(particleListName);
844  PCmsLabTransform T;
845 
846  double output = 0.0;
847 
848  if (ListOfParticles.isValid())
849  {
850  double maximumProb = 0;
851  for (unsigned int i = 0; i < ListOfParticles->getListSize(); ++i) {
852  Particle* particlei = ListOfParticles->getParticle(i);
853  if (particlei != nullptr) {
854  double prob = 0;
855  if (extraInfoName == "isRightTrack(MaximumPstar)") {
856  TLorentzVector momParticlei = T.rotateLabToCms() * particlei -> get4Vector();
857  if (momParticlei == momParticlei) {
858  prob = momParticlei.P();
859  }
860  } else {
861  if (particlei->hasExtraInfo(extraInfoName)) {
862  prob = particlei->getExtraInfo(extraInfoName);
863  }
864  }
865  if (prob > maximumProb) {
866  maximumProb = prob;
867  }
868  }
869  }
870  if ((extraInfoName == "isRightTrack(MaximumPstar)" && (T.rotateLabToCms() * particle -> get4Vector()).P() == maximumProb)) {
871  output = 1.0;
872  } else if (extraInfoName != "isRightTrack(MaximumPstar)" && particle -> hasExtraInfo(extraInfoName)) {
873  if (particle -> getExtraInfo(extraInfoName) == maximumProb) output = 1.0;
874  }
875  }
876  return output;
877  };
878  return func;
879  } else {
880  B2FATAL("Wrong number of arguments (2 required) for meta function hasHighestProbInCat");
881  }
882  }
883 
884  Manager::FunctionPtr HighestProbInCat(const std::vector<std::string>& arguments)
885  {
886  if (arguments.size() == 2) {
887  auto particleListName = arguments[0];
888  auto extraInfoName = arguments[1];
889  auto func = [particleListName, extraInfoName](const Particle*) -> double {
890  if (!(extraInfoName == "isRightTrack(Electron)" || extraInfoName == "isRightTrack(IntermediateElectron)" || extraInfoName == "isRightTrack(Muon)" || extraInfoName == "isRightTrack(IntermediateMuon)"
891  || extraInfoName == "isRightTrack(KinLepton)" || extraInfoName == "isRightTrack(IntermediateKinLepton)" || extraInfoName == "isRightTrack(Kaon)"
892  || extraInfoName == "isRightTrack(SlowPion)" || extraInfoName == "isRightTrack(FastHadron)" || extraInfoName == "isRightTrack(MaximumPstar)" || extraInfoName == "isRightTrack(Lambda)"
893  || extraInfoName == "isRightCategory(Electron)" || extraInfoName == "isRightCategory(IntermediateElectron" || extraInfoName == "isRightCategory(Muon)" || extraInfoName == "isRightCategory(IntermediateMuon)"
894  || extraInfoName == "isRightCategory(KinLepton)" || extraInfoName == "isRightCategory(IntermediateKinLepton)" || extraInfoName == "isRightCategory(Kaon)"
895  || extraInfoName == "isRightCategory(SlowPion)" || extraInfoName == "isRightCategory(FastHadron)" || extraInfoName == "isRightCategory(KaonPion)" || extraInfoName == "isRightCategory(Lambda)"
896  || extraInfoName == "isRightCategory(MaximumPstar)" || extraInfoName == "isRightCategory(FSC)"))
897  {
898  B2FATAL("HighestProbInCat: Not available category" << extraInfoName <<
899  ". The possibilities for isRightTrack() are \nElectron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, MaximumPstar, and Lambda."
900  << endl <<
901  "The possibilities for isRightCategory() are \nElectron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
902  return 0.0;
903  }
904 
905  StoreObjPtr<ParticleList> ListOfParticles(particleListName);
906  PCmsLabTransform T;
907  double maximumProb = 0;
908  if (ListOfParticles.isValid())
909  {
910  for (unsigned int i = 0; i < ListOfParticles->getListSize(); ++i) {
911  Particle* particlei = ListOfParticles->getParticle(i);
912  if (particlei != nullptr) {
913  double prob = 0;
914  if (extraInfoName == "isRightTrack(MaximumPstar)") {
915  TLorentzVector momParticlei = T.rotateLabToCms() * particlei -> get4Vector();
916  if (momParticlei == momParticlei) {
917  prob = momParticlei.P();
918  }
919  } else {
920  if (particlei->hasExtraInfo(extraInfoName)) {
921  prob = particlei->getExtraInfo(extraInfoName);
922  }
923  }
924  if (prob > maximumProb) {
925  maximumProb = prob;
926  }
927  }
928  }
929  }
930  return maximumProb;
931  };
932  return func;
933  } else {
934  B2FATAL("Wrong number of arguments (2 required) for meta function HighestProbInCat");
935  }
936  }
937 
938 // Target Variables ----------------------------------------------------------------------------------------------
939 
940  // Lists used in target variables
941  std::vector<int> charmMesons = { 411, 421, 10411, 10421, 413, 423, 10413, 10423, 20413, 20423, 415, 425, 431, 10431, 433, 10433, 20433, 435};
942 
943  std::vector<int> charmBaryons = { 4122, 4222, 4212, 4112, 4224, 4214, 4114, 4232, 4132, 4322, 4312, 4324, 4314, 4332, 4334, 4412, 4422,
944  4414, 4424, 4432, 4434, 4444
945  };
946 
947  std::vector<int> qqbarMesons = {// light qqbar
948  111, 9000111, 100111, 10111, 200111, 113, 10113, 20113, 9000113, 100113, 9010113, 9020113, 30113, 9030113, 9040113,
949  115, 10115, 100115, 9000115, 117, 9000117, 9010117, 119,
950  // ssbar Mesons
951  221, 331, 9000221, 9010221, 100221, 10221, 100331, 9020221, 10331, 200221, 9030221, 9040221, 9050221, 9060221, 9070221, 223, 333, 10223, 20223,
952  10333, 20333, 100223, 9000223, 9010223, 30223, 100333, 225, 9000225, 335, 9010225, 9020225, 10225, 9030225, 10335, 9040225, 100225, 100335,
953  9050225, 9060225, 9070225, 227, 337, 229, 9000339, 9000229,
954  // ccbar Mesons
955  441, 10441, 100441, 443, 10443, 20443, 100443, 30443, 9000443, 9010443, 9020443, 445, 9000445
956  };
957 
958  std::vector<int> flavorConservingMesons = {// Excited light mesons that can decay into hadrons conserving flavor
959  9000211, 100211, 10211, 200211, 213, 10213, 20213, 9000213, 100213, 9010213, 9020213, 30213, 9030213, 9040213,
960  215, 10215, 100215, 9000215, 217, 9000217, 9010217, 219,
961  // Excited K Mesons that hadronize conserving flavor
962  30343, 10311, 10321, 100311, 100321, 200311, 200321, 9000311, 9000321, 313, 323, 10313, 10323, 20313, 20323, 100313, 100323,
963  9000313, 9000323, 30313, 30323, 315, 325, 9000315, 9000325, 10315, 10325, 20315, 20325, 100315, 100325, 9010315,
964  9010325, 317, 327, 9010317, 9010327, 319, 329, 9000319, 9000329
965  };
966 
967  Manager::FunctionPtr isRightTrack(const std::vector<std::string>& arguments)
968  {
969  if (arguments.size() == 1) {
970  auto particleName = arguments[0];
971 
972  int index = -1;
973  std::vector<std::string> names = { "Electron", // 0
974  "IntermediateElectron", // 1
975  "Muon", // 2
976  "IntermediateMuon", // 3
977  "KinLepton", // 4
978  "IntermediateKinLepton",// 5
979  "Kaon", // 6
980  "SlowPion", // 7
981  "FastHadron", // 8
982  "Lambda", // 9
983  "mcAssociated" // 10
984  };
985 
986  for (unsigned i = 0; i < names.size(); ++i) {
987  if (particleName == names[i]) index = i;
988  }
989 
990  if (index == -1) {
991  B2FATAL("isRightTrack: Not available category " << particleName <<
992  ". The possibilities are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron and Lambda");
993  }
994 
995  auto func = [index](const Particle * particle) -> double {
996 
997  const MCParticle* mcParticle = particle->getRelated<MCParticle>();
998  if (mcParticle == nullptr) return -2.0;
999 
1000  int mcPDG = TMath::Abs(mcParticle->getPDG());
1001 
1002  // ---------------------------- Mothers and Grandmothers ----------------------------------
1003  std::vector<int> mothersPDG;
1004  std::vector<const MCParticle*> mothersPointers;
1005 
1006  const MCParticle* mcMother = mcParticle->getMother();
1007  while (mcMother != nullptr)
1008  {
1009  mothersPDG.push_back(TMath::Abs(mcMother->getPDG()));
1010  if (index == 8) mothersPointers.push_back(mcMother);
1011  if (TMath::Abs(mcMother->getPDG()) == 511) break;
1012  mcMother = mcMother -> getMother();
1013  }
1014 
1015  if (mothersPDG.size() == 0) return -2.0;
1016 
1017  //has associated mothers up to a B meson
1018  if (index == 10) return 1.0;
1019 
1020  // ---------------- Is D Meson in the decay chain --------------------------------------
1021 
1022  bool isCharmedMesonInChain = false;
1023 
1024  if ((index == 6) && mothersPDG.size() > 1)
1025  {
1026 
1027  for (auto& iMCMotherPDG : mothersPDG) {
1028  if (std::find(charmMesons.begin(), charmMesons.end(), iMCMotherPDG) != charmMesons.end()) {
1029  isCharmedMesonInChain = true;
1030  break;
1031  }
1032  }
1033 
1034  }
1035 
1036  // ---------------- Is Charmed Baryon in the decay chain --------------------------------
1037 
1038  bool isCharmedBaryonInChain = false;
1039 
1040  if ((index == 6 || index == 9) && mothersPDG.size() > 1)
1041  {
1042 
1043  for (auto& iMCMotherPDG : mothersPDG) {
1044  if (std::find(charmBaryons.begin(), charmBaryons.end(), iMCMotherPDG) != charmBaryons.end()) {
1045  isCharmedBaryonInChain = true;
1046  break;
1047  }
1048  }
1049  }
1050 
1051  // ---------------- Is neutral qqbar Meson in the decay chain --------------------------------
1052 
1053  bool isQQbarMesonInChain = false;
1054 
1055  if ((index == 1 || index == 3 || index == 5 || index == 6 || index == 8) && mothersPDG.size() > 1)
1056  {
1057 
1058  for (auto& iMCMotherPDG : mothersPDG) {
1059  if (std::find(qqbarMesons.begin(), qqbarMesons.end(), iMCMotherPDG) != qqbarMesons.end()) {
1060  isQQbarMesonInChain = true;
1061  break;
1062  }
1063  }
1064 
1065  }
1066 
1067  // -------------- Is the Hadron a descendent of a Meson that conserves flavor --------------------------
1068 
1069  bool isB0DaughterConservingFlavor = false;
1070 
1071  if ((index == 8) && mothersPDG.size() > 1)
1072  {
1073 
1074  if (std::find(flavorConservingMesons.begin(), flavorConservingMesons.end(),
1075  mothersPDG.rbegin()[1]) != flavorConservingMesons.end()) {
1076  isB0DaughterConservingFlavor = true;
1077  }
1078 
1079  }
1080 
1081  // ----------------------------- Is the Hadron a single daugther of a tau ----- --------------------------
1082 
1083  bool isHadronSingleTauDaughter = false;
1084 
1085  if (index == 8 && mothersPDG.size() > 1 && mothersPDG.rbegin()[1] == 15)
1086  {
1087  int numberOfChargedDaughters = 0;
1088  for (auto& tauDaughter : mothersPointers.rbegin()[1] -> getDaughters()) {
1089  if (tauDaughter -> getCharge() != 0) numberOfChargedDaughters += 1;
1090  }
1091  if (numberOfChargedDaughters == 1) isHadronSingleTauDaughter = true;
1092  }
1093 
1094  //direct electron
1095  if (index == 0
1096  && mcPDG == 11
1097  && mothersPDG[0] == 511)
1098  {
1099  return 1.0;
1100  //intermediate electron
1101  } else if (index == 1
1102  && mcPDG == 11 && mothersPDG.size() > 1
1103  && isQQbarMesonInChain == false)
1104  {
1105  return 1.0;
1106  //direct muon
1107  } else if (index == 2
1108  && mcPDG == 13 && mothersPDG[0] == 511)
1109  {
1110  return 1.0;
1111  //intermediate muon
1112  } else if (index == 3
1113  && mcPDG == 13 && mothersPDG.size() > 1
1114  && isQQbarMesonInChain == false)
1115  {
1116  return 1.0;
1117  //KinLepton
1118  } else if (index == 4
1119  && (mcPDG == 13 || mcPDG == 11) && mothersPDG[0] == 511)
1120  {
1121  return 1.0;
1122  //IntermediateKinLepton
1123  } else if (index == 5
1124  && (mcPDG == 13 || mcPDG == 11) && mothersPDG.size() > 1
1125  && isQQbarMesonInChain == false)
1126  {
1127  return 1.0;
1128  //kaon
1129  } else if (index == 6
1130  && mcPDG == 321 && isQQbarMesonInChain == false && (isCharmedMesonInChain == true || isCharmedBaryonInChain == true))
1131  {
1132  return 1.0;
1133  //slow pion
1134  } else if (index == 7
1135  && mcPDG == 211 && mothersPDG.size() > 1 && mothersPDG[0] == 413 && mothersPDG[1] == 511)
1136  {
1137  return 1.0;
1138  //high momentum hadrons
1139  } else if (index == 8
1140  && (mcPDG == 211 || mcPDG == 321) && isQQbarMesonInChain == false && (mothersPDG[0] == 511 || (mothersPDG.rbegin()[0] == 511
1141  && (isB0DaughterConservingFlavor == true || isHadronSingleTauDaughter == true))))
1142  {
1143  return 1.0;
1144  //lambdas
1145  } else if (index == 9 && mcPDG == 3122 && isCharmedBaryonInChain == true)
1146  {
1147  return 1.0;
1148  } else return 0.0;
1149  };
1150  return func;
1151  } else {
1152  B2FATAL("Wrong number of arguments (1 required) for meta function isRightTrack");
1153  }
1154  }
1155 
1156  Manager::FunctionPtr isRightCategory(const std::vector<std::string>& arguments)
1157  {
1158  if (arguments.size() == 1) {
1159  auto particleName = arguments[0];
1160  int index = -1;
1161  std::vector<std::string> names = { "Electron", // 0
1162  "IntermediateElectron", // 1
1163  "Muon", // 2
1164  "IntermediateMuon", // 3
1165  "KinLepton", // 4
1166  "IntermediateKinLepton",// 5
1167  "Kaon", // 6
1168  "SlowPion", // 7
1169  "FastHadron", // 8
1170  "KaonPion", // 9
1171  "MaximumPstar", // 10
1172  "FSC", // 11
1173  "Lambda", // 12
1174  "mcAssociated" // 13
1175  };
1176 
1177  for (unsigned i = 0; i < names.size(); ++i) {
1178  if (particleName == names[i]) index = i;
1179  }
1180 
1181  if (index == -1) {
1182  B2FATAL("isRightCategory: Not available category " << particleName <<
1183  ". The possibilities are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
1184  }
1185 
1186  auto func = [index](const Particle * particle) -> double {
1187 
1188  Particle* nullParticle = nullptr;
1189  float qTarget = particle -> getCharge();
1190  float qMC = Variable::isRestOfEventB0Flavor(nullParticle);
1191 
1192  const MCParticle* mcParticle = particle->getRelated<MCParticle>();
1193  if (mcParticle == nullptr) return -2.0;
1194 
1195  int mcPDG = TMath::Abs(mcParticle->getPDG());
1196 
1197  // ---------------------------- Mothers and Grandmothers ---------------------------------
1198  std::vector<int> mothersPDG;
1199  std::vector<const MCParticle*> mothersPointers;
1200 
1201  const MCParticle* mcMother = mcParticle->getMother();
1202  while (mcMother != nullptr)
1203  {
1204  mothersPDG.push_back(TMath::Abs(mcMother->getPDG()));
1205  if (index == 8 || index == 9) mothersPointers.push_back(mcMother);
1206  if (TMath::Abs(mcMother->getPDG()) == 511) break;
1207  mcMother = mcMother -> getMother();
1208  }
1209 
1210  if (mothersPDG.size() == 0) return -2.0;
1211  //has associated mothers up to a B meson
1212  if (index == 13) return 1.0;
1213 
1214  // ---------------- Is D Meson in the decay chain --------------------------------------
1215 
1216  bool isCharmedMesonInChain = false;
1217 
1218  if ((index == 6) && mothersPDG.size() > 1)
1219  {
1220 
1221  for (auto& iMCMotherPDG : mothersPDG) {
1222  if (std::find(charmMesons.begin(), charmMesons.end(), iMCMotherPDG) != charmMesons.end()) {
1223  isCharmedMesonInChain = true;
1224  break;
1225  }
1226  }
1227 
1228  }
1229 
1230  // ---------------- Is Charmed Baryon in the decay chain --------------------------------
1231 
1232  bool isCharmedBaryonInChain = false;
1233 
1234  if ((index == 6 || index == 12) && mothersPDG.size() > 1)
1235  {
1236 
1237  for (auto& iMCMotherPDG : mothersPDG) {
1238  if (std::find(charmBaryons.begin(), charmBaryons.end(), iMCMotherPDG) != charmBaryons.end()) {
1239  isCharmedBaryonInChain = true;
1240  break;
1241  }
1242  }
1243  }
1244 
1245  // ---------------- Is neutral qqbar Meson in the decay chain --------------------------------
1246 
1247  bool isQQbarMesonInChain = false;
1248 
1249  if ((index == 1 || index == 3 || index == 5 || index == 6 || index == 8 || index == 11) && mothersPDG.size() > 1)
1250  {
1251 
1252  for (auto& iMCMotherPDG : mothersPDG) {
1253  if (std::find(qqbarMesons.begin(), qqbarMesons.end(), iMCMotherPDG) != qqbarMesons.end()) {
1254  isQQbarMesonInChain = true;
1255  break;
1256  }
1257  }
1258 
1259  }
1260 
1261  // -------------- Is the Hadron a descendent of a Meson that conserves flavor --------------------------
1262 
1263  bool isB0DaughterConservingFlavor = false;
1264 
1265  if ((index == 8) && mothersPDG.size() > 1)
1266  {
1267 
1268  if (std::find(flavorConservingMesons.begin(), flavorConservingMesons.end(),
1269  mothersPDG.rbegin()[1]) != flavorConservingMesons.end()) {
1270  isB0DaughterConservingFlavor = true;
1271  }
1272 
1273  }
1274 
1275  // ----------------------------- Is the Hadron a single daugther of a tau ----- --------------------------
1276 
1277  bool isHadronSingleTauDaughter = false;
1278 
1279  if (index == 8 && mothersPDG.size() > 1 && mothersPDG.rbegin()[1] == 15)
1280  {
1281  int numberOfChargedDaughters = 0;
1282  for (auto& tauDaughter : mothersPointers.rbegin()[1] -> getDaughters()) {
1283  if (tauDaughter -> getCharge() != 0) numberOfChargedDaughters += 1;
1284  }
1285  if (numberOfChargedDaughters == 1) isHadronSingleTauDaughter = true;
1286  }
1287 
1288  // ---------------------------- For KaonPion Category ------------------------------------
1289  bool haveKaonPionSameMother = false;
1290  // if KaonPion
1291  if (index == 9)
1292  {
1293  const MCParticle* mcSlowPionMother = nullptr;
1294  StoreObjPtr<ParticleList> SlowPionList("pi+:inRoe");
1295  Particle* targetSlowPion = nullptr;
1296  if (SlowPionList.isValid()) {
1297  double mcProbSlowPion = 0;
1298  for (unsigned int i = 0; i < SlowPionList->getListSize(); ++i) {
1299  Particle* pSlowPion = SlowPionList->getParticle(i);
1300  if (pSlowPion != nullptr) {
1301  if (pSlowPion -> hasExtraInfo("isRightCategory(SlowPion)")) {
1302  double probSlowPion = pSlowPion->getExtraInfo("isRightCategory(SlowPion)");
1303  if (probSlowPion > mcProbSlowPion) {
1304  mcProbSlowPion = probSlowPion;
1305  targetSlowPion = pSlowPion;
1306  }
1307  }
1308  }
1309  }
1310  if (targetSlowPion != nullptr) {
1311  const MCParticle* mcSlowPion = targetSlowPion ->getRelated<MCParticle>();
1312 // SlowPion_q = targetSlowPion -> getCharge();
1313  if (mcSlowPion != nullptr && mcSlowPion->getMother() != nullptr
1314  && TMath::Abs(mcSlowPion->getPDG()) == 211 && TMath::Abs(mcSlowPion->getMother()->getPDG()) == 413) {
1315  mcSlowPionMother = mcSlowPion->getMother();
1316  }
1317  }
1318  }
1319 
1320  if (std::find(mothersPointers.begin(), mothersPointers.end(), mcSlowPionMother) != mothersPointers.end())
1321  haveKaonPionSameMother = true;
1322 
1323  }
1324 
1325  // ---------------------------- For FastSlowCorrelated Category ----------------------------
1326  int FastParticlePDGMother = 0;
1327  float qFSC = 0;
1328  // FSC",
1329  if (index == 11)
1330  {
1331  StoreObjPtr<ParticleList> FastParticleList("pi+:inRoe");
1332  PCmsLabTransform T;
1333  Particle* targetFastParticle = nullptr;
1334  if (FastParticleList.isValid()) {
1335  double mcProbFastest = 0;
1336  for (unsigned int i = 0; i < FastParticleList->getListSize(); ++i) {
1337  Particle* particlei = FastParticleList->getParticle(i);
1338  if (particlei != nullptr) {
1339  TLorentzVector momParticlei = T.rotateLabToCms() * particlei -> get4Vector();
1340  if (momParticlei == momParticlei) {
1341  double probFastest = momParticlei.P();
1342  if (probFastest > mcProbFastest) {
1343  mcProbFastest = probFastest;
1344  targetFastParticle = particlei;
1345  }
1346  }
1347  }
1348  }
1349  if (targetFastParticle != nullptr) {
1350  const MCParticle* mcFastParticle = targetFastParticle ->getRelated<MCParticle>();
1351 // FastParticle_q = targetFastParticle -> getCharge();
1352  if (mcFastParticle != nullptr && mcFastParticle->getMother() != nullptr) {
1353  FastParticlePDGMother = TMath::Abs(mcFastParticle->getMother()->getPDG());
1354  qFSC = mcFastParticle->getCharge();
1355  }
1356  }
1357  }
1358  }
1359 
1360  // ------------------------------ Outputs -----------------------------------
1361  if (index == 0 // Electron
1362  && qTarget == qMC && mcPDG == 11 && mothersPDG[0] == 511)
1363  {
1364  return 1.0;
1365  } else if (index == 1 // IntermediateElectron
1366  && qTarget != qMC && mcPDG == 11 && mothersPDG.size() > 1
1367  && isQQbarMesonInChain == false)
1368  {
1369  return 1.0;
1370  } else if (index == 2 // Muon
1371  && qTarget == qMC && mcPDG == 13 && mothersPDG[0] == 511)
1372  {
1373  return 1.0;
1374  } else if (index == 3 // IntermediateMuon
1375  && qTarget != qMC && mcPDG == 13 && mothersPDG.size() > 1
1376  && isQQbarMesonInChain == false)
1377  {
1378  return 1.0;
1379  } else if (index == 4 // KinLepton
1380  && qTarget == qMC && (mcPDG == 11 || mcPDG == 13) && mothersPDG[0] == 511)
1381  {
1382  return 1.0;
1383  } else if (index == 5 // IntermediateKinLepton
1384  && qTarget != qMC && (mcPDG == 11 || mcPDG == 13) && mothersPDG.size() > 1
1385  && isQQbarMesonInChain == false)
1386  {
1387  return 1.0;
1388  } else if (index == 6 && qTarget == qMC // Kaon
1389  && mcPDG == 321 && isQQbarMesonInChain == false && (isCharmedMesonInChain == true || isCharmedBaryonInChain == true))
1390  {
1391  return 1.0;
1392  } else if (index == 7 && qTarget != qMC // SlowPion
1393  && mcPDG == 211 && mothersPDG.size() > 1 && mothersPDG[0] == 413 && mothersPDG[1] == 511)
1394  {
1395  return 1.0;
1396  } else if (index == 8 && qTarget == qMC // FastHadron
1397  && (mcPDG == 211 || mcPDG == 321) && isQQbarMesonInChain == false && (mothersPDG[0] == 511 || (mothersPDG.rbegin()[0] == 511
1398  && (isB0DaughterConservingFlavor == true || isHadronSingleTauDaughter == true))))
1399  {
1400  return 1.0;
1401  } else if (index == 9 && qTarget == qMC // KaonPion
1402  && mcPDG == 321 && haveKaonPionSameMother == true)
1403  {
1404  return 1.0;
1405  } else if (index == 10 && qTarget == qMC) // MaximumPstar
1406  {
1407  return 1.0;
1408  } else if (index == 11 && qTarget != qMC && mothersPDG.size() > 1 && qFSC == qMC // "FSC"
1409  && mcPDG == 211 && FastParticlePDGMother == 511 && isQQbarMesonInChain == false)
1410  {
1411  return 1.0;
1412  } else if (index == 12 && (particle->getPDGCode() / TMath::Abs(particle->getPDGCode())) != qMC // Lambda
1413  && mcPDG == 3122 && isCharmedBaryonInChain == true)
1414  {
1415  return 1.0;
1416  } else {
1417  return 0.0;
1418  }
1419  };
1420 
1421  return func;
1422  } else {
1423  B2FATAL("Wrong number of arguments (1 required) for meta function isRightCategory");
1424  }
1425  }
1426 
1427 
1428  // List of available extrainfos used in QpOf, weightedQpOf and variableOfTarget.
1429  std::vector<std::string> availableExtraInfos = { "isRightTrack(Electron)", // 0
1430  "isRightTrack(IntermediateElectron)", // 1
1431  "isRightTrack(Muon)", // 2
1432  "isRightTrack(IntermediateMuon)", // 3
1433  "isRightTrack(KinLepton)", // 4
1434  "isRightTrack(IntermediateKinLepton)",// 5
1435  "isRightTrack(Kaon)", // 6
1436  "isRightTrack(SlowPion)", // 7
1437  "isRightTrack(FastHadron)", // 8
1438  "isRightTrack(MaximumPstar)", // 9
1439  "isRightTrack(Lambda)", // 10
1440  "isRightCategory(Electron)", // 11
1441  "isRightCategory(IntermediateElectron)", // 12
1442  "isRightCategory(Muon)", // 13
1443  "isRightCategory(IntermediateMuon)", // 14
1444  "isRightCategory(KinLepton)", // 15
1445  "isRightCategory(IntermediateKinLepton)",// 16
1446  "isRightCategory(Kaon)", // 17
1447  "isRightCategory(SlowPion)", // 18
1448  "isRightCategory(FastHadron)", // 19
1449  "isRightCategory(MaximumPstar)", // 20
1450  "isRightCategory(Lambda)", // 21
1451  "isRightCategory(KaonPion)", // 22
1452  "isRightCategory(FSC)", // 23
1453  };
1454 
1455  Manager::FunctionPtr QpOf(const std::vector<std::string>& arguments)
1456  {
1457  if (arguments.size() == 3) {
1458  auto particleListName = arguments[0];
1459  auto outputExtraInfo = arguments[1];
1460  auto rankingExtraInfo = arguments[2];
1461 
1462  int indexOutput = -1;
1463  int indexRanking = -1;
1464 
1465  for (unsigned i = 0; i < availableExtraInfos.size(); ++i) {
1466  if (rankingExtraInfo == availableExtraInfos[i]) {indexRanking = i; break;}
1467  }
1468 
1469 
1470  for (unsigned i = 0; i < availableExtraInfos.size(); ++i) {
1471  if (outputExtraInfo == availableExtraInfos[i]) {indexOutput = i; break;}
1472  }
1473 
1474  if (indexRanking == -1) {
1475  B2FATAL("QpOf: Not available category " << rankingExtraInfo <<
1476  ". The possibilities for isRightTrack() are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, MaximumPstar, and Lambda"
1477  <<
1478  ". The possibilities for isRightCategory() are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
1479  }
1480 
1481  if (indexOutput == -1) {
1482  B2FATAL("QpOf: Not available category " << outputExtraInfo <<
1483  ". The possibilities for isRightTrack() are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, MaximumPstar, and Lambda"
1484  <<
1485  ". The possibilities for isRightCategory() are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
1486  }
1487 
1488 
1489  auto func = [particleListName, indexOutput, indexRanking](const Particle*) -> double {
1490  StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1491  PCmsLabTransform T;
1492  Particle* target = nullptr; //Particle selected as target
1493  float prob = 0; //The probability of beeing the right target with the right flavor
1494  float qTarget = 0; //Flavor of the track selected as target
1495 
1496  if (ListOfParticles.isValid())
1497  {
1498  float maximumTargetProb = 0; //Probability of being the target track from the track level
1499  for (unsigned int i = 0; i < ListOfParticles->getListSize(); ++i) {
1500  Particle* particlei = ListOfParticles->getParticle(i);
1501  if (particlei != nullptr) {
1502  double target_prob = 0;
1503  if (indexRanking == 9 || indexRanking == 20) { // MaximumPstar
1504  TLorentzVector momParticlei = T.rotateLabToCms() * particlei -> get4Vector();
1505  if (momParticlei == momParticlei) {
1506  target_prob = momParticlei.P();
1507  }
1508  } else {
1509  if (particlei->hasExtraInfo(availableExtraInfos[indexRanking])) {
1510  target_prob = particlei->getExtraInfo(availableExtraInfos[indexRanking]);
1511  }
1512  }
1513  if (target_prob > maximumTargetProb) {
1514  maximumTargetProb = target_prob;
1515  target = particlei;
1516  }
1517  }
1518  }
1519  if (target != nullptr) {
1520  prob = target -> getExtraInfo(
1521  availableExtraInfos[indexOutput]); //Get the probability of being right classified flavor from event level
1522  // Get the flavor of the track selected as target
1523  if (indexRanking == 10 || indexRanking == 21) { // Lambda
1524  qTarget = (-1) * target->getPDGCode() / TMath::Abs(target->getPDGCode());
1525  // IntermediateElectron IntermediateMuon IntermediateKinLepton SlowPion
1526  } else if (indexRanking == 1 || indexRanking == 3 || indexRanking == 5 || indexRanking == 7 ||
1527  indexRanking == 12 || indexRanking == 14 || indexRanking == 16 || indexRanking == 18
1528  ) {
1529  qTarget = (-1) * target -> getCharge();
1530  } else qTarget = target -> getCharge();
1531  }
1532  }
1533  //float r = TMath::Abs(2 * prob - 1); //Definition of the dilution factor */
1534  //return 0.5 * (qTarget * r + 1);
1535  return qTarget * prob;
1536  };
1537  return func;
1538  } else {
1539  B2FATAL("Wrong number of arguments (3 required) for meta function QpOf");
1540  }
1541  }
1542 
1543  Manager::FunctionPtr weightedQpOf(const std::vector<std::string>& arguments)
1544  {
1545  //used by simple_flavor_tagger
1546  if (arguments.size() == 3) {
1547 
1548  auto particleListName = arguments[0];
1549  auto outputExtraInfo = arguments[1];
1550  auto rankingExtraInfo = arguments[2];
1551 
1552  int indexOutput = -1;
1553  int indexRanking = -1;
1554 
1555 
1556  for (unsigned i = 0; i < availableExtraInfos.size(); ++i) {
1557  if (rankingExtraInfo == availableExtraInfos[i]) {indexRanking = i; break;}
1558  }
1559 
1560 
1561  for (unsigned i = 0; i < availableExtraInfos.size(); ++i) {
1562  if (outputExtraInfo == availableExtraInfos[i]) {indexOutput = i; break;}
1563  }
1564 
1565  if (indexRanking == -1) {
1566  B2FATAL("weightedQpOf: Not available category " << rankingExtraInfo <<
1567  ". The possibilities for isRightTrack() are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, MaximumPstar, and Lambda"
1568  <<
1569  ". The possibilities for isRightCategory() are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
1570  }
1571 
1572  if (indexOutput == -1) {
1573  B2FATAL("weightedQpOf: Not available category " << outputExtraInfo <<
1574  ". The possibilities for isRightTrack() are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, MaximumPstar, and Lambda"
1575  <<
1576  ". The possibilities for isRightCategory() are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
1577  }
1578 
1579  auto func = [particleListName, indexOutput, indexRanking, rankingExtraInfo](const Particle*) -> double {
1580 
1581  double final_value = 0.0;
1582 
1583  auto compare = [rankingExtraInfo](const Particle * part1, const Particle * part2)-> bool {
1584  double info1 = 0;
1585  double info2 = 0;
1586  if (part1->hasExtraInfo(rankingExtraInfo)) info1 = part1->getExtraInfo(rankingExtraInfo);
1587  if (part2->hasExtraInfo(rankingExtraInfo)) info2 = part2->getExtraInfo(rankingExtraInfo);
1588  return (info1 > info2);
1589  };
1590 
1591  auto compareMomentum = [rankingExtraInfo](const Particle * part1, const Particle * part2)-> bool {
1592  PCmsLabTransform T;
1593  double info1 = 0;
1594  double info2 = 0;
1595  info1 = (T.rotateLabToCms() * part1 -> get4Vector()).P();
1596  info2 = (T.rotateLabToCms() * part2 -> get4Vector()).P();
1597  return (info1 > info2);
1598  };
1599 
1600  StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1601  if (ListOfParticles)
1602  {
1603  if (ListOfParticles->getListSize() > 0) {
1604  double val1 = 1.0;
1605  double val2 = 1.0;
1606  std::vector<const Particle*> ParticleVector;
1607  ParticleVector.reserve(ListOfParticles->getListSize());
1608 
1609  for (unsigned int i = 0; i < ListOfParticles->getListSize(); i++) {
1610  ParticleVector.push_back(ListOfParticles->getParticle(i));
1611  }
1612 
1613  if (indexRanking == 9 ||
1614  indexRanking == 20) std::sort(ParticleVector.begin(), ParticleVector.end(), compareMomentum); // MaximumPstar
1615  else std::sort(ParticleVector.begin(), ParticleVector.end(), compare);
1616 
1617  if (ParticleVector.size() != 0) final_value = 1.0;
1618  //Loop over K+ vector until 3 or empty
1619  unsigned int Limit = ParticleVector.size() > 3 ? 3 : ParticleVector.size();
1620  for (unsigned int i = 0; i < Limit; i++) {
1621  if (ParticleVector[i]->hasExtraInfo(availableExtraInfos[indexOutput])) {
1622  double flavor = 0.0;
1623  if (indexRanking == 10 || indexRanking == 21) { // Lambda
1624  flavor = (-1) * ParticleVector[i]->getPDGCode() / TMath::Abs(ParticleVector[i]->getPDGCode());
1625  // IntermediateElectron IntermediateMuon IntermediateKinLepton SlowPion
1626  } else if (indexRanking == 1 || indexRanking == 3 || indexRanking == 5 || indexRanking == 7 ||
1627  indexRanking == 12 || indexRanking == 14 || indexRanking == 16 || indexRanking == 18
1628  ) {
1629  flavor = (-1) * ParticleVector[i] -> getCharge();
1630  } else flavor = ParticleVector[i]->getCharge();
1631 
1632  double p = ParticleVector[i]->getExtraInfo(availableExtraInfos[indexOutput]);
1633 // B2INFO("Right Track:" << ParticleVector[i]->getExtraInfo(availableExtraInfos[indexRanking]));
1634 // B2INFO("Right Cat:" << ParticleVector[i]->getExtraInfo(availableExtraInfos[indexOutput]));
1635  double qp = (flavor * p);
1636  val1 = val1 * (1 + qp);
1637  val2 = val2 * (1 - qp);
1638  }
1639  }
1640  final_value = (val1 - val2) / (val1 + val2);
1641  }
1642  }
1643  return final_value;
1644  };
1645  return func;
1646  } else {
1647  B2FATAL("Wrong number of arguments (3 required) for meta function weightedQpOf");
1648  }
1649  }
1650 
1651  Manager::FunctionPtr variableOfTarget(const std::vector<std::string>& arguments)
1652  {
1653 
1654  if (arguments.size() != 3)
1655  B2FATAL("Wrong number of arguments (3 required) for meta function variableOfTarget");
1656 
1657  auto particleListName = arguments[0];
1658  auto inputVariable = arguments[1];
1659  auto rankingExtraInfo = arguments[2];
1660 
1661  int indexRanking = -1;
1662 
1663  for (unsigned i = 0; i < availableExtraInfos.size(); ++i) {
1664  if (rankingExtraInfo == availableExtraInfos[i]) {indexRanking = i; break;}
1665  }
1666 
1667  if (indexRanking == -1) {
1668  B2FATAL("variableOfTarget: category " << rankingExtraInfo << "not available" <<
1669  ". The possibilities for isRightTrack() are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, MaximumPstar, and Lambda"
1670  <<
1671  ". The possibilities for isRightCategory() are Electron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
1672  }
1673 
1674 
1675  auto func = [particleListName, inputVariable, indexRanking](const Particle*) -> double {
1676  StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1677  PCmsLabTransform T;
1678  Particle* target = nullptr; //Particle selected as target
1679  double output = std::numeric_limits<float>::quiet_NaN();
1680 
1681  if (ListOfParticles.isValid())
1682  {
1683  float maximumTargetProb = 0; //Probability of being the target track from the track level
1684  for (unsigned int i = 0; i < ListOfParticles->getListSize(); ++i) {
1685  Particle* particlei = ListOfParticles->getParticle(i);
1686  if (particlei != nullptr) {
1687  double target_prob = 0;
1688  if (indexRanking == 9 || indexRanking == 20) { // MaximumPstar
1689  TLorentzVector momParticlei = T.rotateLabToCms() * particlei -> get4Vector();
1690  if (momParticlei == momParticlei) {
1691  target_prob = momParticlei.P();
1692  }
1693  } else {
1694  if (particlei->hasExtraInfo(availableExtraInfos[indexRanking])) {
1695  target_prob = particlei->getExtraInfo(availableExtraInfos[indexRanking]);
1696  }
1697  }
1698  if (target_prob > maximumTargetProb) {
1699  maximumTargetProb = target_prob;
1700  target = particlei;
1701  }
1702  }
1703  }
1704  if (target != nullptr) {
1705  Variable::Manager& manager = Variable::Manager::Instance();
1706  output = manager.getVariable(inputVariable)-> function(target);
1707  }
1708  }
1709  return output;
1710  };
1711  return func;
1712  }
1713 
1714  Manager::FunctionPtr hasTrueTarget(const std::vector<std::string>& arguments)
1715  {
1716  if (arguments.size() == 1) {
1717  auto categoryName = arguments[0];
1718  auto func = [categoryName](const Particle*) -> double {
1719  if (!(categoryName == "Electron" || categoryName == "IntermediateElectron" || categoryName == "Muon" || categoryName == "IntermediateMuon" || categoryName == "KinLepton" || categoryName == "IntermediateKinLepton" || categoryName == "Kaon"
1720  || categoryName == "SlowPion" || categoryName == "FastHadron" || categoryName == "KaonPion" || categoryName == "Lambda" || categoryName == "MaximumPstar" || categoryName == "FSC"))
1721  {
1722  B2FATAL("hasTrueTarget: Not available category" << categoryName <<
1723  ". The possibilities for the category name are \nElectron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
1724  return 0.0;
1725  }
1726 
1727  std::string particleListName;
1728  std::string trackTargetName = categoryName;
1729 
1730  if (categoryName == "Electron" || categoryName == "IntermediateElectron") particleListName = "e+:inRoe";
1731  else if (categoryName == "Muon" || categoryName == "IntermediateMuon" || categoryName == "KinLepton" || categoryName == "IntermediateKinLepton") particleListName = "mu+:inRoe";
1732  else if (categoryName == "Kaon" || categoryName == "KaonPion") {particleListName = "K+:inRoe"; trackTargetName = "Kaon";}
1733  else if (categoryName == "Lambda") particleListName = "Lambda0:inRoe";
1734  else particleListName = "pi+:inRoe";
1735 
1736  if (categoryName == "FSC") trackTargetName = "SlowPion";
1737 
1738  StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1739 
1740  double output = std::numeric_limits<double>::quiet_NaN();
1741 
1742  Variable::Manager& manager = Variable::Manager::Instance();
1743 
1744 
1745  if (ListOfParticles.isValid())
1746  {
1747  output = 0;
1748  bool particlesHaveMCAssociated = false;
1749  int nTargets = 0;
1750  for (unsigned int i = 0; i < ListOfParticles->getListSize(); ++i) {
1751  Particle* iParticle = ListOfParticles->getParticle(i);
1752  if (iParticle != nullptr) {
1753  double targetFlag = 0;
1754  if (categoryName == "MaximumPstar") {
1755  targetFlag = manager.getVariable("hasHighestProbInCat(pi+:inRoe, isRightTrack(MaximumPstar))")-> function(iParticle);
1756  } else {
1757  targetFlag = manager.getVariable("isRightTrack(" + trackTargetName + ")")-> function(iParticle);
1758  }
1759  if (targetFlag != -2) particlesHaveMCAssociated = true;
1760  if (targetFlag == 1) {
1761  nTargets += 1;
1762  }
1763  }
1764  }
1765 
1766  if (!particlesHaveMCAssociated) output = std::numeric_limits<double>::quiet_NaN();
1767  if (nTargets > 0) output = 1;
1768 
1769  // if (nTargets > 1); B2INFO("The Category " << categoryName << " has " << std::to_string(nTargets) << " target tracks.");
1770  }
1771  return output;
1772  };
1773  return func;
1774  } else {
1775  B2FATAL("Wrong number of arguments (1 required) for meta function hasTrueTarget");
1776  }
1777  }
1778 
1779  Manager::FunctionPtr isTrueCategory(const std::vector<std::string>& arguments)
1780  {
1781  if (arguments.size() == 1) {
1782  auto categoryName = arguments[0];
1783  auto func = [categoryName](const Particle*) -> double {
1784  if (!(categoryName == "Electron" || categoryName == "IntermediateElectron" || categoryName == "Muon" || categoryName == "IntermediateMuon" || categoryName == "KinLepton" || categoryName == "IntermediateKinLepton" || categoryName == "Kaon"
1785  || categoryName == "SlowPion" || categoryName == "FastHadron" || categoryName == "KaonPion" || categoryName == "Lambda" || categoryName == "MaximumPstar" || categoryName == "FSC"))
1786  {
1787  B2FATAL("isTrueCategory: Not available category" << categoryName <<
1788  ". The possibilities for the category name are \nElectron, IntermediateElectron, Muon, IntermediateMuon, KinLepton, IntermediateKinLepton, Kaon, SlowPion, FastHadron, KaonPion, MaximumPstar, FSC and Lambda");
1789  return 0.0;
1790  }
1791 
1792  std::string particleListName;
1793  std::string trackTargetName = categoryName;
1794 
1795  if (categoryName == "Electron" || categoryName == "IntermediateElectron") particleListName = "e+:inRoe";
1796  else if (categoryName == "Muon" || categoryName == "IntermediateMuon" || categoryName == "KinLepton" || categoryName == "IntermediateKinLepton") particleListName = "mu+:inRoe";
1797  else if (categoryName == "Kaon" || categoryName == "KaonPion") {particleListName = "K+:inRoe"; trackTargetName = "Kaon";}
1798  else if (categoryName == "Lambda") particleListName = "Lambda0:inRoe";
1799  else particleListName = "pi+:inRoe";
1800 
1801  if (categoryName == "FSC") trackTargetName = "SlowPion";
1802 
1803  StoreObjPtr<ParticleList> ListOfParticles(particleListName);
1804 
1805  double output = std::numeric_limits<double>::quiet_NaN();
1806 
1807  std::vector<Particle*> targetParticles;
1808  std::vector<Particle*> targetParticlesCategory;
1809  Variable::Manager& manager = Variable::Manager::Instance();
1810 
1811  if (ListOfParticles.isValid())
1812  {
1813  output = 0;
1814  int nTargets = 0;
1815  for (unsigned int i = 0; i < ListOfParticles->getListSize(); ++i) {
1816  Particle* iParticle = ListOfParticles->getParticle(i);
1817  if (iParticle != nullptr) {
1818  double targetFlag = 0;
1819  if (categoryName == "MaximumPstar") {
1820  targetFlag = manager.getVariable("hasHighestProbInCat(pi+:inRoe, isRightTrack(MaximumPstar))")-> function(iParticle);
1821  } else {
1822  targetFlag = manager.getVariable("isRightTrack(" + trackTargetName + ")")-> function(iParticle);
1823  }
1824  if (targetFlag == 1) {
1825  targetParticles.push_back(iParticle);
1826  }
1827  }
1828  }
1829 
1830  for (auto& targetParticle : targetParticles) {
1831  double isTargetOfRightCategory = manager.getVariable("isRightCategory(" + categoryName + ")")-> function(targetParticle);
1832  if (isTargetOfRightCategory == 1) {
1833  output = 1;
1834  nTargets += 1; targetParticlesCategory.push_back(targetParticle);
1835  } else if (isTargetOfRightCategory == -2 && output != 1) output = std::numeric_limits<double>::quiet_NaN();
1836  }
1837 
1838  /* if (nTargets > 1) {
1839  B2INFO("The Category " << categoryName << " has " << std::to_string(nTargets) << " target tracks.");
1840  for (auto& iTargetParticlesCategory : targetParticlesCategory) {
1841  const MCParticle* MCp = iTargetParticlesCategory -> getRelated<MCParticle>();
1842 
1843  RelationVector<Particle> mcRelations = MCp->getRelationsFrom<Particle>();
1844  if (mcRelations.size() > 1) B2WARNING("MCparticle is related to two particles");
1845 
1846  B2INFO("MCParticle has pdgCode = " << MCp -> getPDG() << ", MCMother has pdgCode = " << MCp-> getMother() -> getPDG() << " and " <<
1847  MCp-> getMother() -> getNDaughters() << " daughters.");
1848 
1849  for (auto& iDaughter : MCp->getMother() -> getDaughters()) B2INFO("iDaughter PDGCode = " << iDaughter -> getPDG());
1850  }
1851  }*/
1852  }
1853  return output;
1854  };
1855  return func;
1856  } else {
1857  B2FATAL("Wrong number of arguments (1 required) for meta function isTrueCategory");
1858  }
1859  }
1860 
1861  Manager::FunctionPtr qrOutput(const std::vector<std::string>& arguments)
1862  {
1863  if (arguments.size() == 1) {
1864  std::string combinerMethod = arguments[0];
1865  auto func = [combinerMethod](const Particle * particle) -> double {
1866 
1867  double output = std::numeric_limits<double>::quiet_NaN();
1868  auto* flavorTaggerInfo = particle -> getRelatedTo<FlavorTaggerInfo>();
1869 
1870  if (flavorTaggerInfo != nullptr)
1871  {
1872  if (flavorTaggerInfo->getUseModeFlavorTagger() == "Expert")
1873  output = flavorTaggerInfo->getMethodMap(combinerMethod)->getQrCombined();
1874  }
1875  return output;
1876  };
1877  return func;
1878  } else {
1879  B2FATAL("Wrong number of arguments for meta function qrOutput");
1880  }
1881  }
1882 
1883  Manager::FunctionPtr qOutput(const std::vector<std::string>& arguments)
1884  {
1885  if (arguments.size() == 1) {
1886  std::string combinerMethod = arguments[0];
1887  auto func = [combinerMethod](const Particle * particle) -> double {
1888 
1889  double output = std::numeric_limits<double>::quiet_NaN();
1890  auto* flavorTaggerInfo = particle -> getRelatedTo<FlavorTaggerInfo>();
1891 
1892  if (flavorTaggerInfo != nullptr)
1893  {
1894  if (flavorTaggerInfo->getUseModeFlavorTagger() == "Expert")
1895  output = TMath::Sign(1, flavorTaggerInfo->getMethodMap(combinerMethod)->getQrCombined());
1896  }
1897  return output;
1898  };
1899  return func;
1900  } else {
1901  B2FATAL("Wrong number of arguments for meta function qOutput");
1902  }
1903  }
1904 
1905  Manager::FunctionPtr rBinBelle(const std::vector<std::string>& arguments)
1906  {
1907  if (arguments.size() == 1) {
1908  std::string combinerMethod = arguments[0];
1909  auto func = [combinerMethod](const Particle * particle) -> double {
1910 
1911  int output = std::numeric_limits<int>::quiet_NaN();
1912  auto* flavorTaggerInfo = particle -> getRelatedTo<FlavorTaggerInfo>();
1913 
1914  if (flavorTaggerInfo != nullptr)
1915  {
1916  if (flavorTaggerInfo->getUseModeFlavorTagger() == "Expert") {
1917  double r = std::abs(flavorTaggerInfo->getMethodMap(combinerMethod)->getQrCombined());
1918  if (r < 0.1) output = 0;
1919  if (r > 0.1 && r < 0.25) output = 1;
1920  if (r > 0.25 && r < 0.5) output = 2;
1921  if (r > 0.5 && r < 0.625) output = 3;
1922  if (r > 0.625 && r < 0.75) output = 4;
1923  if (r > 0.75 && r < 0.875) output = 5;
1924  if (r > 0.875 && r < 1.10) output = 6;
1925  }
1926  }
1927  return output;
1928  };
1929  return func;
1930  } else {
1931  B2FATAL("Wrong number of arguments for meta function rBinBelle");
1932  }
1933  }
1934 
1935  Manager::FunctionPtr qpCategory(const std::vector<std::string>& arguments)
1936  {
1937  if (arguments.size() == 1) {
1938  std::string categoryName = arguments[0];
1939  auto func = [categoryName](const Particle * particle) -> double {
1940 
1941  double output = std::numeric_limits<double>::quiet_NaN();
1942  auto* flavorTaggerInfo = particle -> getRelatedTo<FlavorTaggerInfo>();
1943 
1944  if (flavorTaggerInfo != nullptr)
1945  {
1946  if (flavorTaggerInfo->getUseModeFlavorTagger() == "Expert") {
1947  std::map<std::string, float> iQpCategories = flavorTaggerInfo->getMethodMap("FBDT")->getQpCategory();
1948  if (iQpCategories.find(categoryName) != iQpCategories.end()) output = iQpCategories.at(categoryName);
1949  else if (iQpCategories.size() != 0) B2FATAL("qpCategory: Category with name " << categoryName
1950  << " not found. Check the official category names or if this category is included in the flavor tagger categories list.");
1951  }
1952  }
1953  return output;
1954  };
1955  return func;
1956  } else {
1957  B2FATAL("Wrong number of arguments for meta function qpCategory");
1958  }
1959  }
1960 
1961  Manager::FunctionPtr isTrueFTCategory(const std::vector<std::string>& arguments)
1962  {
1963  if (arguments.size() == 1) {
1964  std::string categoryName = arguments[0];
1965  auto func = [categoryName](const Particle * particle) -> double {
1966 
1967  double output = std::numeric_limits<double>::quiet_NaN();
1968  auto* flavorTaggerInfo = particle -> getRelatedTo<FlavorTaggerInfo>();
1969 
1970  if (flavorTaggerInfo != nullptr)
1971  {
1972  if (flavorTaggerInfo->getUseModeFlavorTagger() == "Expert") {
1973  std::map<std::string, float> iIsTrueCategories = flavorTaggerInfo->getMethodMap("FBDT")->getIsTrueCategory();
1974  if (iIsTrueCategories.find(categoryName) != iIsTrueCategories.end()) output = iIsTrueCategories.at(categoryName);
1975  else if (iIsTrueCategories.size() != 0) B2FATAL("isTrueFTCategory: Category with name " << categoryName
1976  << " not found. Check the official category names or if this category is included in the flavor tagger categories list.");
1977  }
1978  }
1979  return output;
1980  };
1981  return func;
1982  } else {
1983  B2FATAL("Wrong number of arguments for meta function isTrueFTCategory");
1984  }
1985  }
1986 
1987  Manager::FunctionPtr hasTrueTargets(const std::vector<std::string>& arguments)
1988  {
1989  if (arguments.size() == 1) {
1990  std::string categoryName = arguments[0];
1991  auto func = [categoryName](const Particle * particle) -> double {
1992 
1993  double output = std::numeric_limits<double>::quiet_NaN();
1994  auto* flavorTaggerInfo = particle -> getRelatedTo<FlavorTaggerInfo>();
1995 
1996  if (flavorTaggerInfo != nullptr)
1997  {
1998  if (flavorTaggerInfo->getUseModeFlavorTagger() == "Expert") {
1999  std::map<std::string, float> iHasTrueTargets = flavorTaggerInfo->getMethodMap("FBDT")->getHasTrueTarget();
2000  if (iHasTrueTargets.find(categoryName) != iHasTrueTargets.end()) output = iHasTrueTargets.at(categoryName);
2001  else if (iHasTrueTargets.size() != 0) B2FATAL("hasTrueTargets: Category with name " << categoryName
2002  << " not found. Check the official category names or if this category is included in the flavor tagger categories list.");
2003  }
2004  }
2005  return output;
2006  };
2007  return func;
2008  } else {
2009  B2FATAL("Wrong number of arguments for meta function hasTrueTargets");
2010  }
2011  }
2012 
2013  VARIABLE_GROUP("Flavor Tagger Variables");
2014 
2015  REGISTER_VARIABLE("pMissTag", momentumMissingTagSide, "Calculates the missing Momentum for a given particle on the tag side.");
2016  REGISTER_VARIABLE("cosTPTO" , cosTPTO , "cosine of angle between thrust axis of given particle and thrust axis of ROE");
2017  REGISTER_VARIABLE("lambdaFlavor", lambdaFlavor, "1.0 if Lambda0, -1.0 if Anti-Lambda0, 0.0 else.");
2018  REGISTER_VARIABLE("isLambda", isLambda, "1.0 if MCLambda0, 0.0 else.");
2019  REGISTER_VARIABLE("lambdaZError", lambdaZError, "Returns the Matrixelement[2][2] of the PositionErrorMatrix of the Vertex fit.");
2020  REGISTER_VARIABLE("momentumOfSecondDaughter", momentumOfSecondDaughter,
2021  "Returns the Momentum of second daughter if existing, else 0.");
2022  REGISTER_VARIABLE("momentumOfSecondDaughterCMS", momentumOfSecondDaughterCMS,
2023  "Returns the Momentum of second daughter if existing in CMS, else 0.");
2024  REGISTER_VARIABLE("chargeTimesKaonLiklihood", chargeTimesKaonLiklihood,
2025  "Returns the q*(highest PID_Likelihood for Kaons), else 0.");
2026  REGISTER_VARIABLE("ptTracksRoe", transverseMomentumOfChargeTracksInRoe,
2027  "Returns the transverse momentum of all charged tracks if there exists a ROE for the given particle, else 0.");
2028  REGISTER_VARIABLE("NumberOfKShortsInRoe", NumberOfKShortsInRoe,
2029  "Returns the number of K_S0 in the rest of event. The particleList K_S0:inRoe is required");
2030 
2031  REGISTER_VARIABLE("isInElectronOrMuonCat", isInElectronOrMuonCat,
2032  "Returns 1.0 if the particle has been selected as target in the Muon or Electron Category, 0.0 else.");
2033 
2034  REGISTER_VARIABLE("isMajorityInRestOfEventFromB0", isMajorityInRestOfEventFromB0,
2035  "[Eventbased] Check if the majority of the tracks in the current RestOfEvent are from a B0.");
2036  REGISTER_VARIABLE("isMajorityInRestOfEventFromB0bar", isMajorityInRestOfEventFromB0bar,
2037  "[Eventbased] Check if the majority of the tracks in the current RestOfEvent are from a B0bar.");
2038  REGISTER_VARIABLE("hasRestOfEventTracks", hasRestOfEventTracks,
2039  "Returns the amount of tracks in the RestOfEvent related to the given Particle. -2 If ROE is empty.");
2040  REGISTER_VARIABLE("isRelatedRestOfEventB0Flavor", isRelatedRestOfEventB0Flavor,
2041  "-1 (1) if the RestOfEvent related to the given Particle is related to a B0bar (B0). The MCError bit of Breco has to be 0, 1, 2, 16 or 1024. The output of the variable is 0 otherwise. If one Particle in the Rest of Event is found to belong the reconstructed B0, the output is -2(2) for a B0bar (B0) on the reco side.");
2042  REGISTER_VARIABLE("qrCombined", isRestOfEventB0Flavor,
2043  "[Eventbased] -1 (1) if current RestOfEvent is related to a B0bar (B0). The MCError bit of Breco has to be 0, 1, 2, 16 or 1024. The output of the variable is 0 otherwise. If one Particle in the Rest of Event is found to belong the reconstructed B0, the output is -2(2) for a B0bar (B0) on the reco side.");
2044  REGISTER_VARIABLE("ancestorHasWhichFlavor", ancestorHasWhichFlavor,
2045  "checks the decay chain of the given particle upwards up to the Y(4S) resonance.Output is 0 (1) if an ancestor is found to be a B0bar (B0), if not -2.");
2046  REGISTER_VARIABLE("B0mcErrors", B0mcErrors, "mcErrors MCMatching Flag on the reconstructed B0_cp.");
2047  REGISTER_VARIABLE("isRelatedRestOfEventMajorityB0Flavor", isRelatedRestOfEventMajorityB0Flavor,
2048  " 0 (1) if the majority of tracks and clusters of the RestOfEvent related to the given Particle are related to a B0bar (B0).");
2049  REGISTER_VARIABLE("isRestOfEventMajorityB0Flavor", isRestOfEventMajorityB0Flavor,
2050  "0 (1) if the majority of tracks and clusters of the current RestOfEvent are related to a B0bar (B0).");
2051  REGISTER_VARIABLE("mcFlavorOfOtherB", mcFlavorOfOtherB,
2052  "Returns the MC flavor (+-1) of the accompaning tag-side B meson if the given particle is a correctly MC-matched B candidate. It returns 0 else. \n"
2053  "In other words, this variable checks the generated flavor of the other MC Upsilon(4S) daughter.");
2054 
2055  VARIABLE_GROUP("Flavor Tagger MetaFunctions")
2056 
2057  REGISTER_VARIABLE("CheckingVariables(ListName, requestedVariable)", CheckingVariables,
2058  "FlavorTagging:[Eventbased] Available checking variables are getListSize for particle lists.");
2059  REGISTER_VARIABLE("IsDaughterOf(variable)", IsDaughterOf, "Check if the particle is a daughter of the given list.");
2060 
2061  REGISTER_VARIABLE("BtagToWBosonVariables(requestedVariable)", BtagToWBosonVariables,
2062  "FlavorTagging:[Eventbased] Kinematical variables (recoilMass, pMissCMS, cosThetaMissCMS or EW90) assuming a semileptonic decay with the given particle as target.");
2063  REGISTER_VARIABLE("KaonPionVariables(requestedVariable)" , KaonPionVariables ,
2064  " Kinematical variables for KaonPion category (cosKaonPion or HaveOpositeCharges)");
2065  REGISTER_VARIABLE("FSCVariables(requestedVariable)", FSCVariables,
2066  "FlavorTagging:[Eventbased] Kinematical variables for FastSlowCorrelated category (pFastCMS, cosSlowFast, SlowFastHaveOpositeCharges, or cosTPTOFast).");
2067  REGISTER_VARIABLE("hasHighestProbInCat(particleListName, extraInfoName)", hasHighestProbInCat,
2068  "Returns 1.0 if the given Particle is classified as target track, i.e. if it has the highest target track probability in particlelistName. The probability is accessed via extraInfoName.");
2069  REGISTER_VARIABLE("HighestProbInCat(particleListName, extraInfoName)", HighestProbInCat,
2070  "Returns the highest target track probability value for the given category")
2071 
2072  REGISTER_VARIABLE("isRightTrack(particleName)", isRightTrack,
2073  "Checks if the given Particle was really from a B. 1.0 if true otherwise 0.0");
2074  REGISTER_VARIABLE("isRightCategory(particleName)", isRightCategory,
2075  "FlavorTagging: returns 1 if the class track by particleName category has the same flavor as the MC target track 0 else also if there is no target track");
2076  REGISTER_VARIABLE("QpOf(particleListName, outputExtraInfo, rankingExtraInfo)", QpOf,
2077  "FlavorTagging: [Eventbased] Returns the q*p value for a given list (argument[0]), where p is the probability of a category stored as extraInfo (argument[1]).\n"
2078  "The particle is selected after ranking according to a flavor tagging extraInfo (argument[2]).");
2079  REGISTER_VARIABLE("weightedQpOf(particleListName, outputExtraInfo, rankingExtraInfo)", weightedQpOf,
2080  "FlavorTagging: [Eventbased] Returns the weighted q*p value for a given list (argument[0]), where p is the probability of a category stored as extraInfo (argument[1]).\n"
2081  "The particles in the list are ranked according to a flavor tagging extraInfo (argument[2]). \n"
2082  "The values for the three top particles is combined into an effective (weighted) output.");
2083  REGISTER_VARIABLE("variableOfTarget(particleListName, inputVariable, rankingExtraInfo)", variableOfTarget,
2084  "FlavorTagging: [Eventbased] Returns the value of an input variable (argument[1]) for a particle selected from the given list (argument[0]).\n"
2085  "The particles are ranked according to a flavor tagging extraInfo (argument[2]).");
2086 
2087  REGISTER_VARIABLE("hasTrueTarget(categoryName)", hasTrueTarget,
2088  "Returns 1 if the given category has a target. 0 Else.")
2089  REGISTER_VARIABLE("isTrueCategory(categoryName)", isTrueCategory,
2090  "Returns 1 if the given category tags the B0 MC flavor correctly. 0 Else.")
2091  REGISTER_VARIABLE("qrOutput(combinerMethod)", qrOutput,
2092  "Returns the output of the flavorTagger for the given combinerMethod. The default methods are 'FBDT' or 'FANN'.")
2093  REGISTER_VARIABLE("qOutput(combinerMethod)", qOutput,
2094  "Returns the flavor tag q output of the flavorTagger for the given combinerMethod. The default methods are 'FBDT' or 'FANN'.")
2095  REGISTER_VARIABLE("rBinBelle(combinerMethod)", rBinBelle,
2096  "Returns the corresponding r (dilution) bin according to the Belle binning for the given combinerMethod. The default methods are 'FBDT' or 'FANN'.")
2097  REGISTER_VARIABLE("qpCategory(categoryName)", qpCategory,
2098  "Returns the output q (charge of target track) times p (probability that this is the right category) of the category with the given name. The allowed categories are the official Flavor Tagger Category Names.");
2099  REGISTER_VARIABLE("isTrueFTCategory(categoryName)", isTrueFTCategory,
2100  "Returns 1 if the target particle (checking the decay chain) of the category with the given name is found in the mc Particles, and if it provides the right Flavor. The allowed categories are the official Flavor Tagger Category Names.");
2101  REGISTER_VARIABLE("hasTrueTargets(categoryName)", hasTrueTargets,
2102  "Returns 1 if target particles (checking only the decay chain) of the category with the given name is found in the mc Particles. The allowed categories are the official Flavor Tagger Category Names.");
2103  }
2105 }
Belle2::EvtPDLUtil::particleListName
std::string particleListName(int pdgCode, const std::string &label)
Returns the name of the particle ParticleList for particles with given pdg code and with given label.
Definition: EvtPDLUtil.cc:39
Belle2::EvtPDLUtil::particleName
std::string particleName(int pdgCode)
Returns the name of a particle with given pdg code.
Definition: EvtPDLUtil.cc:22
Belle2::RelationsInterface::getRelated
T * getRelated(const std::string &name="", const std::string &namedRelation="") const
Get the object to or from which this object has a relation.
Definition: RelationsObject.h:280
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19