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