Belle II Software  release-05-01-25
ROEVariables.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2010 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Anze Zupanc, Matic Lubej, Sviatoslav Bilokin *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 
11 // Own include
12 #include <analysis/variables/ROEVariables.h>
13 #include <analysis/variables/Variables.h>
14 #include <analysis/utility/PCmsLabTransform.h>
15 
16 #include <analysis/VariableManager/Manager.h>
17 
18 // framework - DataStore
19 #include <framework/datastore/StoreArray.h>
20 #include <framework/datastore/StoreObjPtr.h>
21 
22 // dataobjects
23 #include <analysis/dataobjects/Particle.h>
24 #include <analysis/dataobjects/ParticleList.h>
25 
26 #include <mdst/dataobjects/ECLCluster.h>
27 
28 // framework aux
29 #include <framework/logging/Logger.h>
30 
31 // utility
32 #include <analysis/utility/ReferenceFrame.h>
33 
34 #include <TRandom.h>
35 #include <TMath.h>
36 
37 #include <iostream>
38 
39 using namespace std;
40 
41 namespace Belle2 {
46  namespace Variable {
47 
48  double isInRestOfEvent(const Particle* particle)
49  {
50 
51  StoreObjPtr<RestOfEvent> roeobjptr;
52  if (not roeobjptr.isValid())
53  return 0;
54 
55  const RestOfEvent* roe = &(*roeobjptr);
56 
57  return isInThisRestOfEvent(particle, roe);
58  }
59 
60  double isCloneOfSignalSide(const Particle* particle)
61  {
62 
63  StoreObjPtr<RestOfEvent> roe;
64  if (not roe.isValid()) {
65  B2WARNING("Please use isCloneOfSignalSide variable in for_each ROE loop!");
66  return std::numeric_limits<float>::quiet_NaN();
67  }
68  auto* particleMC = particle->getRelatedTo<MCParticle>();
69  if (!particleMC) {
70  return 0.0;
71  }
72  auto* signal = roe->getRelatedFrom<Particle>();
73  auto signalFSPs = signal->getFinalStateDaughters();
74  for (auto* daughter : signalFSPs) {
75  auto* daughterMC = daughter->getRelatedTo<MCParticle>();
76  if (daughterMC == particleMC) {
77  return 1.0;
78  }
79  }
80  return 0.0;
81  }
82  double hasAncestorFromSignalSide(const Particle* particle)
83  {
84  StoreObjPtr<RestOfEvent> roe;
85  if (!roe.isValid()) {
86  B2WARNING("Please use hasAncestorFromSignalSide variable in for_each ROE loop!");
87  return std::numeric_limits<float>::quiet_NaN();
88  }
89  auto* particleMC = particle->getRelatedTo<MCParticle>();
90  if (!particleMC) {
91  return 0.0;
92  }
93  auto* signalReco = roe->getRelatedFrom<Particle>();
94  auto* signalMC = signalReco->getRelatedTo<MCParticle>();
95  MCParticle* ancestorMC = particleMC->getMother();
96  while (ancestorMC) {
97  if (ancestorMC == signalMC) {
98  return 1.0;
99  }
100  ancestorMC = ancestorMC->getMother();
101  }
102  return 0.0;
103  }
104 
105 
106 
107  Manager::FunctionPtr currentROEIsInList(const std::vector<std::string>& arguments)
108  {
109  if (arguments.size() != 1)
110  B2FATAL("Wrong number of arguments (1 required) for meta function currentROEIsInList");
111 
112  std::string listName = arguments[0];
113 
114  auto func = [listName](const Particle*) -> double {
115 
116  StoreObjPtr<ParticleList> particleList(listName);
117  if (!(particleList.isValid()))
118  {
119  B2FATAL("Invalid Listname " << listName << " given to currentROEIsInList!");
120  }
121  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
122 
123  if (not roe.isValid())
124  return 0;
125 
126  auto* particle = roe->getRelatedFrom<Particle>();
127  if (particle == nullptr)
128  {
129  B2ERROR("Relation between particle and ROE doesn't exist! currentROEIsInList() variable has to be called from ROE loop");
130  return std::numeric_limits<float>::quiet_NaN();
131  }
132  return particleList->contains(particle) ? 1 : 0;
133 
134  };
135  return func;
136  }
137 
138  Manager::FunctionPtr particleRelatedToCurrentROE(const std::vector<std::string>& arguments)
139  {
140  if (arguments.size() != 1)
141  B2FATAL("Wrong number of arguments (1 required) for meta function particleRelatedToCurrentROE");
142 
143  const Variable::Manager::Var* var = Manager::Instance().getVariable(arguments[0]);
144  auto func = [var](const Particle*) -> double {
145 
146  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
147 
148  if (not roe.isValid())
149  return std::numeric_limits<float>::quiet_NaN();
150 
151  auto* particle = roe->getRelatedFrom<Particle>();
152  if (particle == nullptr)
153  {
154  B2ERROR("Relation between particle and ROE doesn't exist! particleRelatedToCurrentROE() variable has to be called from ROE loop");
155  return std::numeric_limits<float>::quiet_NaN();
156  }
157  return var->function(particle);
158 
159  };
160  return func;
161  }
162 
163  Manager::FunctionPtr useROERecoilFrame(const std::vector<std::string>& arguments)
164  {
165  if (arguments.size() == 1) {
166  const Variable::Manager::Var* var = Manager::Instance().getVariable(arguments[0]);
167  auto func = [var](const Particle * particle) -> double {
168  // Here we prioritize old variable behaviour first:
169  const RestOfEvent* roe = particle->getRelatedTo<RestOfEvent>();
170  // if related ROE not found, get the StoreArray pointer
171  if (roe == nullptr)
172  {
173  StoreObjPtr<RestOfEvent> roeObjPtr("RestOfEvent");
174  if (roeObjPtr.isValid()) {
175  roe = &*roeObjPtr;
176  }
177  }
178  if (roe == nullptr)
179  {
180  B2ERROR("Neither relation between particle and ROE doesn't exist nor ROE object has not been found!");
181  return std::numeric_limits<float>::quiet_NaN();
182  }
183  PCmsLabTransform T;
184  TLorentzVector pRecoil = T.getBeamFourMomentum() - roe->get4Vector();
185  Particle tmp(pRecoil, 0);
186  UseReferenceFrame<RestFrame> frame(&tmp);
187  double result = var->function(particle);
188  return result;
189  };
190  return func;
191  } else {
192  B2WARNING("Wrong number of arguments for meta function useROERecoilFrame");
193  return nullptr;
194  }
195  }
196 
197  // only the helper function
198  double nRemainingTracksInROE(const Particle* particle, const std::string& maskName)
199  {
200  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
201  if (not roe.isValid())
202  return 0.0;
203  int n_roe_tracks = roe->getNTracks(maskName);
204  int n_par_tracks = 0;
205  const auto& daughters = particle->getFinalStateDaughters();
206  for (const auto& daughter : daughters) {
207  if (daughter->getParticleSource() == Particle::EParticleSourceObject::c_Track && roe->hasParticle(daughter, maskName)) {
208  n_par_tracks++;
209  }
210  }
211  return n_roe_tracks - n_par_tracks;
212  }
213 
214  Manager::FunctionPtr nROE_RemainingTracksWithMask(const std::vector<std::string>& arguments)
215  {
216  std::string maskName;
217 
218  if (arguments.size() == 0)
219  maskName = "";
220  else if (arguments.size() == 1)
221  maskName = arguments[0];
222  else
223  B2FATAL("Wrong number of arguments (1 required) for meta function nROETracks");
224 
225  auto func = [maskName](const Particle * particle) -> double {
226  return nRemainingTracksInROE(particle, maskName);
227  };
228  return func;
229  }
230 
231  double nROE_RemainingTracks(const Particle* particle)
232  {
233  return nRemainingTracksInROE(particle);
234  }
235 
236  double nROE_KLMClusters(const Particle* particle)
237  {
238  // Get related ROE object
239  const RestOfEvent* roe = getRelatedROEObject(particle);
240 
241  if (!roe) {
242  B2ERROR("Relation between particle and ROE doesn't exist!");
243  return -1;
244  }
245 
246  return roe->getNKLMClusters();
247  }
248 
249  double ROE_MC_E(const Particle* particle)
250  {
251  const MCParticle* mcp = particle->getRelated<MCParticle>();
252 
253  if (!mcp)
254  return std::numeric_limits<float>::quiet_NaN();
255 
256  PCmsLabTransform T;
257  TLorentzVector boostvec = T.getBeamFourMomentum();
258  auto mcroe4vector = boostvec - mcp->get4Vector();
259  const auto& frame = ReferenceFrame::GetCurrent();
260  auto frameMCRoe4Vector = frame.getMomentum(mcroe4vector);
261  return frameMCRoe4Vector.Energy();
262  }
263 
264  double ROE_MC_P(const Particle* particle)
265  {
266  const MCParticle* mcp = particle->getRelated<MCParticle>();
267 
268  if (!mcp)
269  return std::numeric_limits<float>::quiet_NaN();
270 
271  PCmsLabTransform T;
272  TLorentzVector boostvec = T.getBeamFourMomentum();
273  auto mcroe4vector = boostvec - mcp->get4Vector();
274  const auto& frame = ReferenceFrame::GetCurrent();
275  auto frameMCRoe4Vector = frame.getMomentum(mcroe4vector);
276  return frameMCRoe4Vector.Vect().Mag();
277  }
278 
279  double ROE_MC_Px(const Particle* particle)
280  {
281  const MCParticle* mcp = particle->getRelated<MCParticle>();
282 
283  if (!mcp)
284  return std::numeric_limits<float>::quiet_NaN();
285 
286  PCmsLabTransform T;
287  TLorentzVector boostvec = T.getBeamFourMomentum();
288  auto mcroe4vector = boostvec - mcp->get4Vector();
289  const auto& frame = ReferenceFrame::GetCurrent();
290  auto frameMCRoe4Vector = frame.getMomentum(mcroe4vector);
291 
292  return frameMCRoe4Vector.Vect().X();
293  }
294 
295  double ROE_MC_Py(const Particle* particle)
296  {
297  const MCParticle* mcp = particle->getRelated<MCParticle>();
298 
299  if (!mcp)
300  return std::numeric_limits<float>::quiet_NaN();
301 
302  PCmsLabTransform T;
303  TLorentzVector boostvec = T.getBeamFourMomentum();
304  auto mcroe4vector = boostvec - mcp->get4Vector();
305  const auto& frame = ReferenceFrame::GetCurrent();
306  auto frameMCRoe4Vector = frame.getMomentum(mcroe4vector);
307 
308  return frameMCRoe4Vector.Vect().Y();
309  }
310 
311  double ROE_MC_Pz(const Particle* particle)
312  {
313  const MCParticle* mcp = particle->getRelated<MCParticle>();
314 
315  if (!mcp)
316  return std::numeric_limits<float>::quiet_NaN();
317 
318  PCmsLabTransform T;
319  TLorentzVector boostvec = T.getBeamFourMomentum();
320  auto mcroe4vector = boostvec - mcp->get4Vector();
321  const auto& frame = ReferenceFrame::GetCurrent();
322  auto frameMCRoe4Vector = frame.getMomentum(mcroe4vector);
323 
324  return frameMCRoe4Vector.Vect().Z();
325  }
326 
327  double ROE_MC_Pt(const Particle* particle)
328  {
329  const MCParticle* mcp = particle->getRelated<MCParticle>();
330 
331  if (!mcp)
332  return std::numeric_limits<float>::quiet_NaN();
333 
334  PCmsLabTransform T;
335  TLorentzVector boostvec = T.getBeamFourMomentum();
336  auto mcroe4vector = boostvec - mcp->get4Vector();
337  const auto& frame = ReferenceFrame::GetCurrent();
338  auto frameMCRoe4Vector = frame.getMomentum(mcroe4vector);
339 
340  return frameMCRoe4Vector.Vect().Perp();
341  }
342 
343  double ROE_MC_PTheta(const Particle* particle)
344  {
345  const MCParticle* mcp = particle->getRelated<MCParticle>();
346 
347  if (!mcp)
348  return std::numeric_limits<float>::quiet_NaN();
349 
350  PCmsLabTransform T;
351  TLorentzVector boostvec = T.getBeamFourMomentum();
352  auto mcroe4vector = boostvec - mcp->get4Vector();
353  const auto& frame = ReferenceFrame::GetCurrent();
354  auto frameMCRoe4Vector = frame.getMomentum(mcroe4vector);
355 
356  return frameMCRoe4Vector.Theta();
357  }
358 
359  double ROE_MC_M(const Particle* particle)
360  {
361  const MCParticle* mcp = particle->getRelated<MCParticle>();
362 
363  if (!mcp)
364  return std::numeric_limits<float>::quiet_NaN();
365 
366  PCmsLabTransform T;
367  TLorentzVector boostvec = T.getBeamFourMomentum();
368 
369  return (boostvec - mcp->get4Vector()).Mag();
370  }
371 
372  Manager::FunctionPtr ROE_MC_MissingFlags(const std::vector<std::string>& arguments)
373  {
374  std::string maskName;
375 
376  if (arguments.size() == 0)
377  maskName = "";
378  else if (arguments.size() == 1)
379  maskName = arguments[0];
380  else
381  B2FATAL("Wrong number of arguments (1 required) for meta function nROETracks");
382 
383  auto func = [maskName](const Particle * particle) -> double {
384 
385  StoreArray<Particle> particles;
386 
387  //Get MC Particle of the B meson
388  const MCParticle* mcParticle = particle->getRelatedTo<MCParticle>();
389 
390  if (!mcParticle)
391  return std::numeric_limits<float>::quiet_NaN();
392 
393  // Get Mother
394  const MCParticle* mcMother = mcParticle->getMother();
395 
396  if (!mcMother)
397  return std::numeric_limits<float>::quiet_NaN();
398 
399  // Get daughters
400  std::vector<MCParticle*> mcDaughters = mcMother->getDaughters();
401 
402  if (mcDaughters.size() != 2)
403  return std::numeric_limits<float>::quiet_NaN();
404 
405  // Get the companion B meson
406  MCParticle* mcROE = nullptr;
407  if (mcDaughters[0]->getArrayIndex() == mcParticle->getArrayIndex())
408  mcROE = mcDaughters[1];
409  else
410  mcROE = mcDaughters[0];
411 
412  // Get related ROE object
413  const RestOfEvent* roe = getRelatedROEObject(particle);
414 
415  std::set<const MCParticle*> mcROEObjects;
416 
417  auto roeParticles = roe->getParticles(maskName);
418  for (auto* roeParticle : roeParticles)
419  {
420  auto* mcroeParticle = roeParticle->getRelated<MCParticle>();
421  if (mcroeParticle != nullptr) {
422  mcROEObjects.insert(mcroeParticle);
423  }
424  }
425  int flags = 0;
426  checkMCParticleMissingFlags(mcROE, mcROEObjects, flags);
427 
428  return flags;
429  };
430  return func;
431  }
432 
433  Manager::FunctionPtr nROE_Tracks(const std::vector<std::string>& arguments)
434  {
435  std::string maskName;
436 
437  if (arguments.size() == 0)
438  maskName = "";
439  else if (arguments.size() == 1)
440  maskName = arguments[0];
441  else
442  B2FATAL("Wrong number of arguments (1 required) for meta function nROETracks");
443 
444  auto func = [maskName](const Particle * particle) -> double {
445 
446  // Get related ROE object
447  const RestOfEvent* roe = getRelatedROEObject(particle);
448 
449  if (!roe)
450  {
451  B2ERROR("Relation between particle and ROE doesn't exist!");
452  return -1;
453  }
454 
455  return roe->getNTracks(maskName);
456  };
457  return func;
458  }
459 
460  Manager::FunctionPtr nROE_ECLClusters(const std::vector<std::string>& arguments)
461  {
462  std::string maskName;
463 
464  if (arguments.size() == 0)
465  maskName = "";
466  else if (arguments.size() == 1)
467  maskName = arguments[0];
468  else
469  B2FATAL("Wrong number of arguments (1 required) for meta function nROEECLClusters");
470 
471  auto func = [maskName](const Particle * particle) -> double {
472 
473  // Get related ROE object
474  const RestOfEvent* roe = getRelatedROEObject(particle);
475 
476  if (!roe)
477  {
478  B2ERROR("Relation between particle and ROE doesn't exist!");
479  return -1;
480  }
481 
482  return roe->getNECLClusters(maskName);
483  };
484  return func;
485  }
486 
487  Manager::FunctionPtr nROE_NeutralECLClusters(const std::vector<std::string>& arguments)
488  {
489  std::string maskName;
490 
491  if (arguments.size() == 0)
492  maskName = "";
493  else if (arguments.size() == 1)
494  maskName = arguments[0];
495  else
496  B2FATAL("Wrong number of arguments (1 required) for meta function nROENeutralECLClusters");
497 
498  auto func = [maskName](const Particle * particle) -> double {
499 
500  // Get related ROE object
501  const RestOfEvent* roe = getRelatedROEObject(particle);
502 
503  if (!roe)
504  {
505  B2ERROR("Relation between particle and ROE doesn't exist!");
506  return -1;
507  }
508 
509  // Get unused ECLClusters in ROE
510  std::vector<const ECLCluster*> roeClusters = roe->getECLClusters(maskName);
511  int nNeutrals = 0;
512 
513  // Select ECLClusters with no associated tracks
514  for (auto& roeCluster : roeClusters)
515  if (roeCluster->isNeutral())
516  nNeutrals++;
517 
518  return nNeutrals;
519  };
520  return func;
521  }
522 
523  Manager::FunctionPtr nROE_Photons(const std::vector<std::string>& arguments)
524  {
525  std::string maskName = "";
526 
527  if (arguments.size() == 1) {
528  maskName = arguments[0];
529  }
530  if (arguments.size() > 1) {
531  B2FATAL("Wrong number of arguments (1 required) for meta function nROE_Photons");
532  }
533  auto func = [maskName](const Particle * particle) -> double {
534 
535  // Get related ROE object
536  const RestOfEvent* roe = getRelatedROEObject(particle);
537 
538  if (!roe)
539  {
540  B2ERROR("Relation between particle and ROE doesn't exist!");
541  return -1;
542  }
543 
544  return roe->getPhotons(maskName).size();
545  };
546  return func;
547  }
548 
549  Manager::FunctionPtr nROE_NeutralHadrons(const std::vector<std::string>& arguments)
550  {
551  std::string maskName = "";
552 
553  if (arguments.size() == 1) {
554  maskName = arguments[0];
555  }
556  if (arguments.size() > 1) {
557  B2FATAL("Wrong number of arguments (1 optional only) for meta function nROE_NeutralHadrons");
558  }
559  auto func = [maskName](const Particle * particle) -> double {
560 
561  // Get related ROE object
562  const RestOfEvent* roe = getRelatedROEObject(particle);
563 
564  if (!roe)
565  {
566  B2ERROR("Relation between particle and ROE doesn't exist!");
567  return -1;
568  }
569 
570  return roe->getHadrons(maskName).size();
571  };
572  return func;
573  }
574 
575  Manager::FunctionPtr nROE_ChargedParticles(const std::vector<std::string>& arguments)
576  {
577  std::string maskName = "";
578  int pdgCode = 0;
579  if (arguments.size() == 1) {
580  maskName = arguments[0];
581  }
582  if (arguments.size() == 2) {
583  maskName = arguments[0];
584  try {
585  pdgCode = std::stoi(arguments[1]);
586  } catch (std::invalid_argument& e) {
587  B2ERROR("First argument of nROE_ChargedParticles must be a PDG code");
588  return nullptr;
589  }
590  }
591  if (arguments.size() > 2) {
592  B2FATAL("Wrong number of arguments (2 optional) for meta function nROE_ChargedParticles");
593  }
594  auto func = [maskName, pdgCode](const Particle * particle) -> double {
595 
596  // Get related ROE object
597  const RestOfEvent* roe = getRelatedROEObject(particle);
598 
599  if (!roe)
600  {
601  B2ERROR("Relation between particle and ROE doesn't exist!");
602  return -1;
603  }
604 
605  return roe->getChargedParticles(maskName, abs(pdgCode)).size();
606  };
607  return func;
608  }
609 
610  Manager::FunctionPtr nROE_ParticlesInList(const std::vector<std::string>& arguments)
611  {
612  std::string pListName;
613  std::string maskName;
614 
615  if (arguments.size() == 1) {
616  pListName = arguments[0];
617  maskName = "";
618  } else if (arguments.size() == 2) {
619  pListName = arguments[0];
620  maskName = arguments[1];
621  } else
622  B2FATAL("Wrong number of arguments (1 required) for meta function nROE_ParticlesInList");
623 
624  auto func = [pListName, maskName](const Particle * particle) -> double {
625 
626  // Get related ROE object
627  const RestOfEvent* roe = getRelatedROEObject(particle);
628 
629  if (!roe)
630  {
631  B2ERROR("Relation between particle and ROE doesn't exist!");
632  return -1;
633  }
634 
635  int nPart = 0;
636 
637  // Get particle list
638  StoreObjPtr<ParticleList> pList(pListName);
639  if (!pList.isValid())
640  B2FATAL("ParticleList " << pListName << " could not be found or is not valid!");
641 
642  for (unsigned int i = 0; i < pList->getListSize(); i++)
643  {
644  const Particle* part = pList->getParticle(i);
645  if (isInThisRestOfEvent(part, roe, maskName))
646  ++nPart;
647  }
648 
649  return nPart;
650  };
651  return func;
652  }
653 
654  Manager::FunctionPtr ROE_Charge(const std::vector<std::string>& arguments)
655  {
656  std::string maskName;
657 
658  if (arguments.size() == 0)
659  maskName = "";
660  else if (arguments.size() == 1)
661  maskName = arguments[0];
662  else
663  B2FATAL("Wrong number of arguments (1 required) for meta function ROECharge");
664 
665  auto func = [maskName](const Particle * particle) -> double {
666 
667  // Get related ROE object
668  const RestOfEvent* roe = getRelatedROEObject(particle);
669 
670  if (!roe)
671  {
672  B2ERROR("Relation between particle and ROE doesn't exist!");
673  return -1;
674  }
675 
676  // Get tracks in ROE
677  auto roeParticles = roe->getParticles(maskName);
678  int roeCharge = 0;
679 
680  for (auto* roeParticle : roeParticles)
681  {
682  roeCharge += roeParticle->getCharge();
683  }
684 
685  return roeCharge;
686  };
687  return func;
688  }
689 
690  Manager::FunctionPtr ROE_ExtraEnergy(const std::vector<std::string>& arguments)
691  {
692  std::string maskName;
693 
694  if (arguments.size() == 0)
695  maskName = "";
696  else if (arguments.size() == 1)
697  maskName = arguments[0];
698  else
699  B2FATAL("Wrong number of arguments (1 required) for meta function extraEnergy");
700 
701  auto func = [maskName](const Particle * particle) -> double {
702 
703  // Get related ROE object
704  const RestOfEvent* roe = getRelatedROEObject(particle);
705 
706  if (!roe)
707  {
708  B2ERROR("Relation between particle and ROE doesn't exist!");
709  return -1;
710  }
711 
712  std::vector<const ECLCluster*> roeClusters = roe->getECLClusters(maskName);
713  double extraE = 0.0;
714 
715  for (auto& roeCluster : roeClusters)
716  extraE += roeCluster->getEnergy(ECLCluster::EHypothesisBit::c_nPhotons);
717 
718  return extraE;
719  };
720  return func;
721  }
722 
723  Manager::FunctionPtr ROE_NeutralExtraEnergy(const std::vector<std::string>& arguments)
724  {
725  std::string maskName;
726 
727  if (arguments.size() == 0)
728  maskName = "";
729  else if (arguments.size() == 1)
730  maskName = arguments[0];
731  else
732  B2FATAL("Wrong number of arguments (1 required) for meta function extraEnergy");
733 
734  auto func = [maskName](const Particle * particle) -> double {
735 
736  // Get related ROE object
737  const RestOfEvent* roe = getRelatedROEObject(particle);
738 
739  if (!roe)
740  {
741  B2ERROR("Relation between particle and ROE doesn't exist!");
742  return -1;
743  }
744  auto roephotons = roe->getPhotons(maskName);
745  TLorentzVector total4vector;
746  for (auto* photon : roephotons)
747  {
748  total4vector += photon->get4Vector();
749  }
750  const auto& frame = ReferenceFrame::GetCurrent();
751  auto frameRoe4Vector = frame.getMomentum(total4vector);
752  return frameRoe4Vector.Energy();
753  };
754  return func;
755  }
756 
757  Manager::FunctionPtr ROE_E(const std::vector<std::string>& arguments)
758  {
759  std::string maskName;
760  if (arguments.size() == 0)
761  maskName = "";
762  else if (arguments.size() == 1)
763  maskName = arguments[0];
764  else
765  B2FATAL("Wrong number of arguments (1 required) for meta function ROE_E");
766  auto func = [maskName](const Particle * particle) -> double {
767  const RestOfEvent* roe = particle->getRelatedTo<RestOfEvent>();
768  if (!roe)
769  {
770  B2ERROR("Relation between particle and ROE doesn't exist!");
771  return -1;
772  }
773  const auto& frame = ReferenceFrame::GetCurrent();
774  auto frameRoe4Vector = frame.getMomentum(roe->get4Vector(maskName));
775  return frameRoe4Vector.Energy();
776  };
777  return func;
778  }
779 
780  Manager::FunctionPtr ROE_M(const std::vector<std::string>& arguments)
781  {
782  std::string maskName;
783 
784  if (arguments.size() == 0)
785  maskName = "";
786  else if (arguments.size() == 1)
787  maskName = arguments[0];
788  else
789  B2FATAL("Wrong number of arguments (1 required) for meta function ROE_M");
790 
791  auto func = [maskName](const Particle * particle) -> double {
792 
793  // Get related ROE object
794  const RestOfEvent* roe = getRelatedROEObject(particle);
795 
796  if (!roe)
797  {
798  B2ERROR("Relation between particle and ROE doesn't exist!");
799  return -1;
800  }
801 
802  return roe->get4Vector(maskName).Mag();
803  };
804  return func;
805  }
806 
807  Manager::FunctionPtr ROE_P(const std::vector<std::string>& arguments)
808  {
809  std::string maskName;
810 
811  if (arguments.size() == 0)
812  maskName = "";
813  else if (arguments.size() == 1)
814  maskName = arguments[0];
815  else
816  B2FATAL("Wrong number of arguments (1 required) for meta function ROE_P");
817 
818  auto func = [maskName](const Particle * particle) -> double {
819 
820  // Get related ROE object
821  const RestOfEvent* roe = getRelatedROEObject(particle);
822 
823  if (!roe)
824  {
825  B2ERROR("Relation between particle and ROE doesn't exist!");
826  return -1;
827  }
828 
829  const auto& frame = ReferenceFrame::GetCurrent();
830  auto frameRoe4Vector = frame.getMomentum(roe->get4Vector(maskName));
831  return frameRoe4Vector.Vect().Mag();
832  };
833  return func;
834  }
835 
836  Manager::FunctionPtr ROE_Px(const std::vector<std::string>& arguments)
837  {
838  std::string maskName;
839 
840  if (arguments.size() == 0)
841  maskName = "";
842  else if (arguments.size() == 1)
843  maskName = arguments[0];
844  else
845  B2FATAL("Wrong number of arguments (1 required) for meta function ROE_Px");
846 
847  auto func = [maskName](const Particle * particle) -> double {
848 
849  // Get related ROE object
850  const RestOfEvent* roe = getRelatedROEObject(particle);
851 
852  if (!roe)
853  {
854  B2ERROR("Relation between particle and ROE doesn't exist!");
855  return -1;
856  }
857 
858  const auto& frame = ReferenceFrame::GetCurrent();
859  auto frameRoe4Vector = frame.getMomentum(roe->get4Vector(maskName));
860  return frameRoe4Vector.Vect().X();
861  };
862  return func;
863  }
864 
865  Manager::FunctionPtr ROE_Py(const std::vector<std::string>& arguments)
866  {
867  std::string maskName;
868 
869  if (arguments.size() == 0)
870  maskName = "";
871  else if (arguments.size() == 1)
872  maskName = arguments[0];
873  else
874  B2FATAL("Wrong number of arguments (1 required) for meta function ROE_Py");
875 
876  auto func = [maskName](const Particle * particle) -> double {
877 
878  // Get related ROE object
879  const RestOfEvent* roe = getRelatedROEObject(particle);
880 
881  if (!roe)
882  {
883  B2ERROR("Relation between particle and ROE doesn't exist!");
884  return -1;
885  }
886 
887  const auto& frame = ReferenceFrame::GetCurrent();
888  auto frameRoe4Vector = frame.getMomentum(roe->get4Vector(maskName));
889  return frameRoe4Vector.Vect().Y();
890  };
891  return func;
892  }
893 
894  Manager::FunctionPtr ROE_Pt(const std::vector<std::string>& arguments)
895  {
896  std::string maskName;
897 
898  if (arguments.size() == 0)
899  maskName = "";
900  else if (arguments.size() == 1)
901  maskName = arguments[0];
902  else
903  B2FATAL("Wrong number of arguments (1 required) for meta function ROE_Pt");
904 
905  auto func = [maskName](const Particle * particle) -> double {
906 
907  // Get related ROE object
908  const RestOfEvent* roe = getRelatedROEObject(particle);
909 
910  if (!roe)
911  {
912  B2ERROR("Relation between particle and ROE doesn't exist!");
913  return -1;
914  }
915 
916  const auto& frame = ReferenceFrame::GetCurrent();
917  auto frameRoe4Vector = frame.getMomentum(roe->get4Vector(maskName));
918  return frameRoe4Vector.Vect().Perp();
919  };
920  return func;
921  }
922 
923  Manager::FunctionPtr ROE_Pz(const std::vector<std::string>& arguments)
924  {
925  std::string maskName;
926 
927  if (arguments.size() == 0)
928  maskName = "";
929  else if (arguments.size() == 1)
930  maskName = arguments[0];
931  else
932  B2FATAL("Wrong number of arguments (1 required) for meta function ROE_Pz");
933 
934  auto func = [maskName](const Particle * particle) -> double {
935 
936  // Get related ROE object
937  const RestOfEvent* roe = getRelatedROEObject(particle);
938 
939  if (!roe)
940  {
941  B2ERROR("Relation between particle and ROE doesn't exist!");
942  return -1;
943  }
944 
945  const auto& frame = ReferenceFrame::GetCurrent();
946  auto frameRoe4Vector = frame.getMomentum(roe->get4Vector(maskName));
947  return frameRoe4Vector.Vect().Z();
948  };
949  return func;
950  }
951 
952  Manager::FunctionPtr ROE_PTheta(const std::vector<std::string>& arguments)
953  {
954  std::string maskName;
955 
956  if (arguments.size() == 0)
957  maskName = "";
958  else if (arguments.size() == 1)
959  maskName = arguments[0];
960  else
961  B2FATAL("Wrong number of arguments (1 required) for meta function ROE_PTheta");
962 
963  auto func = [maskName](const Particle * particle) -> double {
964 
965  // Get related ROE object
966  const RestOfEvent* roe = getRelatedROEObject(particle);
967 
968  if (!roe)
969  {
970  B2ERROR("Relation between particle and ROE doesn't exist!");
971  return -1;
972  }
973 
974  const auto& frame = ReferenceFrame::GetCurrent();
975  auto frameRoe4Vector = frame.getMomentum(roe->get4Vector(maskName));
976  return frameRoe4Vector.Theta();
977  };
978  return func;
979  }
980 
981  Manager::FunctionPtr ROE_DeltaE(const std::vector<std::string>& arguments)
982  {
983  std::string maskName;
984 
985  if (arguments.size() == 0)
986  maskName = "";
987  else if (arguments.size() == 1)
988  maskName = arguments[0];
989  else
990  B2FATAL("Wrong number of arguments (1 required) for meta function ROE_deltae");
991 
992  auto func = [maskName](const Particle * particle) -> double {
993 
994  // Get related ROE object
995  const RestOfEvent* roe = getRelatedROEObject(particle);
996 
997  if (!roe)
998  {
999  B2ERROR("Relation between particle and ROE doesn't exist!");
1000  return -1;
1001  }
1002 
1003  PCmsLabTransform T;
1004  TLorentzVector vec = T.rotateLabToCms() * roe->get4Vector(maskName);
1005  return vec.E() - T.getCMSEnergy() / 2;
1006  };
1007  return func;
1008  }
1009 
1010  Manager::FunctionPtr ROE_Mbc(const std::vector<std::string>& arguments)
1011  {
1012  std::string maskName;
1013 
1014  if (arguments.size() == 0)
1015  maskName = "";
1016  else if (arguments.size() == 1)
1017  maskName = arguments[0];
1018  else
1019  B2FATAL("Wrong number of arguments (1 required) for meta function ROE_mbc");
1020 
1021  auto func = [maskName](const Particle * particle) -> double {
1022 
1023  // Get related ROE object
1024  const RestOfEvent* roe = getRelatedROEObject(particle);
1025 
1026  if (!roe)
1027  {
1028  B2ERROR("Relation between particle and ROE doesn't exist!");
1029  return -1;
1030  }
1031 
1032  PCmsLabTransform T;
1033  TLorentzVector vec = T.rotateLabToCms() * roe->get4Vector(maskName);
1034 
1035  double E = T.getCMSEnergy() / 2;
1036  double m2 = E * E - vec.Vect().Mag2();
1037  double mbc = m2 > 0 ? sqrt(m2) : 0;
1038 
1039  return mbc;
1040  };
1041  return func;
1042  }
1043 
1044  Manager::FunctionPtr bssMassDifference(const std::vector<std::string>& arguments)
1045  {
1046  std::string maskName;
1047 
1048  if (arguments.size() == 0)
1049  maskName = "";
1050  else if (arguments.size() == 1)
1051  maskName = arguments[0];
1052  else
1053  B2FATAL("Wrong number of arguments (1 required) for meta function bssMassDifference");
1054 
1055  auto func = [maskName](const Particle * particle) -> double {
1056 
1057  // Get related ROE object
1058  TLorentzVector neutrino4vec = missing4Vector(particle->getDaughter(0), maskName, "6");
1059  TLorentzVector sig4vec = particle->getDaughter(0)->get4Vector();
1060 
1061  TLorentzVector bsMom = neutrino4vec + sig4vec;
1062  TLorentzVector bssMom = bsMom + particle->getDaughter(1)->get4Vector();
1063 
1064  return bssMom.M() - bsMom.M();
1065  };
1066  return func;
1067  }
1068 
1069  Manager::FunctionPtr WE_DeltaE(const std::vector<std::string>& arguments)
1070  {
1071  std::string maskName;
1072  std::string opt;
1073 
1074  if (arguments.size() == 1) {
1075  maskName = "";
1076  opt = arguments[0];
1077  } else if (arguments.size() == 2) {
1078  maskName = arguments[0];
1079  opt = arguments[1];
1080  } else
1081  B2FATAL("Wrong number of arguments (2 required) for meta function correctedB_deltae");
1082 
1083  auto func = [maskName, opt](const Particle * particle) -> double {
1084 
1085  PCmsLabTransform T;
1086  TLorentzVector boostvec = T.getBeamFourMomentum();
1087  TLorentzVector sig4vec = T.rotateLabToCms() * particle->get4Vector();
1088  TLorentzVector sig4vecLAB = particle->get4Vector();
1089  TLorentzVector neutrino4vec = missing4Vector(particle, maskName, "1");
1090  TLorentzVector neutrino4vecLAB = missing4Vector(particle, maskName, "6");
1091 
1092  double deltaE = std::numeric_limits<float>::quiet_NaN();
1093 
1094  // Definition 0: CMS
1095  if (opt == "0")
1096  {
1097  double totalSigEnergy = (sig4vec + neutrino4vec).Energy();
1098  double E = T.getCMSEnergy() / 2;
1099  deltaE = totalSigEnergy - E;
1100  }
1101 
1102  // Definition 1: LAB
1103  else if (opt == "1")
1104  {
1105  double Ecms = T.getCMSEnergy();
1106  double s = Ecms * Ecms;
1107  deltaE = ((sig4vecLAB + neutrino4vecLAB) * boostvec - s / 2.0) / sqrt(s);
1108  }
1109 
1110  else
1111  B2FATAL("Option for correctedB_deltae variable should only be 0/1 (CMS/LAB)");
1112 
1113  return deltaE;
1114  };
1115  return func;
1116  }
1117 
1118  Manager::FunctionPtr WE_Mbc(const std::vector<std::string>& arguments)
1119  {
1120  std::string maskName;
1121  std::string opt;
1122 
1123  if (arguments.size() == 1) {
1124  maskName = "";
1125  opt = arguments[0];
1126  } else if (arguments.size() == 2) {
1127  maskName = arguments[0];
1128  opt = arguments[1];
1129  } else
1130  B2FATAL("Wrong number of arguments (2 required) for meta function correctedB_mbc");
1131 
1132  auto func = [maskName, opt](const Particle * particle) -> double {
1133 
1134  PCmsLabTransform T;
1135  TLorentzVector boostvec = T.getBeamFourMomentum();
1136  TLorentzVector sig4vec = T.rotateLabToCms() * particle->get4Vector();
1137  TLorentzVector sig4vecLAB = particle->get4Vector();
1138  TLorentzVector neutrino4vec;
1139 
1140  double mbc = std::numeric_limits<float>::quiet_NaN();
1141 
1142  // Definition 0: CMS
1143  if (opt == "0")
1144  {
1145  neutrino4vec = missing4Vector(particle, maskName, "1");
1146  TVector3 bmom = (sig4vec + neutrino4vec).Vect();
1147  double E = T.getCMSEnergy() / 2;
1148  double m2 = E * E - bmom.Mag2();
1149  mbc = m2 > 0 ? sqrt(m2) : 0;
1150  }
1151 
1152  // Definition 1: LAB
1153  else if (opt == "1")
1154  {
1155  neutrino4vec = missing4Vector(particle, maskName, "6");
1156  TVector3 bmom = (sig4vecLAB + neutrino4vec).Vect();
1157  double Ecms = T.getCMSEnergy();
1158  double s = Ecms * Ecms;
1159  double m2 = pow((s / 2.0 + bmom * boostvec.Vect()) / boostvec.Energy(), 2.0) - bmom.Mag2();
1160  mbc = m2 > 0 ? sqrt(m2) : 0;
1161  }
1162 
1163  // Definition 2: CMS with factor alpha (so that dE == 0)
1164  else if (opt == "2")
1165  {
1166  neutrino4vec = missing4Vector(particle, maskName, "7");
1167  TVector3 bmom = (sig4vec + neutrino4vec).Vect();
1168  double E = T.getCMSEnergy() / 2;
1169  double m2 = E * E - bmom.Mag2();
1170  mbc = m2 > 0 ? sqrt(m2) : 0;
1171  }
1172 
1173  else
1174  B2FATAL("Option for correctedB_mbc variable should only be 0/1/2 (CMS/LAB/CMS with factor)");
1175 
1176  return mbc;
1177  };
1178  return func;
1179  }
1180 
1181  Manager::FunctionPtr WE_MissM2(const std::vector<std::string>& arguments)
1182  {
1183  std::string maskName;
1184  std::string opt;
1185 
1186  if (arguments.size() == 1) {
1187  maskName = "";
1188  opt = arguments[0];
1189  } else if (arguments.size() == 2) {
1190  maskName = arguments[0];
1191  opt = arguments[1];
1192  } else
1193  B2FATAL("Wrong number of arguments (2 required) for meta function missM2");
1194 
1195  auto func = [maskName, opt](const Particle * particle) -> double {
1196 
1197  return missing4Vector(particle, maskName, opt).Mag2();
1198  };
1199  return func;
1200  }
1201 
1202  double REC_MissM2(const Particle* particle)
1203  {
1204  PCmsLabTransform T;
1205  TLorentzVector rec4vecLAB = particle->get4Vector();
1206  TLorentzVector rec4vec = T.rotateLabToCms() * rec4vecLAB;
1207 
1208  TLorentzVector miss4vec;
1209  double E_beam_cms = T.getCMSEnergy() / 2.0;
1210 
1211  miss4vec.SetVect(-rec4vec.Vect());
1212  miss4vec.SetE(E_beam_cms - rec4vec.Energy());
1213 
1214  return miss4vec.Mag2();
1215  }
1216 
1217  Manager::FunctionPtr WE_MissPTheta(const std::vector<std::string>& arguments)
1218  {
1219  std::string maskName;
1220  std::string opt;
1221 
1222  if (arguments.size() == 1) {
1223  maskName = "";
1224  opt = arguments[0];
1225  } else if (arguments.size() == 2) {
1226  maskName = arguments[0];
1227  opt = arguments[1];
1228  } else
1229  B2FATAL("Wrong number of arguments (2 required) for meta function WE_MissPTheta");
1230 
1231  auto func = [maskName, opt](const Particle * particle) -> double {
1232 
1233  // Get related ROE object
1234  const RestOfEvent* roe = getRelatedROEObject(particle);
1235 
1236  if (!roe)
1237  {
1238  B2ERROR("Relation between particle and ROE doesn't exist!");
1239  return -1;
1240  }
1241 
1242  return missing4Vector(particle, maskName, opt).Theta();
1243  };
1244  return func;
1245  }
1246 
1247  Manager::FunctionPtr WE_MissP(const std::vector<std::string>& arguments)
1248  {
1249  std::string maskName;
1250  std::string opt;
1251 
1252  if (arguments.size() == 1) {
1253  maskName = "";
1254  opt = arguments[0];
1255  } else if (arguments.size() == 2) {
1256  maskName = arguments[0];
1257  opt = arguments[1];
1258  } else
1259  B2FATAL("Wrong number of arguments (2 required) for meta function WE_MissP");
1260 
1261  auto func = [maskName, opt](const Particle * particle) -> double {
1262 
1263  // Get related ROE object
1264  const RestOfEvent* roe = getRelatedROEObject(particle);
1265 
1266  if (!roe)
1267  {
1268  B2ERROR("Relation between particle and ROE doesn't exist!");
1269  return -1;
1270  }
1271 
1272  return missing4Vector(particle, maskName, opt).Vect().Mag();
1273  };
1274  return func;
1275  }
1276 
1277  Manager::FunctionPtr WE_MissPx(const std::vector<std::string>& arguments)
1278  {
1279  std::string maskName;
1280  std::string opt;
1281 
1282  if (arguments.size() == 1) {
1283  maskName = "";
1284  opt = arguments[0];
1285  } else if (arguments.size() == 2) {
1286  maskName = arguments[0];
1287  opt = arguments[1];
1288  } else
1289  B2FATAL("Wrong number of arguments (2 required) for meta function WE_MissPx");
1290 
1291  auto func = [maskName, opt](const Particle * particle) -> double {
1292 
1293  // Get related ROE object
1294  const RestOfEvent* roe = getRelatedROEObject(particle);
1295 
1296  if (!roe)
1297  {
1298  B2ERROR("Relation between particle and ROE doesn't exist!");
1299  return -1;
1300  }
1301 
1302  return missing4Vector(particle, maskName, opt).Vect().Px();
1303  };
1304  return func;
1305  }
1306 
1307  Manager::FunctionPtr WE_MissPy(const std::vector<std::string>& arguments)
1308  {
1309  std::string maskName;
1310  std::string opt;
1311 
1312  if (arguments.size() == 1) {
1313  maskName = "";
1314  opt = arguments[0];
1315  } else if (arguments.size() == 2) {
1316  maskName = arguments[0];
1317  opt = arguments[1];
1318  } else
1319  B2FATAL("Wrong number of arguments (2 required) for meta function WE_MissPy");
1320 
1321  auto func = [maskName, opt](const Particle * particle) -> double {
1322 
1323  // Get related ROE object
1324  const RestOfEvent* roe = getRelatedROEObject(particle);
1325 
1326  if (!roe)
1327  {
1328  B2ERROR("Relation between particle and ROE doesn't exist!");
1329  return -1;
1330  }
1331 
1332  return missing4Vector(particle, maskName, opt).Vect().Py();
1333  };
1334  return func;
1335  }
1336 
1337  Manager::FunctionPtr WE_MissPz(const std::vector<std::string>& arguments)
1338  {
1339  std::string maskName;
1340  std::string opt;
1341 
1342  if (arguments.size() == 1) {
1343  maskName = "";
1344  opt = arguments[0];
1345  } else if (arguments.size() == 2) {
1346  maskName = arguments[0];
1347  opt = arguments[1];
1348  } else
1349  B2FATAL("Wrong number of arguments (2 required) for meta function WE_MissPz");
1350 
1351  auto func = [maskName, opt](const Particle * particle) -> double {
1352 
1353  // Get related ROE object
1354  const RestOfEvent* roe = getRelatedROEObject(particle);
1355 
1356  if (!roe)
1357  {
1358  B2ERROR("Relation between particle and ROE doesn't exist!");
1359  return -1;
1360  }
1361 
1362  return missing4Vector(particle, maskName, opt).Vect().Pz();
1363  };
1364  return func;
1365  }
1366 
1367  Manager::FunctionPtr WE_MissE(const std::vector<std::string>& arguments)
1368  {
1369  std::string maskName;
1370  std::string opt;
1371 
1372  if (arguments.size() == 1) {
1373  maskName = "";
1374  opt = arguments[0];
1375  } else if (arguments.size() == 2) {
1376  maskName = arguments[0];
1377  opt = arguments[1];
1378  } else
1379  B2FATAL("Wrong number of arguments (2 required) for meta function WE_MissE");
1380 
1381  auto func = [maskName, opt](const Particle * particle) -> double {
1382 
1383  // Get related ROE object
1384  const RestOfEvent* roe = getRelatedROEObject(particle);
1385 
1386  if (!roe)
1387  {
1388  B2ERROR("Relation between particle and ROE doesn't exist!");
1389  return -1;
1390  }
1391 
1392  return missing4Vector(particle, maskName, opt).Energy();
1393  };
1394  return func;
1395  }
1396 
1397  Manager::FunctionPtr WE_xiZ(const std::vector<std::string>& arguments)
1398  {
1399  std::string maskName;
1400 
1401  if (arguments.size() == 0)
1402  maskName = "";
1403  else if (arguments.size() == 1)
1404  maskName = arguments[0];
1405  else
1406  B2FATAL("Wrong number of arguments (1 required) for meta function xiZ");
1407 
1408  auto func = [maskName](const Particle * particle) -> double {
1409 
1410  // Get related ROE object
1411  const RestOfEvent* roe = getRelatedROEObject(particle);
1412 
1413  if (!roe)
1414  {
1415  B2ERROR("Relation between particle and ROE doesn't exist!");
1416  return -1;
1417  }
1418 
1419  double pz = 0;
1420  double energy = 0;
1421 
1422  // Get all Tracks on reconstructed side
1423  std::vector<const Particle*> recTrackParticles = particle->getFinalStateDaughters();
1424 
1425  // Loop the reconstructed side
1426  for (auto& recTrackParticle : recTrackParticles)
1427  {
1428  pz += recTrackParticle->getPz();
1429  energy += recTrackParticle->getEnergy();
1430  }
1431 
1432  // "Loop" the ROE side
1433  pz += roe->get4VectorTracks(maskName).Vect().Pz();
1434  energy += roe->get4VectorTracks(maskName).Energy();
1435 
1436  return pz / energy;
1437  };
1438  return func;
1439  }
1440 
1441  Manager::FunctionPtr WE_MissM2OverMissE(const std::vector<std::string>& arguments)
1442  {
1443  std::string maskName;
1444 
1445  if (arguments.size() == 0)
1446  maskName = "";
1447  else if (arguments.size() == 1)
1448  maskName = arguments[0];
1449  else
1450  B2FATAL("Wrong number of arguments (1 required) for meta function WE_MissM2OverMissE");
1451 
1452  auto func = [maskName](const Particle * particle) -> double {
1453 
1454  // Get related ROE object
1455  const RestOfEvent* roe = getRelatedROEObject(particle);
1456 
1457  if (!roe)
1458  {
1459  B2ERROR("Relation between particle and ROE doesn't exist!");
1460  return -1;
1461  }
1462 
1463  PCmsLabTransform T;
1464  TLorentzVector missing4Momentum;
1465  TLorentzVector boostvec = T.getBeamFourMomentum();
1466 
1467  return missing4Vector(particle, maskName, "5").Mag2() / (2.0 * missing4Vector(particle, maskName, "5").Energy());
1468  };
1469  return func;
1470  }
1471 
1472  double REC_q2BhSimple(const Particle* particle)
1473  {
1474  // calculates q^2 = (p_B - p_h) in decays of B -> h_1 .. h_n ell nu_ell,
1475  // where p_h = Sum_i^n p_h_i is the 4-momentum of hadrons in the final
1476  // state. The calculation is performed in the CMS system, where B-meson
1477  // is assumed to be at rest p_B = (m_B, 0).
1478 
1479  TLorentzVector hadron4vec;
1480 
1481  int n = particle->getNDaughters();
1482 
1483  if (n < 1)
1484  return std::numeric_limits<float>::quiet_NaN();
1485 
1486  // TODO: avoid hardocoded values
1487  for (unsigned i = 0; i < particle->getNDaughters(); i++) {
1488  int absPDG = abs(particle->getDaughter(i)->getPDGCode());
1489  if (absPDG == 11 || absPDG == 13 || absPDG == 15)
1490  continue;
1491 
1492  hadron4vec += particle->getDaughter(i)->get4Vector();
1493  }
1494 
1495  // boost to CMS
1496  PCmsLabTransform T;
1497  TLorentzVector phCMS = T.rotateLabToCms() * hadron4vec;
1498  TLorentzVector pBCMS;
1499  pBCMS.SetXYZM(0.0, 0.0, 0.0, particle->getPDGMass());
1500 
1501  return (pBCMS - phCMS).Mag2();
1502  }
1503 
1504  double REC_q2Bh(const Particle* particle)
1505  {
1506  // calculates q^2 = (p_B - p_h) in decays of B -> h_1 .. h_n ell nu_ell,
1507  // where p_h = Sum_i^n p_h_i is the 4-momentum of hadrons in the final
1508  // state. The calculation is performed in the CMS system,
1509  // with a weighter average in a cone around the true B direction
1510 
1511  TLorentzVector hadron4vec;
1512 
1513  int n = particle->getNDaughters();
1514 
1515  if (n < 1)
1516  return std::numeric_limits<float>::quiet_NaN();
1517 
1518  for (unsigned i = 0; i < particle->getNDaughters(); i++) {
1519  int absPDG = abs(particle->getDaughter(i)->getPDGCode());
1520  if (absPDG == 11 || absPDG == 13 || absPDG == 15)
1521  continue;
1522 
1523  hadron4vec += particle->getDaughter(i)->get4Vector();
1524  }
1525 
1526  // boost to CMS
1527  PCmsLabTransform T;
1528  TLorentzVector had_cm = T.rotateLabToCms() * hadron4vec;
1529  TLorentzVector Y_cm = T.rotateLabToCms() * particle->get4Vector();
1530 
1531  // Recycled code from Uwe Gebauer <uwe.gebauer@phys.uni-goettingen.de>
1532 
1533  double bmass = particle->getPDGMass();
1534 
1535  // B theta angle
1536  double cos_cone_angle = Variable::cosThetaBetweenParticleAndNominalB(particle);
1537 
1538  if (abs(cos_cone_angle) > 1) {
1539  //makes no sense in this case, return simple value
1540  return Variable::REC_q2BhSimple(particle);
1541  }
1542 
1543  double thetaBY = TMath::ACos(cos_cone_angle);
1544  const double E_B = T.getCMSEnergy() / 2.0;
1545  const double p_B = sqrt(E_B * E_B - bmass * bmass);
1546 
1547  double phi_start = gRandom->Uniform(0, TMath::Pi() / 2);
1548 
1549  double q2 = 0;
1550  double denom = 0;
1551 
1552  for (int around_the_cone = 0; around_the_cone < 4; around_the_cone++) {
1553  TLorentzVector one_B(1, 1, 1, E_B);
1554  double B_theta = Y_cm.Theta() + thetaBY * cos(phi_start + around_the_cone / 2.*TMath::Pi());
1555  double B_phi = Y_cm.Phi() + thetaBY * sin(phi_start + around_the_cone / 2.*TMath::Pi());
1556  one_B.SetTheta(B_theta);
1557  one_B.SetPhi(B_phi);
1558  one_B.SetRho(p_B);
1559  one_B.SetE(E_B);
1560  double this_q2 = (one_B - had_cm).Mag2();
1561  q2 += this_q2 * sin(B_theta) * sin(B_theta);
1562  denom += sin(B_theta) * sin(B_theta);
1563  }
1564 
1565  q2 /= denom;
1566 
1567  return q2;
1568  }
1569 
1570  Manager::FunctionPtr WE_q2lnuSimple(const std::vector<std::string>& arguments)
1571  {
1572  std::string maskName("");
1573  std::string option("1");
1574 
1575  if (arguments.size() == 1) {
1576  maskName = arguments[0];
1577  } else if (arguments.size() == 2) {
1578  maskName = arguments[0];
1579  option = arguments[1];
1580  } else if (arguments.size() > 2) {
1581  B2FATAL("Too many arguments. At most two arguments are allowed for meta function q2lnuSimple(maskname,option)");
1582  }
1583 
1584  auto func = [maskName, option](const Particle * particle) -> double {
1585 
1586  // Get related ROE object
1587  const RestOfEvent* roe = getRelatedROEObject(particle);
1588 
1589  if (!roe)
1590  {
1591  B2ERROR("Relation between particle and ROE doesn't exist!");
1592  return -1;
1593  }
1594 
1595  int n = particle->getNDaughters();
1596 
1597  if (n < 1)
1598  return std::numeric_limits<float>::quiet_NaN();
1599 
1600  // Assumes lepton is the last particle in the reco decay chain!
1601  PCmsLabTransform T;
1602  const Particle* lep = particle->getDaughter(n - 1);
1603  TLorentzVector lep4vec = T.rotateLabToCms() * lep->get4Vector();
1604  TLorentzVector nu4vec = missing4Vector(particle, maskName, option);
1605 
1606  return (lep4vec + nu4vec).Mag2();
1607  };
1608  return func;
1609  }
1610 
1611  Manager::FunctionPtr WE_q2lnu(const std::vector<std::string>& arguments)
1612  {
1613  std::string maskName("");
1614  std::string option("7");
1615 
1616  if (arguments.size() == 1) {
1617  maskName = arguments[0];
1618  } else if (arguments.size() == 2) {
1619  maskName = arguments[0];
1620  option = arguments[1];
1621  } else if (arguments.size() > 2) {
1622  B2FATAL("Too many arguments. At most two arguments are allowed for meta function q2lnu(maskname, option)");
1623  }
1624 
1625  auto func = [maskName, option](const Particle * particle) -> double {
1626 
1627  // Get related ROE object
1628  const RestOfEvent* roe = getRelatedROEObject(particle);
1629 
1630  if (!roe)
1631  {
1632  B2ERROR("Relation between particle and ROE doesn't exist!");
1633  return -1;
1634  }
1635 
1636  int n = particle->getNDaughters();
1637 
1638  if (n < 1)
1639  return std::numeric_limits<float>::quiet_NaN();
1640 
1641  PCmsLabTransform T;
1642  const Particle* lep = particle->getDaughter(n - 1);
1643  TLorentzVector lep_cm = T.rotateLabToCms() * lep->get4Vector();
1644 
1645  TLorentzVector Y_cm = T.rotateLabToCms() * particle->get4Vector();
1646  TLorentzVector neu_cm = missing4Vector(particle, maskName, option);
1647 
1648  // Recycled code from Uwe Gebauer <uwe.gebauer@phys.uni-goettingen.de>
1649  double e_beam = T.getCMSEnergy() / 2.0;
1650 
1651  //just to make the formula simpler
1652  double bmass = particle->getPDGMass();
1653  double pB2 = e_beam * e_beam - bmass * bmass;
1654 
1655  //angle between the Y and the neutrino, from the Mbc=M_B constraint
1656  double cos_angle_nu = (pB2 - Y_cm.Vect().Mag2() - neu_cm.Vect().Mag2()) / (2.0 * Y_cm.Vect().Mag() * neu_cm.Vect().Mag());
1657  if (abs(cos_angle_nu) > 1)
1658  {
1659  return (lep_cm + neu_cm).Mag2();
1660  }
1661 
1662  double angle_nu = TMath::ACos(cos_angle_nu);
1663  //first get one random neutrino, on the allowed cone for the constraint
1664  TLorentzVector rotated_neu(-1 * Y_cm.Vect(), Y_cm.E()); //first get reverse Y
1665 
1666  double nu_theta = rotated_neu.Theta() + (TMath::Pi() - angle_nu);
1667  double nu_phi = rotated_neu.Phi();
1668  rotated_neu.SetTheta(nu_theta);
1669  rotated_neu.SetPhi(nu_phi);
1670  rotated_neu.SetRho(neu_cm.Rho());
1671  rotated_neu.SetE(neu_cm.E());
1672 
1673  TVector3 Yneu_norm = Y_cm.Vect().Cross(neu_cm.Vect());
1674  TVector3 Yrot_norm = Y_cm.Vect().Cross(rotated_neu.Vect());
1675  //angle between the two crossproducts -> angle between the two vectors perpendicular to the Y-p_inc and Y-B planes -> angle between the planes
1676  //this angle needs to come out as zero
1677 
1678  double rot_angle = Yneu_norm.Angle(Yrot_norm);
1679 
1680  TLorentzVector rotated_neu2(rotated_neu);
1681  //unfortunately don't -and probably can't- know in which direction to rotate without trying
1682  //so create a copy of the vector, and later choose the correct one
1683  //However, rotation by 180 degrees is never needed, direction of the cross-product vector assures that when after rotation
1684  //the B-vector is in the plane, it always is on the side closer to pcm_lv_inc.
1685  //rotate around Y into the Y-neutrino-plane
1686  rotated_neu.Rotate(rot_angle, Y_cm.Vect());
1687  rotated_neu2.Rotate(-rot_angle, Y_cm.Vect());
1688 
1689  double dot1 = rotated_neu.Vect().Dot(Yneu_norm);
1690  double dot2 = rotated_neu2.Vect().Dot(Yneu_norm);
1691 
1692  if (abs(dot2) < abs(dot1)) rotated_neu = rotated_neu2;
1693 
1694  return (lep_cm + rotated_neu).Mag2();
1695  };
1696  return func;
1697  }
1698 
1699  Manager::FunctionPtr WE_cosThetaEll(const std::vector<std::string>& arguments)
1700  {
1701  std::string maskName;
1702 
1703  if (arguments.size() == 0)
1704  maskName = "";
1705  else if (arguments.size() == 1)
1706  maskName = arguments[0];
1707  else
1708  B2FATAL("Wrong number of arguments (1 required) for meta function cosThetaEll");
1709 
1710  auto func = [maskName](const Particle * particle) -> double {
1711 
1712  PCmsLabTransform T;
1713  TLorentzVector boostvec = T.getBeamFourMomentum();
1714  TLorentzVector pNu = missing4Vector(particle, maskName, "6");
1715 
1716  TLorentzVector pLep;
1717  // TODO: avoid hardocoded values
1718  for (unsigned i = 0; i < particle->getNDaughters(); i++)
1719  {
1720  int absPDG = abs(particle->getDaughter(i)->getPDGCode());
1721  if (absPDG == 11 || absPDG == 13 || absPDG == 15) {
1722  pLep = particle->getDaughter(i)->get4Vector();
1723  break;
1724  }
1725  }
1726 
1727  TLorentzVector pW = pNu + pLep;
1728  TLorentzVector pB = particle->get4Vector() + pNu;
1729 
1730  // boost lepton and B momentum to W frame
1731  TVector3 boost2W = -(pW.BoostVector());
1732  pLep.Boost(boost2W);
1733  pB.Boost(boost2W);
1734 
1735  TVector3 lep3Vector = pLep.Vect();
1736  TVector3 B3Vector = pB.Vect();
1737  double numerator = lep3Vector.Dot(B3Vector);
1738  double denominator = (lep3Vector.Mag()) * (B3Vector.Mag());
1739 
1740  return numerator / denominator;
1741  };
1742  return func;
1743  }
1744 
1745  Manager::FunctionPtr passesROEMask(const std::vector<std::string>& arguments)
1746  {
1747  std::string maskName;
1748 
1749  if (arguments.size() == 0)
1750  maskName = "";
1751  else if (arguments.size() == 1)
1752  maskName = arguments[0];
1753  else
1754  B2FATAL("Wrong number of arguments (1 required) for meta function passesROEMask");
1755 
1756  auto func = [maskName](const Particle * particle) -> double {
1757 
1758  double result = -1;
1759 
1760  StoreObjPtr<RestOfEvent> roe("RestOfEvent");
1761  if (not roe.isValid())
1762  return result;
1763 
1764  if (maskName == "")
1765  return 1.0;
1766  if (roe->hasParticle(particle, maskName))
1767  {
1768  return 1.0;
1769  }
1770 
1771  return result;
1772  };
1773  return func;
1774  }
1775 
1776  double printROE(const Particle* particle)
1777  {
1778  const RestOfEvent* roe = getRelatedROEObject(particle);
1779 
1780  if (!roe) {
1781  B2ERROR("Relation between particle and ROE doesn't exist!");
1782  } else roe->print();
1783  return 0.0;
1784  }
1785 
1786 
1787  Manager::FunctionPtr pi0Prob(const std::vector<std::string>& arguments)
1788  {
1789  if (arguments.size() != 1)
1790  B2ERROR("Wrong number of arguments (1 required) for pi0Prob");
1791 
1792  std::string mode;
1793  mode = arguments[0];
1794 
1795  if (mode != "standard" and mode != "tight" and mode != "cluster" and mode != "both")
1796  B2ERROR("the given argument is not supported in pi0Prob!");
1797 
1798  auto func = [mode](const Particle * particle) -> double {
1799  if (mode == "standard")
1800  {
1801  if (particle->hasExtraInfo("Pi0ProbOrigin")) {
1802  return particle->getExtraInfo("Pi0ProbOrigin");
1803  } else {
1804  B2WARNING("Pi0ProbOrigin is not registerted in extraInfo! \n"
1805  "the function writePi0EtaVeto has to be executed to register this extraInfo.");
1806  return std::numeric_limits<float>::quiet_NaN();
1807  }
1808  }
1809 
1810  else if (mode == "tight")
1811  {
1812  if (particle->hasExtraInfo("Pi0ProbTightEnergyThreshold")) {
1813  return particle->getExtraInfo("Pi0ProbTightEnergyThreshold");
1814  } else {
1815  B2WARNING("Pi0ProbTightEnergyThreshold is not registerted in extraInfo! \n"
1816  "the function writePi0EtaVeto has to be executed to register this extraInfo.");
1817  return std::numeric_limits<float>::quiet_NaN();
1818  }
1819  }
1820 
1821  else if (mode == "cluster")
1822  {
1823  if (particle->hasExtraInfo("Pi0ProbLargeClusterSize")) {
1824  return particle->getExtraInfo("Pi0ProbLargeClusterSize");
1825  } else {
1826  B2WARNING("Pi0ProbLargeClusterSize is not registerted in extraInfo! \n"
1827  "the function writePi0EtaVeto has to be executed to register this extraInfo.");
1828  return std::numeric_limits<float>::quiet_NaN();
1829  }
1830  }
1831 
1832  else if (mode == "both")
1833  {
1834  if (particle->hasExtraInfo("Pi0ProbTightEnergyThresholdAndLargeClusterSize")) {
1835  return particle->getExtraInfo("Pi0ProbTightEnergyThresholdAndLargeClusterSize");
1836  } else {
1837  B2WARNING("Pi0ProbTightEnergyThresholdAndLargeClusterSize is not registerted in extraInfo! \n"
1838  "the function writePi0EtaVeto has to be executed to register this extraInfo.");
1839  return std::numeric_limits<float>::quiet_NaN();
1840  }
1841  }
1842 
1843  else
1844  {
1845  return std::numeric_limits<float>::quiet_NaN();
1846  }
1847  };
1848  return func;
1849  }
1850 
1851  Manager::FunctionPtr etaProb(const std::vector<std::string>& arguments)
1852  {
1853  if (arguments.size() != 1)
1854  B2ERROR("Wrong number of arguments (1 required) for etaProb");
1855 
1856  std::string mode;
1857  mode = arguments[0];
1858 
1859  if (mode != "standard" and mode != "tight" and mode != "cluster" and mode != "both")
1860  B2ERROR("the given argument is not supported in etaProb!");
1861 
1862  auto func = [mode](const Particle * particle) -> double {
1863  if (mode == "standard")
1864  {
1865  if (particle->hasExtraInfo("EtaProbOrigin")) {
1866  return particle->getExtraInfo("EtaProbOrigin");
1867  } else {
1868  B2WARNING("EtaProbOrigin is not registerted in extraInfo! \n"
1869  "the function writePi0EtaVeto has to be executed to register this extraInfo.");
1870  return std::numeric_limits<float>::quiet_NaN();
1871  }
1872  }
1873 
1874  else if (mode == "tight")
1875  {
1876  if (particle->hasExtraInfo("EtaProbTightEnergyThreshold")) {
1877  return particle->getExtraInfo("EtaProbTightEnergyThreshold");
1878  } else {
1879  B2WARNING("EtaProbTightEnergyThreshold is not registerted in extraInfo! \n"
1880  "the function writePi0EtaVeto has to be executed to register this extraInfo.");
1881  return std::numeric_limits<float>::quiet_NaN();
1882  }
1883  }
1884 
1885  else if (mode == "cluster")
1886  {
1887  if (particle->hasExtraInfo("EtaProbLargeClusterSize")) {
1888  return particle->getExtraInfo("EtaProbLargeClusterSize");
1889  } else {
1890  B2WARNING("EtaProbLargeClusterSize is not registerted in extraInfo! \n"
1891  "the function writePi0EtaVeto has to be executed to register this extraInfo.");
1892  return std::numeric_limits<float>::quiet_NaN();
1893  }
1894  }
1895 
1896  else if (mode == "both")
1897  {
1898  if (particle->hasExtraInfo("EtaProbTightEnergyThresholdAndLargeClusterSize")) {
1899  return particle->getExtraInfo("EtaProbTightEnergyThresholdAndLargeClusterSize");
1900  } else {
1901  B2WARNING("EtaProbTightEnergyThresholdAndLargeClusterSize is not registerted in extraInfo! \n"
1902  "the function writePi0EtaVeto has to be executed to register this extraInfo.");
1903  return std::numeric_limits<float>::quiet_NaN();
1904  }
1905  }
1906 
1907  else
1908  {
1909  return std::numeric_limits<float>::quiet_NaN();
1910  }
1911  };
1912  return func;
1913  }
1914 
1915  // ------------------------------------------------------------------------------
1916  // Below are some functions for ease of usage, they are not a part of variables
1917  // ------------------------------------------------------------------------------
1918 
1919  TLorentzVector missing4Vector(const Particle* particle, const std::string& maskName, const std::string& opt)
1920  {
1921  // Get related ROE object
1922  const RestOfEvent* roe = getRelatedROEObject(particle);
1923 
1924  if (!roe) {
1925  B2ERROR("Relation between particle and ROE doesn't exist!");
1926  TLorentzVector empty;
1927  return empty;
1928  }
1929 
1930  PCmsLabTransform T;
1931  TLorentzVector boostvec = T.getBeamFourMomentum();
1932 
1933  TLorentzVector rec4vecLAB = particle->get4Vector();
1934  TLorentzVector roe4vecLAB = roe->get4Vector(maskName);
1935 
1936  TLorentzVector rec4vec = T.rotateLabToCms() * rec4vecLAB;
1937  TLorentzVector roe4vec = T.rotateLabToCms() * roe4vecLAB;
1938 
1939  TLorentzVector miss4vec;
1940  double E_beam_cms = T.getCMSEnergy() / 2.0;
1941 
1942  // Definition 0: CMS, use energy and momentum of tracks and clusters
1943  if (opt == "0") {
1944  miss4vec.SetVect(- (rec4vec.Vect() + roe4vec.Vect()));
1945  miss4vec.SetE(2 * E_beam_cms - (rec4vec.E() + roe4vec.E()));
1946  }
1947 
1948  // Definition 1: CMS, same as 0, fix Emiss = pmiss
1949  else if (opt == "1") {
1950  miss4vec.SetVect(- (rec4vec.Vect() + roe4vec.Vect()));
1951  miss4vec.SetE(miss4vec.Vect().Mag());
1952  }
1953 
1954  // Definition 2: CMS, same as 0, fix Eroe = Ecms/2
1955  else if (opt == "2") {
1956  miss4vec.SetVect(- (rec4vec.Vect() + roe4vec.Vect()));
1957  miss4vec.SetE(E_beam_cms - rec4vec.E());
1958  }
1959 
1960  // Definition 3: CMS, use only energy and momentum of signal side
1961  else if (opt == "3") {
1962  miss4vec.SetVect(- rec4vec.Vect());
1963  miss4vec.SetE(E_beam_cms - rec4vec.E());
1964  }
1965 
1966  // Definition 4: CMS, same as 3, update with direction of ROE momentum
1967  else if (opt == "4") {
1968  TVector3 pB = - roe4vec.Vect();
1969  pB.SetMag(0.340);
1970  miss4vec.SetVect(pB - rec4vec.Vect());
1971  miss4vec.SetE(E_beam_cms - rec4vec.E());
1972  }
1973 
1974  // Definition 5: LAB, use energy and momentum of tracks and clusters from whole event
1975  else if (opt == "5") {
1976  miss4vec.SetVect(boostvec.Vect() - (rec4vecLAB.Vect() + roe4vecLAB.Vect()));
1977  miss4vec.SetE(boostvec.E() - (rec4vecLAB.E() + roe4vecLAB.E()));
1978  }
1979 
1980  // Definition 6: LAB, same as 5, fix Emiss = pmiss
1981  else if (opt == "6") {
1982  miss4vec.SetVect(boostvec.Vect() - (rec4vecLAB.Vect() + roe4vecLAB.Vect()));
1983  miss4vec.SetE(miss4vec.Vect().Mag());
1984  }
1985 
1986  // Definition 7: CMS, correct pmiss 3-momentum vector with factor alpha so that dE = 0 (used for Mbc calculation)
1987  else if (opt == "7") {
1988  miss4vec.SetVect(-(rec4vec.Vect() + roe4vec.Vect()));
1989  miss4vec.SetE(miss4vec.Vect().Mag());
1990  double factorAlpha = (E_beam_cms - rec4vec.E()) / miss4vec.E();
1991  miss4vec.SetRho(factorAlpha * miss4vec.Rho());
1992  miss4vec.SetE(miss4vec.Rho());
1993  }
1994 
1995  return miss4vec;
1996  }
1997 
1998  void checkMCParticleMissingFlags(const MCParticle* mcp, std::set<const MCParticle*> mcROEObjects, int& missingFlags)
1999  {
2000  std::vector<MCParticle*> daughters = mcp->getDaughters();
2001  for (auto& daughter : daughters) {
2002 
2003  if (!daughter->hasStatus(MCParticle::c_PrimaryParticle))
2004  continue;
2005 
2006  if (mcROEObjects.find(daughter) == mcROEObjects.end()) {
2007 
2008  int pdg = abs(daughter->getPDG());
2009 
2010  // photon
2011  if (pdg == Const::photon.getPDGCode() and (missingFlags & 1) == 0)
2012  missingFlags += 1;
2013 
2014  // electrons
2015  else if (pdg == Const::electron.getPDGCode() and (missingFlags & 2) == 0)
2016  missingFlags += 2;
2017 
2018  // muons
2019  else if (pdg == Const::muon.getPDGCode() and (missingFlags & 4) == 0)
2020  missingFlags += 4;
2021 
2022  // pions
2023  else if (pdg == Const::pion.getPDGCode() and (missingFlags & 8) == 0)
2024  missingFlags += 8;
2025 
2026  // kaons
2027  else if (pdg == Const::kaon.getPDGCode() and (missingFlags & 16) == 0)
2028  missingFlags += 16;
2029 
2030  // protons
2031  else if (pdg == Const::proton.getPDGCode() and (missingFlags & 32) == 0)
2032  missingFlags += 32;
2033 
2034  // neutrons
2035  else if (pdg == Const::neutron.getPDGCode() and (missingFlags & 64) == 0)
2036  missingFlags += 64;
2037 
2038  // kshort
2039  else if (pdg == Const::Kshort.getPDGCode() and ((missingFlags & 128) == 0 or (missingFlags & 256) == 0)) {
2040  std::vector<MCParticle*> ksDaug = daughter->getDaughters();
2041  if (ksDaug.size() == 2) {
2042  // K_S0 -> pi+ pi-
2043  if (abs(ksDaug[0]->getPDG()) == Const::pion.getPDGCode() and abs(ksDaug[1]->getPDG()) == Const::pion.getPDGCode()
2044  and (missingFlags & 128) == 0) {
2045  if (mcROEObjects.find(ksDaug[0]) == mcROEObjects.end() or mcROEObjects.find(ksDaug[1]) == mcROEObjects.end())
2046  missingFlags += 128;
2047  }
2048  // K_S0 -> pi0 pi0
2049  else if (abs(ksDaug[0]->getPDG()) == Const::pi0.getPDGCode() and abs(ksDaug[1]->getPDG()) == Const::pi0.getPDGCode()
2050  and (missingFlags & 256) == 0) {
2051  std::vector<MCParticle*> pi0Daug0 = ksDaug[0]->getDaughters();
2052  std::vector<MCParticle*> pi0Daug1 = ksDaug[1]->getDaughters();
2053  if (mcROEObjects.find(pi0Daug0[0]) == mcROEObjects.end() or
2054  mcROEObjects.find(pi0Daug0[1]) == mcROEObjects.end() or
2055  mcROEObjects.find(pi0Daug1[0]) == mcROEObjects.end() or
2056  mcROEObjects.find(pi0Daug1[1]) == mcROEObjects.end())
2057  missingFlags += 256;
2058  }
2059  }
2060  }
2061 
2062  // klong
2063  else if (pdg == Const::Klong.getPDGCode() and (missingFlags & 512) == 0)
2064  missingFlags += 512;
2065 
2066  // neutrinos, which are not in the Const::
2067  else if ((pdg == 12 or pdg == 14 or pdg == 16) and (missingFlags & 1024) == 0)
2068  missingFlags += 1024;
2069  }
2070  checkMCParticleMissingFlags(daughter, mcROEObjects, missingFlags);
2071  }
2072  }
2073 
2074  double isInThisRestOfEvent(const Particle* particle, const RestOfEvent* roe, const std::string& maskName)
2075  {
2076  if (particle->getParticleSource() == Particle::c_Composite or
2077  particle->getParticleSource() == Particle::c_V0) {
2078  std::vector<const Particle*> fspDaug = particle->getFinalStateDaughters();
2079  for (auto& i : fspDaug) {
2080  if (isInThisRestOfEvent(i, roe, maskName) == 0)
2081  return 0;
2082  }
2083  return 1.0;
2084  }
2085  return roe->hasParticle(particle, maskName);
2086  }
2087 
2088  const RestOfEvent* getRelatedROEObject(const Particle* particle, bool returnHostOnly)
2089  {
2090  // Get related ROE object
2091  const RestOfEvent* roe = particle->getRelatedTo<RestOfEvent>();
2092  if (!roe && !returnHostOnly) {
2093  roe = particle->getRelatedTo<RestOfEvent>("NestedRestOfEvents");
2094 
2095  }
2096  return roe;
2097  }
2098 
2099  VARIABLE_GROUP("Rest Of Event");
2100 
2101  REGISTER_VARIABLE("useROERecoilFrame(variable)", useROERecoilFrame,
2102  "Returns the value of the variable using the rest frame of the ROE recoil as current reference frame.\n"
2103  "Can be used inside for_each loop or outside of it if the particle has associated Rest of Event.\n"
2104  "E.g. ``useROERecoilFrame(E)`` returns the energy of a particle in the ROE recoil frame.");
2105 
2106  REGISTER_VARIABLE("isInRestOfEvent", isInRestOfEvent,
2107  "Returns 1 if a track, ecl or klmCluster associated to particle is in the current RestOfEvent object, 0 otherwise."
2108  "One can use this variable only in a for_each loop over the RestOfEvent StoreArray.");
2109 
2110  REGISTER_VARIABLE("isCloneOfSignalSide", isCloneOfSignalSide,
2111  "Returns 1 if a particle is a clone of signal side final state particles, 0 otherwise. "
2112  "Requires generator information and truth-matching. "
2113  "One can use this variable only in a ``for_each`` loop over the RestOfEvent StoreArray.");
2114 
2115  REGISTER_VARIABLE("hasAncestorFromSignalSide", hasAncestorFromSignalSide,
2116  "Returns 1 if a particle has ancestor from signal side, 0 otherwise. "
2117  "Requires generator information and truth-matching. "
2118  "One can use this variable only in a ``for_each`` loop over the RestOfEvent StoreArray.");
2119 
2120  REGISTER_VARIABLE("currentROEIsInList(particleList)", currentROEIsInList,
2121  "[Eventbased] Returns 1 the associated particle of the current ROE is contained in the given list or its charge-conjugated."
2122  "Useful to restrict the for_each loop over ROEs to ROEs of a certain ParticleList.");
2123 
2124  REGISTER_VARIABLE("nROE_RemainingTracks", nROE_RemainingTracks,
2125  "Returns number of tracks in ROE - number of tracks of given particle"
2126  "One can use this variable only in a for_each loop over the RestOfEvent StoreArray.");
2127 
2128  REGISTER_VARIABLE("nROE_RemainingTracks(maskName)", nROE_RemainingTracksWithMask,
2129  "Returns number of remaining tracks between the ROE (specified via a mask) and the given particle. For the given particle only tracks are counted which are in the RoE."
2130  "One can use this variable only in a for_each loop over the RestOfEvent StoreArray."
2131  "Is required for the specific FEI. :noindex:");
2132  // nROE_RemainingTracks is overloaded (two C++ functions sharing one
2133  // variable name) so one of the two needs to be made the indexed
2134  // variable in sphinx
2135 
2136  REGISTER_VARIABLE("nROE_KLMClusters", nROE_KLMClusters,
2137  "Returns number of all remaining KLM clusters in the related RestOfEvent object.");
2138 
2139  REGISTER_VARIABLE("nROE_Charged(maskName, PDGcode = 0)", nROE_ChargedParticles,
2140  "Returns number of all charged particles in the related RestOfEvent object. First optional argument is ROE mask name. "
2141  "Second argument is a PDG code to count only one charged particle species, independently of charge. "
2142  "For example: ``nROE_Charged(cleanMask, 321)`` will output number of kaons in Rest Of Event with ``cleanMask``. "
2143  "PDG code 0 is used to count all charged particles");
2144 
2145  REGISTER_VARIABLE("nROE_Photons(maskName)", nROE_Photons,
2146  "Returns number of all photons in the related RestOfEvent object, accepts 1 optional argument of ROE mask name. ");
2147 
2148  REGISTER_VARIABLE("nROE_NeutralHadrons(maskName)", nROE_NeutralHadrons,
2149  "Returns number of all neutral hadrons in the related RestOfEvent object, accepts 1 optional argument of ROE mask name. ");
2150 
2151  REGISTER_VARIABLE("particleRelatedToCurrentROE(var)", particleRelatedToCurrentROE,
2152  "[Eventbased] Returns variable applied to the particle which is related to the current RestOfEvent object"
2153  "One can use this variable only in a for_each loop over the RestOfEvent StoreArray.");
2154 
2155  REGISTER_VARIABLE("roeMC_E", ROE_MC_E,
2156  "Returns true energy of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2157 
2158  REGISTER_VARIABLE("roeMC_M", ROE_MC_M,
2159  "Returns true invariant mass of unused tracks and clusters in ROE");
2160 
2161  REGISTER_VARIABLE("roeMC_P", ROE_MC_P,
2162  "Returns true momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2163 
2164  REGISTER_VARIABLE("roeMC_Px", ROE_MC_Px,
2165  "Returns x component of true momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2166 
2167  REGISTER_VARIABLE("roeMC_Py", ROE_MC_Py,
2168  "Returns y component of true momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2169 
2170  REGISTER_VARIABLE("roeMC_Pz", ROE_MC_Pz,
2171  "Returns z component of true momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2172 
2173  REGISTER_VARIABLE("roeMC_Pt", ROE_MC_Pt,
2174  "Returns transverse component of true momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2175 
2176  REGISTER_VARIABLE("roeMC_PTheta", ROE_MC_PTheta,
2177  "Returns polar angle of true momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2178 
2179  REGISTER_VARIABLE("roeMC_MissFlags(maskName)", ROE_MC_MissingFlags,
2180  "Returns flags corresponding to missing particles on ROE side.");
2181 
2182  REGISTER_VARIABLE("nROE_Tracks(maskName)", nROE_Tracks,
2183  "Returns number of tracks in the related RestOfEvent object that pass the selection criteria.");
2184 
2185  REGISTER_VARIABLE("nROE_ECLClusters(maskName)", nROE_ECLClusters,
2186  "Returns number of ECL clusters in the related RestOfEvent object that pass the selection criteria.");
2187 
2188  REGISTER_VARIABLE("nROE_NeutralECLClusters(maskName)", nROE_NeutralECLClusters,
2189  "Returns number of neutral ECL clusters in the related RestOfEvent object that pass the selection criteria.");
2190 
2191  REGISTER_VARIABLE("nROE_ParticlesInList(pListName)", nROE_ParticlesInList,
2192  "Returns the number of particles in ROE from the given particle list.\n"
2193  "Use of variable aliases is advised.");
2194 
2195  REGISTER_VARIABLE("roeCharge(maskName)", ROE_Charge,
2196  "Returns total charge of the related RestOfEvent object.");
2197 
2198  REGISTER_VARIABLE("roeEextra(maskName)", ROE_ExtraEnergy,
2199  "Returns extra energy from ECLClusters in the calorimeter that is not associated to the given Particle");
2200 
2201  REGISTER_VARIABLE("roeNeextra(maskName)", ROE_NeutralExtraEnergy,
2202  "Returns extra energy from neutral ECLClusters in the calorimeter that is not associated to the given Particle, can be used with ``use***Frame()`` function.");
2203 
2204  REGISTER_VARIABLE("roeE(maskName)", ROE_E,
2205  "Returns energy of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2206 
2207  REGISTER_VARIABLE("roeM(maskName)", ROE_M,
2208  "Returns invariant mass of unused tracks and clusters in ROE");
2209 
2210  REGISTER_VARIABLE("roeP(maskName)", ROE_P,
2211  "Returns momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2212 
2213  REGISTER_VARIABLE("roePt(maskName)", ROE_Pt,
2214  "Returns transverse component of momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2215 
2216  REGISTER_VARIABLE("roePx(maskName)", ROE_Px,
2217  "Returns x component of momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2218 
2219  REGISTER_VARIABLE("roePy(maskName)", ROE_Py,
2220  "Returns y component of momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2221 
2222  REGISTER_VARIABLE("roePz(maskName)", ROE_Pz,
2223  "Returns z component of momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2224 
2225  REGISTER_VARIABLE("roePTheta(maskName)", ROE_PTheta,
2226  "Returns theta angle of momentum of unused tracks and clusters in ROE, can be used with ``use***Frame()`` function.");
2227 
2228  REGISTER_VARIABLE("roeDeltae(maskName)", ROE_DeltaE,
2229  "Returns energy difference of the related RestOfEvent object with respect to :math:`E_\\mathrm{cms}/2`.");
2230 
2231  REGISTER_VARIABLE("roeMbc(maskName)", ROE_Mbc,
2232  "Returns beam constrained mass of the related RestOfEvent object with respect to :math:`E_\\mathrm{cms}/2`.");
2233 
2234  REGISTER_VARIABLE("weDeltae(maskName, opt)", WE_DeltaE,
2235  "Returns the energy difference of the B meson, corrected with the missing neutrino momentum (reconstructed side + neutrino) with respect to :math:`E_\\mathrm{cms}/2`.");
2236 
2237  REGISTER_VARIABLE("weMbc(maskName, opt)", WE_Mbc,
2238  "Returns beam constrained mass of B meson, corrected with the missing neutrino momentum (reconstructed side + neutrino) with respect to :math:`E_\\mathrm{cms}/2`.");
2239 
2240  REGISTER_VARIABLE("weMissM2(maskName, opt)", WE_MissM2,
2241  "Returns the invariant mass squared of the missing momentum (see :b2:var:`weMissE` possible options)");
2242 
2243  REGISTER_VARIABLE("recMissM2", REC_MissM2,
2244  "Returns the invariant mass squared of the missing momentum calculated assumings the"
2245  "reco B is at rest and calculating the neutrino (missing) momentum from :math:`p_\\nu = p_B - p_\\mathrm{had} - p_\\mathrm{lep}`");
2246 
2247  REGISTER_VARIABLE("weMissPTheta(maskName, opt)", WE_MissPTheta,
2248  "Returns the polar angle of the missing momentum (see possible :b2:var:`weMissE` options)");
2249 
2250  REGISTER_VARIABLE("weMissP(maskName, opt)", WE_MissP,
2251  "Returns the magnitude of the missing momentum (see possible :b2:var:`weMissE` options)");
2252 
2253  REGISTER_VARIABLE("weMissPx(maskName, opt)", WE_MissPx,
2254  "Returns the x component of the missing momentum (see :b2:var:`weMissE` possible options)");
2255 
2256  REGISTER_VARIABLE("weMissPy(maskName, opt)", WE_MissPy,
2257  "Returns the y component of the missing momentum (see :b2:var:`weMissE` possible options)");
2258 
2259  REGISTER_VARIABLE("weMissPz(maskName, opt)", WE_MissPz,
2260  "Returns the z component of the missing momentum (see :b2:var:`weMissE` possible options)");
2261 
2262  REGISTER_VARIABLE("weMissE(maskName, opt)", WE_MissE,
2263  R"DOC(Returns the energy of the missing momentum, possible options ``opt`` are the following:
2264 
2265 - ``0``: CMS, use energy and momentum of charged particles and photons
2266 - ``1``: CMS, same as ``0``, fix :math:`E_\mathrm{miss} = p_\mathrm{miss}`
2267 - ``2``: CMS, same as ``0``, fix :math:`E_\mathrm{roe} = E_\mathrm{cms}/2`
2268 - ``3``: CMS, use only energy and momentum of signal side
2269 - ``4``: CMS, same as ``3``, update with direction of ROE momentum
2270 - ``5``: LAB, use energy and momentum of charged particles and photons from whole event
2271 - ``6``: LAB, same as ``5``, fix :math:`E_\mathrm{miss} = p_\mathrm{miss}``
2272 - ``7``: CMS, correct pmiss 3-momentum vector with factor alpha so that :math:`d_E = 0`` (used for :math:`M_\mathrm{bc}` calculation).)DOC");
2273 
2274  REGISTER_VARIABLE("weXiZ(maskName)", WE_xiZ,
2275  "Returns Xi_z in event (for Bhabha suppression and two-photon scattering)");
2276 
2277  REGISTER_VARIABLE("bssMassDifference(maskName)", bssMassDifference,
2278  "Bs* - Bs mass difference");
2279 
2280  REGISTER_VARIABLE("weCosThetaEll(maskName)", WE_cosThetaEll, R"DOC(
2281 
2282 Returns the angle between :math:`M` and lepton in :math:`W` rest frame in the decays of the type:
2283 :math:`M \to h_1 ... h_n \ell`, where W 4-momentum is given as
2284 
2285 .. math::
2286  p_W = p_\ell + p_\nu.
2287 
2288 The neutrino momentum is calculated from ROE taking into account the specified mask, and setting
2289 
2290 .. math::
2291  E_{\nu} = |p_{miss}|.
2292 
2293 )DOC");
2294 
2295  REGISTER_VARIABLE("recQ2BhSimple", REC_q2BhSimple,
2296  "Returns the momentum transfer squared, :math:`q^2`, calculated in CMS as :math:`q^2 = (p_B - p_h)^2`, \n"
2297  "where p_h is the CMS momentum of all hadrons in the decay :math:`B \\to H_1 ... H_n \\ell \\nu_\\ell`.\n"
2298  "The B meson momentum in CMS is assumed to be 0.");
2299 
2300  REGISTER_VARIABLE("recQ2Bh", REC_q2Bh,
2301  "Returns the momentum transfer squared, :math:`q^2`, calculated in CMS as :math:`q^2 = (p_B - p_h)^2`, \n"
2302  "where p_h is the CMS momentum of all hadrons in the decay :math:`B \\to H_1\\dots H_n \\ell \\nu_\\ell`.\n"
2303  "This calculation uses a weighted average of the B meson around the reco B cone");
2304 
2305  REGISTER_VARIABLE("weQ2lnuSimple(maskName,option)", WE_q2lnuSimple,
2306  "Returns the momentum transfer squared, :math:`q^2`, calculated in CMS as :math:`q^2 = (p_l + p_\\nu)^2`, \n"
2307  "where :math:`B \\to H_1\\dots H_n \\ell \\nu_\\ell`. Lepton is assumed to be the last reconstructed daughter. \n"
2308  "By default, option is set to ``1`` (see :b2:var:`weMissE`). Unless you know what you are doing, keep this default value.");
2309 
2310  REGISTER_VARIABLE("weQ2lnu(maskName,option)", WE_q2lnu,
2311  "Returns the momentum transfer squared, :math:`q^2`, calculated in CMS as :math:`q^2 = (p_l + p_\\nu)^2`, \n"
2312  "where :math:`B \\to H_1\\dots H_n \\ell \\nu_\\ell`. Lepton is assumed to be the last reconstructed daughter. \n"
2313  "This calculation uses constraints from dE = 0 and Mbc = Mb to correct the neutrino direction. \n"
2314  "By default, option is set to ``7`` (see :b2:var:`weMissE`). Unless you know what you are doing, keep this default value.");
2315 
2316  REGISTER_VARIABLE("weMissM2OverMissE(maskName)", WE_MissM2OverMissE,
2317  "Returns missing mass squared over missing energy");
2318 
2319  REGISTER_VARIABLE("passesROEMask(maskName)", passesROEMask,
2320  "Returns boolean value if track or eclCluster type particle passes a certain mask or not. Only to be used in for_each path");
2321 
2322  REGISTER_VARIABLE("printROE", printROE,
2323  "For debugging, prints indices of all particles in the ROE and all masks. Returns 0.");
2324 
2325  REGISTER_VARIABLE("pi0Prob(mode)", pi0Prob,
2326  "Returns pi0 probability, where mode is used to specify the selection criteria for soft photon. \n"
2327  "The following strings are available. \n\n"
2328  "- ``standard``: loose energy cut and no clusterNHits cut are applied to soft photon \n"
2329  "- ``tight``: tight energy cut and no clusterNHits cut are applied to soft photon \n"
2330  "- ``cluster``: loose energy cut and clusterNHits cut are applied to soft photon \n"
2331  "- ``both``: tight energy cut and clusterNHits cut are applied to soft photon \n\n"
2332  "You can find more details in `writePi0EtaVeto` function in modularAnalysis.py.");
2333 
2334  REGISTER_VARIABLE("etaProb(mode)", etaProb,
2335  "Returns eta probability, where mode is used to specify the selection criteria for soft photon. \n"
2336  "The following strings are available. \n\n"
2337  "- ``standard``: loose energy cut and no clusterNHits cut are applied to soft photon \n"
2338  "- ``tight``: tight energy cut and no clusterNHits cut are applied to soft photon \n"
2339  "- ``cluster``: loose energy cut and clusterNHits cut are applied to soft photon \n"
2340  "- ``both``: tight energy cut and clusterNHits cut are applied to soft photon \n\n"
2341  "You can find more details in `writePi0EtaVeto` function in modularAnalysis.py.");
2342 
2343  }
2345 }
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::RelationsInterface::getRelatedFrom
FROM * getRelatedFrom(const std::string &name="", const std::string &namedRelation="") const
Get the object from which this object has a relation.
Definition: RelationsObject.h:265