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 valid for crystals in CDC acceptance
757 unsigned short cellID = cluster->getMaxECellId(); // [1, 8736]
758 const unsigned short firstCellID = 161; // first cellID in CDC acceptance
759 const unsigned short lastCellID = 8608; // last cellID in CDC acceptance
760 if (cellID < firstCellID or cellID > lastCellID) {return Const::doubleNaN;}
761 int iCrys = cellID - 1; // [0, 8735]
762
763 //..clusterTiming. Dither to remove artifacts from compression
764 double rawTime = cluster->getTime();
765 const double timingBit = 2000. / 4096.;
766 double tSmear = timingBit * (gRandom->Uniform() - 0.5);
767 double time = rawTime + tSmear;
768
769 //..Uncorrected single crystal energy
770 double clusterECorrected = cluster->getEnergy(ECLCluster::EHypothesisBit::c_nPhotons);
771 double clusterERaw = cluster->getEnergyRaw();
772 double singleECorrected = cluster->getEnergyHighestCrystal();
773 double singleCrystalE = singleECorrected * clusterERaw / clusterECorrected;
774 double basicEScale = 0.1 / singleCrystalE;
775
776 //..Background level for the region for this cellID
777 const int firstBarrel = 1153; // first cellID in barrel
778 const int lastBarrel = 7776; // last cellID in barrel
779 double ootCrys = elci->getNECLCalDigitsOutOfTimeBarrel();
780 if (cellID < firstBarrel) {ootCrys = elci->getNECLCalDigitsOutOfTimeFWD();}
781 if (cellID > lastBarrel) {ootCrys = elci->getNECLCalDigitsOutOfTimeBWD();}
782
783 //..Time walk correction (7 parameters)
784 // E0 / bias at E0 / lowE slope / highE slope / curvature / Emin / Emax
785 const auto& par7 = ECLTimingNormalization->getTimeWalkPar();
786 float EForCor = singleCrystalE;
787 if (EForCor < par7[iCrys][5]) {EForCor = par7[iCrys][5];}
788 if (EForCor > par7[iCrys][6]) {EForCor = par7[iCrys][6];}
789 float dE = EForCor - par7[iCrys][0];
790 double timeWalkCor = par7[iCrys][1] + par7[iCrys][2] * dE;
791 if (dE > 0) {
792 timeWalkCor = par7[iCrys][1] + par7[iCrys][3] * dE + par7[iCrys][4] * dE * dE;
793 }
794
795 //..Dependence on regional background level (5 parameters)
796 // intercept / slope / p2 / min ootCrys / max ootCrys
797 const auto& bPar = ECLTimingNormalization->getBackgroundPar();
798 float oot = ootCrys;
799 if (oot < bPar[iCrys][3]) {oot = bPar[iCrys][3];}
800 if (oot > bPar[iCrys][4]) {oot = bPar[iCrys][4];}
801 double backgroundNorm = bPar[iCrys][0] + bPar[iCrys][1] * oot + bPar[iCrys][2] * oot * oot;
802
803 //..Dependence on single crystal energy (7 parameters)
804 // E0 / res at E0 / lowE slope / highE slope / curvature / Emin / Emax
805 const auto& par7Energy = ECLTimingNormalization->getEnergyPar();
806
807 EForCor = singleCrystalE;
808 if (EForCor < par7Energy[iCrys][5]) {EForCor = par7Energy[iCrys][5];}
809 if (EForCor > par7Energy[iCrys][6]) {EForCor = par7Energy[iCrys][6];}
810 dE = EForCor - par7Energy[iCrys][0];
811 double energyNorm = par7Energy[iCrys][1] + par7Energy[iCrys][2] * dE;
812 if (dE > 0) {
813 energyNorm = par7Energy[iCrys][1] + par7Energy[iCrys][3] * dE + par7Energy[iCrys][4] * dE * dE;
814 }
815
816 //..Overall normalization. Cannot be too small.
817 double minTNorm = (double)ECLTimingNormalization->getMinTNormalization();
818 double tNormalization = basicEScale * backgroundNorm * energyNorm;
819 if (tNormalization < minTNorm) {tNormalization = minTNorm;}
820 double tNorm90 = (time - timeWalkCor) / tNormalization;
821 return tNorm90;
822
823 } else {
824 return Const::doubleNaN;
825
826 }
827 }
828
829
830 /*************************************************************
831 * Event-based ECL clustering information
832 */
833 double nECLOutOfTimeCrystalsFWDEndcap(const Particle*)
834 {
835 StoreObjPtr<EventLevelClusteringInfo> elci;
836 if (!elci) return Const::doubleNaN;
837 return (double)elci->getNECLCalDigitsOutOfTimeFWD();
838 }
839
840 double nECLOutOfTimeCrystalsBarrel(const Particle*)
841 {
842 StoreObjPtr<EventLevelClusteringInfo> elci;
843 if (!elci) return Const::doubleNaN;
844 return (double)elci->getNECLCalDigitsOutOfTimeBarrel();
845 }
846
847 double nECLOutOfTimeCrystalsBWDEndcap(const Particle*)
848 {
849 StoreObjPtr<EventLevelClusteringInfo> elci;
850 if (!elci) return Const::doubleNaN;
851 return (double)elci->getNECLCalDigitsOutOfTimeBWD();
852 }
853
854 double nECLOutOfTimeCrystals(const Particle*)
855 {
856 StoreObjPtr<EventLevelClusteringInfo> elci;
857 if (!elci) return Const::doubleNaN;
858 return (double)elci->getNECLCalDigitsOutOfTime();
859 }
860
861 double nRejectedECLShowersFWDEndcap(const Particle*)
862 {
863 StoreObjPtr<EventLevelClusteringInfo> elci;
864 if (!elci) return Const::doubleNaN;
865 return (double)elci->getNECLShowersRejectedFWD();
866 }
867
868 double nRejectedECLShowersBarrel(const Particle*)
869 {
870 StoreObjPtr<EventLevelClusteringInfo> elci;
871 if (!elci) return Const::doubleNaN;
872 return (double)elci->getNECLShowersRejectedBarrel();
873 }
874
875 double nRejectedECLShowersBWDEndcap(const Particle*)
876 {
877 StoreObjPtr<EventLevelClusteringInfo> elci;
878 if (!elci) return Const::doubleNaN;
879 return (double)elci->getNECLShowersRejectedBWD();
880 }
881
882 double nRejectedECLShowers(const Particle*)
883 {
884 StoreObjPtr<EventLevelClusteringInfo> elci;
885 if (!elci) return Const::doubleNaN;
886 return (double) elci->getNECLShowersRejected();
887 }
888
889 double nKLMMultistripHitsFWDEndcap(const Particle*)
890 {
891 StoreObjPtr<EventLevelClusteringInfo> elci;
892 if (!elci) return Const::doubleNaN;
893 return (double) elci->getNKLMDigitsMultiStripFWD();
894 }
895
896 double nKLMMultistripHitsBarrel(const Particle*)
897 {
898 StoreObjPtr<EventLevelClusteringInfo> elci;
899 if (!elci) return Const::doubleNaN;
900 return (double) elci->getNKLMDigitsMultiStripBarrel();
901 }
902
903 double nKLMMultistripHitsBWDEndcap(const Particle*)
904 {
905 StoreObjPtr<EventLevelClusteringInfo> elci;
906 if (!elci) return Const::doubleNaN;
907 return (double) elci->getNKLMDigitsMultiStripBWD();
908 }
909
910 double nKLMMultistripHits(const Particle*)
911 {
912 StoreObjPtr<EventLevelClusteringInfo> elci;
913 if (!elci) return Const::doubleNaN;
914 return (double) elci->getNKLMDigitsMultiStrip();
915 }
916
917 double nECLShowersFWDEndcap(const Particle*)
918 {
919 StoreObjPtr<EventLevelClusteringInfo> elci;
920 if (!elci) return Const::doubleNaN;
921 return (double) elci->getNECLShowersFWD();
922 }
923
924 double nECLShowersBarrel(const Particle*)
925 {
926 StoreObjPtr<EventLevelClusteringInfo> elci;
927 if (!elci) return Const::doubleNaN;
928 return (double) elci->getNECLShowersBarrel();
929 }
930
931 double nECLShowersBWDEndcap(const Particle*)
932 {
933 StoreObjPtr<EventLevelClusteringInfo> elci;
934 if (!elci) return Const::doubleNaN;
935 return (double) elci->getNECLShowersBWD();
936 }
937
938 double nECLShowers(const Particle*)
939 {
940 StoreObjPtr<EventLevelClusteringInfo> elci;
941 if (!elci) return Const::doubleNaN;
942 return (double) elci->getNECLShowers();
943 }
944
945 double nECLLocalMaximumsFWDEndcap(const Particle*)
946 {
947 StoreObjPtr<EventLevelClusteringInfo> elci;
948 if (!elci) return Const::doubleNaN;
949 return (double) elci->getNECLLocalMaximumsFWD();
950 }
951
952 double nECLLocalMaximumsBarrel(const Particle*)
953 {
954 StoreObjPtr<EventLevelClusteringInfo> elci;
955 if (!elci) return Const::doubleNaN;
956 return (double) elci->getNECLLocalMaximumsBarrel();
957 }
958
959 double nECLLocalMaximumsBWDEndcap(const Particle*)
960 {
961 StoreObjPtr<EventLevelClusteringInfo> elci;
962 if (!elci) return Const::doubleNaN;
963 return (double) elci->getNECLLocalMaximumsBWD();
964 }
965
966 double nECLLocalMaximums(const Particle*)
967 {
968 StoreObjPtr<EventLevelClusteringInfo> elci;
969 if (!elci) return Const::doubleNaN;
970 return (double) elci->getNECLLocalMaximums();
971 }
972
973 double nECLTriggerCellsFWDEndcap(const Particle*)
974 {
975 StoreObjPtr<EventLevelClusteringInfo> elci;
976 if (!elci) return Const::doubleNaN;
977 return (double) elci->getNECLTriggerCellsFWD();
978 }
979
980 double nECLTriggerCellsBarrel(const Particle*)
981 {
982 StoreObjPtr<EventLevelClusteringInfo> elci;
983 if (!elci) return Const::doubleNaN;
984 return (double) elci->getNECLTriggerCellsBarrel();
985 }
986
987 double nECLTriggerCellsBWDEndcap(const Particle*)
988 {
989 StoreObjPtr<EventLevelClusteringInfo> elci;
990 if (!elci) return Const::doubleNaN;
991 return (double) elci->getNECLTriggerCellsBWD();
992 }
993
994 double nECLTriggerCells(const Particle*)
995 {
996 StoreObjPtr<EventLevelClusteringInfo> elci;
997 if (!elci) return Const::doubleNaN;
998 return (double) elci->getNECLTriggerCells();
999 }
1000
1001 double eclClusterEoP(const Particle* part)
1002 {
1003 double E = eclClusterE(part);
1004 if (part->hasExtraInfo("bremsCorrectedPhotonEnergy")) {
1005 E += part->getExtraInfo("bremsCorrectedPhotonEnergy");
1006 }
1007 const double p = part->getMomentumMagnitude();
1008 if (0 == p) { return Const::doubleNaN;}
1009 return E / p;
1010 }
1011
1012 double eclClusterOnlyInvariantMass(const Particle* part)
1013 {
1014 int nDaughters = part->getNDaughters();
1015 ROOT::Math::PxPyPzEVector sum;
1016
1017 if (nDaughters < 1) {
1018 return part->getMass();
1019 } else {
1020 int nClusterDaughters = 0;
1021 std::stack<const Particle*> stacked;
1022 stacked.push(part);
1023 while (!stacked.empty()) {
1024 const Particle* current = stacked.top();
1025 stacked.pop();
1026
1027 const ECLCluster* cluster = current->getECLCluster();
1028 if (cluster) {
1029 const ECLCluster::EHypothesisBit clusterBit = current->getECLClusterEHypothesisBit();
1030 nClusterDaughters ++;
1031 ClusterUtils clutls;
1032 ROOT::Math::PxPyPzEVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, clusterBit);
1033 sum += p4Cluster;
1034 } else {
1035 const std::vector<Particle*> daughters = current->getDaughters();
1036 nDaughters = current->getNDaughters();
1037 for (int iDaughter = 0; iDaughter < nDaughters; iDaughter++) {
1038 stacked.push(daughters[iDaughter]);
1039 }
1040 }
1041 }
1042
1043 if (nClusterDaughters < 1) {
1044 B2WARNING("There are no clusters amongst the daughters of the provided particle!");
1045 return Const::doubleNaN;
1046 }
1047 B2DEBUG(10, "Number of daughters with cluster associated = " << nClusterDaughters);
1048 return sum.M();
1049 }
1050 }
1051
1052 Manager::FunctionPtr photonHasOverlap(const std::vector<std::string>& arguments)
1053 {
1054 std::string cutString = "";
1055 if (arguments.size() > 0) {
1056 cutString = arguments[0];
1057 }
1058 std::shared_ptr<Variable::Cut> cut = std::shared_ptr<Variable::Cut>(Variable::Cut::compile(cutString));
1059
1060 std::string photonlistname = "gamma:all";
1061 if (arguments.size() > 1) {
1062 photonlistname = arguments[1];
1063 }
1064
1065 std::string tracklistname = "e-:all";
1066 if (arguments.size() > 2) {
1067 tracklistname = arguments[2];
1068 }
1069
1070 auto func = [cut, photonlistname, tracklistname](const Particle * particle) -> double {
1071
1072 if (particle->getPDGCode() != Const::photon.getPDGCode())
1073 {
1074 B2WARNING("The variable photonHasOverlap is supposed to be calculated for photons. Returning NaN.");
1075 return Const::doubleNaN;
1076 }
1077
1078 StoreObjPtr<ParticleList> photonlist(photonlistname);
1079 if (!(photonlist.isValid()))
1080 {
1081 B2WARNING("The provided particle list " << photonlistname << " does not exist."
1082 " Therefore, the variable photonHasOverlap can not be calculated. Returning NaN.");
1083 return Const::doubleNaN;
1084 }
1085 if (photonlist->getPDGCode() != Const::photon.getPDGCode())
1086 {
1087 B2WARNING("The list " << photonlistname << " does not contain photons."
1088 " Therefore, the variable photonHasOverlap can not be calculated reliably. Returning NaN.");
1089 return Const::doubleNaN;
1090 }
1091
1092 StoreObjPtr<ParticleList> tracklist(tracklistname);
1093 if (!(tracklist.isValid()))
1094 {
1095 B2WARNING("The provided particle list " << tracklistname << " does not exist."
1096 " Therefore, the variable photonHasOverlap can not be calculated. Returning NaN.");
1097 return Const::doubleNaN;
1098 }
1099 if (!Const::chargedStableSet.contains(Const::ParticleType(abs(tracklist->getPDGCode()))))
1100 {
1101 B2WARNING("The list " << tracklistname << " does not contain charged final state particles."
1102 " Therefore, the variable photonHasOverlap can not be calculated reliably. Returning NaN.");
1103 return Const::doubleNaN;
1104 }
1105
1106 double connectedRegionID = eclClusterConnectedRegionID(particle);
1107 int mdstSource = particle->getMdstSource();
1108
1109 for (unsigned int i = 0; i < photonlist->getListSize(); i++)
1110 {
1111 const Particle* part = photonlist->getParticle(i);
1112
1113 // skip the particle itself
1114 if (part->getMdstSource() == mdstSource) {
1115 continue;
1116 }
1117
1118 // skip photons that do not fulfill the provided criteria
1119 if (!cut->check(part)) {
1120 continue;
1121 }
1122
1123 if (connectedRegionID == eclClusterConnectedRegionID(part)) {
1124 return 1;
1125 }
1126 }
1127
1128 for (unsigned int i = 0; i < tracklist->getListSize(); i++)
1129 {
1130 const Particle* part = tracklist->getParticle(i);
1131
1132 // skip tracks that do not fulfill the provided criteria
1133 if (!cut->check(part)) {
1134 continue;
1135 }
1136
1137 if (connectedRegionID == eclClusterConnectedRegionID(part)) {
1138 return 1;
1139 }
1140 }
1141
1142 return 0;
1143 };
1144 return func;
1145 }
1146
1147 VARIABLE_GROUP("ECL cluster related");
1148 REGISTER_VARIABLE("clusterEoP", eclClusterEoP, R"DOC(
1149Returns ratio of the cluster energy `clusterE` over momentum :math:`p`.
1150
1151.. attention::
1152 The cluster energy is already corrected for Bremsstrahlung.
1153
1154)DOC");
1155 REGISTER_VARIABLE("clusterReg", eclClusterDetectionRegion, R"DOC(
1156Returns an integer code representing the ECL region for the cluster:
1157
1158- 1: forward, 2: barrel, 3: backward
1159- 11: between forward endcap and barrel, 13: between backward endcap and barrel
1160- 0: outside the ECL acceptance region
1161
1162)DOC");
1163 REGISTER_VARIABLE("clusterDeltaLTemp", eclClusterDeltaL, R"DOC(
1164Returns the :math:`\Delta L` for the cluster shape as defined below.
1165
1166First, the cluster direction is constructed by calculating the weighted average of the orientation
1167for the crystals in the cluster. The POCA of the vector with this direction originating from the
1168cluster center and an extrapolated track can be used to the calculate the shower
1169depth. :math:`\Delta L` is then defined as the distance between this intersection and the cluster center.
1170
1171.. attention::
1172 This distance is calculated on the reconstruction level and is temporarily
1173 included in mdst for investigation purposes. If it is found
1174 that it is not crucial for physics analyses then this variable will be removed
1175 in future releases. So keep in mind that this variable might be removed in the future.
1176
1177.. note::
1178 Please read `this <importantNoteECL>` first.
1179
1180 - Lower limit: :math:`-250.0`
1181 - Upper limit: :math:`250.0`
1182 - Precision: :math:`10` bit
1183
1184)DOC","cm");
1185 REGISTER_VARIABLE("minC2TDist", eclClusterIsolation, R"DOC(
1186Returns the distance between the cluster and its nearest track.
1187
1188For all tracks in the event, the distance between each of their extrapolated hits in the ECL and the ECL shower
1189position is calculated, and the overall smallest distance is returned. If there are no extrapolated hits found in the ECL
1190for the event, ``NaN`` will be returned. The track array index of the track that is closest to the cluster can be
1191retrieved using `minC2TDistID`.
1192
1193.. note::
1194 Please read `this <importantNoteECL>` first.
1195
1196 - Lower limit: :math:`0.0`
1197 - Upper limit: :math:`250.0`
1198 - Precision: :math:`10` bit
1199
1200)DOC","cm");
1201 REGISTER_VARIABLE("minC2TDistID", eclClusterIsolationID, R"DOC(
1202Returns the track array index of the nearest track to the cluster. The nearest track is calculated
1203using the `minC2TDist` variable.
1204
1205)DOC");
1206 REGISTER_METAVARIABLE("minC2TDistVar(variable,particleList='pi-:all')", eclClusterIsolationVar, R"DOC(
1207Returns the value of your chosen variable for the track nearest to the given cluster as calculated by
1208`minC2TDist`.
1209
1210The first parameter ``variable`` is the variable name e.g. `nCDCHits`, while the second (optional) parameter ``particleList``
1211is the particle list name which will be used in the calculation of `minC2TDist`. The default particle list used
1212is ``pi-:all``.
1213
1214)DOC", Manager::VariableDataType::c_double);
1215 REGISTER_VARIABLE("clusterE", eclClusterE, R"DOC(
1216Returns the cluster energy corrected for leakage and background.
1217
1218.. attention::
1219 We only store clusters with :math:`E > 20\,` MeV.
1220
1221.. topic:: Calculating Photon Energy
1222
1223 The raw photon energy is given by the weighted sum of all crystal energies within the cluster.
1224 The weights per crystals are :math:`\leq 1` after cluster energy splitting in the case of overlapping
1225 clusters. The number of crystals that are included in the sum depends on a initial energy estimation
1226 and local beam background levels for the highest energy crystal. The crystal number is optimized to minimize
1227 the resolution of photons. Photon energy distributions always show a low energy tail
1228 due to unavoidable longitudinal and transverse leakage. The peak position of the photon energy distributions are
1229 corrected to match the true photon energy in MC. The corrections applied include:
1230
1231 - Leakage correction: using MC samples of mono-energetic single photon, a correction factor
1232 :math:`f` as function of the reconstructed detector position, photon energy and beam background level
1233 is determined via :math:`f = \frac{\text{peak_reconstructed}}{\text{energy_true}}`
1234
1235 - Cluster energy calibration (data only): to reach the target precision of :math:`< 1.8\%` energy
1236 resolution for high energetic photons, the remaining difference between MC and data is calibrated
1237 using kinematically fits to muon pairs
1238
1239 It is important to note that after perfect leakage corrections and cluster energy calibrations,
1240 the :math:`\pi^{0}` mass peak will be shifted slightly to smaller values than the PDG average
1241 due to the low energy tails of photons.
1242
1243.. note::
1244 Please read `this <importantNoteECL>` first.
1245
1246 - Lower limit: :math:`-5` (:math:`e^{-5} = 0.00674\,` GeV in the lab frame)
1247 - Upper limit: :math:`3.0` (:math:`e^3 = 20.08553\,` GeV in the lab frame)
1248 - Precision: :math:`18` bit
1249
1250)DOC","GeV");
1251 REGISTER_VARIABLE("clusterErrorE", eclClusterErrorE, R"DOC(
1252Returns the uncertainty on the cluster energy. It is derived from
1253a background level and energy-dependent error tabulation.
1254
1255.. danger::
1256 This variable should not be used a selection variable or in an MVA for photon identification as it is not
1257 a directly-reconstructed quantity. For more information please see the
1258 `ECL Cluster Recommendations <https://indico.belle2.org/event/13722/contributions/84645/attachments/31512/51585/ecl_recommendation.pdf>`_
1259 slides.
1260
1261)DOC","GeV");
1262 REGISTER_VARIABLE("clusterErrorPhi", eclClusterErrorPhi, R"DOC(
1263Returns the uncertainty on the phi angle of the cluster. It is derived from
1264a background level and energy-dependent error tabulation.
1265
1266.. danger::
1267 This variable should not be used a selection variable or in an MVA for photon identification as it is not
1268 a directly-reconstructed quantity. For more information please see the
1269 `ECL Cluster Recommendations <https://indico.belle2.org/event/13722/contributions/84645/attachments/31512/51585/ecl_recommendation.pdf>`_
1270 slides.
1271
1272)DOC","rad");
1273 REGISTER_VARIABLE("clusterErrorTheta", eclClusterErrorTheta, R"DOC(
1274Returns the uncertainty on the theta angle of the cluster. It is derived from
1275a background level and energy-dependent error tabulation.
1276
1277.. danger::
1278 This variable should not be used a selection variable or in an MVA for photon identification as it is not
1279 a directly-reconstructed quantity. For more information please see the
1280 `ECL Cluster Recommendations <https://indico.belle2.org/event/13722/contributions/84645/attachments/31512/51585/ecl_recommendation.pdf>`_
1281 slides.
1282
1283)DOC","rad");
1284 REGISTER_VARIABLE("clusterR", eclClusterR, R"DOC(
1285Returns the distance of the cluster centroid from :math:`(0,0,0)`.
1286
1287.. warning::
1288 This variable is not recommended for use in analyses as they are difficult to interpret. For more information please see the
1289 `ECL Cluster Recommendations <https://indico.belle2.org/event/13722/contributions/84645/attachments/31512/51585/ecl_recommendation.pdf>`_
1290 slides.
1291
1292)DOC","cm");
1293 REGISTER_VARIABLE("clusterPhi", eclClusterPhi, R"DOC(
1294Returns the azimuthal angle :math:`\phi` of the cluster. This is generally not equal
1295to the azimuthal angle of the photon.
1296
1297.. topic:: Calculating Cluster Direction
1298
1299 The direction of a cluster is given by the connecting line from :math:`\,(0,0,0)\,` to
1300 cluster centroid position in the ECL. The centroid position is calculated using up to 21 crystals
1301 (as 5x5 grid excluding corners) after the crystal energies are split in the case of overlapping clusters.
1302 The centroid position is the logarithmically weighted average of all crystals evaluated at the
1303 crystal centers. The centroid is generally biased towards the centers of the highest energetic
1304 crystal. This effect is larger for low energy photons. Beam backgrounds slightly decrease the
1305 position resolution, and mainly effects the low energy photons.
1306
1307 Unlike for charged tracks, the uncertainty (covariance) of the photon direction is not determined
1308 based on individual cluster properties but taken from MC-based parametrizations of the resolution
1309 as function of true photon energy, true photon direction and beam background level.
1310
1311.. note::
1312 Please read `this <importantNoteECL>` first.
1313
1314 - Lower limit: :math:`-\pi`
1315 - Upper limit: :math:`\pi`
1316 - Precision: :math:`16` bit
1317
1318)DOC","rad");
1319 REGISTER_VARIABLE("clusterConnectedRegionID", eclClusterConnectedRegionID, R"DOC(
1320Returns connected region ID for the cluster.
1321)DOC");
1322 REGISTER_VARIABLE("clusterTheta", eclClusterTheta, R"DOC(
1323Returns the polar angle :math:`\theta` of the cluster. This is generally not equal
1324to the polar angle of the photon.
1325
1326.. topic:: Calculating Cluster Direction
1327
1328 The direction of a cluster is given by the connecting line from :math:`\,(0,0,0)\,` to
1329 cluster centroid position in the ECL. The centroid position is calculated using up to 21 crystals
1330 (as 5x5 grid excluding corners) after the crystal energies are split in the case of overlapping clusters.
1331 The centroid position is the logarithmically weighted average of all crystals evaluated at the
1332 crystal centers. The centroid is generally biased towards the centers of the highest energetic
1333 crystal. This effect is larger for low energy photons. Beam backgrounds slightly decrease the
1334 position resolution, and mainly effects the low energy photons.
1335
1336 Unlike for charged tracks, the uncertainty (covariance) of the photon direction is not determined
1337 based on individual cluster properties but taken from MC-based parametrizations of the resolution
1338 as function of true photon energy, true photon direction and beam background level.
1339
1340.. note::
1341 Please read `this <importantNoteECL>` first.
1342
1343 - Lower limit: :math:`0.0`
1344 - Upper limit: :math:`\pi`
1345 - Precision: :math:`16` bit
1346
1347)DOC","rad");
1348 REGISTER_VARIABLE("clusterTiming", eclClusterTiming, R"DOC(
1349Returns the time of the cluster. This is calculated **differently** in Belle and Belle II. Please
1350read their definitions below.
1351
1352.. topic:: In Belle II
1353
1354 It is calculated as the cluster time minus the `eventT0`. The cluster time is obtained by a fit to
1355 the recorded waveform of the highest energy crystal in the cluster. For a cluster produced by a
1356 particle from the IP, the cluster time should be consistent with `eventT0` within the uncertainties
1357 following all calibrations and corrections. For MC, note that the calibrations and corrections are not
1358 fully simulated. In order to see if the waveform fit fails, see `clusterHasFailedTiming`.
1359
1360.. note::
1361 Please read `this <importantNoteECL>` first.
1362
1363 - Lower limit: :math:`-1000.0`
1364 - Upper limit: :math:`1000.0`
1365 - Precision: :math:`12` bit
1366
1367.. topic:: In Belle
1368
1369 It is equal to the trigger cell (TC) time corresponding to the cluster. This information is only
1370 available in Belle data since experiment 31, and not available in Belle MC. Clusters produced at the IP
1371 in time with the event have a TC time in the range of 9000 - 11000. More information can be found in the
1372 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
1377 - Lower limit: :math:`-1000.0`
1378 - Upper limit: :math:`1000.0`
1379 - Precision: :math:`12` bit
1380
1381)DOC","ns");
1382 REGISTER_VARIABLE("clusterHasFailedTiming", eclClusterHasFailedTiming, R"DOC(
1383Status bit indicating if the waveform fit for the `clusterTiming` calculation has failed.
1384)DOC");
1385 REGISTER_VARIABLE("clusterErrorTiming", eclClusterErrorTiming, R"DOC(
1386Returns the cluster timing uncertainty which is equal to the :math:`dt99` value as defined below. Very large
1387values of :math:`dt99` are an indication of a failed waveform fit for the cluster.
1388
1389The timing distribution for each cluster is non-Gaussian and so the value :math:`dt99` is stored where
1390:math:`|\text{timing}| / \text{dt99} < 1` is designed to give a :math:`99\%` timing efficiency for
1391true photons from the IP. (This definition results in an efficiency that is approximately flat in energy
1392and independent of the beam background level). The :math:`dt99` value stored is determined using MC with a
1393parametrisation that depends on the true energy deposition in the highest energetic crystal and the
1394local beam background level in that crystal.
1395
1396.. warning::
1397 This variable should should only be used for relative timing selections as it is not
1398 a directly-reconstructed quantity. For more information please see the
1399 `ECL Cluster Recommendations <https://indico.belle2.org/event/13722/contributions/84645/attachments/31512/51585/ecl_recommendation.pdf>`_
1400 slides.
1401
1402.. note::
1403 Please read `this <importantNoteECL>` first.
1404
1405 - Lower limit: :math:`0.0`
1406 - Upper limit: :math:`1000.0`
1407 - Precision: :math:`12` bit
1408
1409)DOC","ns");
1410 REGISTER_VARIABLE("clusterHasFailedErrorTiming", eclClusterHasFailedErrorTiming, R"DOC(
1411Status bit indicating if the calculation of `clusterErrorTiming` has failed due to a failed
1412waveform fit.
1413)DOC");
1414 REGISTER_VARIABLE("clusterHighestE", eclClusterHighestE, R"DOC(
1415Returns the energy of the highest energetic crystal in the cluster after reweighting.
1416
1417.. warning::
1418 This variable is not recommended for use in analyses as they are difficult to interpret. For more information please see the
1419 `ECL Cluster Recommendations <https://indico.belle2.org/event/13722/contributions/84645/attachments/31512/51585/ecl_recommendation.pdf>`_
1420 slides.
1421
1422.. note::
1423 Please read `this <importantNoteECL>` first.
1424
1425 - Lower limit: :math:`-5` (:math:`e^{-5} = 0.00674\,` GeV)
1426 - Upper limit: :math:`3.0` (:math:`e^3 = 20.08553\,` GeV)
1427 - Precision: :math:`18` bit
1428
1429)DOC","GeV");
1430 REGISTER_VARIABLE("clusterCellID", eclClusterCellId,
1431 "Returns the cell ID of the crystal with highest energy in the cluster.");
1432 REGISTER_VARIABLE("clusterThetaID", eclClusterThetaId, R"DOC(
1433Returns the :math:`\theta` ID of the crystal with highest energy in the cluster. There are
143469 :math:`\theta` IDs in total covering the entire ECL acceptance. The mapping between cell ID number
1435and :math:`\theta` ID can be found in the source code linked to the right of this variable description.
1436)DOC");
1437 REGISTER_VARIABLE("clusterPhiID", eclClusterPhiId, R"DOC(
1438Returns the :math:`\phi` ID of the crystal with highest energy in the cluster.
1439While :math:`\theta` ID indicates the specific ring of the calorimeter,
1440:math:`\phi` ID indicates a position of a crystal in that ring. When facing
1441towards the direction of an electron beam, :math:`\phi` IDs go clockwise, with
14420 corresponding to the crystal closest to the outer side of the main ring tunnel.
1443
1444.. admonition:: Diagram
1445 :class: dropdown xhint stacked
1446
1447 .. code-block:: text
1448
1449 phi_id = (nring/4) phi_id = (nring/4) - 1
1450
1451 . ... ││. .. .
1452 .... . . ││.. .. . .
1453 .. . . .... ││ ..... . . . .
1454 .. . . . . . . . .
1455 ... ... .. . ..
1456 ... .. ... . ..
1457 . . . .. . .
1458 ... . ....
1459 . . .. .. .
1460 . . . .. ..
1461 nring/2 ───── (towards the ───── phi_id = 0
1462 nring/2 - 1 ───── electron beam) ───── phi_id = (nring - 1)
1463 . .. .. ..
1464 . .... . . .
1465 .. .. ... .
1466 . .. . .. ...
1467 . . .. .. . .
1468 .. . ... .. ...
1469 . . . . . .. .. ..
1470 ... . . . .. ││. .. . .... .
1471 . . . . .││ ... ... .
1472 .....││.. . .
1473
1474 phi_id = (nring*3/4) - 1 phi_id = (nring/4) - 1
1475
1476 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>`_.
1477
1478)DOC");
1479 REGISTER_VARIABLE("clusterE1E9", eclClusterE1E9, R"DOC(
1480Returns the ratio of the energy in the central crystal (:math:`E_1`) to the total energy in the
14813x3 crystal grid around the central crystal (:math:`E_9`). Since :math:`E_1 \leq E_9`, this ratio is
1482:math:`\leq 1` and tends towards larger values for photons and smaller values for hadrons.
1483
1484.. note::
1485 Please read `this <importantNoteECL>` first.
1486
1487 - Lower limit: :math:`0.0`
1488 - Upper limit: :math:`1.0`
1489 - Precision: :math:`10` bit
1490
1491)DOC");
1492 REGISTER_VARIABLE("clusterE9E25", eclClusterE9E25, R"DOC(
1493Returns `clusterE9E21`. This variable is kept for backwards compatibility.
1494)DOC");
1495 REGISTER_VARIABLE("clusterE9E21", eclClusterE9E21, R"DOC(
1496Returns the ratio of the total energy in the 3x3 crystal grid around the central
1497crystal (:math:`E_9`) to the total energy in the 5x5 crystal grid around the central crystal
1498excluding the corners (:math:`E_{21}`). Since :math:`E_9 \leq E_{21}`, this ratio is :math:`\leq 1` and tends towards larger
1499values for photons and smaller values for hadrons.
1500
1501.. note::
1502 Please read `this <importantNoteECL>` first.
1503
1504 - Lower limit: :math:`0.0`
1505 - Upper limit: :math:`1.0`
1506 - Precision: :math:`10` bit
1507
1508)DOC");
1509 REGISTER_VARIABLE("clusterAbsZernikeMoment40", eclClusterAbsZernikeMoment40, R"DOC(
1510Returns absolute value of the 40th Zernike moment :math:`|Z_{40}|`. An explanation on this shower
1511shape variable is in the description for the `clusterZernikeMVA` variable.
1512
1513.. note::
1514 Please read `this <importantNoteECL>` first.
1515
1516 - Lower limit: :math:`0.0`
1517 - Upper limit: :math:`1.7`
1518 - Precision: :math:`10` bit
1519
1520)DOC");
1521 REGISTER_VARIABLE("clusterAbsZernikeMoment51", eclClusterAbsZernikeMoment51, R"DOC(
1522Returns absolute value of the 51st Zernike moment :math:`|Z_{51}|`. An explanation on this shower
1523shape variable is in the description for the `clusterZernikeMVA` variable.
1524
1525.. note::
1526 Please read `this <importantNoteECL>` first.
1527
1528 - Lower limit: :math:`0.0`
1529 - Upper limit: :math:`1.2`
1530 - Precision: :math:`10` bit
1531
1532)DOC");
1533 REGISTER_VARIABLE("clusterZernikeMVA", eclClusterZernikeMVA, R"DOC(
1534Returns output of an MVA trained to use eleven Zernike moments of the cluster.
1535
1536Zernike moments are calculated for each shower in the plane perpendicular to
1537the shower direction via
1538
1539.. math::
1540 |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|
1541
1542where :math:`n, m` are the integers, :math:`i` runs over each crystal in the shower,
1543:math:`E_{i}` is the energy of the i-th crystal in the shower,
1544:math:`R_{nm}` is a polynomial of degree :math:`n`,
1545:math:`\rho_{i}` is the radial distance of the :math:`i`-th crystal in the perpendicular plane,
1546and :math:`\alpha_{i}` is the polar angle of the :math:`i`-th crystal in the perpendicular plane.
1547As a crystal can be related to more than one shower, :math:`w_{i}` is the fraction of the
1548energy of the :math:`i`-th crystal associated with the shower.
1549
1550.. caution::
1551 This variable is sensitive to other nearby particles and so cluster isolation properties shoud
1552 always be checked. For more information please see the
1553 `ECL Cluster Recommendations <https://indico.belle2.org/event/13722/contributions/84645/attachments/31512/51585/ecl_recommendation.pdf>`_
1554 slides.
1555
1556.. seealso::
1557 - More details about the implementation can be found in `BELLE2-NOTE-TE-2017-001 <https://docs.belle2.org/record/454?ln=en>`_ .
1558 - More details about Zernike polynomials can be found on `Wikipedia <https://en.wikipedia.org/wiki/Zernike_polynomials>`_ .
1559
1560.. note::
1561 Please read `this <importantNoteECL>` first.
1562
1563 - Lower limit: :math:`0.0`
1564 - Upper limit: :math:`1.0`
1565 - Precision: :math:`10` bit
1566
1567)DOC");
1568 REGISTER_VARIABLE("clusterSecondMoment", eclClusterSecondMoment, R"DOC(
1569Returns the second moment :math:`S` of the cluster. This is mainly implemented for reconstructing high a
1570energy :math:`\pi^0` originating from merged clusters.
1571
1572It is defined as:
1573
1574.. math::
1575 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}}
1576
1577where :math:`E_{i} = (E_0, E_1, ...)` are the crystal energies sorted by descending energy, :math:`w_{i}` is
1578the fraction of the crystal energy associated with the shower, and :math:`r_{i}` is the distance of
1579the :math:`i`-th digit to the shower center projected onto a plane perpendicular to the
1580shower axis. :math:`S_{0}(\theta)` normalizes :math:`S` to 1 for isolated photons.
1581
1582.. note::
1583 Please read `this <importantNoteECL>` first.
1584
1585 - Lower limit: :math:`0.0`
1586 - Upper limit: :math:`40.0`
1587 - Precision: :math:`10` bit
1588
1589)DOC","dimensionless");
1590 REGISTER_VARIABLE("clusterLAT", eclClusterLAT, R"DOC(
1591Returns lateral energy distribution of the shower. For radially-symmetric electromagnetic showers, this
1592variable peaks at :math:`\approx 0.3`. It is larger for hadronic particles and electrons with a nearby relative
1593or Bremsstrahlung photon.
1594
1595It is defined as following:
1596
1597.. math::
1598 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}}
1599
1600where :math:`E_{i} = (E_0, E_1, ...)` are the crystal energies sorted by descending energy, :math:`w_{i}` is
1601the fraction of the crystal energy associated with the shower, :math:`r_{i}` is the distance of
1602the :math:`i`-th digit to the shower center projected onto a plane perpendicular to the shower axis,
1603and :math:`r_{0} \approx 5\,cm` is the average distance between two crystal centres.
1604
1605.. tip::
1606 This variable peaks around 0.3 for symmetrical electromagnetic showers and is larger for hadronic
1607 showers and electrons with a close-by radiative or Bremsstrahlung photon.
1608
1609.. note::
1610 Please read `this <importantNoteECL>` first.
1611
1612 - Lower limit: :math:`0.0`
1613 - Upper limit: :math:`1.0`
1614 - Precision: :math:`10` bit
1615
1616)DOC");
1617 REGISTER_VARIABLE("clusterNHits", eclClusterNHits, R"DOC(
1618Returns sum of weights :math:`w_{i}` (:math:`w_{i} \leq 1`) of all crystals in the cluster.
1619For non-overlapping clusters this is equal to the number of crystals in the cluster. However, in the case
1620of overlapping clusters where individual crystal energies are split among them, this can be a non-integer value.
1621
1622.. tip::
1623 If fractional weights are not of interest, this value should be cast to the nearest `int`
1624
1625.. note::
1626 Please read `this <importantNoteECL>` first.
1627
1628 - Lower limit: :math:`0.0`
1629 - Upper limit: :math:`200.0`
1630 - Precision: :math:`10` bit
1631
1632)DOC");
1633 REGISTER_VARIABLE("clusterTrackMatch", eclClusterTrackMatched, R"DOC(
1634Returns 1.0 if at least one reconstructed charged track is matched to the cluster. Track-cluster
1635matching is briefly described below.
1636
1637Every reconstructed track is extrapolated to the ECL. Every ECL crystal that is crossed by
1638the extrapolated track is marked. Following this, every cluster that contains a marked crystal
1639becomes associated with the original track. The current algorithm matches only one cluster to a
1640track but can match multiple tracks to the same cluster. In the latter case, all tracks matched
1641to the same cluster will return the same cluster variables e.g. all will have the same `clusterE`.
1642)DOC");
1643 REGISTER_VARIABLE("nECLClusterTrackMatches", nECLClusterTrackMatches, R"DOC(
1644Returns the number of tracks matched to the cluster. For more information on track-cluster matching
1645please see the description for `clusterTrackMatch`.
1646
1647For the clusters of neutral particles, this should always return 0. If there is no cluster ``NaN`` is
1648returned.
1649)DOC");
1650 REGISTER_VARIABLE("clusterHasPulseShapeDiscrimination", eclClusterHasPulseShapeDiscrimination, R"DOC(
1651Status bit to indicate if the waveforms from the cluster pass the requirements for computing pulse
1652shape discrimination variables such as `clusterPulseShapeDiscriminationMVA`.
1653
1654.. topic:: Pulse Shape Information Requirements
1655
1656 The exact requirements for a cluster have pulse shape information are as follows:
1657 - there is at least one crystal with energy above 30 MeV for phase 2 data or 50 MeV for phase 3 data
1658 (this is the energy threshold requirement for saving waveforms offline)
1659 - one of the waveforms for the cluster must have a good :math:`\chi^2` fit
1660
1661)DOC");
1662 REGISTER_VARIABLE("beamBackgroundSuppression", beamBackgroundSuppression, R"DOC(
1663Returns the output of an MVA classifier that uses shower-related variables to distinguish true photon clusters from beam background clusters.
1664Class 1 is for true photon clusters while class 0 is for beam background clusters.
1665
1666The MVA has been trained using MC and the features used, in decreasing importance, are:
1667
1668- `clusterTiming`
1669- `clusterPulseShapeDiscriminationMVA`
1670- `clusterE`
1671- `clusterTheta`
1672- `clusterZernikeMVA` (this has been removed starting from the MC16 training)
1673
1674.. seealso::
1675
1676 For the correct usage, please see
1677 the `Performance Recommendations Webpage <https://belle2.pages.desy.de/performance/recommendations/>`_.
1678
1679.. important::
1680
1681 Please cite `this proceeding <https://inspirehep.net/literature/2785196>`_ if using this tool.
1682)DOC");
1683 REGISTER_VARIABLE("fakePhotonSuppression", fakePhotonSuppression, R"DOC(
1684Returns the output of an MVA classifier that uses shower-related variables to distinguish true photon clusters from fake photon clusters.
1685Class 1 is for true photon clusters while class 0 is for fake photon clusters.
1686
1687The MVA has been trained using MC and the features, in decreasing importance, are:
1688
1689- `clusterPulseShapeDiscriminationMVA`
1690- `minC2TDist`
1691- `clusterE`
1692- `clusterTiming`
1693- `clusterTheta`
1694- `clusterZernikeMVA` (this has been removed starting from the MC16 training)
1695
1696.. seealso::
1697 For the correct usage, please see
1698 the `Performance Recommendations Webpage <https://belle2.pages.desy.de/performance/recommendations/>`_.
1699
1700.. important::
1701 Please cite `this proceeding <https://inspirehep.net/literature/2785196>`_ if using this tool.
1702
1703)DOC");
1704 REGISTER_VARIABLE("hadronicSplitOffSuppression", hadronicSplitOffSuppression, R"DOC(
1705Returns the output of an MVA classifier that uses shower-related variables to distinguish true photon clusters from hadronic splitoff clusters.
1706The classes are:
1707
1708- 1 for true photon clusters
1709- 0 for hadronic splitoff clusters
1710
1711The MVA has been trained using samples of signal photons and hadronic splitoff photons coming from MC.
1712The features used are (in decreasing order of significance):
1713
1714- `clusterPulseShapeDiscriminationMVA`
1715- `minC2TDist`
1716- `clusterZernikeMVA`
1717- `clusterE`
1718- `clusterLAT`
1719- `clusterE1E9`
1720- `clusterSecondMoment`
1721
1722)DOC");
1723 MAKE_DEPRECATED("hadronicSplitOffSuppression", true, "light-2302-genetta", R"DOC(
1724 Use the variable `fakePhotonSuppression` instead which is maintained and uses the latest weight files.
1725)DOC");
1726 REGISTER_VARIABLE("clusterKlId", eclClusterKlId, R"DOC(
1727Returns MVA classifier that uses ECL clusters variables to discriminate Klong clusters from em background.
1728
1729- 1 for Kl
1730- 0 for background
1731
1732)DOC");
1733 MAKE_DEPRECATED("clusterKlId", true, "light-2603-i", R"DOC(
1734
1735)DOC");
1736 REGISTER_VARIABLE("clusterPulseShapeDiscriminationMVA", eclPulseShapeDiscriminationMVA, R"DOC(
1737Returns the output of an MVA classifier that uses pulse shape information to discriminate between electromagnetic
1738and hadronic showers. Class 1 is for electromagnetic showers while class 0 is for hadronic showers.
1739
1740.. important::
1741 Please cite `this paper <https://inspirehep.net/literature/1807894>`_ if using this tool.
1742
1743)DOC");
1744 REGISTER_VARIABLE("clusterNumberOfHadronDigits", eclClusterNumberOfHadronDigits, R"DOC(
1745Returns the number of hadron digits in the cluster based on pulse shape information. This is the weight sum of cluster digits
1746that have :math:`> 3\,` MeV for the hadronic scintillation component. The digits must have pulse shape information available
1747(see `clusterHasPulseShapeDiscrimination` for more information).
1748
1749.. warning::
1750 This is a purely technical flag and should not be used for any physics-level selection
1751
1752.. note::
1753 Please read `this <importantNoteECL>` first.
1754
1755 - Lower limit: :math:`0.0`
1756 - Upper limit: :math:`255.0`
1757 - Precision: :math:`18` bit
1758
1759)DOC");
1760 REGISTER_VARIABLE("clusterClusterID", eclClusterId, R"DOC(
1761Returns the ID the cluster within the connected region to which it belongs.
1762)DOC");
1763 REGISTER_VARIABLE("clusterHasNPhotons", eclClusterHasNPhotonsHypothesis, R"DOC(
1764Returns 1.0 if the cluster has the "N photons" hypothesis (historically called "N1"),
17650.0 if not, and ``NaN`` if no cluster is associated to the particle.
1766)DOC");
1767 REGISTER_VARIABLE("clusterHasNeutralHadron", eclClusterHasNeutralHadronHypothesis, R"DOC(
1768Returns 1.0 if the cluster has the "neutral hadrons" hypothesis (historically called "N2"),
17690.0 if not, and ``NaN`` if no cluster is associated to the particle.
1770)DOC");
1771 REGISTER_VARIABLE("eclExtTheta", eclExtTheta, R"DOC(
1772Returns the :math:`\theta` angle of the extrapolated track associated to the cluster (if any).
1773
1774.. warning::
1775 This requires the ``ECLTrackCalDigitMatch`` module to be executed.
1776
1777)DOC","rad");
1778 REGISTER_VARIABLE("eclExtPhi", eclExtPhi, R"DOC(
1779Returns the :math:`\phi` angle of the extrapolated track associated to the cluster (if any).
1780
1781.. warning::
1782 This requires the ``ECLTrackCalDigitMatch`` module to be executed.
1783
1784)DOC","rad");
1785 REGISTER_VARIABLE("eclExtPhiId", eclExtPhiId, R"DOC(
1786Returns the :math:`\phi` ID of the extrapolated track associated to the cluster (if any).
1787
1788.. warning::
1789 This requires the ``ECLTrackCalDigitMatch`` module to be executed.
1790
1791)DOC");
1792 REGISTER_VARIABLE("weightedAverageECLTime", weightedAverageECLTime, R"DOC(
1793Returns the weighted average time of all clusters corresponding to daughter particles of the provided particle.
1794
1795)DOC", "ns");
1796 REGISTER_VARIABLE("maxWeightedDistanceFromAverageECLTime", maxWeightedDistanceFromAverageECLTime, R"DOC(
1797Returns maximum weighted distance between time of the cluster of a photon and the ECL average time, amongst
1798the clusters (neutrals) and matched clusters (charged) of daughters (of all generations) of the provided particle.
1799
1800)DOC", "ns");
1801 REGISTER_VARIABLE("clusterMdstIndex", eclClusterMdstIndex, R"DOC(
1802Returns the ``StoreArray`` index of the cluster mDST object. This can be useful for track-based particles that are matched to an cluster.
1803)DOC");
1804
1805 REGISTER_VARIABLE("nECLOutOfTimeCrystals", nECLOutOfTimeCrystals, R"DOC(
1806**[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
18077 MeV are are counted.
1808)DOC");
1809
1810 REGISTER_VARIABLE("nECLOutOfTimeCrystalsFWDEndcap", nECLOutOfTimeCrystalsFWDEndcap, R"DOC(
1811**[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
18127 MeV are are counted.
1813)DOC");
1814
1815 REGISTER_VARIABLE("nECLOutOfTimeCrystalsBarrel", nECLOutOfTimeCrystalsBarrel, R"DOC(
1816**[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
18177 MeV are are counted.
1818)DOC");
1819
1820 REGISTER_VARIABLE("nECLOutOfTimeCrystalsBWDEndcap", nECLOutOfTimeCrystalsBWDEndcap, R"DOC(
1821**[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
18227 MeV are are counted.
1823)DOC");
1824
1825 REGISTER_VARIABLE("nRejectedECLShowers", nRejectedECLShowers, R"DOC(
1826**[Eventbased]** Returns the number of ECL showers that do not become clusters. If the number exceeds 255, the variable is set to 255.
1827)DOC");
1828
1829 REGISTER_VARIABLE("nRejectedECLShowersFWDEndcap", nRejectedECLShowersFWDEndcap, R"DOC(
1830**[Eventbased]** Returns the number of ECL showers in the forward endcap that do not become clusters.
1831If the number exceeds 255, the variable is set to 255.
1832)DOC");
1833
1834 REGISTER_VARIABLE("nRejectedECLShowersBarrel", nRejectedECLShowersBarrel, R"DOC(
1835**[Eventbased]** Returns the number of ECL showers in the barrel that do not become clusters.
1836If the number exceeds 255, the variable is set to 255.
1837)DOC");
1838
1839 REGISTER_VARIABLE("nRejectedECLShowersBWDEndcap", nRejectedECLShowersBWDEndcap, R"DOC(
1840**[Eventbased]** Returns the number of ECL showers in the backward endcap that do not become clusters.
1841If the number exceeds 255, the variable is set to 255.
1842)DOC");
1843
1844 REGISTER_VARIABLE("nKLMMultistripHitsFWDEndcap", nKLMMultistripHitsFWDEndcap, R"DOC(
1845**[Eventbased]** Returns the number of multi-strip hits in the KLM forward endcap associated with the ECL cluster.
1846)DOC");
1847
1848 REGISTER_VARIABLE("nKLMMultistripHitsBarrel", nKLMMultistripHitsBarrel, R"DOC(
1849**[Eventbased]** Returns the number of multi-strip hits in the KLM barrel associated with the ECL cluster.
1850)DOC");
1851
1852 REGISTER_VARIABLE("nKLMMultistripHitsBWDEndcap", nKLMMultistripHitsBWDEndcap, R"DOC(
1853**[Eventbased]** Returns the number of multi-strip hits in the KLM backward endcap associated with the ECL cluster.
1854)DOC");
1855
1856 REGISTER_VARIABLE("nKLMMultistripHits", nKLMMultistripHits, R"DOC(
1857**[Eventbased]** Returns the number of multi-strip hits in the KLM associated with the ECL cluster.
1858)DOC");
1859
1860 REGISTER_VARIABLE("nECLShowersFWDEndcap", nECLShowersFWDEndcap, R"DOC(
1861**[Eventbased]** Returns the number of ECL showers in the forward endcap.
1862)DOC");
1863
1864 REGISTER_VARIABLE("nECLShowersBarrel", nECLShowersBarrel, R"DOC(
1865**[Eventbased]** Returns the number of ECL showers in the barrel.
1866)DOC");
1867
1868 REGISTER_VARIABLE("nECLShowersBWDEndcap", nECLShowersBWDEndcap, R"DOC(
1869**[Eventbased]** Returns the number of ECL showers in the backward endcap.
1870)DOC");
1871
1872 REGISTER_VARIABLE("nECLShowers", nECLShowers, R"DOC(
1873**[Eventbased]** Returns the number of ECL showers.
1874)DOC");
1875
1876 REGISTER_VARIABLE("nECLLocalMaximumsFWDEndcap", nECLLocalMaximumsFWDEndcap, R"DOC(
1877**[Eventbased]** Returns the number of Local Maximums in the ECL forward endcap.
1878)DOC");
1879
1880 REGISTER_VARIABLE("nECLLocalMaximumsBarrel", nECLLocalMaximumsBarrel, R"DOC(
1881**[Eventbased]** Returns the number of Local Maximums in the ECL barrel.
1882)DOC");
1883
1884 REGISTER_VARIABLE("nECLLocalMaximumsBWDEndcap", nECLLocalMaximumsBWDEndcap, R"DOC(
1885**[Eventbased]** Returns the number of Local Maximums in the ECL backward endcap.
1886)DOC");
1887
1888 REGISTER_VARIABLE("nECLLocalMaximums", nECLLocalMaximums, R"DOC(
1889**[Eventbased]** Returns the number of Local Maximums in the ECL.
1890)DOC");
1891
1892 REGISTER_VARIABLE("nECLTriggerCellsFWDEndcap", nECLTriggerCellsFWDEndcap, R"DOC(
1893**[Eventbased]** Returns the number of ECL trigger cells above 100 MeV in the forward endcap.
1894)DOC");
1895
1896 REGISTER_VARIABLE("nECLTriggerCellsBarrel", nECLTriggerCellsBarrel, R"DOC(
1897**[Eventbased]** Returns the number of ECL trigger cells above 100 MeV in the barrel.
1898)DOC");
1899
1900 REGISTER_VARIABLE("nECLTriggerCellsBWDEndcap", nECLTriggerCellsBWDEndcap, R"DOC(
1901**[Eventbased]** Returns the number of ECL trigger cells above 100 MeV in the backward endcap.
1902)DOC");
1903
1904 REGISTER_VARIABLE("nECLTriggerCells", nECLTriggerCells, R"DOC(
1905**[Eventbased]** Returns the number of ECL trigger cells above 100 MeV.
1906)DOC");
1907
1908 REGISTER_VARIABLE("eclClusterOnlyInvariantMass", eclClusterOnlyInvariantMass, R"DOC(
1909Returns the invariant mass calculated from all neutral and track-matched cluster daughters using the cluster 4-momenta.
1910This is primarily used for ECL-based dark sector physics and debugging track-cluster matching.
1911
1912)DOC","GeV/:math:`\\text{c}^2`");
1913
1914 REGISTER_METAVARIABLE("photonHasOverlap(cutString, photonlistname, tracklistname)", photonHasOverlap, R"DOC(
1915Returns ``True`` if the connection region of the cluster is shared by another cluster. Both neutral and track-matched clusters
1916are considered.
1917
1918A ``cutString`` can be provided in order to ignore clusters that do not satisfy a given criteria. By default, the particle lists
1919``gamma:all`` and ``e-:all`` are used to check for neutral and track-matched clusters respectively. However, this can be customised
1920by using the ``photonlistname`` and ``tracklistname`` parameters. If ``gamma:all`` or ``e-:all`` does not exist or if this variable is applied
1921to a particle that is not a photon, ``NaN`` will be returned.
1922)DOC", Manager::VariableDataType::c_double);
1923
1924 REGISTER_VARIABLE("clusterUncorrE", eclClusterUncorrectedE, R"DOC(
1925Returns the uncorrected energy of the cluster.
1926
1927.. danger::
1928 This variable should not be used for any physics analysis but only for ECL or calibration studies.
1929
1930)DOC","GeV");
1931
1932 REGISTER_VARIABLE("distanceToMcKl",distanceToMcKl,R"DOC(
1933Returns the distance to the nearest truth-matched :math:`K_L^0` particle that has been extrapolated to the cluster.
1934
1935.. warning::
1936 This requires the `getNeutralHadronGeomMatches` function to be used.
1937
1938)DOC", "cm");
1939
1940 REGISTER_VARIABLE("distanceToMcNeutron",distanceToMcNeutron,R"DOC(
1941Returns the distance to the nearest truth-matched (anti)neutron particle that has been extrapolated to the cluster.
1942
1943.. warning::
1944 This requires the `getNeutralHadronGeomMatches` function to be used.
1945
1946)DOC", "cm");
1947
1948 REGISTER_VARIABLE("mdstIndexMcKl",mdstIndexMcKl,R"DOC(
1949Returns the ``StoreArray`` index of the mDST object corresponding to the nearest truth-matched :math:`K_L^0` particle as determined
1950during the calculation of the `distanceToMcKl` variable.
1951
1952.. warning::
1953 This requires the `getNeutralHadronGeomMatches` function to be used.
1954
1955)DOC");
1956
1957 REGISTER_VARIABLE("mdstIndexMcNeutron",mdstIndexMcNeutron,R"DOC(
1958Returns the ``StoreArray`` index of the mDST object corresponding to the nearest truth-matched (anti)neutron particle as determined
1959during the calculation of the `distanceToMcKl` variable.
1960
1961.. warning::
1962 This requires the `getNeutralHadronGeomMatches` function to be used.
1963)DOC");
1964 REGISTER_VARIABLE("clusterTimeNorm90", eclClusterTimeNorm90,
1965 R"DOC(
1966 Returns cluster's timing normalized such that :math:`90\%` of real photons will
1967 have :math:`|\text{clusterTimeNorm90}| < 1`. Normalization depends on energy, background
1968 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",
1969 "dimensionless");
1970
1971 }
1973}
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.