Belle II Software  release-06-02-00
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 include
10 #include <analysis/variables/ECLVariables.h>
11 
12 //framework
13 #include <framework/logging/Logger.h>
14 
15 //analysis
16 #include <analysis/dataobjects/Particle.h>
17 #include <analysis/dataobjects/ParticleList.h>
18 #include <analysis/dataobjects/ECLEnergyCloseToTrack.h>
19 #include <analysis/utility/ReferenceFrame.h>
20 #include <analysis/ClusterUtility/ClusterUtils.h>
21 #include <analysis/VariableManager/Utility.h>
22 
23 //MDST
24 #include <mdst/dataobjects/KlId.h>
25 #include <mdst/dataobjects/ECLCluster.h>
26 #include <mdst/dataobjects/Track.h>
27 #include <mdst/dataobjects/EventLevelClusteringInfo.h>
28 
29 #include <cmath>
30 #include <stack>
31 
32 
33 
34 namespace Belle2 {
39  namespace Variable {
40  double beamBackgroundProbabilityMVA(const Particle* particle)
41  {
42  if (particle->hasExtraInfo("beamBackgroundProbabilityMVA")) {
43  return particle->getExtraInfo("beamBackgroundProbabilityMVA");
44  } else {
45  B2WARNING("The extraInfo beamBackgroundProbabilityMVA is not registered! \n"
46  "This variable is only available for photons, and you either have to run the function getBeamBackgroundProbabilityMVA or turn the argument loadPhotonBeamBackgroundMVA to True when using fillParticleList.");
47  return std::numeric_limits<float>::quiet_NaN();
48  }
49  }
50 
51  double eclClusterKlId(const Particle* particle)
52  {
53  const ECLCluster* cluster = particle->getECLCluster();
54  if (!cluster) {
55  return std::numeric_limits<double>::quiet_NaN();
56  }
57  const KlId* klid = cluster->getRelatedTo<KlId>();
58  if (!klid) {
59  return std::numeric_limits<double>::quiet_NaN();
60  }
61  return klid->getKlId();
62  }
63 
64 
65  double eclPulseShapeDiscriminationMVA(const Particle* particle)
66  {
67  const ECLCluster* cluster = particle->getECLCluster();
68  if (cluster) {
69  if (eclClusterHasPulseShapeDiscrimination(particle)) {
70  return cluster->getPulseShapeDiscriminationMVA();
71  } else {
72  return std::numeric_limits<float>::quiet_NaN();
73  }
74  }
75  return std::numeric_limits<float>::quiet_NaN();
76  }
77 
78 
79 
80  double eclClusterNumberOfHadronDigits(const Particle* particle)
81  {
82 
83  const ECLCluster* cluster = particle->getECLCluster();
84  if (cluster) {
85  if (eclClusterHasPulseShapeDiscrimination(particle)) {
86  return cluster->getNumberOfHadronDigits();
87  } else
88  return std::numeric_limits<float>::quiet_NaN();
89  }
90  return std::numeric_limits<float>::quiet_NaN();
91  }
92 
93  double eclClusterDetectionRegion(const Particle* particle)
94  {
95 
96  const ECLCluster* cluster = particle->getECLCluster();
97  if (cluster)
98  return cluster->getDetectorRegion();
99 
100  return std::numeric_limits<float>::quiet_NaN();
101  }
102 
103  double eclClusterIsolation(const Particle* particle)
104  {
105 
106  const ECLCluster* cluster = particle->getECLCluster();
107  if (cluster)
108  return cluster->getMinTrkDistance();
109 
110  return std::numeric_limits<float>::quiet_NaN();
111  }
112 
113  double eclClusterIsolationID(const Particle* particle)
114  {
115 
116  const ECLCluster* cluster = particle->getECLCluster();
117  if (cluster)
118  return cluster->getMinTrkDistanceID();
119 
120  return std::numeric_limits<float>::quiet_NaN();
121  }
122 
123  Manager::FunctionPtr eclClusterIsolationVar(const std::vector<std::string>& arguments)
124  {
125  if (arguments.size() > 2 or arguments.size() == 0)
126  B2FATAL("Wrong number of arguments (2 required) for meta variable minC2TDistVar");
127  std::string listName = "pi-:all";
128  std::string variableName = arguments[0];
129  if (arguments.size() == 2)
130  listName = arguments[1];
131 
132 
133  auto func = [listName, variableName](const Particle * particle) -> double {
134  StoreObjPtr<ParticleList> particleList(listName);
135  if (!(particleList.isValid()))
136  {
137  B2FATAL("Invalid Listname " << listName << " given to minC2TDistVar!");
138  }
139  const Variable::Manager::Var* var = Manager::Instance().getVariable(variableName);
140  const ECLCluster* cluster = particle->getECLCluster();
141  if (!cluster)
142  return std::numeric_limits<float>::quiet_NaN();
143  auto trackID = cluster->getMinTrkDistanceID();
144  double result = std::numeric_limits<float>::quiet_NaN();
145  // Find particle with that track ID:
146  for (unsigned int i = 0; i < particleList->getListSize(); i++)
147  {
148  const Particle* listParticle = particleList->getParticle(i);
149  if (listParticle and listParticle->getTrack() and listParticle->getTrack()->getArrayIndex() == trackID) {
150  result = var->function(listParticle);
151  break;
152  }
153  }
154  return result;
155  };
156  return func;
157  }
158 
159  double eclClusterConnectedRegionID(const Particle* particle)
160  {
161 
162  const ECLCluster* cluster = particle->getECLCluster();
163  if (cluster)
164  return cluster->getConnectedRegionId();
165 
166  return std::numeric_limits<float>::quiet_NaN();
167  }
168 
169  double eclClusterDeltaL(const Particle* particle)
170  {
171 
172  const ECLCluster* cluster = particle->getECLCluster();
173  if (cluster)
174  return cluster->getDeltaL();
175 
176  return std::numeric_limits<float>::quiet_NaN();
177  }
178 
179 
180  double eclClusterErrorE(const Particle* particle)
181  {
182 
183  const ECLCluster* cluster = particle->getECLCluster();
184  if (cluster) {
185  return cluster->getUncertaintyEnergy();
186  }
187  return std::numeric_limits<float>::quiet_NaN();
188  }
189 
190  double eclClusterUncorrectedE(const Particle* particle)
191  {
192 
193  const ECLCluster* cluster = particle->getECLCluster();
194  if (cluster) {
195  return cluster->getEnergyRaw();
196  }
197  return std::numeric_limits<float>::quiet_NaN();
198  }
199 
200  double eclClusterE(const Particle* particle)
201  {
202  const auto& frame = ReferenceFrame::GetCurrent();
203 
204  const ECLCluster* cluster = particle->getECLCluster();
205  if (cluster) {
206  ClusterUtils clutls;
207  TLorentzVector p4Cluster = clutls.GetCluster4MomentumFromCluster(cluster, particle->getECLClusterEHypothesisBit());
208 
209  return frame.getMomentum(p4Cluster).E();
210  }
211  return std::numeric_limits<float>::quiet_NaN();
212  }
213 
214  double eclClusterHighestE(const Particle* particle)
215  {
216 
217  const ECLCluster* cluster = particle->getECLCluster();
218  if (cluster) {
219  return cluster->getEnergyHighestCrystal();
220  }
221  return std::numeric_limits<float>::quiet_NaN();
222  }
223 
224  double eclClusterCellId(const Particle* particle)
225  {
226 
227  const ECLCluster* cluster = particle->getECLCluster();
228  if (cluster) {
229  return cluster->getMaxECellId();
230  }
231  return std::numeric_limits<float>::quiet_NaN();
232  }
233 
234  // An array with each number representing the last number of the cellID per thetaID. There are 69 thetaIDs in total.
235  const std::array<int, 69> lastCellIDperThetaID{48, 96, 160, 224, 288, 384, 480, 576, 672, 768, 864,
236  1008, 1152, 1296, 1440, 1584, 1728, 1872, 2016, 2160, 2304, 2448,
237  2592, 2736, 2880, 3024, 3168, 3312, 3456, 3600, 3744, 3888, 4032,
238  4176, 4320, 4464, 4608, 4752, 4896, 5040, 5184, 5328, 5472, 5616,
239  5760, 5904, 6048, 6192, 6336, 6480, 6624, 6768, 6912, 7056, 7200,
240  7344, 7488, 7632, 7776, 7920, 8064, 8160, 8256, 8352, 8448, 8544,
241  8608, 8672, 8736};
242 
243  double eclClusterThetaId(const Particle* particle)
244  {
245 
246  const ECLCluster* cluster = particle->getECLCluster();
247  if (cluster) {
248  int cellID = cluster->getMaxECellId();
249  return std::distance(lastCellIDperThetaID.begin(), std::lower_bound(lastCellIDperThetaID.begin(), lastCellIDperThetaID.end(),
250  cellID));
251  }
252  return std::numeric_limits<float>::quiet_NaN();
253  }
254 
255  double eclClusterPhiId(const Particle* particle)
256  {
257 
258  const ECLCluster* cluster = particle->getECLCluster();
259  if (cluster) {
260  int cellID = cluster->getMaxECellId();
261  if (cellID <= 48) {
262  return cellID - 1;
263  } else {
264  int closestinlist = lastCellIDperThetaID[std::distance(lastCellIDperThetaID.begin(), std::lower_bound(lastCellIDperThetaID.begin(),
265  lastCellIDperThetaID.end(), cellID)) - 1];
266  return cellID - closestinlist - 1;
267  }
268  }
269  return std::numeric_limits<float>::quiet_NaN();
270  }
271 
272  double eclClusterTiming(const Particle* particle)
273  {
274 
275  const ECLCluster* cluster = particle->getECLCluster();
276  if (cluster) {
277  return cluster->getTime();
278  }
279  return std::numeric_limits<float>::quiet_NaN();
280  }
281 
282  double eclClusterHasFailedTiming(const Particle* particle)
283  {
284  const ECLCluster* cluster = particle->getECLCluster();
285  if (cluster) {
286  return cluster->hasFailedFitTime();
287  }
288  return std::numeric_limits<float>::quiet_NaN();
289  }
290 
291  double eclClusterErrorTiming(const Particle* particle)
292  {
293 
294  const ECLCluster* cluster = particle->getECLCluster();
295  if (cluster) {
296  return cluster->getDeltaTime99();
297  }
298  return std::numeric_limits<float>::quiet_NaN();
299  }
300 
301  double eclClusterHasFailedErrorTiming(const Particle* particle)
302  {
303  const ECLCluster* cluster = particle->getECLCluster();
304  if (cluster) {
305  return cluster->hasFailedTimeResolution();
306  }
307  return std::numeric_limits<float>::quiet_NaN();
308  }
309 
310  double eclClusterTheta(const Particle* particle)
311  {
312  const auto& frame = ReferenceFrame::GetCurrent();
313 
314  const ECLCluster* cluster = particle->getECLCluster();
315  if (cluster) {
316  ClusterUtils clutls;
317  TLorentzVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, particle->getECLClusterEHypothesisBit());
318 
319  return frame.getMomentum(p4Cluster).Theta();
320  }
321  return std::numeric_limits<float>::quiet_NaN();
322  }
323 
324  double eclClusterErrorTheta(const Particle* particle)
325  {
326 
327  const ECLCluster* cluster = particle->getECLCluster();
328  if (cluster) {
329  return cluster->getUncertaintyTheta();
330  }
331  return std::numeric_limits<float>::quiet_NaN();
332  }
333 
334  double eclClusterErrorPhi(const Particle* particle)
335  {
336 
337  const ECLCluster* cluster = particle->getECLCluster();
338  if (cluster) {
339  return cluster->getUncertaintyPhi();
340  }
341  return std::numeric_limits<float>::quiet_NaN();
342  }
343 
344  double eclClusterPhi(const Particle* particle)
345  {
346  const auto& frame = ReferenceFrame::GetCurrent();
347 
348  const ECLCluster* cluster = particle->getECLCluster();
349  if (cluster) {
350  ClusterUtils clutls;
351  TLorentzVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, particle->getECLClusterEHypothesisBit());
352 
353  return frame.getMomentum(p4Cluster).Phi();
354  }
355  return std::numeric_limits<float>::quiet_NaN();
356  }
357 
358  double eclClusterR(const Particle* particle)
359  {
360 
361  const ECLCluster* cluster = particle->getECLCluster();
362  if (cluster) {
363  return cluster->getR();
364  }
365  return std::numeric_limits<float>::quiet_NaN();
366  }
367 
368  double eclClusterE1E9(const Particle* particle)
369  {
370 
371  const ECLCluster* cluster = particle->getECLCluster();
372  if (cluster) {
373  return cluster->getE1oE9();
374  }
375  return std::numeric_limits<float>::quiet_NaN();
376  }
377 
378  double eclClusterE9E21(const Particle* particle)
379  {
380 
381  const ECLCluster* cluster = particle->getECLCluster();
382  if (cluster) {
383  return cluster->getE9oE21();
384  }
385  return std::numeric_limits<float>::quiet_NaN();
386  }
387 
388  double eclClusterAbsZernikeMoment40(const Particle* particle)
389  {
390 
391  const ECLCluster* cluster = particle->getECLCluster();
392  if (cluster) {
393  return cluster->getAbsZernike40();
394  }
395  return std::numeric_limits<float>::quiet_NaN();
396  }
397 
398  double eclClusterAbsZernikeMoment51(const Particle* particle)
399  {
400 
401  const ECLCluster* cluster = particle->getECLCluster();
402  if (cluster) {
403  return cluster->getAbsZernike51();
404  }
405  return std::numeric_limits<float>::quiet_NaN();
406  }
407 
408  double eclClusterZernikeMVA(const Particle* particle)
409  {
410 
411  const ECLCluster* cluster = particle->getECLCluster();
412  if (cluster) {
413  return cluster->getZernikeMVA();
414  }
415  return std::numeric_limits<float>::quiet_NaN();
416  }
417 
418  double eclClusterSecondMoment(const Particle* particle)
419  {
420 
421  const ECLCluster* cluster = particle->getECLCluster();
422  if (cluster) {
423  return cluster->getSecondMoment();
424  }
425  return std::numeric_limits<float>::quiet_NaN();
426  }
427 
428  double eclClusterLAT(const Particle* particle)
429  {
430 
431  const ECLCluster* cluster = particle->getECLCluster();
432  if (cluster) {
433  return cluster->getLAT();
434  }
435  return std::numeric_limits<float>::quiet_NaN();
436  }
437 
438  double eclClusterNHits(const Particle* particle)
439  {
440 
441  const ECLCluster* cluster = particle->getECLCluster();
442  if (cluster) {
443  return cluster->getNumberOfCrystals();
444  }
445  return std::numeric_limits<float>::quiet_NaN();
446  }
447 
448  double eclClusterTrackMatched(const Particle* particle)
449  {
450 
451  const ECLCluster* cluster = particle->getECLCluster();
452  if (cluster) {
453  const Track* track = cluster->getRelatedFrom<Track>();
454 
455  if (track)
456  return 1.0;
457  else
458  return 0.0;
459  }
460  return std::numeric_limits<float>::quiet_NaN();
461  }
462 
463  double nECLClusterTrackMatches(const Particle* particle)
464  {
465  // if no ECL cluster then nan
466  const ECLCluster* cluster = particle->getECLCluster();
467  if (!cluster)
468  return std::numeric_limits<double>::quiet_NaN();
469 
470  // one or more tracks may be matched to charged particles
471  size_t out = cluster->getRelationsFrom<Track>().size();
472  return double(out);
473  }
474 
475  double eclClusterConnectedRegionId(const Particle* particle)
476  {
477  const ECLCluster* cluster = particle->getECLCluster();
478  if (cluster) {
479  return cluster->getConnectedRegionId();
480  }
481  return std::numeric_limits<float>::quiet_NaN();
482  }
483 
484  double eclClusterId(const Particle* particle)
485  {
486  const ECLCluster* cluster = particle->getECLCluster();
487  if (cluster) {
488  return cluster->getClusterId();
489  }
490  return std::numeric_limits<float>::quiet_NaN();
491  }
492 
493  double eclClusterHasNPhotonsHypothesis(const Particle* particle)
494  {
495  const ECLCluster* cluster = particle->getECLCluster();
496  if (cluster) {
497  return cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_nPhotons);
498  }
499  return std::numeric_limits<float>::quiet_NaN();
500  }
501 
502  double eclClusterHasNeutralHadronHypothesis(const Particle* particle)
503  {
504  const ECLCluster* cluster = particle->getECLCluster();
505  if (cluster) {
506  return cluster->hasHypothesis(ECLCluster::EHypothesisBit::c_neutralHadron);
507  }
508  return std::numeric_limits<float>::quiet_NaN();
509  }
510 
511  double eclClusterHasPulseShapeDiscrimination(const Particle* particle)
512  {
513  const ECLCluster* cluster = particle->getECLCluster();
514  if (cluster) {
515  return cluster->hasPulseShapeDiscrimination();
516  }
517  return std::numeric_limits<float>::quiet_NaN();
518  }
519 
520  double eclExtTheta(const Particle* particle)
521  {
522 
523  const Track* track = particle->getTrack();
524  if (track) {
525 
526  auto* eclinfo = track->getRelatedTo<ECLEnergyCloseToTrack>();
527 
528  if (eclinfo) {
529  return eclinfo->getExtTheta();
530  } else {
531  B2WARNING("Relation to ECLEnergyCloseToTrack not found, did you forget to run ECLTrackCalDigitMatchModule?");
532  return std::numeric_limits<float>::quiet_NaN();
533  }
534  }
535 
536  return std::numeric_limits<float>::quiet_NaN();
537  }
538 
539  double eclExtPhi(const Particle* particle)
540  {
541 
542  const Track* track = particle->getTrack();
543  if (track) {
544 
545  auto* eclinfo = track->getRelatedTo<ECLEnergyCloseToTrack>();
546 
547  if (eclinfo) {
548  return eclinfo->getExtPhi();
549  } else {
550  B2WARNING("Relation to ECLEnergyCloseToTrack not found, did you forget to run ECLTrackCalDigitMatchModule?");
551  return std::numeric_limits<float>::quiet_NaN();
552  }
553  }
554 
555  return std::numeric_limits<float>::quiet_NaN();
556  }
557 
558  double eclExtPhiId(const Particle* particle)
559  {
560  const Track* track = particle->getTrack();
561  if (track) {
562 
563  auto* eclinfo = track->getRelatedTo<ECLEnergyCloseToTrack>();
564 
565  if (eclinfo) {
566  return eclinfo->getExtPhiId();
567  } else {
568  B2WARNING("Relation to ECLEnergyCloseToTrack not found, did you forget to run ECLTrackCalDigitMatchModule?");
569  return std::numeric_limits<float>::quiet_NaN();
570  }
571  }
572 
573  return std::numeric_limits<float>::quiet_NaN();
574  }
575 
576  double weightedAverageECLTime(const Particle* particle)
577  {
578  int nDaughters = particle->getNDaughters();
579  if (nDaughters < 1) {
580  B2WARNING("The provided particle has no daughters!");
581  return std::numeric_limits<float>::quiet_NaN();
582  }
583 
584  double numer = 0, denom = 0;
585  int numberOfClusterDaughters = 0;
586 
587  auto weightedECLTimeAverage = [&numer, &denom, &numberOfClusterDaughters](const Particle * p) {
588  const ECLCluster* cluster = p->getECLCluster();
589  if (cluster and not cluster->hasFailedFitTime()) {
590  numberOfClusterDaughters ++;
591 
592  double time = cluster->getTime();
593  B2DEBUG(10, "time[" << numberOfClusterDaughters << "] = " << time);
594  double deltatime = cluster->getDeltaTime99();
595  B2DEBUG(10, "deltatime[" << numberOfClusterDaughters << "] = " << deltatime);
596  numer += time / pow(deltatime, 2);
597  B2DEBUG(11, "numer[" << numberOfClusterDaughters << "] = " << numer);
598  denom += 1 / pow(deltatime, 2);
599  B2DEBUG(11, "denom[" << numberOfClusterDaughters << "] = " << denom);
600  }
601  return false;
602  };
603 
604  particle->forEachDaughter(weightedECLTimeAverage, true, true);
605 
606  if (numberOfClusterDaughters < 1) {
607  B2WARNING("There are no clusters or cluster matches amongst the daughters of the provided particle!");
608  return std::numeric_limits<float>::quiet_NaN();
609  }
610 
611  if (denom == 0) {
612  B2WARNING("The denominator of the weighted mean is zero!");
613  return std::numeric_limits<float>::quiet_NaN();
614  } else {
615  B2DEBUG(10, "numer/denom = " << numer / denom);
616  return numer / denom;
617  }
618  }
619 
620  double maxWeightedDistanceFromAverageECLTime(const Particle* particle)
621  {
622  int nDaughters = particle->getNDaughters();
623  if (nDaughters < 1) {
624  B2WARNING("The provided particle has no daughters!");
625  return std::numeric_limits<float>::quiet_NaN();
626  }
627 
628  double maxTimeDiff = -DBL_MAX;
629  int numberOfClusterDaughters = 0;
630 
631  double averageECLTime = weightedAverageECLTime(particle);
632 
633  auto maxTimeDifference = [&maxTimeDiff, &numberOfClusterDaughters, &averageECLTime](const Particle * p) {
634 
635  const ECLCluster* cluster = p->getECLCluster();
636  if (cluster) {
637  numberOfClusterDaughters ++;
638 
639  double time = cluster->getTime();
640  B2DEBUG(10, "time[" << numberOfClusterDaughters << "] = " << time);
641  double deltatime = cluster->getDeltaTime99();
642  B2DEBUG(10, "deltatime[" << numberOfClusterDaughters << "] = " << deltatime);
643  double maxTimeDiff_temp = fabs((time - averageECLTime) / deltatime);
644  B2DEBUG(11, "maxTimeDiff_temp[" << numberOfClusterDaughters << "] = " << maxTimeDiff_temp);
645  if (maxTimeDiff_temp > maxTimeDiff)
646  maxTimeDiff = maxTimeDiff_temp;
647  B2DEBUG(11, "maxTimeDiff[" << numberOfClusterDaughters << "] = " << maxTimeDiff);
648  }
649  return false;
650  };
651 
652  particle->forEachDaughter(maxTimeDifference, true, true);
653 
654  if (numberOfClusterDaughters < 1) {
655  B2WARNING("There are no clusters or cluster matches amongst the daughters of the provided particle!");
656  return std::numeric_limits<float>::quiet_NaN();
657  }
658 
659  if (maxTimeDiff < 0) {
660  B2WARNING("The max time difference is negative!");
661  return std::numeric_limits<float>::quiet_NaN();
662  } else {
663  B2DEBUG(10, "maxTimeDiff = " << maxTimeDiff);
664  return maxTimeDiff;
665  }
666  }
667 
668  double eclClusterMdstIndex(const Particle* particle)
669  {
670  const ECLCluster* cluster = particle->getECLCluster();
671  if (cluster) {
672  return cluster->getArrayIndex();
673  } else return std::numeric_limits<double>::quiet_NaN();
674 
675  return std::numeric_limits<double>::quiet_NaN();
676  }
677 
678 
679  /*************************************************************
680  * Event-based ECL clustering information
681  */
682  double nECLOutOfTimeCrystalsFWDEndcap(const Particle*)
683  {
684  StoreObjPtr<EventLevelClusteringInfo> elci;
685  if (!elci) return std::numeric_limits<double>::quiet_NaN();
686  return (double)elci->getNECLCalDigitsOutOfTimeFWD();
687  }
688 
689  double nECLOutOfTimeCrystalsBarrel(const Particle*)
690  {
691  StoreObjPtr<EventLevelClusteringInfo> elci;
692  if (!elci) return std::numeric_limits<double>::quiet_NaN();
693  return (double)elci->getNECLCalDigitsOutOfTimeBarrel();
694  }
695 
696  double nECLOutOfTimeCrystalsBWDEndcap(const Particle*)
697  {
698  StoreObjPtr<EventLevelClusteringInfo> elci;
699  if (!elci) return std::numeric_limits<double>::quiet_NaN();
700  return (double)elci->getNECLCalDigitsOutOfTimeBWD();
701  }
702 
703  double nECLOutOfTimeCrystals(const Particle*)
704  {
705  StoreObjPtr<EventLevelClusteringInfo> elci;
706  if (!elci) return std::numeric_limits<double>::quiet_NaN();
707  return (double)elci->getNECLCalDigitsOutOfTime();
708  }
709 
710  double nRejectedECLShowersFWDEndcap(const Particle*)
711  {
712  StoreObjPtr<EventLevelClusteringInfo> elci;
713  if (!elci) return std::numeric_limits<double>::quiet_NaN();
714  return (double)elci->getNECLShowersRejectedFWD();
715  }
716 
717  double nRejectedECLShowersBarrel(const Particle*)
718  {
719  StoreObjPtr<EventLevelClusteringInfo> elci;
720  if (!elci) return std::numeric_limits<double>::quiet_NaN();
721  return (double)elci->getNECLShowersRejectedBarrel();
722  }
723 
724  double nRejectedECLShowersBWDEndcap(const Particle*)
725  {
726  StoreObjPtr<EventLevelClusteringInfo> elci;
727  if (!elci) return std::numeric_limits<double>::quiet_NaN();
728  return (double)elci->getNECLShowersRejectedBWD();
729  }
730 
731  double nRejectedECLShowers(const Particle*)
732  {
733  StoreObjPtr<EventLevelClusteringInfo> elci;
734  if (!elci) return std::numeric_limits<double>::quiet_NaN();
735  return (double) elci->getNECLShowersRejected();
736  }
737 
738  double eclClusterEoP(const Particle* part)
739  {
740  double E = eclClusterE(part);
741  if (part->hasExtraInfo("bremsCorrectedPhotonEnergy")) {
742  E += part->getExtraInfo("bremsCorrectedPhotonEnergy");
743  }
744  const double p = part->getMomentumMagnitude();
745  if (0 == p) { return std::numeric_limits<float>::quiet_NaN();}
746  return E / p;
747  }
748 
749  double eclClusterOnlyInvariantMass(const Particle* part)
750  {
751  int nDaughters = part->getNDaughters();
752  TLorentzVector sum;
753 
754  if (nDaughters < 1) {
755  return part->getMass();
756  } else {
757  int nClusterDaughters = 0;
758  std::stack<const Particle*> stacked;
759  stacked.push(part);
760  while (!stacked.empty()) {
761  const Particle* current = stacked.top();
762  stacked.pop();
763 
764  const ECLCluster* cluster = current->getECLCluster();
765  if (cluster) {
766  const ECLCluster::EHypothesisBit clusterBit = current->getECLClusterEHypothesisBit();
767  nClusterDaughters ++;
768  ClusterUtils clutls;
769  TLorentzVector p4Cluster = clutls.Get4MomentumFromCluster(cluster, clusterBit);
770  sum += p4Cluster;
771  } else {
772  const std::vector<Particle*> daughters = current->getDaughters();
773  nDaughters = current->getNDaughters();
774  for (int iDaughter = 0; iDaughter < nDaughters; iDaughter++) {
775  stacked.push(daughters[iDaughter]);
776  }
777  }
778  }
779 
780  if (nClusterDaughters < 1) {
781  B2WARNING("There are no clusters amongst the daughters of the provided particle!");
782  return std::numeric_limits<double>::quiet_NaN();
783  }
784  B2DEBUG(10, "Number of daughters with cluster associated = " << nClusterDaughters);
785  return sum.M();
786  }
787  }
788 
789  Manager::FunctionPtr photonHasOverlap(const std::vector<std::string>& arguments)
790  {
791  std::string cutString = "";
792  if (arguments.size() > 0) {
793  cutString = arguments[0];
794  }
795  std::shared_ptr<Variable::Cut> cut = std::shared_ptr<Variable::Cut>(Variable::Cut::compile(cutString));
796 
797  std::string photonlistname = "gamma:all";
798  if (arguments.size() > 1) {
799  photonlistname = arguments[1];
800  }
801 
802  std::string tracklistname = "e-:all";
803  if (arguments.size() > 2) {
804  tracklistname = arguments[2];
805  }
806 
807  auto func = [cut, photonlistname, tracklistname](const Particle * particle) -> double {
808 
809  if (particle->getPDGCode() != Const::photon.getPDGCode())
810  {
811  B2WARNING("The variable photonHasOverlap is supposed to be calculated for photons. Returning NaN.");
812  return std::numeric_limits<double>::quiet_NaN();
813  }
814 
815  StoreObjPtr<ParticleList> photonlist(photonlistname);
816  if (!(photonlist.isValid()))
817  {
818  B2WARNING("The provided particle list " << photonlistname << " does not exist."
819  " Therefore, the variable photonHasOverlap can not be calculated. Returning NaN.");
820  return std::numeric_limits<double>::quiet_NaN();
821  }
822  if (photonlist->getPDGCode() != Const::photon.getPDGCode())
823  {
824  B2WARNING("The list " << photonlistname << " does not contain photons."
825  " Therefore, the variable photonHasOverlap can not be calculated reliably. Returning NaN.");
826  return std::numeric_limits<double>::quiet_NaN();
827  }
828 
829  StoreObjPtr<ParticleList> tracklist(tracklistname);
830  if (!(tracklist.isValid()))
831  {
832  B2WARNING("The provided particle list " << tracklistname << " does not exist."
833  " Therefore, the variable photonHasOverlap can not be calculated. Returning NaN.");
834  return std::numeric_limits<double>::quiet_NaN();
835  }
836  if (!Const::chargedStableSet.contains(Const::ParticleType(abs(tracklist->getPDGCode()))))
837  {
838  B2WARNING("The list " << tracklistname << " does not contain charged final state particles."
839  " Therefore, the variable photonHasOverlap can not be calculated reliably. Returning NaN.");
840  return std::numeric_limits<double>::quiet_NaN();
841  }
842 
843  double connectedRegionID = eclClusterConnectedRegionID(particle);
844  unsigned mdstArrayIndex = particle->getMdstArrayIndex();
845 
846  for (unsigned int i = 0; i < photonlist->getListSize(); i++)
847  {
848  const Particle* part = photonlist->getParticle(i);
849 
850  // skip the particle itself
851  if (part->getMdstArrayIndex() == mdstArrayIndex) {
852  continue;
853  }
854 
855  // skip photons that do not fulfill the provided criteria
856  if (!cut->check(part)) {
857  continue;
858  }
859 
860  if (connectedRegionID == eclClusterConnectedRegionID(part)) {
861  return 1;
862  }
863  }
864 
865  for (unsigned int i = 0; i < tracklist->getListSize(); i++)
866  {
867  const Particle* part = tracklist->getParticle(i);
868 
869  // skip tracks that do not fulfill the provided criteria
870  if (!cut->check(part)) {
871  continue;
872  }
873 
874  if (connectedRegionID == eclClusterConnectedRegionID(part)) {
875  return 1;
876  }
877  }
878 
879  return 0;
880  };
881  return func;
882  }
883 
884  VARIABLE_GROUP("ECL Cluster related");
885  REGISTER_VARIABLE("clusterEoP", eclClusterEoP, R"DOC(
886 Returns ratio of uncorrelated energy E over momentum p, a convenience
887 alias for (clusterE / p).
888 )DOC");
889  REGISTER_VARIABLE("clusterReg", eclClusterDetectionRegion, R"DOC(
890 Returns an integer code for the ECL region of a cluster.
891 
892  - 1: forward, 2: barrel, 3: backward,
893  - 11: between FWD and barrel, 13: between BWD and barrel,
894  - 0: otherwise
895 )DOC");
896  REGISTER_VARIABLE("clusterDeltaLTemp", eclClusterDeltaL, R"DOC(
897 | Returns DeltaL for the shower shape.
898 | A cluster comprises the energy depositions of several crystals. All these crystals have slightly
899  different orientations in space. A shower direction can be constructed by calculating the weighted
900  average of these orientations using the corresponding energy depositions as weights. The intersection
901  (more precisely the point of closest approach) of the vector with this direction originating from the
902  cluster center and an extrapolated track can be used as reference for the calculation of the shower
903  depth. It is defined as the distance between this intersection and the cluster center.
904 
905 .. warning::
906  This distance is calculated on the reconstructed level and is temporarily
907  included to the ECL cluster MDST data format for studying purposes. If it is found
908  that it is not crucial for physics analysis then this variable will be removed
909  in future releases.
910  Therefore, keep in mind that this variable might be removed in the future!
911 
912 .. note::
913  | Please read `this <importantNoteECL>` first.
914  | Lower limit: :math:`-250.0`
915  | Upper limit: :math:`250.0`
916  | Precision: :math:`10` bit
917 )DOC");
918 
919 
920  REGISTER_VARIABLE("minC2TDist", eclClusterIsolation, R"DOC(
921 Returns distance between ECL cluster and nearest track hitting the ECL.
922 
923 A cluster comprises the energy depositions of several crystals. All these crystals have slightly
924 different orientations in space. A shower direction can be constructed by calculating the weighted
925 average of these orientations using the corresponding energy depositions as weights. The intersection
926 (more precisely the point of closest approach) of the vector with this direction originating from the
927 cluster center and an extrapolated track can be used as reference for the calculation of the track depth.
928 It is defined as the distance between this intersection and the track hit position on the front face of the ECL.
929 
930 .. note::
931  This distance is calculated on the reconstructed level.
932 
933 .. note::
934  | Please read `this <importantNoteECL>` first.
935  | Lower limit: :math:`0.0`
936  | Upper limit: :math:`250.0`
937  | Precision: :math:`10` bit
938 )DOC");
939  REGISTER_VARIABLE("minC2TDistID", eclClusterIsolationID, "Nearest track array index");
940  REGISTER_VARIABLE("minC2TDistVar(variable,particleList=pi-:all)", eclClusterIsolationVar, R"DOC(
941 Returns variable value for the nearest track to the given ECL cluster. First argument is a variable name, e.g. nCDCHits.
942 The second argument is the particle list name which will be used to pick up the nearest track, default is pi-:all.
943 )DOC");
944  REGISTER_VARIABLE("clusterE", eclClusterE, R"DOC(
945 Returns ECL cluster's energy corrected for leakage and background.
946 
947 The raw photon energy is given by the weighted sum of all ECL crystal energies within the ECL cluster.
948 The weights per crystals are :math:`\leq 1` after cluster energy splitting in the case of overlapping
949 clusters. The number of crystals that are included in the sum depends on a initial energy estimation
950 and local beam background levels at the highest energy crystal position. It is optimized to minimize
951 the core width (resolution) of true photons. Photon energy distributions always show a low energy tail
952 due to unavoidable longitudinal and transverse leakage that can be further modified by the clustering
953 algorithm and beam backgrounds.The peak position of the photon energy distributions are corrected to
954 match the true photon energy in MC:
955 
956  - Leakage correction: Using large MC samples of mono-energetic single photons, a correction factor
957  :math:`f` as function of reconstructed detector position, reconstructed photon energy and beam backgrounds
958  is determined via :math:`f = \frac{\text{peak_reconstructed}}{\text{energy_true}}`.
959 
960  - Cluster energy calibration (data only): To reach the target precision of :math:`< 1.8\%` energy
961  resolution for high energetic photons, the remaining difference between MC and data must be calibrated
962  using kinematically fit muon pairs. This calibration is only applied to data and not to MC and will
963  take time to develop.
964 
965  - Energy Bias Correction module, sub-percent correction, is NOT applied on clusterE, but on photon energy
966  and momentum. Only applied to data.
967 
968 It is important to note that after perfect leakage correction and cluster energy calibration,
969 the :math:`\pi^{0}` mass peak will be shifted slightly to smaller values than the PDG average
970 due to the low energy tails of photons. The :math:`\pi^{0}` mass peak must not be corrected
971 to the PDG value by adjusting the reconstructed photon energies. Selection criteria based on
972 the mass for :math:`\pi^{0}` candidates must be based on the biased value. Most analysis
973 will used mass constrained :math:`\pi^{0}` s anyhow.
974 
975 .. warning::
976  We only store clusters with :math:`E > 20\,` MeV.
977 
978 .. note::
979  | Please read `this <importantNoteECL>` first.
980  | Lower limit: :math:`-5` (:math:`e^{-5} = 0.00674\,` GeV)
981  | Upper limit: :math:`3.0` (:math:`e^3 = 20.08553\,` GeV)
982  | Precision: :math:`18` bit
983  | This value can be changed to a different reference frame with :b2:var:`useCMSFrame`.
984 )DOC");
985  REGISTER_VARIABLE("clusterErrorE", eclClusterErrorE, R"DOC(
986 Returns ECL cluster's uncertainty on energy
987 (from background level and energy dependent tabulation).
988 )DOC");
989  REGISTER_VARIABLE("clusterErrorPhi", eclClusterErrorPhi, R"DOC(
990 Returns ECL cluster's uncertainty on :math:`\phi`
991 (from background level and energy dependent tabulation).
992 )DOC");
993  REGISTER_VARIABLE("clusterErrorTheta", eclClusterErrorTheta, R"DOC(
994 Returns ECL cluster's uncertainty on :math:`\theta`
995 (from background level and energy dependent tabulation).
996 )DOC");
997 
998  REGISTER_VARIABLE("clusterR", eclClusterR, R"DOC(
999 Returns ECL cluster's centroid distance from :math:`(0,0,0)`.
1000 )DOC");
1001  REGISTER_VARIABLE("clusterPhi", eclClusterPhi, R"DOC(
1002 Returns ECL cluster's azimuthal angle :math:`\phi`
1003 (this is not generally equal to a photon azimuthal angle).
1004 
1005 | The direction of a cluster is given by the connecting line of :math:`\,(0,0,0)\,` and
1006  cluster centroid position in the ECL.
1007 | The cluster centroid position is calculated using up to 21 crystals (5x5 excluding corners)
1008  after cluster energy splitting in the case of overlapping clusters.
1009 | The centroid position is the logarithmically weighted average of all crystals evaluated at
1010  the crystal centers. Cluster centroids are generally biased towards the centers of the
1011  highest energetic crystal. This effect is larger for low energetic photons.
1012 | Beam backgrounds slightly decrease the position resolution, mainly for low energetic photons.
1013 
1014 .. note::
1015  Radius of a cluster is almost constant in the barrel and should not be used directly in any selection.
1016 
1017 Unlike for charged tracks, the uncertainty (covariance) of the photon directions is not determined
1018 based on individual cluster properties but taken from on MC-based parametrizations of the resolution
1019 as function of true photon energy, true photon direction and beam background level.
1020 
1021 .. warning::
1022  Users must use the actual particle direction (done automatically in the modularAnalysis using the average
1023  IP position (can be changed if needed)) and not the ECL Cluster direction (position in the ECL measured
1024  from :math:`(0,0,0)`) for particle kinematics.
1025 
1026 .. note::
1027  | Please read `this <importantNoteECL>` first.
1028  | Lower limit: :math:`-\pi`
1029  | Upper limit: :math:`\pi`
1030  | Precision: :math:`16` bit
1031 )DOC");
1032  REGISTER_VARIABLE("clusterConnectedRegionID", eclClusterConnectedRegionID, R"DOC(
1033 Returns ECL cluster's connected region ID.
1034 )DOC");
1035  REGISTER_VARIABLE("clusterTheta", eclClusterTheta, R"DOC(
1036 Returns ECL cluster's polar angle :math:`\theta`
1037 (this is not generally equal to a photon polar angle).
1038 
1039 | The direction of a cluster is given by the connecting line of :math:`\,(0,0,0)\,` and
1040  cluster centroid position in the ECL.
1041 | The cluster centroid position is calculated using up to 21 crystals (5x5 excluding corners)
1042  after cluster energy splitting in the case of overlapping clusters.
1043 | The centroid position is the logarithmically weighted average of all crystals evaluated at
1044  the crystal centers. Cluster centroids are generally biased towards the centers of the
1045  highest energetic crystal. This effect is larger for low energetic photons.
1046 | Beam backgrounds slightly decrease the position resolution, mainly for low energetic photons.
1047 
1048 .. note::
1049  Radius of a cluster is almost constant in the barrel and should not be used directly in any selection.
1050 
1051 Unlike for charged tracks, the uncertainty (covariance) of the photon directions is not determined
1052 based on individual cluster properties but taken from on MC-based parametrizations of the resolution
1053 as function of true photon energy, true photon direction and beam background level.
1054 
1055 .. warning::
1056  Users must use the actual particle direction (done automatically in the modularAnalysis using the average
1057  IP position (can be changed if needed)) and not the ECL Cluster direction (position in the ECL measured
1058  from :math:`(0,0,0)`) for particle kinematics.
1059 
1060 .. note::
1061  | Please read `this <importantNoteECL>` first.
1062  | Lower limit: :math:`0.0`
1063  | Upper limit: :math:`\pi`
1064  | Precision: :math:`16` bit
1065 )DOC");
1066  REGISTER_VARIABLE("clusterTiming", eclClusterTiming, R"DOC(
1067 Returns the time of the ECL cluster. It is calculated as the Photon timing minus the Event t0.
1068 Photon timing is given by the fitted time of the recorded waveform of the highest energy crystal in the
1069 cluster. After all calibrations and corrections (including Time-Of-Flight), photons from the interaction
1070 point (IP) should have a Photon timing that corresponds to the Event t0, :math:`t_{0}`. The Event t0 is the
1071 time of the event and may be measured by a different sub-detector (see Event t0 documentation). For an ECL
1072 cluster produced at the interaction point in time with the event, the cluster time should be consistent with zero
1073 within the uncertainties. Special values are returned if the fit for the Photon timing fails (see
1074 documentation for `clusterHasFailedTiming`). (For MC, the calibrations and corrections are not fully simulated).
1075 
1076 .. note::
1077  | Please read `this <importantNoteECL>` first.
1078  | Lower limit: :math:`-1000.0`
1079  | Upper limit: :math:`1000.0`
1080  | Precision: :math:`12` bit
1081 )DOC");
1082  REGISTER_VARIABLE("clusterHasFailedTiming", eclClusterHasFailedTiming, R"DOC(
1083 Status bit for if the ECL cluster's timing fit failed. Photon timing is given by the fitted time
1084 of the recorded waveform of the highest energetic crystal in a cluster; however, that fit can fail and so
1085 this variable tells the user if that has happened.
1086 )DOC");
1087  REGISTER_VARIABLE("clusterErrorTiming", eclClusterErrorTiming, R"DOC(
1088 Returns ECL cluster's timing uncertainty that contains :math:`99\%` of true photons (dt99).
1089 
1090 The photon timing uncertainty is currently determined using MC. The resulting parametrization depends on
1091 the true energy deposition in the highest energetic crystal and the local beam background level in that crystal.
1092 The resulting timing distribution is non-Gaussian and for each photon the value dt99 is stored,
1093 where :math:`|\text{timing}| / \text{dt99} < 1` is designed to give a :math:`99\%`
1094 timing efficiency for true photons from the IP.
1095 The resulting efficiency is approximately flat in energy and independent of beam background levels.
1096 
1097 Very large values of dt99 are an indication of failed waveform fits in the ECL.
1098 We remove such clusters in most physics photon lists.
1099 
1100 .. note::
1101  | Please read `this <importantNoteECL>` first.
1102  | Lower limit: :math:`0.0`
1103  | Upper limit: :math:`1000.0`
1104  | Precision: :math:`12` bit
1105 
1106 .. warning::
1107  In real data there will be a sizeable number of high energetic Bhabha events
1108  (from previous or later bunch collisions) that can easily be rejected by timing cuts.
1109  However, these events create large ECL clusters that can overlap with other ECL clusters
1110  and it is not clear that a simple rejection is the correction strategy.
1111 )DOC");
1112  REGISTER_VARIABLE("clusterHasFailedErrorTiming", eclClusterHasFailedErrorTiming, R"DOC(
1113 Status bit for if the ECL cluster's timing uncertainty calculation failed. Photon timing is given by the fitted time
1114 of the recorded waveform of the highest energetic crystal in a cluster; however, that fit can fail and so
1115 this variable tells the user if that has happened.
1116 )DOC");
1117  REGISTER_VARIABLE("clusterHighestE", eclClusterHighestE, R"DOC(
1118 Returns energy of the highest energetic crystal in the ECL cluster after reweighting.
1119 
1120 .. warning::
1121  This variable must be used carefully since it can bias shower selection
1122  towards photons that hit crystals in the center and hence have a large energy
1123  deposition in the highest energy crystal.
1124 
1125 .. note::
1126  | Please read `this <importantNoteECL>` first.
1127  | Lower limit: :math:`-5` (:math:`e^{-5} = 0.00674\,` GeV)
1128  | Upper limit: :math:`3.0` (:math:`e^3 = 20.08553\,` GeV)
1129  | Precision: :math:`18` bit
1130 )DOC");
1131  REGISTER_VARIABLE("clusterCellID", eclClusterCellId,
1132  "Returns cellId of the crystal with highest energy in the ECLCluster.");
1133  REGISTER_VARIABLE("clusterThetaID", eclClusterThetaId,
1134  "Returns thetaId of the crystal with highest energy in the ECLCluster.");
1135  REGISTER_VARIABLE("clusterPhiID", eclClusterPhiId,
1136  "Returns phiId of the crystal with highest energy in the ECLCluster.");
1137  REGISTER_VARIABLE("clusterE1E9", eclClusterE1E9, R"DOC(
1138 Returns ratio of energies of the central crystal, E1, and 3x3 crystals, E9, around the central crystal.
1139 Since :math:`E1 \leq E9`, this ratio is :math:`\leq 1` and tends towards larger values for photons
1140 and smaller values for hadrons.
1141 
1142 .. note::
1143  | Please read `this <importantNoteECL>` first.
1144  | Lower limit: :math:`0.0`
1145  | Upper limit: :math:`1.0`
1146  | Precision: :math:`10` bit
1147 )DOC");
1148  REGISTER_VARIABLE("clusterE9E25", eclClusterE9E25, R"DOC(
1149 Deprecated - kept for backwards compatibility - returns clusterE9E21.
1150 )DOC");
1151  REGISTER_VARIABLE("clusterE9E21", eclClusterE9E21, R"DOC(
1152 Returns ratio of energies in inner 3x3 crystals, E9, and 5x5 crystals around the central crystal without corners.
1153 Since :math:`E9 \leq E21`, this ratio is :math:`\leq 1` and tends towards larger values for photons
1154 and smaller values for hadrons.
1155 
1156 .. note::
1157  | Please read `this <importantNoteECL>` first.
1158  | Lower limit: :math:`0.0`
1159  | Upper limit: :math:`1.0`
1160  | Precision: :math:`10` bit
1161 )DOC");
1162  REGISTER_VARIABLE("clusterAbsZernikeMoment40", eclClusterAbsZernikeMoment40, R"DOC(
1163 Returns absolute value of Zernike moment 40 (:math:`|Z_{40}|`). (shower shape variable).
1164 
1165 .. note::
1166  | Please read `this <importantNoteECL>` first.
1167  | Lower limit: :math:`0.0`
1168  | Upper limit: :math:`1.7`
1169  | Precision: :math:`10` bit
1170 )DOC");
1171  REGISTER_VARIABLE("clusterAbsZernikeMoment51", eclClusterAbsZernikeMoment51, R"DOC(
1172 Returns absolute value of Zernike moment 51 (:math:`|Z_{51}|`). (shower shape variable).
1173 
1174 .. note::
1175  | Please read `this <importantNoteECL>` first.
1176  | Lower limit: :math:`0.0`
1177  | Upper limit: :math:`1.2`
1178  | Precision: :math:`10` bit
1179 )DOC");
1180  REGISTER_VARIABLE("clusterZernikeMVA", eclClusterZernikeMVA, R"DOC(
1181 Returns output of a MVA using eleven Zernike moments of the cluster. Zernike moments are calculated per
1182 shower in a plane perpendicular to the shower direction via
1183 
1184 .. math::
1185  |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|
1186 
1187 where n, m are the integers, :math:`i` runs over the crystals in the shower,
1188 :math:`E_{i}` is the energy of the i-th crystal in the shower,
1189 :math:`R_{nm}` is a polynomial of degree :math:`n`,
1190 :math:`\rho_{i}` is the radial distance of the :math:`i`-th crystal in the perpendicular plane,
1191 and :math:`\alpha_{i}` is the polar angle of the :math:`i`-th crystal in the perpendicular plane.
1192 As a crystal can be related to more than one shower, :math:`w_{i}` is the fraction of the
1193 energy of the :math:`i`-th crystal associated with the shower.
1194 
1195 More details about the implementation can be found in `BELLE2-NOTE-TE-2017-001 <https://docs.belle2.org/record/454?ln=en>`_ .
1196 
1197 More details about Zernike polynomials can be found in `Wikipedia <https://en.wikipedia.org/wiki/Zernike_polynomials>`_ .
1198 
1199 | For cluster with hypothesisId==N1: raw MVA output.
1200 | For cluster with hypothesisId==N2: 1 - prod{clusterZernikeMVA}, where the product is on all N1 showers
1201  belonging to the same connected region (shower shape variable).
1202 
1203 .. note::
1204  | Please read `this <importantNoteECL>` first.
1205  | Lower limit: :math:`0.0`
1206  | Upper limit: :math:`1.0`
1207  | Precision: :math:`10` bit
1208 )DOC");
1209  REGISTER_VARIABLE("clusterSecondMoment", eclClusterSecondMoment, R"DOC(
1210 Returns second moment :math:`S`. It is defined as:
1211 
1212 .. math::
1213  S = \frac{\sum_{i=0}^{n} w_{i} E_{i} r^2_{i}}{\sum_{i=0}^{n} w_{i} E_{i}}
1214 
1215 where :math:`E_{i} = (E_0, E_1, ...)` are the single crystal energies sorted by energy, :math:`w_{i}` is
1216 the crystal weight, and :math:`r_{i}` is the distance of the :math:`i`-th digit to the shower center projected
1217 to a plane perpendicular to the shower axis.
1218 
1219 .. note::
1220  | Please read `this <importantNoteECL>` first.
1221  | Lower limit: :math:`0.0`
1222  | Upper limit: :math:`40.0`
1223  | Precision: :math:`10` bit
1224 )DOC");
1225  REGISTER_VARIABLE("clusterLAT", eclClusterLAT, R"DOC(
1226 Returns lateral energy distribution (shower variable). It is defined as following:
1227 
1228 .. math::
1229  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}}
1230 
1231 where :math:`E_{i} = (E_{0}, E_{1}, ...)` are the single crystal energies sorted by energy
1232 (:math:`E_{0}` is the highest energy and :math:`E_{1}` the second highest), :math:`w_{i}`
1233 is the crystal weight, :math:`r_{i}` is the distance of the :math:`i`-th digit to the
1234 shower center projected to a plane perpendicular to the shower axis,
1235 and :math:`r_{0} \approx 5\,cm` is the distance between two crystals.
1236 
1237 clusterLAT peaks around 0.3 for radially symmetrical electromagnetic showers and is larger
1238 for hadronic events, and electrons with a close-by radiative or Bremsstrahlung photon.
1239 
1240 .. note::
1241  | Please read `this <importantNoteECL>` first.
1242  | Lower limit: :math:`0.0`
1243  | Upper limit: :math:`1.0`
1244  | Precision: :math:`10` bit
1245 )DOC");
1246  REGISTER_VARIABLE("clusterNHits", eclClusterNHits, R"DOC(
1247 Returns sum of weights :math:`w_{i}` (:math:`w_{i} \leq 1`) of all crystals in an ECL cluster.
1248 For non-overlapping clusters this is equal to the number of crystals in the cluster.
1249 In case of energy splitting among nearby clusters, this can be a non-integer value.
1250 
1251 .. note::
1252  | Please read `this <importantNoteECL>` first.
1253  | Lower limit: :math:`0.0`
1254  | Upper limit: :math:`200.0`
1255  | Precision: :math:`10` bit
1256  | If fractional weights are not of interest, this value should be cast to the nearest integer.
1257 )DOC");
1258  REGISTER_VARIABLE("clusterTrackMatch", eclClusterTrackMatched, R"DOC(
1259 Returns 1.0 if at least one reconstructed charged track is matched to the ECL cluster.
1260 
1261 Every reconstructed charged track is extrapolated into the ECL.
1262 Every ECL crystal that is crossed by the track extrapolation is marked.
1263 Each ECL cluster that contains any marked crystal is matched to the track.
1264 Multiple tracks can be matched to one cluster and multiple clusters can be matched to one track.
1265 It is conceptually correct to have two tracks matched to the same cluster.
1266 )DOC");
1267  REGISTER_VARIABLE("nECLClusterTrackMatches", nECLClusterTrackMatches, R"DOC(
1268 Returns number of charged tracks matched to this cluster.
1269 
1270 .. note::
1271  Sometimes (perfectly correctly) two tracks are extrapolated into the same cluster.
1272 
1273  - For charged particles, this should return at least 1 (but sometimes 2 or more).
1274  - For neutrals, this should always return 0.
1275  - Returns NaN if there is no cluster.
1276 )DOC");
1277  REGISTER_VARIABLE("clusterHasPulseShapeDiscrimination", eclClusterHasPulseShapeDiscrimination, R"DOC(
1278 Status bit to indicate if cluster has digits with waveforms that passed energy and :math:`\chi^2`
1279 thresholds for computing PSD variables.
1280 )DOC");
1281  REGISTER_VARIABLE("beamBackgroundProbabilityMVA", beamBackgroundProbabilityMVA, R"DOC(
1282 Returns MVA classifier that uses shower shape variables to distinguish true clusters from beam background clusters.
1283 
1284  - 1 for true photon clusters
1285  - 0 for beam background clusters
1286 
1287 The variables used in the training (in decreasing order of significance): clusterTiming, clusterE, clusterTheta,
1288 clusterZernikeMVA, clusterE1E9, clusterLat, clusterSecondMoment and clusterPhi. )DOC");
1289  REGISTER_VARIABLE("clusterKlId", eclClusterKlId, R"DOC(
1290 Returns MVA classifier that uses ECL clusters variables to discriminate Klong clusters from em background.
1291 
1292  - 1 for Kl
1293  - 0 for background
1294 )DOC");
1295  REGISTER_VARIABLE("clusterPulseShapeDiscriminationMVA", eclPulseShapeDiscriminationMVA, R"DOC(
1296 Returns MVA classifier that uses pulse shape discrimination to identify electromagnetic vs hadronic showers.
1297 
1298  - 1 for electromagnetic showers
1299  - 0 for hadronic showers
1300 )DOC");
1301  REGISTER_VARIABLE("clusterNumberOfHadronDigits", eclClusterNumberOfHadronDigits, R"DOC(
1302 Returns ECL cluster's number of hadron digits in cluster (pulse shape discrimination variable).
1303 Weighted sum of digits in cluster with significant scintillation emission (:math:`> 3\,` MeV)
1304 in the hadronic scintillation component.
1305 Computed only using cluster digits with energy :math:`> 50\,` MeV and good offline waveform fit :math:`\chi^2`.
1306 
1307 .. note::
1308  | Please read `this <importantNoteECL>` first.
1309  | Lower limit: :math:`0.0`
1310  | Upper limit: :math:`255.0`
1311  | Precision: :math:`18` bit
1312 )DOC");
1313  REGISTER_VARIABLE("clusterClusterID", eclClusterId, R"DOC(
1314 Returns ECL cluster ID of this ECL cluster within the connected region (CR) to which it belongs to.
1315 )DOC");
1316  REGISTER_VARIABLE("clusterHasNPhotons", eclClusterHasNPhotonsHypothesis, R"DOC(
1317 Returns 1.0 if cluster has the 'N photons' hypothesis (historically called 'N1'),
1318 0.0 if not, and NaN if no cluster is associated to the particle.
1319 )DOC");
1320  REGISTER_VARIABLE("clusterHasNeutralHadron", eclClusterHasNeutralHadronHypothesis, R"DOC(
1321 Returns 1.0 if the cluster has the 'neutral hadrons' hypothesis (historically called 'N2'),
1322 0.0 if not, and NaN if no cluster is associated to the particle.
1323 )DOC");
1324  REGISTER_VARIABLE("eclExtTheta", eclExtTheta, R"DOC(
1325 Returns extrapolated :math:`\theta`.
1326 )DOC");
1327  REGISTER_VARIABLE("eclExtPhi", eclExtPhi, R"DOC(
1328 Returns extrapolated :math:`\phi`.
1329 )DOC");
1330  REGISTER_VARIABLE("eclExtPhiId", eclExtPhiId, R"DOC(
1331 Returns extrapolated :math:`\phi` ID.
1332 )DOC");
1333  REGISTER_VARIABLE("weightedAverageECLTime", weightedAverageECLTime, R"DOC(
1334 Returns ECL weighted average time of all clusters (neutrals) and matched clusters (charged) of daughters
1335 (of any generation) of the provided particle.
1336 )DOC");
1337  REGISTER_VARIABLE("maxWeightedDistanceFromAverageECLTime", maxWeightedDistanceFromAverageECLTime, R"DOC(
1338 Returns maximum weighted distance between time of the cluster of a photon and the ECL average time, amongst
1339 the clusters (neutrals) and matched clusters (charged) of daughters (of all generations) of the provided particle.
1340 )DOC");
1341  REGISTER_VARIABLE("clusterMdstIndex", eclClusterMdstIndex, R"DOC(
1342 StoreArray index(0 - based) of the MDST ECLCluster (useful for track-based particles matched to a cluster).
1343 )DOC");
1344 
1345  REGISTER_VARIABLE("nECLOutOfTimeCrystals", nECLOutOfTimeCrystals, R"DOC(
1346 [Eventbased] Returns the number of crystals (ECLCalDigits) that are out of time.
1347 )DOC");
1348 
1349  REGISTER_VARIABLE("nECLOutOfTimeCrystalsFWDEndcap", nECLOutOfTimeCrystalsFWDEndcap, R"DOC(
1350 [Eventbased] Returns the number of crystals (ECLCalDigits) that are out of time in the forward endcap.
1351 )DOC");
1352 
1353  REGISTER_VARIABLE("nECLOutOfTimeCrystalsBarrel", nECLOutOfTimeCrystalsBarrel, R"DOC(
1354 [Eventbased] Returns the number of crystals (ECLCalDigits) that are out of time in the barrel.
1355 )DOC");
1356 
1357  REGISTER_VARIABLE("nECLOutOfTimeCrystalsBWDEndcap", nECLOutOfTimeCrystalsBWDEndcap, R"DOC(
1358 [Eventbased] Returns the number of crystals (ECLCalDigits) that are out of time in the backward endcap.
1359 )DOC");
1360 
1361  REGISTER_VARIABLE("nRejectedECLShowers", nRejectedECLShowers, R"DOC(
1362 [Eventbased] Returns the number of showers in the ECL that do not become clusters.
1363 )DOC");
1364 
1365  REGISTER_VARIABLE("nRejectedECLShowersFWDEndcap", nRejectedECLShowersFWDEndcap, R"DOC(
1366 [Eventbased] Returns the number of showers in the ECL that do not become clusters, from the forward endcap.
1367 )DOC");
1368 
1369  REGISTER_VARIABLE("nRejectedECLShowersBarrel", nRejectedECLShowersBarrel, R"DOC(
1370 [Eventbased] Returns the number of showers in the ECL that do not become clusters, from the barrel.
1371 )DOC");
1372 
1373  REGISTER_VARIABLE("nRejectedECLShowersBWDEndcap", nRejectedECLShowersBWDEndcap, R"DOC(
1374 [Eventbased] Returns the number of showers in the ECL that do not become clusters, from the backward endcap.
1375 )DOC");
1376 
1377  REGISTER_VARIABLE("eclClusterOnlyInvariantMass", eclClusterOnlyInvariantMass, R"DOC(
1378 [Expert] The invariant mass calculated from all ECLCluster daughters (i.e. photons) and
1379 cluster-matched tracks using the cluster 4-momenta.
1380 
1381 Used for ECL-based dark sector physics and debugging track-cluster matching.
1382 )DOC");
1383 
1384  REGISTER_VARIABLE("photonHasOverlap(cutString, photonlistname, tracklistname)", photonHasOverlap, R"DOC(
1385  Returns true if the connected ECL region of the particle's cluster is shared by another particle's cluster.
1386  Neutral and charged cluster are considered.
1387  A cut string can be provided to ignore cluster that do not satisfy the given criteria.
1388  By default, the ParticleList ``gamma:all`` is used for the check of neutral ECL cluster,
1389  and the ParticleList ``e-:all`` for the check of charged ECL cluster.
1390  However, one can customize the name of the ParticleLists via additional arguments.
1391  If no argument or only a cut string is provided and ``gamma:all`` or ``e-:all`` does not exist
1392  or if the variable is requested for a particle that is not a photon, NaN is returned.
1393  )DOC");
1394 
1395  REGISTER_VARIABLE("clusterUncorrE", eclClusterUncorrectedE, R"DOC(
1396 [Expert] [Calibration] Returns ECL cluster's uncorrected energy. That is, before leakage corrections.
1397 This variable should only be used for study of the ECL. Please see :b2:var:`clusterE`.
1398 )DOC");
1399 
1400  }
1402 }
int getPDGCode() const
PDG code.
Definition: Const.h:354
static const ParticleSet chargedStableSet
set of charged stable particles
Definition: Const.h:499
static const ParticleType photon
photon particle
Definition: Const.h:554
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)
@ c_neutralHadron
CR is reconstructed as a neutral hadron (N2)
static std::unique_ptr< GeneralCut > compile(const std::string &cut)
Creates an instance of a cut and returns a unique_ptr to it, if you need a copy-able object instead y...
Definition: GeneralCut.h:104
static const ReferenceFrame & GetCurrent()
Get current rest frame.
const Var * getVariable(std::string name)
Get the variable belonging to the given key.
Definition: Manager.cc:31
static Manager & Instance()
get singleton instance.
Definition: Manager.cc:25
std::function< double(const Particle *)> FunctionPtr
NOTE: the python interface is documented manually in analysis/doc/Variables.rst (because we use ROOT ...
Definition: Manager.h:108
Abstract base class for different kinds of events.