Belle II Software light-2601-hyperion
ECLVariables.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/ECLVariables.h>
11
12//framework
13#include <framework/logging/Logger.h>
14#include <framework/database/DBObjPtr.h>
15#include <framework/core/Environment.h>
16
17//analysis
18#include <analysis/dataobjects/Particle.h>
19#include <analysis/dataobjects/ParticleList.h>
20#include <analysis/dataobjects/ECLEnergyCloseToTrack.h>
21#include <analysis/utility/ReferenceFrame.h>
22#include <analysis/ClusterUtility/ClusterUtils.h>
23#include <analysis/VariableManager/Utility.h>
24#include <analysis/dbobjects/ECLTimingNormalization.h>
25
26//MDST
27#include <mdst/dataobjects/KlId.h>
28#include <mdst/dataobjects/ECLCluster.h>
29#include <mdst/dataobjects/Track.h>
30#include <mdst/dataobjects/EventLevelClusteringInfo.h>
31
32#include <Math/Vector4D.h>
33#include <TRandom.h>
34#include <cmath>
35#include <stack>
36
37
38
39namespace Belle2 {
44 namespace Variable {
45 double distanceToMcKl(const Particle* particle)
46 {
47 if (particle->hasExtraInfo("mcdistanceKL")) {
48 return particle->getExtraInfo("mcdistanceKL");
49 } else {
50 B2WARNING("The extraInfo mcdistanceKL is not registered! \n"
51 "This variable is only available for ECL based lists, and you have to run the function getNeutralHadronGeomMatches to use it");
52 return Const::doubleNaN;
53 }
54 }
55
56 double distanceToMcNeutron(const Particle* particle)
57 {
58 if (particle->hasExtraInfo("mcdistanceNeutron")) {
59 return particle->getExtraInfo("mcdistanceNeutron");
60 } else {
61 B2WARNING("The extraInfo mcdistanceNeutron is not registered! \n"
62 "This variable is only available for ECL based lists, and you have to run the function getNeutralHadronGeomMatches to use it");
63 return Const::doubleNaN;
64 }
65 }
66
67 int mdstIndexMcKl(const Particle* particle)
68 {
69 if (particle->hasExtraInfo("mdstIndexTruthKL")) {
70 return int(particle->getExtraInfo("mdstIndexTruthKL") + 0.1);
71 } else {
72 B2WARNING("The extraInfo mdstIndexTruthKL is not registered! \n"
73 "This variable is only available for ECL based lists, and you have to run the function getNeutralHadronGeomMatches to use it");
74 return -1;
75 }
76 }
77
78 int mdstIndexMcNeutron(const Particle* particle)
79 {
80 if (particle->hasExtraInfo("mdstIndexTruthNeutron")) {
81 return int(particle->getExtraInfo("mdstIndexTruthNeutron") + 0.1);
82 } else {
83 B2WARNING("The extraInfo mdstIndexTruthNeutron is not registered! \n"
84 "This variable is only available for ECL based lists, and you have to run the function getNeutralHadronGeomMatches to use it");
85 return -1;
86 }
87 }
88
89
90 double beamBackgroundSuppression(const Particle* particle)
91 {
92 if (particle->hasExtraInfo("beamBackgroundSuppression")) {
93 return particle->getExtraInfo("beamBackgroundSuppression");
94 } else {
95 B2WARNING("The extraInfo beamBackgroundSuppression is not registered! \n"
96 "This variable is only available for photons, and you either have to use the standard particle lists (stdPhotons or stdPi0s) or run getBeamBackgroundProbability on a photon list.");
97 return Const::doubleNaN;
98 }
99 }
100
101 double fakePhotonSuppression(const Particle* particle)
102 {
103 if (particle->hasExtraInfo("fakePhotonSuppression")) {
104 return particle->getExtraInfo("fakePhotonSuppression");
105 } else {
106 B2WARNING("The extraInfo fakePhotonSuppression is not registered! \n"
107 "This variable is only available for photons, and you either have to use the standard particle lists (stdPhotons or stdPi0s) or run getFakePhotonProbability on a photon list.");
108 return Const::doubleNaN;
109 }
110 }
111
112 double hadronicSplitOffSuppression(const Particle* particle)
113 {
114 B2WARNING("This variable has been deprecated since light-2302-genetta and is no longer maintained with up to date weights. Please use the variable fakePhotonSuppression instead.");
115 return fakePhotonSuppression(particle);
116 }
117
118 double eclClusterKlId(const Particle* particle)
119 {
120 const ECLCluster* cluster = particle->getECLCluster();
121 if (!cluster) {
122 return Const::doubleNaN;
123 }
124 const KlId* klid = cluster->getRelatedTo<KlId>();
125 if (!klid) {
126 return Const::doubleNaN;
127 }
128 return klid->getKlId();
129 }
130
131
132 double eclPulseShapeDiscriminationMVA(const Particle* particle)
133 {
134 const ECLCluster* cluster = particle->getECLCluster();
135 if (cluster) {
136 if (eclClusterHasPulseShapeDiscrimination(particle)) {
137 return cluster->getPulseShapeDiscriminationMVA();
138 } else {
139 return Const::doubleNaN;
140 }
141 }
142 return Const::doubleNaN;
143 }
144
145 double eclClusterNumberOfHadronDigits(const Particle* particle)
146 {
147
148 const ECLCluster* cluster = particle->getECLCluster();
149 if (cluster) {
150 if (eclClusterHasPulseShapeDiscrimination(particle)) {
151 return cluster->getNumberOfHadronDigits();
152 } else
153 return Const::doubleNaN;
154 }
155 return Const::doubleNaN;
156 }
157
158 double eclClusterDetectionRegion(const Particle* particle)
159 {
160
161 const ECLCluster* cluster = particle->getECLCluster();
162 if (cluster)
163 return cluster->getDetectorRegion();
164
165 return Const::doubleNaN;
166 }
167
168 double eclClusterIsolation(const Particle* particle)
169 {
170
171 const ECLCluster* cluster = particle->getECLCluster();
172 if (cluster) {
173 auto minDist = cluster->getMinTrkDistance();
174 if (minDist > 0)
175 return minDist;
176 }
177 return Const::doubleNaN;
178 }
179
180 double eclClusterIsolationID(const Particle* particle)
181 {
182
183 const ECLCluster* cluster = particle->getECLCluster();
184 if (cluster)
185 return cluster->getMinTrkDistanceID();
186
187 return Const::doubleNaN;
188 }
189
190 Manager::FunctionPtr eclClusterIsolationVar(const std::vector<std::string>& arguments)
191 {
192 if (arguments.size() > 2 or arguments.size() == 0)
193 B2FATAL("Wrong number of arguments (2 required) for meta variable minC2TDistVar");
194 std::string listName = "pi-:all";
195 std::string variableName = arguments[0];
196 if (arguments.size() == 2)
197 listName = arguments[1];
198
199
200 auto func = [listName, variableName](const Particle * particle) -> double {
201 StoreObjPtr<ParticleList> particleList(listName);
202 if (!(particleList.isValid()))
203 {
204 B2FATAL("Invalid Listname " << listName << " given to minC2TDistVar!");
205 }
206 const Variable::Manager::Var* var = Manager::Instance().getVariable(variableName);
207 const ECLCluster* cluster = particle->getECLCluster();
208 if (!cluster)
209 return Const::doubleNaN;
210 auto trackID = cluster->getMinTrkDistanceID();
211 double result = Const::doubleNaN;
212 // Find particle with that track ID:
213 for (unsigned int i = 0; i < particleList->getListSize(); i++)
214 {
215 const Particle* listParticle = particleList->getParticle(i);
216 if (listParticle and listParticle->getTrack() and listParticle->getTrack()->getArrayIndex() == trackID) {
217 result = std::get<double>(var->function(listParticle));
218 break;
219 }
220 }
221 return result;
222 };
223 return func;
224 }
225
226 double eclClusterConnectedRegionID(const Particle* particle)
227 {
228
229 const ECLCluster* cluster = particle->getECLCluster();
230 if (cluster)
231 return cluster->getConnectedRegionId();
232
233 return Const::doubleNaN;
234 }
235
236 double eclClusterDeltaL(const Particle* particle)
237 {
238
239 const ECLCluster* cluster = particle->getECLCluster();
240 if (cluster)
241 return cluster->getDeltaL();
242
243 return Const::doubleNaN;
244 }
245
246 double eclClusterErrorE(const Particle* particle)
247 {
248
249 const ECLCluster* cluster = particle->getECLCluster();
250 if (cluster) {
251 ClusterUtils clutls;
252 const auto EPhiThetaCov = clutls.GetCovarianceMatrix3x3FromCluster(cluster);
253 return sqrt(fabs(EPhiThetaCov[0][0]));
254 }
255 return Const::doubleNaN;
256 }
257
258 double eclClusterUncorrectedE(const Particle* particle)
259 {
260
261 const ECLCluster* cluster = particle->getECLCluster();
262 if (cluster) {
263 return cluster->getEnergyRaw();
264 }
265 return Const::doubleNaN;
266 }
267
268 double eclClusterE(const Particle* particle)
269 {
270 const auto& frame = ReferenceFrame::GetCurrent();
271
272 const ECLCluster* cluster = particle->getECLCluster();
273 if (cluster) {
274 ClusterUtils clutls;
275 ROOT::Math::PxPyPzEVector p4Cluster = clutls.GetCluster4MomentumFromCluster(cluster, particle->getECLClusterEHypothesisBit());
276
277 return frame.getMomentum(p4Cluster).E();
278 }
279 return Const::doubleNaN;
280 }
281
282 double eclClusterHighestE(const Particle* particle)
283 {
284
285 const ECLCluster* cluster = particle->getECLCluster();
286 if (cluster) {
287 return cluster->getEnergyHighestCrystal();
288 }
289 return Const::doubleNaN;
290 }
291
292 double eclClusterCellId(const Particle* particle)
293 {
294
295 const ECLCluster* cluster = particle->getECLCluster();
296 if (cluster) {
297 return cluster->getMaxECellId();
298 }
299 return Const::doubleNaN;
300 }
301
302 // An array with each number representing the last number of the cellID per thetaID. There are 69 thetaIDs in total.
303 const std::array<int, 69> lastCellIDperThetaID{48, 96, 160, 224, 288, 384, 480, 576, 672, 768, 864,
304 1008, 1152, 1296, 1440, 1584, 1728, 1872, 2016, 2160, 2304, 2448,
305 2592, 2736, 2880, 3024, 3168, 3312, 3456, 3600, 3744, 3888, 4032,
306 4176, 4320, 4464, 4608, 4752, 4896, 5040, 5184, 5328, 5472, 5616,
307 5760, 5904, 6048, 6192, 6336, 6480, 6624, 6768, 6912, 7056, 7200,
308 7344, 7488, 7632, 7776, 7920, 8064, 8160, 8256, 8352, 8448, 8544,
309 8608, 8672, 8736};
310
311 double eclClusterThetaId(const Particle* particle)
312 {
313
314 const ECLCluster* cluster = particle->getECLCluster();
315 if (cluster) {
316 int cellID = cluster->getMaxECellId();
317 return std::distance(lastCellIDperThetaID.begin(), std::lower_bound(lastCellIDperThetaID.begin(), lastCellIDperThetaID.end(),
318 cellID));
319 }
320 return Const::doubleNaN;
321 }
322
323 double eclClusterPhiId(const Particle* particle)
324 {
325
326 const ECLCluster* cluster = particle->getECLCluster();
327 if (cluster) {
328 int cellID = cluster->getMaxECellId();
329 if (cellID <= 48) {
330 return cellID - 1;
331 } else {
332 int closestinlist = lastCellIDperThetaID[std::distance(lastCellIDperThetaID.begin(), std::lower_bound(lastCellIDperThetaID.begin(),
333 lastCellIDperThetaID.end(), cellID)) - 1];
334 return cellID - closestinlist - 1;
335 }
336 }
337 return Const::doubleNaN;
338 }
339
340 double eclClusterTiming(const Particle* particle)
341 {
342
343 const ECLCluster* cluster = particle->getECLCluster();
344 if (cluster) {
345 return cluster->getTime();
346 }
347 return Const::doubleNaN;
348 }
349
350 double eclClusterHasFailedTiming(const Particle* particle)
351 {
352 const ECLCluster* cluster = particle->getECLCluster();
353 if (cluster) {
354 return cluster->hasFailedFitTime();
355 }
356 return Const::doubleNaN;
357 }
358
359 double eclClusterErrorTiming(const Particle* particle)
360 {
361
362 const ECLCluster* cluster = particle->getECLCluster();
363 if (cluster) {
364 return cluster->getDeltaTime99();
365 }
366 return Const::doubleNaN;
367 }
368
369 double eclClusterHasFailedErrorTiming(const Particle* particle)
370 {
371 const ECLCluster* cluster = particle->getECLCluster();
372 if (cluster) {
373 return cluster->hasFailedTimeResolution();
374 }
375 return Const::doubleNaN;
376 }
377
378 double eclClusterTheta(const Particle* particle)
379 {
380 const auto& frame = ReferenceFrame::GetCurrent();
381
382 const ECLCluster* cluster = particle->getECLCluster();
383 if (cluster) {
384 ClusterUtils clutls;
385 ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, particle->getECLClusterEHypothesisBit());
386
387 return frame.getMomentum(p4Cluster).Theta();
388 }
389 return Const::doubleNaN;
390 }
391
392 double eclClusterErrorTheta(const Particle* particle)
393 {
394
395 const ECLCluster* cluster = particle->getECLCluster();
396 if (cluster) {
397 ClusterUtils clutls;
398 const auto EPhiThetaCov = clutls.GetCovarianceMatrix3x3FromCluster(cluster);
399 return sqrt(fabs(EPhiThetaCov[2][2]));
400 }
401 return Const::doubleNaN;
402 }
403
404 double eclClusterErrorPhi(const Particle* particle)
405 {
406
407 const ECLCluster* cluster = particle->getECLCluster();
408 if (cluster) {
409 ClusterUtils clutls;
410 const auto EPhiThetaCov = clutls.GetCovarianceMatrix3x3FromCluster(cluster);
411 return sqrt(fabs(EPhiThetaCov[1][1]));
412 }
413 return Const::doubleNaN;
414 }
415
416 double eclClusterPhi(const Particle* particle)
417 {
418 const auto& frame = ReferenceFrame::GetCurrent();
419
420 const ECLCluster* cluster = particle->getECLCluster();
421 if (cluster) {
422 ClusterUtils clutls;
423 ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, particle->getECLClusterEHypothesisBit());
424
425 return frame.getMomentum(p4Cluster).Phi();
426 }
427 return Const::doubleNaN;
428 }
429
430 double eclClusterR(const Particle* particle)
431 {
432
433 const ECLCluster* cluster = particle->getECLCluster();
434 if (cluster) {
435 return cluster->getR();
436 }
437 return Const::doubleNaN;
438 }
439
440 double eclClusterE1E9(const Particle* particle)
441 {
442
443 const ECLCluster* cluster = particle->getECLCluster();
444 if (cluster) {
445 return cluster->getE1oE9();
446 }
447 return Const::doubleNaN;
448 }
449
450 double eclClusterE9E21(const Particle* particle)
451 {
452
453 const ECLCluster* cluster = particle->getECLCluster();
454 if (cluster) {
455 return cluster->getE9oE21();
456 }
457 return Const::doubleNaN;
458 }
459
460 double eclClusterAbsZernikeMoment40(const Particle* particle)
461 {
462
463 const ECLCluster* cluster = particle->getECLCluster();
464 if (cluster) {
465 return cluster->getAbsZernike40();
466 }
467 return Const::doubleNaN;
468 }
469
470 double eclClusterAbsZernikeMoment51(const Particle* particle)
471 {
472
473 const ECLCluster* cluster = particle->getECLCluster();
474 if (cluster) {
475 return cluster->getAbsZernike51();
476 }
477 return Const::doubleNaN;
478 }
479
480 double eclClusterZernikeMVA(const Particle* particle)
481 {
482
483 const ECLCluster* cluster = particle->getECLCluster();
484 if (cluster) {
485 return cluster->getZernikeMVA();
486 }
487 return Const::doubleNaN;
488 }
489
490 double eclClusterSecondMoment(const Particle* particle)
491 {
492
493 const ECLCluster* cluster = particle->getECLCluster();
494 if (cluster) {
495 return cluster->getSecondMoment();
496 }
497 return Const::doubleNaN;
498 }
499
500 double eclClusterLAT(const Particle* particle)
501 {
502
503 const ECLCluster* cluster = particle->getECLCluster();
504 if (cluster) {
505 return cluster->getLAT();
506 }
507 return Const::doubleNaN;
508 }
509
510 double eclClusterNHits(const Particle* particle)
511 {
512
513 const ECLCluster* cluster = particle->getECLCluster();
514 if (cluster) {
515 return cluster->getNumberOfCrystals();
516 }
517 return Const::doubleNaN;
518 }
519
520 double eclClusterTrackMatched(const Particle* particle)
521 {
522
523 const ECLCluster* cluster = particle->getECLCluster();
524 if (cluster) {
525 const Track* track = cluster->getRelatedFrom<Track>();
526
527 if (track)
528 return 1.0;
529 else
530 return 0.0;
531 }
532 return Const::doubleNaN;
533 }
534
535 double nECLClusterTrackMatches(const Particle* particle)
536 {
537 // if no ECL cluster then nan
538 const ECLCluster* cluster = particle->getECLCluster();
539 if (!cluster)
540 return Const::doubleNaN;
541
542 // one or more tracks may be matched to charged particles
543 size_t out = cluster->getRelationsFrom<Track>().size();
544 return double(out);
545 }
546
547 double eclClusterId(const Particle* particle)
548 {
549 const ECLCluster* cluster = particle->getECLCluster();
550 if (cluster) {
551 return cluster->getClusterId();
552 }
553 return Const::doubleNaN;
554 }
555
556 double eclClusterHasNPhotonsHypothesis(const Particle* particle)
557 {
558 const ECLCluster* cluster = particle->getECLCluster();
559 if (cluster) {
560 return cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
561 }
562 return Const::doubleNaN;
563 }
564
565 double eclClusterHasNeutralHadronHypothesis(const Particle* particle)
566 {
567 const ECLCluster* cluster = particle->getECLCluster();
568 if (cluster) {
569 return cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron);
570 }
571 return Const::doubleNaN;
572 }
573
574 double eclClusterHasPulseShapeDiscrimination(const Particle* particle)
575 {
576 const ECLCluster* cluster = particle->getECLCluster();
577 if (cluster) {
578 return cluster->hasPulseShapeDiscrimination();
579 }
580 return Const::doubleNaN;
581 }
582
583 double eclExtTheta(const Particle* particle)
584 {
585
586 const Track* track = particle->getTrack();
587 if (track) {
588
589 auto* eclinfo = track->getRelatedTo<ECLEnergyCloseToTrack>();
590
591 if (eclinfo) {
592 return eclinfo->getExtTheta();
593 } else {
594 B2WARNING("Relation to ECLEnergyCloseToTrack not found, did you forget to run ECLTrackCalDigitMatchModule?");
595 return Const::doubleNaN;
596 }
597 }
598
599 return Const::doubleNaN;
600 }
601
602 double eclExtPhi(const Particle* particle)
603 {
604
605 const Track* track = particle->getTrack();
606 if (track) {
607
608 auto* eclinfo = track->getRelatedTo<ECLEnergyCloseToTrack>();
609
610 if (eclinfo) {
611 return eclinfo->getExtPhi();
612 } else {
613 B2WARNING("Relation to ECLEnergyCloseToTrack not found, did you forget to run ECLTrackCalDigitMatchModule?");
614 return Const::doubleNaN;
615 }
616 }
617
618 return Const::doubleNaN;
619 }
620
621 double eclExtPhiId(const Particle* particle)
622 {
623 const Track* track = particle->getTrack();
624 if (track) {
625
626 auto* eclinfo = track->getRelatedTo<ECLEnergyCloseToTrack>();
627
628 if (eclinfo) {
629 return eclinfo->getExtPhiId();
630 } else {
631 B2WARNING("Relation to ECLEnergyCloseToTrack not found, did you forget to run ECLTrackCalDigitMatchModule?");
632 return Const::doubleNaN;
633 }
634 }
635
636 return Const::doubleNaN;
637 }
638
639 double weightedAverageECLTime(const Particle* particle)
640 {
641 int nDaughters = particle->getNDaughters();
642 if (nDaughters < 1) {
643 B2WARNING("The provided particle has no daughters!");
644 return Const::doubleNaN;
645 }
646
647 double numer = 0, denom = 0;
648 int numberOfClusterDaughters = 0;
649
650 auto weightedECLTimeAverage = [&numer, &denom, &numberOfClusterDaughters](const Particle * p) {
651 const ECLCluster* cluster = p->getECLCluster();
652 if (cluster and not cluster->hasFailedFitTime()) {
653 numberOfClusterDaughters ++;
654
655 double time = cluster->getTime();
656 B2DEBUG(10, "time[" << numberOfClusterDaughters << "] = " << time);
657 double deltatime = cluster->getDeltaTime99();
658 B2DEBUG(10, "deltatime[" << numberOfClusterDaughters << "] = " << deltatime);
659 numer += time / pow(deltatime, 2);
660 B2DEBUG(11, "numer[" << numberOfClusterDaughters << "] = " << numer);
661 denom += 1 / pow(deltatime, 2);
662 B2DEBUG(11, "denom[" << numberOfClusterDaughters << "] = " << denom);
663 }
664 return false;
665 };
666
667 particle->forEachDaughter(weightedECLTimeAverage, true, true);
668
669 if (numberOfClusterDaughters < 1) {
670 B2WARNING("There are no clusters or cluster matches amongst the daughters of the provided particle!");
671 return Const::doubleNaN;
672 }
673
674 if (denom == 0) {
675 B2WARNING("The denominator of the weighted mean is zero!");
676 return Const::doubleNaN;
677 } else {
678 B2DEBUG(10, "numer/denom = " << numer / denom);
679 return numer / denom;
680 }
681 }
682
683 double maxWeightedDistanceFromAverageECLTime(const Particle* particle)
684 {
685 int nDaughters = particle->getNDaughters();
686 if (nDaughters < 1) {
687 B2WARNING("The provided particle has no daughters!");
688 return Const::doubleNaN;
689 }
690
691 double maxTimeDiff = -DBL_MAX;
692 int numberOfClusterDaughters = 0;
693
694 double averageECLTime = weightedAverageECLTime(particle);
695
696 auto maxTimeDifference = [&maxTimeDiff, &numberOfClusterDaughters, &averageECLTime](const Particle * p) {
697
698 const ECLCluster* cluster = p->getECLCluster();
699 if (cluster) {
700 numberOfClusterDaughters ++;
701
702 double time = cluster->getTime();
703 B2DEBUG(10, "time[" << numberOfClusterDaughters << "] = " << time);
704 double deltatime = cluster->getDeltaTime99();
705 B2DEBUG(10, "deltatime[" << numberOfClusterDaughters << "] = " << deltatime);
706 double maxTimeDiff_temp = fabs((time - averageECLTime) / deltatime);
707 B2DEBUG(11, "maxTimeDiff_temp[" << numberOfClusterDaughters << "] = " << maxTimeDiff_temp);
708 if (maxTimeDiff_temp > maxTimeDiff)
709 maxTimeDiff = maxTimeDiff_temp;
710 B2DEBUG(11, "maxTimeDiff[" << numberOfClusterDaughters << "] = " << maxTimeDiff);
711 }
712 return false;
713 };
714
715 particle->forEachDaughter(maxTimeDifference, true, true);
716
717 if (numberOfClusterDaughters < 1) {
718 B2WARNING("There are no clusters or cluster matches amongst the daughters of the provided particle!");
719 return Const::doubleNaN;
720 }
721
722 if (maxTimeDiff < 0) {
723 B2WARNING("The max time difference is negative!");
724 return Const::doubleNaN;
725 } else {
726 B2DEBUG(10, "maxTimeDiff = " << maxTimeDiff);
727 return maxTimeDiff;
728 }
729 }
730
731 double eclClusterMdstIndex(const Particle* particle)
732 {
733 const ECLCluster* cluster = particle->getECLCluster();
734 if (cluster) {
735 return cluster->getArrayIndex();
736 } else return Const::doubleNaN;
737
738 return Const::doubleNaN;
739 }
740
741 double eclClusterTimeNorm90(const Particle* particle)
742 {
743
744 const ECLCluster* cluster = particle->getECLCluster();
745 StoreObjPtr<EventLevelClusteringInfo> elci;
746
747 //..Get the appropriate (data or MC) payload
748 std::string payloadName = "ECLTimingNormalization_data";
749 if (Environment::Instance().isMC()) {payloadName = "ECLTimingNormalization_MC";}
750 static DBObjPtr<ECLTimingNormalization> ECLTimingNormalization(payloadName);
751 if (!ECLTimingNormalization.isValid()) {
752 B2FATAL(payloadName << " payload is not available");
753 }
754
755 if (elci and cluster) {
756
757 //..Only valid for crystals in CDC acceptance
758 unsigned short cellID = cluster->getMaxECellId(); // [1, 8736]
759 const unsigned short firstCellID = 161; // first cellID in CDC acceptance
760 const unsigned short lastCellID = 8608; // last cellID in CDC acceptance
761 if (cellID < firstCellID or cellID > lastCellID) {return Const::doubleNaN;}
762 int iCrys = cellID - 1; // [0, 8735]
763
764 //..clusterTiming. Dither to remove artifacts from compression
765 double rawTime = cluster->getTime();
766 const double timingBit = 2000. / 4096.;
767 double tSmear = timingBit * (gRandom->Uniform() - 0.5);
768 double time = rawTime + tSmear;
769
770 //..Uncorrected single crystal energy
771 double clusterECorrected = cluster->getEnergy(ECLCluster::EHypothesisBit::c_nPhotons);
772 double clusterERaw = cluster->getEnergyRaw();
773 double singleECorrected = cluster->getEnergyHighestCrystal();
774 double singleCrystalE = singleECorrected * clusterERaw / clusterECorrected;
775 double basicEScale = 0.1 / singleCrystalE;
776
777 //..Background level for the region for this cellID
778 const int firstBarrel = 1153; // first cellID in barrel
779 const int lastBarrel = 7776; // last cellID in barrel
780 double ootCrys = elci->getNECLCalDigitsOutOfTimeBarrel();
781 if (cellID < firstBarrel) {ootCrys = elci->getNECLCalDigitsOutOfTimeFWD();}
782 if (cellID > lastBarrel) {ootCrys = elci->getNECLCalDigitsOutOfTimeBWD();}
783
784 //..Time walk correction (7 parameters)
785 // E0 / bias at E0 / lowE slope / highE slope / curvature / Emin / Emax
786 std::array< std::array<float, 7>, 8736> par7 = ECLTimingNormalization->getTimeWalkPar();
787
788 float EForCor = singleCrystalE;
789 if (EForCor < par7[iCrys][5]) {EForCor = par7[iCrys][5];}
790 if (EForCor > par7[iCrys][6]) {EForCor = par7[iCrys][6];}
791 float dE = EForCor - par7[iCrys][0];
792 double timeWalkCor = par7[iCrys][1] + par7[iCrys][2] * dE;
793 if (dE > 0) {
794 timeWalkCor = par7[iCrys][1] + par7[iCrys][3] * dE + par7[iCrys][4] * dE * dE;
795 }
796
797 //..Dependence on regional background level (5 parameters)
798 // intercept / slope / p2 / min ootCrys / max ootCrys
799 std::array< std::array<float, 5>, 8736> bPar = ECLTimingNormalization->getBackgroundPar();
800
801 float oot = ootCrys;
802 if (oot < bPar[iCrys][3]) {oot = bPar[iCrys][3];}
803 if (oot > bPar[iCrys][4]) {oot = bPar[iCrys][4];}
804 double backgroundNorm = bPar[iCrys][0] + bPar[iCrys][1] * oot + bPar[iCrys][2] * oot * oot;
805
806 //..Dependence on single crystal energy (7 parameters)
807 // E0 / res at E0 / lowE slope / highE slope / curvature / Emin / Emax
808 par7 = ECLTimingNormalization->getEnergyPar();
809
810 EForCor = singleCrystalE;
811 if (EForCor < par7[iCrys][5]) {EForCor = par7[iCrys][5];}
812 if (EForCor > par7[iCrys][6]) {EForCor = par7[iCrys][6];}
813 dE = EForCor - par7[iCrys][0];
814 double energyNorm = par7[iCrys][1] + par7[iCrys][2] * dE;
815 if (dE > 0) {
816 energyNorm = par7[iCrys][1] + par7[iCrys][3] * dE + par7[iCrys][4] * dE * dE;
817 }
818
819 //..Overall normalization. Cannot be too small.
820 double minTNorm = (double)ECLTimingNormalization->getMinTNormalization();
821 double tNormalization = basicEScale * backgroundNorm * energyNorm;
822 if (tNormalization < minTNorm) {tNormalization = minTNorm;}
823 double tNorm90 = (time - timeWalkCor) / tNormalization;
824 return tNorm90;
825
826 } else {
827 return Const::doubleNaN;
828
829 }
830 }
831
832
833 /*************************************************************
834 * Event-based ECL clustering information
835 */
836 double nECLOutOfTimeCrystalsFWDEndcap(const Particle*)
837 {
838 StoreObjPtr<EventLevelClusteringInfo> elci;
839 if (!elci) return Const::doubleNaN;
840 return (double)elci->getNECLCalDigitsOutOfTimeFWD();
841 }
842
843 double nECLOutOfTimeCrystalsBarrel(const Particle*)
844 {
845 StoreObjPtr<EventLevelClusteringInfo> elci;
846 if (!elci) return Const::doubleNaN;
847 return (double)elci->getNECLCalDigitsOutOfTimeBarrel();
848 }
849
850 double nECLOutOfTimeCrystalsBWDEndcap(const Particle*)
851 {
852 StoreObjPtr<EventLevelClusteringInfo> elci;
853 if (!elci) return Const::doubleNaN;
854 return (double)elci->getNECLCalDigitsOutOfTimeBWD();
855 }
856
857 double nECLOutOfTimeCrystals(const Particle*)
858 {
859 StoreObjPtr<EventLevelClusteringInfo> elci;
860 if (!elci) return Const::doubleNaN;
861 return (double)elci->getNECLCalDigitsOutOfTime();
862 }
863
864 double nRejectedECLShowersFWDEndcap(const Particle*)
865 {
866 StoreObjPtr<EventLevelClusteringInfo> elci;
867 if (!elci) return Const::doubleNaN;
868 return (double)elci->getNECLShowersRejectedFWD();
869 }
870
871 double nRejectedECLShowersBarrel(const Particle*)
872 {
873 StoreObjPtr<EventLevelClusteringInfo> elci;
874 if (!elci) return Const::doubleNaN;
875 return (double)elci->getNECLShowersRejectedBarrel();
876 }
877
878 double nRejectedECLShowersBWDEndcap(const Particle*)
879 {
880 StoreObjPtr<EventLevelClusteringInfo> elci;
881 if (!elci) return Const::doubleNaN;
882 return (double)elci->getNECLShowersRejectedBWD();
883 }
884
885 double nRejectedECLShowers(const Particle*)
886 {
887 StoreObjPtr<EventLevelClusteringInfo> elci;
888 if (!elci) return Const::doubleNaN;
889 return (double) elci->getNECLShowersRejected();
890 }
891
892 double nKLMMultistripHitsFWDEndcap(const Particle*)
893 {
894 StoreObjPtr<EventLevelClusteringInfo> elci;
895 if (!elci) return Const::doubleNaN;
896 return (double) elci->getNKLMDigitsMultiStripFWD();
897 }
898
899 double nKLMMultistripHitsBarrel(const Particle*)
900 {
901 StoreObjPtr<EventLevelClusteringInfo> elci;
902 if (!elci) return Const::doubleNaN;
903 return (double) elci->getNKLMDigitsMultiStripBarrel();
904 }
905
906 double nKLMMultistripHitsBWDEndcap(const Particle*)
907 {
908 StoreObjPtr<EventLevelClusteringInfo> elci;
909 if (!elci) return Const::doubleNaN;
910 return (double) elci->getNKLMDigitsMultiStripBWD();
911 }
912
913 double nKLMMultistripHits(const Particle*)
914 {
915 StoreObjPtr<EventLevelClusteringInfo> elci;
916 if (!elci) return Const::doubleNaN;
917 return (double) elci->getNKLMDigitsMultiStrip();
918 }
919
920 double nECLShowersFWDEndcap(const Particle*)
921 {
922 StoreObjPtr<EventLevelClusteringInfo> elci;
923 if (!elci) return Const::doubleNaN;
924 return (double) elci->getNECLShowersFWD();
925 }
926
927 double nECLShowersBarrel(const Particle*)
928 {
929 StoreObjPtr<EventLevelClusteringInfo> elci;
930 if (!elci) return Const::doubleNaN;
931 return (double) elci->getNECLShowersBarrel();
932 }
933
934 double nECLShowersBWDEndcap(const Particle*)
935 {
936 StoreObjPtr<EventLevelClusteringInfo> elci;
937 if (!elci) return Const::doubleNaN;
938 return (double) elci->getNECLShowersBWD();
939 }
940
941 double nECLShowers(const Particle*)
942 {
943 StoreObjPtr<EventLevelClusteringInfo> elci;
944 if (!elci) return Const::doubleNaN;
945 return (double) elci->getNECLShowers();
946 }
947
948 double nECLLocalMaximumsFWDEndcap(const Particle*)
949 {
950 StoreObjPtr<EventLevelClusteringInfo> elci;
951 if (!elci) return Const::doubleNaN;
952 return (double) elci->getNECLLocalMaximumsFWD();
953 }
954
955 double nECLLocalMaximumsBarrel(const Particle*)
956 {
957 StoreObjPtr<EventLevelClusteringInfo> elci;
958 if (!elci) return Const::doubleNaN;
959 return (double) elci->getNECLLocalMaximumsBarrel();
960 }
961
962 double nECLLocalMaximumsBWDEndcap(const Particle*)
963 {
964 StoreObjPtr<EventLevelClusteringInfo> elci;
965 if (!elci) return Const::doubleNaN;
966 return (double) elci->getNECLLocalMaximumsBWD();
967 }
968
969 double nECLLocalMaximums(const Particle*)
970 {
971 StoreObjPtr<EventLevelClusteringInfo> elci;
972 if (!elci) return Const::doubleNaN;
973 return (double) elci->getNECLLocalMaximums();
974 }
975
976 double nECLTriggerCellsFWDEndcap(const Particle*)
977 {
978 StoreObjPtr<EventLevelClusteringInfo> elci;
979 if (!elci) return Const::doubleNaN;
980 return (double) elci->getNECLTriggerCellsFWD();
981 }
982
983 double nECLTriggerCellsBarrel(const Particle*)
984 {
985 StoreObjPtr<EventLevelClusteringInfo> elci;
986 if (!elci) return Const::doubleNaN;
987 return (double) elci->getNECLTriggerCellsBarrel();
988 }
989
990 double nECLTriggerCellsBWDEndcap(const Particle*)
991 {
992 StoreObjPtr<EventLevelClusteringInfo> elci;
993 if (!elci) return Const::doubleNaN;
994 return (double) elci->getNECLTriggerCellsBWD();
995 }
996
997 double nECLTriggerCells(const Particle*)
998 {
999 StoreObjPtr<EventLevelClusteringInfo> elci;
1000 if (!elci) return Const::doubleNaN;
1001 return (double) elci->getNECLTriggerCells();
1002 }
1003
1004 double eclClusterEoP(const Particle* part)
1005 {
1006 double E = eclClusterE(part);
1007 if (part->hasExtraInfo("bremsCorrectedPhotonEnergy")) {
1008 E += part->getExtraInfo("bremsCorrectedPhotonEnergy");
1009 }
1010 const double p = part->getMomentumMagnitude();
1011 if (0 == p) { return Const::doubleNaN;}
1012 return E / p;
1013 }
1014
1015 double eclClusterOnlyInvariantMass(const Particle* part)
1016 {
1017 int nDaughters = part->getNDaughters();
1018 ROOT::Math::PxPyPzEVector sum;
1019
1020 if (nDaughters < 1) {
1021 return part->getMass();
1022 } else {
1023 int nClusterDaughters = 0;
1024 std::stack<const Particle*> stacked;
1025 stacked.push(part);
1026 while (!stacked.empty()) {
1027 const Particle* current = stacked.top();
1028 stacked.pop();
1029
1030 const ECLCluster* cluster = current->getECLCluster();
1031 if (cluster) {
1032 const ECLCluster::EHypothesisBit clusterBit = current->getECLClusterEHypothesisBit();
1033 nClusterDaughters ++;
1034 ClusterUtils clutls;
1035 ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, clusterBit);
1036 sum += p4Cluster;
1037 } else {
1038 const std::vector<Particle*> daughters = current->getDaughters();
1039 nDaughters = current->getNDaughters();
1040 for (int iDaughter = 0; iDaughter < nDaughters; iDaughter++) {
1041 stacked.push(daughters[iDaughter]);
1042 }
1043 }
1044 }
1045
1046 if (nClusterDaughters < 1) {
1047 B2WARNING("There are no clusters amongst the daughters of the provided particle!");
1048 return Const::doubleNaN;
1049 }
1050 B2DEBUG(10, "Number of daughters with cluster associated = " << nClusterDaughters);
1051 return sum.M();
1052 }
1053 }
1054
1055 Manager::FunctionPtr photonHasOverlap(const std::vector<std::string>& arguments)
1056 {
1057 std::string cutString = "";
1058 if (arguments.size() > 0) {
1059 cutString = arguments[0];
1060 }
1061 std::shared_ptr<Variable::Cut> cut = std::shared_ptr<Variable::Cut>(Variable::Cut::compile(cutString));
1062
1063 std::string photonlistname = "gamma:all";
1064 if (arguments.size() > 1) {
1065 photonlistname = arguments[1];
1066 }
1067
1068 std::string tracklistname = "e-:all";
1069 if (arguments.size() > 2) {
1070 tracklistname = arguments[2];
1071 }
1072
1073 auto func = [cut, photonlistname, tracklistname](const Particle * particle) -> double {
1074
1075 if (particle->getPDGCode() != Const::photon.getPDGCode())
1076 {
1077 B2WARNING("The variable photonHasOverlap is supposed to be calculated for photons. Returning NaN.");
1078 return Const::doubleNaN;
1079 }
1080
1081 StoreObjPtr<ParticleList> photonlist(photonlistname);
1082 if (!(photonlist.isValid()))
1083 {
1084 B2WARNING("The provided particle list " << photonlistname << " does not exist."
1085 " Therefore, the variable photonHasOverlap can not be calculated. Returning NaN.");
1086 return Const::doubleNaN;
1087 }
1088 if (photonlist->getPDGCode() != Const::photon.getPDGCode())
1089 {
1090 B2WARNING("The list " << photonlistname << " does not contain photons."
1091 " Therefore, the variable photonHasOverlap can not be calculated reliably. Returning NaN.");
1092 return Const::doubleNaN;
1093 }
1094
1095 StoreObjPtr<ParticleList> tracklist(tracklistname);
1096 if (!(tracklist.isValid()))
1097 {
1098 B2WARNING("The provided particle list " << tracklistname << " does not exist."
1099 " Therefore, the variable photonHasOverlap can not be calculated. Returning NaN.");
1100 return Const::doubleNaN;
1101 }
1102 if (!Const::chargedStableSet.contains(Const::ParticleType(abs(tracklist->getPDGCode()))))
1103 {
1104 B2WARNING("The list " << tracklistname << " does not contain charged final state particles."
1105 " Therefore, the variable photonHasOverlap can not be calculated reliably. Returning NaN.");
1106 return Const::doubleNaN;
1107 }
1108
1109 double connectedRegionID = eclClusterConnectedRegionID(particle);
1110 int mdstSource = particle->getMdstSource();
1111
1112 for (unsigned int i = 0; i < photonlist->getListSize(); i++)
1113 {
1114 const Particle* part = photonlist->getParticle(i);
1115
1116 // skip the particle itself
1117 if (part->getMdstSource() == mdstSource) {
1118 continue;
1119 }
1120
1121 // skip photons that do not fulfill the provided criteria
1122 if (!cut->check(part)) {
1123 continue;
1124 }
1125
1126 if (connectedRegionID == eclClusterConnectedRegionID(part)) {
1127 return 1;
1128 }
1129 }
1130
1131 for (unsigned int i = 0; i < tracklist->getListSize(); i++)
1132 {
1133 const Particle* part = tracklist->getParticle(i);
1134
1135 // skip tracks that do not fulfill the provided criteria
1136 if (!cut->check(part)) {
1137 continue;
1138 }
1139
1140 if (connectedRegionID == eclClusterConnectedRegionID(part)) {
1141 return 1;
1142 }
1143 }
1144
1145 return 0;
1146 };
1147 return func;
1148 }
1149
1150 VARIABLE_GROUP("ECL Cluster related");
1151 REGISTER_VARIABLE("clusterEoP", eclClusterEoP, R"DOC(
1152Returns ratio of uncorrelated energy E over momentum p, a convenience
1153alias for (clusterE / p).
1154)DOC");
1155 REGISTER_VARIABLE("clusterReg", eclClusterDetectionRegion, R"DOC(
1156Returns an integer code for the ECL region of a cluster.
1157
1158- 1: forward, 2: barrel, 3: backward,
1159- 11: between FWD and barrel, 13: between BWD and barrel,
1160- 0: otherwise
1161)DOC");
1162 REGISTER_VARIABLE("clusterDeltaLTemp", eclClusterDeltaL, R"DOC(
1163| Returns DeltaL for the shower shape.
1164| A cluster comprises the energy depositions of several crystals. All these crystals have slightly
1165 different orientations in space. A shower direction can be constructed by calculating the weighted
1166 average of these orientations using the corresponding energy depositions as weights. The intersection
1167 (more precisely the point of closest approach) of the vector with this direction originating from the
1168 cluster center and an extrapolated track can be used as reference for the calculation of the shower
1169 depth. It is defined as the distance between this intersection and the cluster center.
1170
1171.. warning::
1172 This distance is calculated on the reconstructed level and is temporarily
1173 included to the ECL cluster MDST data format for studying purposes. If it is found
1174 that it is not crucial for physics analysis then this variable will be removed
1175 in future releases.
1176 Therefore, keep in mind that this variable might be removed in the future!
1177
1178.. note::
1179 | Please read `this <importantNoteECL>` first.
1180 | Lower limit: :math:`-250.0`
1181 | Upper limit: :math:`250.0`
1182 | Precision: :math:`10` bit
1183..
1184
1185)DOC","cm");
1186
1187 REGISTER_VARIABLE("minC2TDist", eclClusterIsolation, R"DOC(
1188Returns the distance between the ECL cluster and its nearest track.
1189
1190For all tracks in the event, the distance between each of their extrapolated hits in the ECL and the ECL shower
1191position is calculated, and the overall smallest distance is returned. The track array index of the track that is
1192closest to the ECL cluster can be retrieved using `minC2TDistID`.
1193
1194If the calculated distance is greater than :math:`250.0`, the returned distance will be capped at :math:`250.0`.
1195If there are no extrapolated hits found in the ECL for the event, NaN will be returned.
1196
1197.. note::
1198 This distance is calculated on the reconstructed level.
1199
1200.. note::
1201 | Please read `this <importantNoteECL>` first.
1202 | Lower limit: :math:`0.0`
1203 | Upper limit: :math:`250.0`
1204 | Precision: :math:`10` bit
1205..
1206
1207)DOC","cm");
1208 REGISTER_VARIABLE("minC2TDistID", eclClusterIsolationID, R"DOC(
1209Returns the track array index of the nearest track to the ECL cluster. The nearest track is calculated
1210using the `minC2TDist` variable.
1211)DOC");
1212 REGISTER_METAVARIABLE("minC2TDistVar(variable,particleList=pi-:all)", eclClusterIsolationVar, R"DOC(
1213Returns the variable value of the nearest track to the given ECL cluster as calculated by `minC2TDist`. The
1214first argument is the variable name, e.g. `nCDCHits`, while the second (optional) argument is the particle list name which
1215will be used to pick up the nearest track in the calculation of `minC2TDist`. The default particle list used
1216is ``pi-:all``.
1217)DOC", Manager::VariableDataType::c_double);
1218 REGISTER_VARIABLE("clusterE", eclClusterE, R"DOC(
1219Returns ECL cluster's energy corrected for leakage and background.
1220
1221The raw photon energy is given by the weighted sum of all ECL crystal energies within the ECL cluster.
1222The weights per crystals are :math:`\leq 1` after cluster energy splitting in the case of overlapping
1223clusters. The number of crystals that are included in the sum depends on a initial energy estimation
1224and local beam background levels at the highest energy crystal position. It is optimized to minimize
1225the core width (resolution) of true photons. Photon energy distributions always show a low energy tail
1226due to unavoidable longitudinal and transverse leakage that can be further modified by the clustering
1227algorithm and beam backgrounds.The peak position of the photon energy distributions are corrected to
1228match the true photon energy in MC:
1229
1230- Leakage correction: Using large MC samples of mono-energetic single photons, a correction factor
1231 :math:`f` as function of reconstructed detector position, reconstructed photon energy and beam backgrounds
1232 is determined via :math:`f = \frac{\text{peak_reconstructed}}{\text{energy_true}}`.
1233
1234- Cluster energy calibration (data only): To reach the target precision of :math:`< 1.8\%` energy
1235 resolution for high energetic photons, the remaining difference between MC and data must be calibrated
1236 using kinematically fit muon pairs. This calibration is only applied to data and not to MC and will
1237 take time to develop.
1238
1239- Energy Bias Correction module, sub-percent correction, is NOT applied on clusterE, but on photon energy
1240 and momentum. Only applied to data.
1241
1242It is important to note that after perfect leakage correction and cluster energy calibration,
1243the :math:`\pi^{0}` mass peak will be shifted slightly to smaller values than the PDG average
1244due to the low energy tails of photons. The :math:`\pi^{0}` mass peak must not be corrected
1245to the PDG value by adjusting the reconstructed photon energies. Selection criteria based on
1246the mass for :math:`\pi^{0}` candidates must be based on the biased value. Most analysis
1247will used mass constrained :math:`\pi^{0}` s anyhow.
1248
1249.. warning::
1250 We only store clusters with :math:`E > 20\,` MeV.
1251
1252.. note::
1253 | Please read `this <importantNoteECL>` first.
1254 | Lower limit: :math:`-5` (:math:`e^{-5} = 0.00674\,` GeV)
1255 | Upper limit: :math:`3.0` (:math:`e^3 = 20.08553\,` GeV)
1256 | Precision: :math:`18` bit
1257 | This value can be changed to a different reference frame with :b2:var:`useCMSFrame`.
1258..
1259
1260)DOC","GeV");
1261 REGISTER_VARIABLE("clusterErrorE", eclClusterErrorE, R"DOC(
1262Returns ECL cluster's uncertainty on energy
1263(from background level and energy dependent tabulation).
1264
1265)DOC","GeV");
1266 REGISTER_VARIABLE("clusterErrorPhi", eclClusterErrorPhi, R"DOC(
1267Returns ECL cluster's uncertainty on :math:`\phi`
1268(from background level and energy dependent tabulation).
1269
1270)DOC","rad");
1271 REGISTER_VARIABLE("clusterErrorTheta", eclClusterErrorTheta, R"DOC(
1272Returns ECL cluster's uncertainty on :math:`\theta`
1273(from background level and energy dependent tabulation).
1274
1275)DOC","rad");
1276
1277 REGISTER_VARIABLE("clusterR", eclClusterR, R"DOC(
1278Returns ECL cluster's centroid distance from :math:`(0,0,0)`.
1279
1280)DOC","cm");
1281 REGISTER_VARIABLE("clusterPhi", eclClusterPhi, R"DOC(
1282Returns ECL cluster's azimuthal angle :math:`\phi`
1283(this is not generally equal to a photon azimuthal angle).
1284
1285| The direction of a cluster is given by the connecting line of :math:`\,(0,0,0)\,` and
1286 cluster centroid position in the ECL.
1287| The cluster centroid position is calculated using up to 21 crystals (5x5 excluding corners)
1288 after cluster energy splitting in the case of overlapping clusters.
1289| The centroid position is the logarithmically weighted average of all crystals evaluated at
1290 the crystal centers. Cluster centroids are generally biased towards the centers of the
1291 highest energetic crystal. This effect is larger for low energetic photons.
1292| Beam backgrounds slightly decrease the position resolution, mainly for low energetic photons.
1293
1294.. note::
1295 Radius of a cluster is almost constant in the barrel and should not be used directly in any selection.
1296
1297Unlike for charged tracks, the uncertainty (covariance) of the photon directions is not determined
1298based on individual cluster properties but taken from on MC-based parametrizations of the resolution
1299as function of true photon energy, true photon direction and beam background level.
1300
1301.. warning::
1302 Users must use the actual particle direction (done automatically in the modularAnalysis using the average
1303 IP position (can be changed if needed)) and not the ECL Cluster direction (position in the ECL measured
1304 from :math:`(0,0,0)`) for particle kinematics.
1305
1306.. note::
1307 | Please read `this <importantNoteECL>` first.
1308 | Lower limit: :math:`-\pi`
1309 | Upper limit: :math:`\pi`
1310 | Precision: :math:`16` bit
1311..
1312
1313)DOC","rad");
1314 REGISTER_VARIABLE("clusterConnectedRegionID", eclClusterConnectedRegionID, R"DOC(
1315Returns ECL cluster's connected region ID.
1316)DOC");
1317 REGISTER_VARIABLE("clusterTheta", eclClusterTheta, R"DOC(
1318Returns ECL cluster's polar angle :math:`\theta`
1319(this is not generally equal to a photon polar angle).
1320
1321| The direction of a cluster is given by the connecting line of :math:`\,(0,0,0)\,` and
1322 cluster centroid position in the ECL.
1323| The cluster centroid position is calculated using up to 21 crystals (5x5 excluding corners)
1324 after cluster energy splitting in the case of overlapping clusters.
1325| The centroid position is the logarithmically weighted average of all crystals evaluated at
1326 the crystal centers. Cluster centroids are generally biased towards the centers of the
1327 highest energetic crystal. This effect is larger for low energetic photons.
1328| Beam backgrounds slightly decrease the position resolution, mainly for low energetic photons.
1329
1330.. note::
1331 Radius of a cluster is almost constant in the barrel and should not be used directly in any selection.
1332
1333Unlike for charged tracks, the uncertainty (covariance) of the photon directions is not determined
1334based on individual cluster properties but taken from on MC-based parametrizations of the resolution
1335as function of true photon energy, true photon direction and beam background level.
1336
1337.. warning::
1338 Users must use the actual particle direction (done automatically in the modularAnalysis using the average
1339 IP position (can be changed if needed)) and not the ECL Cluster direction (position in the ECL measured
1340 from :math:`(0,0,0)`) for particle kinematics.
1341
1342.. note::
1343 | Please read `this <importantNoteECL>` first.
1344 | Lower limit: :math:`0.0`
1345 | Upper limit: :math:`\pi`
1346 | Precision: :math:`16` bit
1347..
1348
1349)DOC","rad");
1350 REGISTER_VARIABLE("clusterTiming", eclClusterTiming, R"DOC(
1351**In Belle II:**
1352Returns the time of the ECL cluster. It is calculated as the Photon timing minus the Event t0.
1353Photon timing is given by the fitted time of the recorded waveform of the highest energy crystal in the
1354cluster. After all calibrations and corrections (including Time-Of-Flight), photons from the interaction
1355point (IP) should have a Photon timing that corresponds to the Event t0, :math:`t_{0}`. The Event t0 is the
1356time of the event and may be measured by a different sub-detector (see Event t0 documentation). For an ECL
1357cluster produced at the interaction point in time with the event, the cluster time should be consistent with zero
1358within the uncertainties. Special values are returned if the fit for the Photon timing fails (see
1359documentation for `clusterHasFailedTiming`). (For MC, the calibrations and corrections are not fully simulated).
1360
1361.. note::
1362 | Please read `this <importantNoteECL>` first.
1363 | Lower limit: :math:`-1000.0`
1364 | Upper limit: :math:`1000.0`
1365 | Precision: :math:`12` bit
1366..
1367
1368**In Belle:**
1369Returns the trigger cell (TC) time of the ECL cluster (photon).
1370This information is available only in Belle data since experiment 31, and not available in Belle MC.
1371Clusters produced at the interaction point in time with the event, have TC time in the range of 9000-11000
1372Calculated based on the Appendix of Belle note 831.
1373
1374.. note::
1375 | In case this variable is obtained from Belle data that is stored in Belle II mdst/udst format, it will be truncated to:
1376 | Lower limit: :math:`-1000.0`
1377 | Upper limit: :math:`1000.0`
1378 | Precision: :math:`12` bit
1379..
1380
1381)DOC","ns");
1382 REGISTER_VARIABLE("clusterHasFailedTiming", eclClusterHasFailedTiming, R"DOC(
1383Status bit for if the ECL cluster's timing fit failed. Photon timing is given by the fitted time
1384of the recorded waveform of the highest energetic crystal in a cluster; however, that fit can fail and so
1385this variable tells the user if that has happened.
1386)DOC");
1387 REGISTER_VARIABLE("clusterErrorTiming", eclClusterErrorTiming, R"DOC(
1388Returns ECL cluster's timing uncertainty that contains :math:`99\%` of true photons (dt99).
1389
1390The photon timing uncertainty is currently determined using MC. The resulting parametrization depends on
1391the true energy deposition in the highest energetic crystal and the local beam background level in that crystal.
1392The resulting timing distribution is non-Gaussian and for each photon the value dt99 is stored,
1393where :math:`|\text{timing}| / \text{dt99} < 1` is designed to give a :math:`99\%`
1394timing efficiency for true photons from the IP.
1395The resulting efficiency is approximately flat in energy and independent of beam background levels.
1396
1397Very large values of dt99 are an indication of failed waveform fits in the ECL.
1398We remove such clusters in most physics photon lists.
1399
1400.. note::
1401 | Please read `this <importantNoteECL>` first.
1402 | Lower limit: :math:`0.0`
1403 | Upper limit: :math:`1000.0`
1404 | Precision: :math:`12` bit
1405
1406.. warning::
1407 In real data there will be a sizeable number of high energetic Bhabha events
1408 (from previous or later bunch collisions) that can easily be rejected by timing cuts.
1409 However, these events create large ECL clusters that can overlap with other ECL clusters
1410 and it is not clear that a simple rejection is the correction strategy.
1411..
1412
1413)DOC","ns");
1414 REGISTER_VARIABLE("clusterHasFailedErrorTiming", eclClusterHasFailedErrorTiming, R"DOC(
1415Status bit for if the ECL cluster's timing uncertainty calculation failed. Photon timing is given by the fitted time
1416of the recorded waveform of the highest energetic crystal in a cluster; however, that fit can fail and so
1417this variable tells the user if that has happened.
1418)DOC");
1419 REGISTER_VARIABLE("clusterHighestE", eclClusterHighestE, R"DOC(
1420Returns energy of the highest energetic crystal in the ECL cluster after reweighting.
1421
1422.. warning::
1423 This variable must be used carefully since it can bias shower selection
1424 towards photons that hit crystals in the center and hence have a large energy
1425 deposition in the highest energy crystal.
1426
1427.. note::
1428 | Please read `this <importantNoteECL>` first.
1429 | Lower limit: :math:`-5` (:math:`e^{-5} = 0.00674\,` GeV)
1430 | Upper limit: :math:`3.0` (:math:`e^3 = 20.08553\,` GeV)
1431 | Precision: :math:`18` bit
1432..
1433
1434)DOC","GeV");
1435 REGISTER_VARIABLE("clusterCellID", eclClusterCellId,
1436 "Returns cellId of the crystal with highest energy in the ECLCluster.");
1437 REGISTER_VARIABLE("clusterThetaID", eclClusterThetaId,
1438 "Returns thetaId of the crystal with highest energy in the ECLCluster.");
1439 REGISTER_VARIABLE("clusterPhiID", eclClusterPhiId,
1440 "Returns phiId of the crystal with highest energy in the ECLCluster.");
1441 REGISTER_VARIABLE("clusterE1E9", eclClusterE1E9, R"DOC(
1442Returns ratio of energies of the central crystal, E1, and 3x3 crystals, E9, around the central crystal.
1443Since :math:`E1 \leq E9`, this ratio is :math:`\leq 1` and tends towards larger values for photons
1444and smaller values for hadrons.
1445
1446.. note::
1447 | Please read `this <importantNoteECL>` first.
1448 | Lower limit: :math:`0.0`
1449 | Upper limit: :math:`1.0`
1450 | Precision: :math:`10` bit
1451)DOC");
1452 REGISTER_VARIABLE("clusterE9E25", eclClusterE9E25, R"DOC(
1453Deprecated - kept for backwards compatibility - returns clusterE9E21.
1454)DOC");
1455 REGISTER_VARIABLE("clusterE9E21", eclClusterE9E21, R"DOC(
1456Returns ratio of energies in inner 3x3 crystals, E9, and 5x5 crystals around the central crystal without corners.
1457Since :math:`E9 \leq E21`, this ratio is :math:`\leq 1` and tends towards larger values for photons
1458and smaller values for hadrons.
1459
1460.. note::
1461 | Please read `this <importantNoteECL>` first.
1462 | Lower limit: :math:`0.0`
1463 | Upper limit: :math:`1.0`
1464 | Precision: :math:`10` bit
1465)DOC");
1466 REGISTER_VARIABLE("clusterAbsZernikeMoment40", eclClusterAbsZernikeMoment40, R"DOC(
1467Returns absolute value of Zernike moment 40 (:math:`|Z_{40}|`). (shower shape variable).
1468
1469.. note::
1470 | Please read `this <importantNoteECL>` first.
1471 | Lower limit: :math:`0.0`
1472 | Upper limit: :math:`1.7`
1473 | Precision: :math:`10` bit
1474)DOC");
1475 REGISTER_VARIABLE("clusterAbsZernikeMoment51", eclClusterAbsZernikeMoment51, R"DOC(
1476Returns absolute value of Zernike moment 51 (:math:`|Z_{51}|`). (shower shape variable).
1477
1478.. note::
1479 | Please read `this <importantNoteECL>` first.
1480 | Lower limit: :math:`0.0`
1481 | Upper limit: :math:`1.2`
1482 | Precision: :math:`10` bit
1483)DOC");
1484 REGISTER_VARIABLE("clusterZernikeMVA", eclClusterZernikeMVA, R"DOC(
1485Returns output of a MVA using eleven Zernike moments of the cluster. Zernike moments are calculated per
1486shower in a plane perpendicular to the shower direction via
1487
1488.. math::
1489 |Z_{nm}| = \frac{n+1}{\pi} \frac{1}{\sum_{i} w_{i} E_{i}} \left|\sum_{i} R_{nm}(\rho_{i}) e^{-im\alpha_{i}} w_{i} E_{i} \right|
1490
1491where n, m are the integers, :math:`i` runs over the crystals in the shower,
1492:math:`E_{i}` is the energy of the i-th crystal in the shower,
1493:math:`R_{nm}` is a polynomial of degree :math:`n`,
1494:math:`\rho_{i}` is the radial distance of the :math:`i`-th crystal in the perpendicular plane,
1495and :math:`\alpha_{i}` is the polar angle of the :math:`i`-th crystal in the perpendicular plane.
1496As a crystal can be related to more than one shower, :math:`w_{i}` is the fraction of the
1497energy of the :math:`i`-th crystal associated with the shower.
1498
1499**Note:** this variable is sensitive to other nearby particles and so cluster isolation properties should always be checked;
1500for more information please see the
1501`ECL Cluster Recommendations <https://indico.belle2.org/event/13722/contributions/84645/attachments/31512/51585/ecl_recommendation.pdf>`_.
1502
1503More details about the implementation can be found in `BELLE2-NOTE-TE-2017-001 <https://docs.belle2.org/record/454?ln=en>`_ .
1504
1505More details about Zernike polynomials can be found in `Wikipedia <https://en.wikipedia.org/wiki/Zernike_polynomials>`_ .
1506
1507| For cluster with hypothesisId==N1: raw MVA output.
1508| For cluster with hypothesisId==N2: 1 - prod{clusterZernikeMVA}, where the product is on all N1 showers
1509 belonging to the same connected region (shower shape variable).
1510
1511.. note::
1512 | Please read `this <importantNoteECL>` first.
1513 | Lower limit: :math:`0.0`
1514 | Upper limit: :math:`1.0`
1515 | Precision: :math:`10` bit
1516)DOC");
1517 REGISTER_VARIABLE("clusterSecondMoment", eclClusterSecondMoment, R"DOC(
1518Returns second moment :math:`S`. It is defined as:
1519
1520.. math::
1521 S = \frac{1}{S_{0}(\theta)}\frac{\sum_{i=0}^{n} w_{i} E_{i} r^2_{i}}{\sum_{i=0}^{n} w_{i} E_{i}}
1522
1523where :math:`E_{i} = (E_0, E_1, ...)` are the single crystal energies sorted by energy, :math:`w_{i}` is
1524the crystal weight, and :math:`r_{i}` is the distance of the :math:`i`-th digit to the shower center projected
1525to a plane perpendicular to the shower axis. :math:`S_{0}(\theta)` normalizes :math:`S` to 1 for isolated photons.
1526
1527.. note::
1528 | Please read `this <importantNoteECL>` first.
1529 | Lower limit: :math:`0.0`
1530 | Upper limit: :math:`40.0`
1531 | Precision: :math:`10` bit
1532..
1533
1534)DOC","dimensionless");
1535 REGISTER_VARIABLE("clusterLAT", eclClusterLAT, R"DOC(
1536Returns lateral energy distribution (shower variable). It is defined as following:
1537
1538.. math::
1539 S = \frac{\sum_{i=2}^{n} w_{i} E_{i} r^2_{i}}{(w_{0} E_{0} + w_{1} E_{1}) r^2_{0} + \sum_{i=2}^{n} w_{i} E_{i} r^2_{i}}
1540
1541where :math:`E_{i} = (E_{0}, E_{1}, ...)` are the single crystal energies sorted by energy
1542(:math:`E_{0}` is the highest energy and :math:`E_{1}` the second highest), :math:`w_{i}`
1543is the crystal weight, :math:`r_{i}` is the distance of the :math:`i`-th digit to the
1544shower center projected to a plane perpendicular to the shower axis,
1545and :math:`r_{0} \approx 5\,cm` is the distance between two crystals.
1546
1547clusterLAT peaks around 0.3 for radially symmetrical electromagnetic showers and is larger
1548for hadronic events, and electrons with a close-by radiative or Bremsstrahlung photon.
1549
1550.. note::
1551 | Please read `this <importantNoteECL>` first.
1552 | Lower limit: :math:`0.0`
1553 | Upper limit: :math:`1.0`
1554 | Precision: :math:`10` bit
1555)DOC");
1556 REGISTER_VARIABLE("clusterNHits", eclClusterNHits, R"DOC(
1557Returns sum of weights :math:`w_{i}` (:math:`w_{i} \leq 1`) of all crystals in an ECL cluster.
1558For non-overlapping clusters this is equal to the number of crystals in the cluster.
1559In case of energy splitting among nearby clusters, this can be a non-integer value.
1560
1561.. note::
1562 | Please read `this <importantNoteECL>` first.
1563 | Lower limit: :math:`0.0`
1564 | Upper limit: :math:`200.0`
1565 | Precision: :math:`10` bit
1566 | If fractional weights are not of interest, this value should be cast to the nearest integer.
1567)DOC");
1568 REGISTER_VARIABLE("clusterTrackMatch", eclClusterTrackMatched, R"DOC(
1569Returns 1.0 if at least one reconstructed charged track is matched to the ECL cluster.
1570
1571Every reconstructed charged track is extrapolated into the ECL.
1572Every ECL crystal that is crossed by the track extrapolation is marked.
1573Each ECL cluster that contains any marked crystal is matched to the track.
1574Multiple tracks can be matched to one cluster and multiple clusters can be matched to one track.
1575It is conceptually correct to have two tracks matched to the same cluster.
1576)DOC");
1577 REGISTER_VARIABLE("nECLClusterTrackMatches", nECLClusterTrackMatches, R"DOC(
1578Returns number of charged tracks matched to this cluster.
1579
1580.. note::
1581 Sometimes (perfectly correctly) two tracks are extrapolated into the same cluster.
1582
1583 - For charged particles, this should return at least 1 (but sometimes 2 or more).
1584 - For neutrals, this should always return 0.
1585 - Returns NaN if there is no cluster.
1586)DOC");
1587 REGISTER_VARIABLE("clusterHasPulseShapeDiscrimination", eclClusterHasPulseShapeDiscrimination, R"DOC(
1588Status bit to indicate if cluster has digits with waveforms that passed energy and :math:`\chi^2`
1589thresholds for computing PSD variables.
1590)DOC");
1591 REGISTER_VARIABLE("beamBackgroundSuppression", beamBackgroundSuppression, R"DOC(
1592Returns the output of an MVA classifier that uses shower-related variables to distinguish true photon clusters from beam background clusters.
1593Class 1 is for true photon clusters while class 0 is for beam background clusters.
1594
1595The MVA has been trained using MC and the features used are:
1596
1597- `clusterTiming`
1598- `clusterPulseShapeDiscriminationMVA`
1599- `clusterE`
1600- `clusterTheta`
1601
1602The variable `clusterZernikeMVA` is also used but only for the MC15 training.
1603Both run-dependent and run-independent weights are available. For more information on this, and for usage recommendations, please see
1604the `Neutrals Performance XWiki Page <https://xwiki.desy.de/xwiki/rest/p/e23c8>`_.
1605
1606Please cite `this <https://inspirehep.net/literature/2785196>`_ if using this tool.
1607)DOC");
1608 REGISTER_VARIABLE("fakePhotonSuppression", fakePhotonSuppression, R"DOC(
1609Returns the output of an MVA classifier that uses shower-related variables to distinguish true photon clusters from fake photon clusters (e.g. split-offs,
1610track-cluster matching failures etc.). Class 1 is for true photon clusters while class 0 is for fake photon clusters.
1611
1612The MVA has been trained using MC and the features are:
1613
1614- `clusterPulseShapeDiscriminationMVA`
1615- `minC2TDist`
1616- `clusterE`
1617- `clusterTiming`
1618- `clusterTheta`
1619
1620The variable `clusterZernikeMVA` is also used but only for the MC15 training.
1621Both run-dependent and run-independent weights are available. For more information on this, and for usage recommendations, please see
1622the `Neutrals Performance XWiki Page <https://xwiki.desy.de/xwiki/rest/p/e23c8>`_.
1623
1624Please cite `this <https://inspirehep.net/literature/2785196>`_ if using this tool.
1625
1626(This MVA is the same as the one used for `hadronicSplitOffSuppression` but that variable should not be used as it is deprecated and does not use the new weights).
1627)DOC");
1628 REGISTER_VARIABLE("hadronicSplitOffSuppression", hadronicSplitOffSuppression, R"DOC(
1629Returns the output of an MVA classifier that uses shower-related variables to distinguish true photon clusters from hadronic splitoff clusters.
1630The classes are:
1631
1632- 1 for true photon clusters
1633- 0 for hadronic splitoff clusters
1634
1635The MVA has been trained using samples of signal photons and hadronic splitoff photons coming from MC. The features used are (in decreasing order of significance):
1636
1637- `clusterPulseShapeDiscriminationMVA`
1638- `minC2TDist`
1639- `clusterZernikeMVA`
1640- `clusterE`
1641- `clusterLAT`
1642- `clusterE1E9`
1643- `clusterSecondMoment`
1644)DOC");
1645 MAKE_DEPRECATED("hadronicSplitOffSuppression", true, "light-2302-genetta", R"DOC(
1646 Use the variable `fakePhotonSuppression` instead which is maintained and uses the latest weight files.
1647)DOC");
1648 REGISTER_VARIABLE("clusterKlId", eclClusterKlId, R"DOC(
1649Returns MVA classifier that uses ECL clusters variables to discriminate Klong clusters from em background.
1650
1651- 1 for Kl
1652- 0 for background
1653)DOC");
1654 REGISTER_VARIABLE("clusterPulseShapeDiscriminationMVA", eclPulseShapeDiscriminationMVA, R"DOC(
1655Returns MVA classifier that uses pulse shape discrimination to identify electromagnetic vs hadronic showers.
1656
1657- 1 for electromagnetic showers
1658- 0 for hadronic showers
1659
1660For details, see the following `PSD arxiv paper <https://arxiv.org/pdf/2007.09642>`_
1661)DOC");
1662 REGISTER_VARIABLE("clusterNumberOfHadronDigits", eclClusterNumberOfHadronDigits, R"DOC(
1663Returns ECL cluster's number of hadron digits in cluster (pulse shape discrimination variable).
1664Weighted sum of digits in cluster with significant scintillation emission (:math:`> 3\,` MeV)
1665in the hadronic scintillation component.
1666Computed only using cluster digits with energy :math:`> 50\,` MeV and good offline waveform fit :math:`\chi^2`.
1667
1668.. note::
1669 | Please read `this <importantNoteECL>` first.
1670 | Lower limit: :math:`0.0`
1671 | Upper limit: :math:`255.0`
1672 | Precision: :math:`18` bit
1673)DOC");
1674 REGISTER_VARIABLE("clusterClusterID", eclClusterId, R"DOC(
1675Returns ECL cluster ID of this ECL cluster within the connected region (CR) to which it belongs to.
1676)DOC");
1677 REGISTER_VARIABLE("clusterHasNPhotons", eclClusterHasNPhotonsHypothesis, R"DOC(
1678Returns 1.0 if cluster has the 'N photons' hypothesis (historically called 'N1'),
16790.0 if not, and NaN if no cluster is associated to the particle.
1680)DOC");
1681 REGISTER_VARIABLE("clusterHasNeutralHadron", eclClusterHasNeutralHadronHypothesis, R"DOC(
1682Returns 1.0 if the cluster has the 'neutral hadrons' hypothesis (historically called 'N2'),
16830.0 if not, and NaN if no cluster is associated to the particle.
1684)DOC");
1685 REGISTER_VARIABLE("eclExtTheta", eclExtTheta, R"DOC(
1686Returns extrapolated :math:`\theta` of particle track associated to the cluster (if any). Requires module ECLTrackCalDigitMatch to be executed.
1687
1688)DOC","rad");
1689 REGISTER_VARIABLE("eclExtPhi", eclExtPhi, R"DOC(
1690Returns extrapolated :math:`\phi` of particle track associated to the cluster (if any). Requires module ECLTrackCalDigitMatch to be executed..
1691
1692)DOC","rad");
1693 REGISTER_VARIABLE("eclExtPhiId", eclExtPhiId, R"DOC(
1694Returns extrapolated :math:`\phi` ID of particle track associated to the cluster (if any). Requires module ECLTrackCalDigitMatch to be executed..
1695)DOC");
1696 REGISTER_VARIABLE("weightedAverageECLTime", weightedAverageECLTime, R"DOC(
1697Returns ECL weighted average time of all clusters (neutrals) and matched clusters (charged) of daughters
1698(of any generation) of the provided particle.
1699
1700)DOC", "ns");
1701 REGISTER_VARIABLE("maxWeightedDistanceFromAverageECLTime", maxWeightedDistanceFromAverageECLTime, R"DOC(
1702Returns maximum weighted distance between time of the cluster of a photon and the ECL average time, amongst
1703the clusters (neutrals) and matched clusters (charged) of daughters (of all generations) of the provided particle.
1704
1705)DOC", "ns");
1706 REGISTER_VARIABLE("clusterMdstIndex", eclClusterMdstIndex, R"DOC(
1707StoreArray index(0 - based) of the MDST ECLCluster (useful for track-based particles matched to a cluster).
1708)DOC");
1709
1710 REGISTER_VARIABLE("nECLOutOfTimeCrystals", nECLOutOfTimeCrystals, R"DOC(
1711[Eventbased] Returns the number of crystals (ECLCalDigits) that are out of time.
1712)DOC");
1713
1714 REGISTER_VARIABLE("nECLOutOfTimeCrystalsFWDEndcap", nECLOutOfTimeCrystalsFWDEndcap, R"DOC(
1715[Eventbased] Returns the number of crystals (ECLCalDigits) that are out of time in the forward endcap.
1716)DOC");
1717
1718 REGISTER_VARIABLE("nECLOutOfTimeCrystalsBarrel", nECLOutOfTimeCrystalsBarrel, R"DOC(
1719[Eventbased] Returns the number of crystals (ECLCalDigits) that are out of time in the barrel.
1720)DOC");
1721
1722 REGISTER_VARIABLE("nECLOutOfTimeCrystalsBWDEndcap", nECLOutOfTimeCrystalsBWDEndcap, R"DOC(
1723[Eventbased] Returns the number of crystals (ECLCalDigits) that are out of time in the backward endcap.
1724)DOC");
1725
1726 REGISTER_VARIABLE("nRejectedECLShowers", nRejectedECLShowers, R"DOC(
1727[Eventbased] Returns the number of showers in the ECL that do not become clusters.
1728)DOC");
1729
1730 REGISTER_VARIABLE("nRejectedECLShowersFWDEndcap", nRejectedECLShowersFWDEndcap, R"DOC(
1731[Eventbased] Returns the number of showers in the ECL that do not become clusters, from the forward endcap.
1732If the number exceeds 255 (uint8_t maximum value) the variable is set to 255.
1733)DOC");
1734
1735 REGISTER_VARIABLE("nRejectedECLShowersBarrel", nRejectedECLShowersBarrel, R"DOC(
1736[Eventbased] Returns the number of showers in the ECL that do not become clusters, from the barrel.
1737If the number exceeds 255 (uint8_t maximum value) the variable is set to 255.
1738)DOC");
1739
1740 REGISTER_VARIABLE("nRejectedECLShowersBWDEndcap", nRejectedECLShowersBWDEndcap, R"DOC(
1741[Eventbased] Returns the number of showers in the ECL that do not become clusters, from the backward endcap.
1742If the number exceeds 255 (uint8_t maximum value) the variable is set to 255.
1743)DOC");
1744
1745 REGISTER_VARIABLE("nKLMMultistripHitsFWDEndcap", nKLMMultistripHitsFWDEndcap, R"DOC(
1746[Eventbased] Returns the number of multi-strip hits in the KLM forward endcap.
1747)DOC");
1748
1749 REGISTER_VARIABLE("nKLMMultistripHitsBarrel", nKLMMultistripHitsBarrel, R"DOC(
1750[Eventbased] Returns the number of multi-strip hits in the KLM barrel.
1751)DOC");
1752
1753 REGISTER_VARIABLE("nKLMMultistripHitsBWDEndcap", nKLMMultistripHitsBWDEndcap, R"DOC(
1754[Eventbased] Returns the number of multi-strip hits in the KLM backward endcap.
1755)DOC");
1756
1757 REGISTER_VARIABLE("nKLMMultistripHits", nKLMMultistripHits, R"DOC(
1758[Eventbased] Returns the number of multi-strip hits in the KLM.
1759)DOC");
1760
1761 REGISTER_VARIABLE("nECLShowersFWDEndcap", nECLShowersFWDEndcap, R"DOC(
1762[Eventbased] Returns the number of ECLShowers in the forward endcap.
1763)DOC");
1764
1765 REGISTER_VARIABLE("nECLShowersBarrel", nECLShowersBarrel, R"DOC(
1766[Eventbased] Returns the number of ECLShowers in the barrel.
1767)DOC");
1768
1769 REGISTER_VARIABLE("nECLShowersBWDEndcap", nECLShowersBWDEndcap, R"DOC(
1770[Eventbased] Returns the number of ECLShowers in the backward endcap.
1771)DOC");
1772
1773 REGISTER_VARIABLE("nECLShowers", nECLShowers, R"DOC(
1774[Eventbased] Returns the number of ECLShowers.
1775)DOC");
1776
1777 REGISTER_VARIABLE("nECLLocalMaximumsFWDEndcap", nECLLocalMaximumsFWDEndcap, R"DOC(
1778[Eventbased] Returns the number of LocalMaximums in the ECL forward endcap.
1779)DOC");
1780
1781 REGISTER_VARIABLE("nECLLocalMaximumsBarrel", nECLLocalMaximumsBarrel, R"DOC(
1782[Eventbased] Returns the number of LocalMaximums in the ECL barrel.
1783)DOC");
1784
1785 REGISTER_VARIABLE("nECLLocalMaximumsBWDEndcap", nECLLocalMaximumsBWDEndcap, R"DOC(
1786[Eventbased] Returns the number of LocalMaximums in the ECL backward endcap.
1787)DOC");
1788
1789 REGISTER_VARIABLE("nECLLocalMaximums", nECLLocalMaximums, R"DOC(
1790[Eventbased] Returns the number of LocalMaximums in the ECL.
1791)DOC");
1792
1793 REGISTER_VARIABLE("nECLTriggerCellsFWDEndcap", nECLTriggerCellsFWDEndcap, R"DOC(
1794[Eventbased] Returns the number of ECL trigger cells above 100 MeV in the forward endcap.
1795)DOC");
1796
1797 REGISTER_VARIABLE("nECLTriggerCellsBarrel", nECLTriggerCellsBarrel, R"DOC(
1798[Eventbased] Returns the number of ECL trigger cells above 100 MeV in the barrel.
1799)DOC");
1800
1801 REGISTER_VARIABLE("nECLTriggerCellsBWDEndcap", nECLTriggerCellsBWDEndcap, R"DOC(
1802[Eventbased] Returns the number of ECL trigger cells above 100 MeV in the backward endcap.
1803)DOC");
1804
1805 REGISTER_VARIABLE("nECLTriggerCells", nECLTriggerCells, R"DOC(
1806[Eventbased] Returns the number of ECL trigger cells above 100 MeV.
1807)DOC");
1808
1809 REGISTER_VARIABLE("eclClusterOnlyInvariantMass", eclClusterOnlyInvariantMass, R"DOC(
1810[Expert] The invariant mass calculated from all ECLCluster daughters (i.e. photons) and
1811cluster-matched tracks using the cluster 4-momenta.
1812
1813Used for ECL-based dark sector physics and debugging track-cluster matching.
1814
1815)DOC","GeV/:math:`\\text{c}^2`");
1816
1817 REGISTER_METAVARIABLE("photonHasOverlap(cutString, photonlistname, tracklistname)", photonHasOverlap, R"DOC(
1818 Returns true if the connected ECL region of the particle's cluster is shared by another particle's cluster.
1819 Neutral and charged cluster are considered.
1820 A cut string can be provided to ignore cluster that do not satisfy the given criteria.
1821 By default, the ParticleList ``gamma:all`` is used for the check of neutral ECL cluster,
1822 and the ParticleList ``e-:all`` for the check of charged ECL cluster.
1823 However, one can customize the name of the ParticleLists via additional arguments.
1824 If no argument or only a cut string is provided and ``gamma:all`` or ``e-:all`` does not exist
1825 or if the variable is requested for a particle that is not a photon, NaN is returned.
1826 )DOC", Manager::VariableDataType::c_double);
1827
1828 REGISTER_VARIABLE("clusterUncorrE", eclClusterUncorrectedE, R"DOC(
1829[Expert] [Calibration] Returns ECL cluster's uncorrected energy. That is, before leakage corrections.
1830This variable should only be used for study of the ECL. Please see :b2:var:`clusterE`.
1831
1832)DOC","GeV");
1833
1834 REGISTER_VARIABLE("distanceToMcKl",distanceToMcKl,R"DOC(
1835Returns the distance to the nearest truth KL particle, extrapolated to the cluster radius. To use
1836this variable, it is required to run getNeutralHadronGeomMatches function. Optionally, it can return
1837negative values to indicate that the ECL cluster should be removed from the analysis to correct for data
1838to MC difference in KL efficiency.
1839
1840)DOC", "cm");
1841
1842 REGISTER_VARIABLE("distanceToMcNeutron",distanceToMcNeutron,R"DOC(
1843Returns the distance to the nearest truth (anti)neutron, extrapolated to the cluster radius. To use
1844this variable, it is required to run getNeutralHadronGeomMatches function. Optionally, it can return
1845negative values to indicate that the ECL cluster should be removed from the analysis to correct for data
1846to MC difference in KL efficiency.
1847
1848)DOC", "cm");
1849
1850 REGISTER_VARIABLE("mdstIndexMcKl",mdstIndexMcKl,R"DOC(
1851 Returns the mdst index of the nearest truth KL, extrapolated to the cluster radius, if it is
1852 within the matching cone. To use this variable, it is required to run getNeutralHadronGeomMatches function.
1853)DOC");
1854
1855 REGISTER_VARIABLE("mdstIndexMcNeutron",mdstIndexMcNeutron,R"DOC(
1856 Returns the mdst index of the nearest truth (anti)neutron, extrapolated to the cluster radius, if it is
1857 within the matching cone. To use this variable, it is required to run getNeutralHadronGeomMatches function.
1858)DOC");
1859 REGISTER_VARIABLE("clusterTimeNorm90", eclClusterTimeNorm90,
1860 R"DOC(
1861 Returns ECL cluster's timing normalized such that :math:`90\%` of real photons will
1862 have :math:`|\text{clusterTimeNorm90}| < 1`. Normalization depends on energy, background
1863 level, and cellID, and differs for data and MC. Valid only for crystals within the CDC acceptance, :math:`161 <= |\text{clusterCellID}| <= 8608`. Note: the required payloads are stored in the neutrals global tag. Please find the latest recommendation using :ref:`b2help-recommendation`.)DOC",
1864 "dimensionless");
1865
1866 }
1868}
int getPDGCode() const
PDG code.
Definition Const.h:473
static const ParticleSet chargedStableSet
set of charged stable particles
Definition Const.h:618
static const double doubleNaN
quiet_NaN
Definition Const.h:703
static const ParticleType photon
photon particle
Definition Const.h:673
EHypothesisBit
The hypothesis bits for this ECLCluster (Connected region (CR) is split using this hypothesis.
Definition ECLCluster.h:31
@ c_nPhotons
CR is split into n photons (N1)
Definition ECLCluster.h:41
@ c_neutralHadron
CR is reconstructed as a neutral hadron (N2)
Definition ECLCluster.h:43
static Environment & Instance()
Static method to get a reference to the Environment instance.
static std::unique_ptr< GeneralCut > compile(const std::string &cut)
Definition GeneralCut.h:84
static const ReferenceFrame & GetCurrent()
Get current rest frame.
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
#define MAKE_DEPRECATED(name, make_fatal, version, description)
Registers a variable as deprecated.
Definition Manager.h:456
Abstract base class for different kinds of events.