Belle II Software  release-05-02-19
ECLEventT0Module.cc
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2018 - Belle II Collaboration *
4  * *
5  * Author: The Belle II Collaboration *
6  * Contributors: Christopher Hearty hearty@physics.ubc.ca *
7  * *
8  * This software is provided "as is" without any warranty. *
9  **************************************************************************/
10 //This module
11 #include <ecl/modules/eclEventT0/ECLEventT0Module.h>
12 
13 //Root
14 #include <TMath.h>
15 
16 //Frameork
17 #include <framework/dataobjects/EventT0.h>
18 
19 //ECL
20 #include <ecl/dataobjects/ECLCalDigit.h>
21 
22 using namespace Belle2;
23 using namespace std;
24 
25 //-----------------------------------------------------------------
26 // Register the Module
27 //-----------------------------------------------------------------
28 REG_MODULE(ECLEventT0)
29 
30 //-----------------------------------------------------------------
31 // Implementation
32 //-----------------------------------------------------------------
33 
35 {
36  // Set module properties
37  setDescription("EventT0 calculated using ECLCalDigits");
38  addParam("ethresh", m_ethresh, "Minimum energy (GeV) for an ECLCalDigit to be used", 0.06);
39  addParam("maxDigitT", m_maxDigitT, "Maximum absolute time (ns) for an ECLCalDigit to be used", 150.);
40  addParam("sigmaScale", m_sigmaScale, "Scale factor between dt99 and ECLCalDigit time resolution", 0.15);
41  addParam("maxT0", m_maxT0, "Maximum absolute value (ns) for T0", 135.);
42  addParam("T0bin", m_T0bin, "Step size between T0 hypotheses (ns)", 1.);
43  addParam("primaryT0", m_primaryT0, "Select which T0 estimate is primary", 0);
44  setPropertyFlags(c_ParallelProcessingCertified);
45 }
46 
48 {
50  m_eventT0.registerInDataStore();
51  m_eclCalDigitArray.isRequired();
52 }
53 
55 {
56 
57  //-----------------------------------------------------------------
59  std::vector<float> tLike;
60  std::vector<float> sigmaLike;
61  float tmin = 9999.;
62  int itmin = -1;
63  float tmax = -9999.;
64  int itmax = -1;
65  for (auto& eclCalDigit : m_eclCalDigitArray) {
66  float digitT = eclCalDigit.getTime();
67  float dt99 = eclCalDigit.getTimeResolution();
68  if (eclCalDigit.getEnergy() > m_ethresh && abs(digitT) < m_maxDigitT && dt99 < 1000.) {
69  tLike.push_back(digitT);
70  sigmaLike.push_back(dt99 * m_sigmaScale);
71  if (digitT < tmin) {
72  tmin = digitT;
73  itmin = tLike.size() - 1;
74  }
75  if (digitT > tmax) {
76  tmax = digitT;
77  itmax = tLike.size() - 1;
78  }
79  }
80  }
81  int nLike = tLike.size();
82 
83  //-----------------------------------------------------------------
85  double T0 = -99999.;
86  double T0Unc = m_maxT0;
87  double quality = NAN;
88  int nT0Values = 0;
89  std::vector<float> localT0;
90  std::vector<float> localT0Unc;
91  std::vector<float> localquality;
92 
93  if (nLike == 1) {
94  nT0Values = 1;
95  T0 = tLike[0];
96  T0Unc = sigmaLike[0];
97  quality = 0;
98  localT0.push_back(T0);
99  localT0Unc.push_back(T0Unc);
100  localquality.push_back(0.);
101 
102  } else if (nLike >= 2) {
103 
104  //-----------------------------------------------------------------
106  float minrange = 50.; /* performance is not sensitive to the particular value */
107  tmin = tLike[itmin] - 3 * sigmaLike[itmin]; /* 3 sigma to ensure minima is away from boundary. Specific value is not important. */
108  if (tmin < -m_maxT0) {tmin = -m_maxT0;}
109  tmax = tLike[itmax] + 3 * sigmaLike[itmax];
110  if (tmax > m_maxT0) {tmax = m_maxT0;}
111 
112  if (tmin > m_maxT0 - minrange) {
113  tmin = m_maxT0 - minrange;
114  tmax = m_maxT0;
115  } else if (tmax < minrange - m_maxT0) {
116  tmin = -m_maxT0;
117  tmax = minrange - m_maxT0;
118  } else if (tmax - tmin < minrange) {
119  float drange = 0.5 * (minrange + tmin - tmax);
120  tmin = tmin - drange;
121  tmax = tmax + drange;
122  }
123 
124  //-----------------------------------------------------------------
126  int nhypo = (0.5 + tmax - tmin) / m_T0bin;
127  float trange = nhypo * m_T0bin;
128  std::vector<float> t0hypo;
129  for (int it0 = 0; it0 < nhypo; it0++) {
130  t0hypo.push_back(tmin + (it0 + 0.5)*m_T0bin);
131  }
132 
133  //-----------------------------------------------------------------
135  std::vector<float> sigFracVsT0(nhypo, 0.);
136  std::vector<float> chiVsT0(nhypo, 0.);
137  float minChi2 = 99999.;
138  int it0minChi2 = -1;
139  for (int it0 = 0; it0 < nhypo; it0++) {
140  float n3sig = 0.;
141  for (int iLike = 0; iLike < nLike; iLike++) {
142  if (abs(tLike[iLike] - t0hypo[it0]) < 3.*sigmaLike[iLike]) {n3sig++;}
143  }
144  float signalFrac = n3sig / nLike;
145  sigFracVsT0[it0] = signalFrac;
146 
148  float chi2 = 0.;
149  for (int iLike = 0; iLike < nLike; iLike++) {
150  float arg = (tLike[iLike] - t0hypo[it0]) / sigmaLike[iLike];
151  float sigProb = sigFracVsT0[it0] * TMath::Exp(-0.5 * arg * arg) / sigmaLike[iLike] / sqrt(2.*TMath::Pi()) +
152  (1. - sigFracVsT0[it0]) / trange;
153  chi2 += -2.*TMath::Log(sigProb);
154  }
155  chiVsT0[it0] = chi2;
156 
158  if (chi2 < minChi2) {
159  minChi2 = chi2;
160  it0minChi2 = it0;
161  }
162  }
163 
164  //-----------------------------------------------------------------
165  /* Look for local minima in the chi square vs T0 hypothesis distribution. */
166  /* Local minima have negative slope on the lower side, positive slope on the upper. */
167  /* Calculate slope using the bin and its neighbour, if they have the same sigFrac; */
168  /* otherwise, use the closest adjacent pair that do have the same sigFrac. */
169 
171  std::vector<float> LHslope(nhypo, 0.);
172  float slope = 0.;
173  for (int it0 = 1; it0 < nhypo; it0++) {
174  if (sigFracVsT0[it0 - 1] == sigFracVsT0[it0]) {
175  slope = chiVsT0[it0] - chiVsT0[it0 - 1];
176  }
177  LHslope[it0] = slope;
178  }
179 
181  std::vector<float> HLslope(nhypo, 0.);
182  slope = 0.;
183  for (int it0 = nhypo - 2; it0 >= 0; it0--) {
184  if (sigFracVsT0[it0] == sigFracVsT0[it0 + 1]) {
185  slope = chiVsT0[it0 + 1] - chiVsT0[it0];
186  }
187  HLslope[it0] = slope;
188  }
189 
190  //-----------------------------------------------------------------
192  /* and the one closest to 0 */
193  float minLocalChi2 = chiVsT0[0];
194  int it0min = -1;
195  float T0ClosestTo0 = 99999.;
196  int itClosest = -1;
197  std::vector<int> itlocal;
198  for (int it0 = 1; it0 < nhypo - 1; it0++) {
199  if ((LHslope[it0] < 0. && HLslope[it0] > 0.) || (LHslope[it0] == 0. && HLslope[it0] > 0. && LHslope[it0 - 1] < 0.
200  && HLslope[it0 - 1] == 0.)) {
201  localT0.push_back(t0hypo[it0]);
202  localquality.push_back(chiVsT0[it0]);
203  itlocal.push_back(it0);
204  if (chiVsT0[it0] < minLocalChi2) {
205  minLocalChi2 = chiVsT0[it0];
206  it0min = it0;
207  }
208  if (abs(t0hypo[it0]) < abs(T0ClosestTo0)) {
209  T0ClosestTo0 = t0hypo[it0];
210  itClosest = it0;
211  }
212  }
213  }
214  nT0Values = localT0.size();
215 
216  //-----------------------------------------------------------------
218  for (int imin = 0; imin < nT0Values; imin++) {
219  float localUnc = m_maxT0;
220  if (itlocal[imin] > 0 && itlocal[imin] < nhypo) {
221  float chiTarget = chiVsT0[itlocal[imin]] + 4.;
222  int ih = itlocal[imin];
223  while (ih < nhypo - 1 and chiVsT0[ih] < chiTarget) {ih++;}
224  int il = itlocal[imin];
225  while (il > 0 and chiVsT0[il] < chiTarget) {il--;};
226  localUnc = (t0hypo[ih] - t0hypo[il]) / 4.;
227  }
228  localT0Unc.push_back(localUnc);
229  }
230 
231  //-----------------------------------------------------------------
233  int itsel = it0min;
234  if (m_primaryT0 == 1) {itsel = it0minChi2;}
235  if (m_primaryT0 == 2) {itsel = itClosest;}
236 
237  if (itsel >= 0) {
238  T0 = t0hypo[itsel];
239  quality = chiVsT0[itsel];
240 
242  if (itsel > 0 && itsel < nhypo) {
243  float chiTarget = chiVsT0[itsel] + 4.;
244  int ih = itsel;
245  while (ih < nhypo - 1 and chiVsT0[ih] < chiTarget) {ih++;}
246  float ta = t0hypo[ih - 1];
247  float tb = t0hypo[ih];
248  float ca = chiVsT0[ih - 1];
249  float cb = chiVsT0[ih];
250  float th = tb;
251  if (cb != ca) {th = ta + (tb - ta) * (chiTarget - ca) / (cb - ca);}
252  int il = itsel;
253  while (il > 0 and chiVsT0[il] < chiTarget) {il--;}
254  ta = t0hypo[il];
255  tb = t0hypo[il + 1];
256  ca = chiVsT0[il];
257  cb = chiVsT0[il + 1];
258  float tl = ta;
259  if (cb != ca) {tl = ta + (tb - ta) * (chiTarget - ca) / (cb - ca);}
260  T0Unc = (th - tl) / 4.;
261  }
262  }
263  }
264 
265  //-----------------------------------------------------------------
267  if (!m_eventT0) {m_eventT0.create();}
268 
270  for (int it = 0; it < nT0Values; it++) {
271  m_eventT0->addTemporaryEventT0(EventT0::EventT0Component(localT0[it], localT0Unc[it], Const::ECL, "", localquality[it]));
272  }
273 
275  if (T0 > -99998.0) {
276  m_eventT0->setEventT0(EventT0::EventT0Component(T0, T0Unc, Const::ECL, "", quality));
277  }
278 }
Belle2::ECLEventT0Module::event
virtual void event() override
Event.
Definition: ECLEventT0Module.cc:54
REG_MODULE
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:652
Belle2::ECLEventT0Module
EventT0 from ECL.
Definition: ECLEventT0Module.h:46
Belle2::EventT0::EventT0Component
Structure for storing the extracted event t0s together with its detector and its uncertainty.
Definition: EventT0.h:44
Belle2::Module
Base class for Modules.
Definition: Module.h:74
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::ECLEventT0Module::initialize
virtual void initialize() override
Register input and output data.
Definition: ECLEventT0Module.cc:47