Belle II Software  release-08-01-10
SimpleClusterCandidate.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 #include <framework/logging/Logger.h>
10 #include <svd/reconstruction/SimpleClusterCandidate.h>
11 #include <vxd/geometry/GeoCache.h>
12 #include <svd/geometry/SensorInfo.h>
13 #include <framework/core/Environment.h>
14 
15 #include <framework/datastore/StoreArray.h>
16 #include <svd/dataobjects/SVDRecoDigit.h>
17 
18 #include <TMath.h>
19 
20 using namespace std;
21 
22 namespace Belle2 {
28  namespace SVD {
29 
30  SimpleClusterCandidate::SimpleClusterCandidate(VxdID vxdID, bool isUside, int sizeHeadTail, double cutSeed, double cutAdjacent,
31  double cutCluster, int timeAlgorithm)
32  : m_vxdID(vxdID)
33  , m_isUside(isUside)
34  , m_sizeHeadTail(sizeHeadTail)
35  , m_cutSeed(cutSeed)
36  , m_cutAdjacent(cutAdjacent)
37  , m_cutCluster(cutCluster)
38  , m_timeAlgorithm(timeAlgorithm)
39  , m_charge(0)
40  , m_chargeError(0)
41  , m_seedCharge(0)
42  , m_6SampleTime(0)
43  , m_6SampleTimeError(0)
44  , m_position(0)
45  , m_positionError(0)
46  , m_SNR(0)
47  , m_seedSNR(0)
48  , m_seedIndex(-1)
49  , m_strips(4)
50  , m_storeShaperDigitsName("SVDShaperDigits")
51  , m_storeRecoDigitsName("SVDRecoDigits")
52  {m_strips.clear();};
53 
54  SimpleClusterCandidate::SimpleClusterCandidate(VxdID vxdID, bool isUside, int sizeHeadTail, double cutSeed, double cutAdjacent,
55  double cutCluster, int timeAlgorithm, const std::string& storeShaperDigitsName, const std::string& storeRecoDigitsName)
56  : m_vxdID(vxdID)
57  , m_isUside(isUside)
58  , m_sizeHeadTail(sizeHeadTail)
59  , m_cutSeed(cutSeed)
60  , m_cutAdjacent(cutAdjacent)
61  , m_cutCluster(cutCluster)
62  , m_timeAlgorithm(timeAlgorithm)
63  , m_charge(0)
64  , m_chargeError(0)
65  , m_seedCharge(0)
66  , m_6SampleTime(0)
67  , m_6SampleTimeError(0)
68  , m_position(0)
69  , m_positionError(0)
70  , m_SNR(0)
71  , m_seedSNR(0)
72  , m_seedIndex(-1)
73  , m_strips(4)
74  , m_storeShaperDigitsName(storeShaperDigitsName)
75  , m_storeRecoDigitsName(storeRecoDigitsName)
76  {m_strips.clear();};
77 
78  bool SimpleClusterCandidate::add(VxdID vxdID, bool isUside, struct stripInCluster& aStrip)
79  {
80 
81  bool added = false;
82 
83  //do not add if you are on the wrong sensor or side
84  if ((m_vxdID != vxdID) || (m_isUside != isUside))
85  return false;
86 
87  //add if it's the first strip
88  if (m_strips.size() == 0)
89  added = true;
90 
91  //add if it adjacent to the last strip added
92  //(we assume that SVDRecoDigits are ordered)
93  if ((m_strips.size() > 0 && (aStrip.cellID == m_strips.at(m_strips.size() - 1).cellID + 1)))
94  added = true;
95 
96  //add it to the vector od strips, update the seed charge and index:
97  if (added) {
98  m_strips.push_back(aStrip);
99 
100  if (aStrip.charge > m_seedCharge) {
101  m_seedCharge = aStrip.charge;
102  m_seedSNR = aStrip.charge / aStrip.noise;
103  m_seedIndex = m_strips.size() - 1;
104  }
105  }
106  return added;
107 
108  };
109 
111  {
112 
113  m_stopCreationCluster = false;
114 
116  const VXD::SensorInfoBase& info = geo.getSensorInfo(m_vxdID);
117 
118  double pitch = m_isUside ? info.getUPitch() : info.getVPitch();
119 
120  int maxStripCellID = m_strips.at(m_strips.size() - 1).cellID;
121  double maxStripCharge = m_strips.at(m_strips.size() - 1).charge;
122  int minStripCellID = m_strips.at(0).cellID;
123  double minStripCharge = m_strips.at(0).charge;
124 
125  int clusterSize = m_strips.size();
126 
127  double weightSum = 0;
128  double noise = 0;
129  for (auto aStrip : m_strips) {
130  double stripPos = m_isUside ? info.getUCellPosition(aStrip.cellID) : info.getVCellPosition(aStrip.cellID);
131  m_position += stripPos * aStrip.charge;
132  m_charge += aStrip.charge;
133  m_6SampleTime += aStrip.time * aStrip.charge;
134 
135  float tmp_sigmaSquared = aStrip.timeError * aStrip.timeError;
136  weightSum += tmp_sigmaSquared;
137  //FIXME: use error to weight the time of each strip in the cluster
138  // it seems to yield a worst resolution vs EventT0 and an additional 1 ns bias
139  // m_6SampleTime += aStrip.time / tmp_sigmaSquared;
140  // additional change also below: m_6SampleTime /= weightSum instead of m_6SampleTime/=m_charge
141  noise += aStrip.noise * aStrip.noise;
142  }
143 
144  if ((m_charge == 0) || (noise == 0)) {
145  m_stopCreationCluster = true;
146  return;
147  }
148 
149  noise = sqrt(noise);
151  // m_6SampleTime /= weightSum;
152  m_6SampleTimeError = 1. / TMath::Sqrt(weightSum);
153  m_SNR = m_charge / noise;
154 
155 
156  if (clusterSize < m_sizeHeadTail) { // COG, size = 1 or 2
157  m_position /= m_charge;
158  // Compute position error
159  if (clusterSize == 1) {
160  // Add a strip charge equal to the zero-suppression threshold to compute the error
161  double phantomCharge = m_cutAdjacent * m_strips.at(0).noise;
162  m_positionError = pitch * phantomCharge / (m_charge + phantomCharge);
163  } else {
164  double a = m_cutAdjacent;
165  if (m_strips.at(0).noise == 0) {
166  m_stopCreationCluster = true;
167  return;
168  }
169  double sn = m_charge / m_strips.at(0).noise;
170  if (sn == 0) {
171  m_stopCreationCluster = true;
172  return;
173  }
174  m_positionError = a * pitch / sn;
175  }
176  } else { // Head-tail
177  double centreCharge = (m_charge - minStripCharge - maxStripCharge) / (clusterSize - 2);
178  if (centreCharge == 0) {
179  m_stopCreationCluster = true;
180  return;
181  }
182 
183  minStripCharge = (minStripCharge < centreCharge) ? minStripCharge : centreCharge;
184  maxStripCharge = (maxStripCharge < centreCharge) ? maxStripCharge : centreCharge;
185  double minPos = m_isUside ? info.getUCellPosition(minStripCellID) : info.getVCellPosition(minStripCellID);
186  double maxPos = m_isUside ? info.getUCellPosition(maxStripCellID) : info.getVCellPosition(maxStripCellID);
187  m_position = 0.5 * (minPos + maxPos + (maxStripCharge - minStripCharge) / centreCharge * pitch);
188 
189  double sn = centreCharge / m_cutAdjacent / noise;
190  // Rough estimates of Landau noise
191  double landauHead = minStripCharge / centreCharge;
192  double landauTail = maxStripCharge / centreCharge;
193  m_positionError = 0.5 * pitch * sqrt(1.0 / sn / sn +
194  0.5 * landauHead * landauHead +
195  0.5 * landauTail * landauTail);
196  }
197 
198  //Lorentz shift correction - PATCHED
199  //NOTE: layer 3 is upside down with respect to L4,5,6 in the real data (real SVD), but _not_ in the simulation. We need to change the sign of the Lorentz correction on L3 only if reconstructing data, i.e. if Environment::Instance().isMC() is FALSE.
200  const SensorInfo& sensorInfo = dynamic_cast<const SensorInfo&>(VXD::GeoCache::get(m_vxdID));
201 
202  bool isMC = Environment::Instance().isMC();
203 
204  if ((m_vxdID.getLayerNumber() == 3) && ! isMC)
206  else
208 
209  };
210 
212  {
213 
214  bool isGood = false;
215 
216  if (m_stopCreationCluster) {
217  B2WARNING("Something is wrong in the cluster creation, this cluster will not be created!");
218  return false;
219  }
220 
221  if (m_seedCharge > 0 && m_seedSNR >= m_cutSeed && m_SNR >= m_cutCluster)
222  isGood = true;
223 
224  return isGood;
225  };
226 
227 
229  {
230 
231  if (m_timeAlgorithm == 0)
232  return get6SampleCoGTime();
233  else if (m_timeAlgorithm == 1)
234  return get3SampleCoGRawTime();
235  else if (m_timeAlgorithm == 2)
236  return get3SampleELSRawTime();
237  else {
238  B2FATAL("unrecognized timeAlgorithm, please check the input parameter and select a value among {0 (6-sample CoG), 1 (3-sample CoG), 2 (3-sample ELS)} to select the algorithm that you want to reconstruct the cluster time");
239  return 0;
240  }
241  }
242 
244  {
245 
246  if (m_timeAlgorithm == 0)
247  return get6SampleCoGTimeError();
248  else if (m_timeAlgorithm == 1)
249  return get3SampleCoGTimeError();
250  else if (m_timeAlgorithm == 2)
251  return get3SampleELSTimeError();
252  else {
253  B2FATAL("unrecognized timeAlgorithm, please check the input parameter and select a value among {0 (6-sample CoG), 1 (3-sample CoG), 2 (3-sample ELS)} to select the algorithm that you want to reconstruct the cluster time");
254  return 0;
255  }
256  }
257 
259  {
260 
261  //take the MaxSum 3 samples
262  std::vector<float> clustered3s = getMaxSum3Samples().second;
263  auto begin = clustered3s.begin();
264  const auto end = clustered3s.end();
265 
266  //calculate 'raw' CoG3 hit-time
267  constexpr auto stepSize = 16000. / 509; //APV25 clock period = 31.4 ns
268  auto retval = 0., norm = 0.;
269  for (auto step = 0.; begin != end; ++begin, step += stepSize) {
270  norm += static_cast<double>(*begin);
271  retval += static_cast<double>(*begin) * step;
272  }
273  float rawtime = retval / norm;
274 
275  return rawtime;
276  }
277 
279  {
280 
281  //take the MaxSum 3 samples
282  std::vector<float> clustered3s = getMaxSum3Samples().second;
283  const auto begin = clustered3s.begin();
284 
285  //calculate 'raw' ELS hit-time
286  constexpr auto stepSize = 16000. / 509; //APV25 clock period = 31.4 ns
287  constexpr auto tau = 55;//ELS time constant, default55
288  auto num = 2 * stepSize * std::exp(-4 * stepSize / tau) + std::exp(-2 * stepSize / tau) * stepSize / 2 * (*begin - std::exp(
289  -2 * stepSize / tau) * (*(begin + 2))) / (*begin + std::exp(-stepSize / tau) * (*(begin + 1)) / 2);
290  auto denom = 1 - std::exp(-4 * stepSize / tau) - (1 + std::exp(-2 * stepSize / tau) / 2) * (*begin - std::exp(
291  -2 * stepSize / tau) * (*(begin + 2))) / (*begin + std::exp(-stepSize / tau) * (*(begin + 1)) / 2);
292  float rawtime = - num / denom;
293 
294  return rawtime;
295 
296  }
298  {
299 
300  //no obvious way to compute the error yet
301  return 6;
302  }
303 
305  {
306 
307  //no obvious way to compute the error yet
308  return 6;
309  }
310 
311 
313  {
314 
315  if (m_strips.size() == 0)
316  B2ERROR(" you are asking fo the cluster samples for a cluster candidate with no strips, it make no sense to ask for the cluster time!");
317 
318  //steps:
319  //1.loop on m_strips
320  //2. access the index of the recodigit from the element of m_strip
321  //3. get the shaperdigit related to the recodigit of index recoDigitIndex
322  //4. sum each sample for each strip accessed in the loop
323  //5. you are done
324 
325  Belle2::SVDShaperDigit::APVFloatSamples returnSamples = {0, 0, 0, 0, 0, 0};
326  //FIXME: the name of the StoreArray of RecoDigits and ShaperDigits
327  // must be taken from the SimpleClusterizer.
328  const StoreArray<SVDRecoDigit> m_storeRecoDigits(m_storeRecoDigitsName.c_str());
329  for (auto istrip : m_strips) {
330  const SVDShaperDigit* shaperdigit = m_storeRecoDigits[istrip.recoDigitIndex]->getRelatedTo<SVDShaperDigit>
331  (m_storeShaperDigitsName.c_str());
332  if (!shaperdigit) B2ERROR("No shaperdigit for strip!?");
333  Belle2::SVDShaperDigit::APVFloatSamples APVsamples = shaperdigit->getSamples();
334  for (int iSample = 0; iSample < static_cast<int>(APVsamples.size()); ++iSample)
335  returnSamples.at(iSample) += APVsamples.at(iSample);
336  }
337 
338  return returnSamples;
339  }
340 
341  std::pair<int, std::vector<float>> SimpleClusterCandidate::getMaxSum3Samples() const
342  {
343 
344  //take the cluster samples
346 
347  //Max Sum selection
348  if (clsSamples.size() < 3) B2ERROR("APV25 samples less than 3!?");
349  std::vector<float> Sum2bin(clsSamples.size() - 1, 0);
350  for (int iBin = 0; iBin < static_cast<int>(clsSamples.size()) - 1; ++iBin)
351  Sum2bin.at(iBin) = clsSamples.at(iBin) + clsSamples.at(iBin + 1);
352  auto itSum = std::max_element(std::begin(Sum2bin), std::end(Sum2bin));
353  int ctrFrame = std::distance(std::begin(Sum2bin), itSum);
354  if (ctrFrame == 0) ctrFrame = 1;
355  std::vector<float> clustered3s = {clsSamples.at(ctrFrame - 1), clsSamples.at(ctrFrame), clsSamples.at(ctrFrame + 1)};
356 
357  return std::make_pair(ctrFrame - 1, clustered3s);
358 
359  }
360 
361 
362  } //SVD namespace
364 } //Belle2 namespace
bool isMC() const
Do we have generated, not real data?
Definition: Environment.cc:54
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:28
The SVD ShaperDigit class.
std::array< APVFloatSampleType, c_nAPVSamples > APVFloatSamples
array of APVFloatSampleType objects
APVFloatSamples getSamples() const
Get array of samples.
Specific implementation of SensorInfo for SVD Sensors which provides additional sensor specific infor...
Definition: SensorInfo.h:25
const ROOT::Math::XYZVector & getLorentzShift(double uCoord, double vCoord) const
Calculate Lorentz shift along a given coordinate in a magnetic field at a given position.
Definition: SensorInfo.cc:104
std::string m_storeRecoDigitsName
Name of the collection to use for the SVDRecoDigits.
float m_position
Position of the cluster.
float m_6SampleTimeError
Error on Time of the cluster computed with the 6-sample CoG (not implemented yet)
float getTime() const
return the time of the cluster depending on the m_timeAlgorithm
float get3SampleELSRawTime() const
return the raw time of the cluster for the 3-sample ELS
bool m_stopCreationCluster
cluster is not good if something goes wrong
std::string m_storeShaperDigitsName
Name of the collection to use for the SVDShaperDigits.
double m_cutCluster
SNR above which the cluster is ok.
std::vector< stripInCluster > m_strips
first frame selected with the max-sum algorithm
float get6SampleCoGTime() const
return the time of the cluster for the 6-sample CoG
Belle2::SVDShaperDigit::APVFloatSamples getClsSamples() const
returns the APVFloatSamples obtained summing sample-by-sample all the strips on the cluster
bool add(VxdID vxdID, bool isUside, struct stripInCluster &aStrip)
Add a Strip to the current cluster.
void finalizeCluster()
compute the position, time and their error of the cluster
float m_6SampleTime
Time of the cluster computed with the 6-sample CoG.
bool isGoodCluster()
return true if the cluster candidate can be promoted to cluster
float get3SampleCoGTimeError() const
return the time of the cluster for the 3-sample CoG
float m_positionError
Error on Position of the cluster.
float get3SampleCoGRawTime() const
return the raw time of the cluster for the 3-sample CoG
float get6SampleCoGTimeError() const
return the time of the cluster for the 6-sample CoG
std::pair< int, std::vector< float > > getMaxSum3Samples() const
returns the float vector of clustered 3-samples selected by the MaxSum method with First Frame of the...
int m_sizeHeadTail
number of strips after which we switch from COG to HeadTail estimation of the position
int m_timeAlgorithm
selects the algorithm to compute the cluster tim 0 = 6-sample CoG (default) 1 = 3-sample CoG 2 = 3-sa...
double m_cutSeed
SNR above which the strip can be considered as seed.
float get3SampleELSTimeError() const
return the time of the cluster for the 3-sample ELS
SimpleClusterCandidate(VxdID vxdID, bool isUside, int sizeHeadTail, double cutSeed, double cutAdjacent, double cutSNR, int timeAlgorithm)
Constructor to create an empty Cluster.
float m_seedCharge
Seed Charge of the cluster.
float getTimeError() const
return the error on the time of the cluster depending on the m_timeAlgorithm, implemented only for th...
int m_seedIndex
SVDRecoDigit index of the seed strip of the cluster.
double m_cutAdjacent
SNR above which the strip can be considered for clustering.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
Class to faciliate easy access to sensor information of the VXD like coordinate transformations or pi...
Definition: GeoCache.h:39
const SensorInfoBase & getSensorInfo(Belle2::VxdID id) const
Return a referecne to the SensorInfo of a given SensorID.
Definition: GeoCache.cc:67
static GeoCache & getInstance()
Return a reference to the singleton instance.
Definition: GeoCache.cc:214
static const SensorInfoBase & get(Belle2::VxdID id)
Return a reference to the SensorInfo of a given SensorID.
Definition: GeoCache.h:139
Base class to provide Sensor Information for PXD and SVD.
Class to uniquely identify a any structure of the PXD and SVD.
Definition: VxdID.h:33
baseType getLayerNumber() const
Get the layer id.
Definition: VxdID.h:96
double sqrt(double a)
sqrt for double
Definition: beamHelpers.h:28
Abstract base class for different kinds of events.
structure containing the relevant informations of eachstrip of the cluster