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