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