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