Belle II Software  release-06-02-00
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 using namespace std;
19 
20 namespace Belle2 {
26  namespace SVD {
27 
28  SimpleClusterCandidate::SimpleClusterCandidate(VxdID vxdID, bool isUside, int sizeHeadTail, double cutSeed, double cutAdjacent,
29  double cutCluster, int timeAlgorithm)
30  : m_vxdID(vxdID)
31  , m_isUside(isUside)
32  , m_sizeHeadTail(sizeHeadTail)
33  , m_cutSeed(cutSeed)
34  , m_cutAdjacent(cutAdjacent)
35  , m_cutCluster(cutCluster)
36  , m_timeAlgorithm(timeAlgorithm)
37  , m_charge(0)
38  , m_chargeError(0)
39  , m_seedCharge(0)
40  , m_6SampleTime(0)
41  , m_6SampleTimeError(0)
42  , m_position(0)
43  , m_positionError(0)
44  , m_SNR(0)
45  , m_seedSNR(0)
46  , m_seedIndex(-1)
47  , m_strips(4)
48  , m_storeShaperDigitsName("SVDShaperDigits")
49  , m_storeRecoDigitsName("SVDRecoDigits")
50  {m_strips.clear();};
51 
52  SimpleClusterCandidate::SimpleClusterCandidate(VxdID vxdID, bool isUside, int sizeHeadTail, double cutSeed, double cutAdjacent,
53  double cutCluster, int timeAlgorithm, const std::string& storeShaperDigitsName, const std::string& storeRecoDigitsName)
54  : m_vxdID(vxdID)
55  , m_isUside(isUside)
56  , m_sizeHeadTail(sizeHeadTail)
57  , m_cutSeed(cutSeed)
58  , m_cutAdjacent(cutAdjacent)
59  , m_cutCluster(cutCluster)
60  , m_timeAlgorithm(timeAlgorithm)
61  , m_charge(0)
62  , m_chargeError(0)
63  , m_seedCharge(0)
64  , m_6SampleTime(0)
65  , m_6SampleTimeError(0)
66  , m_position(0)
67  , m_positionError(0)
68  , m_SNR(0)
69  , m_seedSNR(0)
70  , m_seedIndex(-1)
71  , m_strips(4)
72  , m_storeShaperDigitsName(storeShaperDigitsName)
73  , m_storeRecoDigitsName(storeRecoDigitsName)
74  {m_strips.clear();};
75 
76  bool SimpleClusterCandidate::add(VxdID vxdID, bool isUside, struct stripInCluster& aStrip)
77  {
78 
79  bool added = false;
80 
81  //do not add if you are on the wrong sensor or side
82  if ((m_vxdID != vxdID) || (m_isUside != isUside))
83  return false;
84 
85  //add if it's the first strip
86  if (m_strips.size() == 0)
87  added = true;
88 
89  //add if it adjacent to the last strip added
90  //(we assume that SVDRecoDigits are ordered)
91  if ((m_strips.size() > 0 && (aStrip.cellID == m_strips.at(m_strips.size() - 1).cellID + 1)))
92  added = true;
93 
94  //add it to the vector od strips, update the seed charge and index:
95  if (added) {
96  m_strips.push_back(aStrip);
97 
98  if (aStrip.charge > m_seedCharge) {
99  m_seedCharge = aStrip.charge;
100  m_seedSNR = aStrip.charge / aStrip.noise;
101  m_seedIndex = m_strips.size() - 1;
102  }
103  }
104  return added;
105 
106  };
107 
109  {
110 
111  m_stopCreationCluster = false;
112 
114  const VXD::SensorInfoBase& info = geo.getSensorInfo(m_vxdID);
115 
116  double pitch = m_isUside ? info.getUPitch() : info.getVPitch();
117 
118  int maxStripCellID = m_strips.at(m_strips.size() - 1).cellID;
119  double maxStripCharge = m_strips.at(m_strips.size() - 1).charge;
120  int minStripCellID = m_strips.at(0).cellID;
121  double minStripCharge = m_strips.at(0).charge;
122 
123  int clusterSize = m_strips.size();
124 
125  double weightSum = 0;
126  double noise = 0;
127  for (auto aStrip : m_strips) {
128  double stripPos = m_isUside ? info.getUCellPosition(aStrip.cellID) : info.getVCellPosition(aStrip.cellID);
129  m_position += stripPos * aStrip.charge;
130  m_charge += aStrip.charge;
131  m_6SampleTime += aStrip.time * aStrip.charge;
132 
133  float tmp_sigmaSquared = aStrip.timeError * aStrip.timeError;
134  weightSum += tmp_sigmaSquared;
135  //FIXME: use error to weight the time of each strip in the cluster
136  // it seems to yield a worst resolution vs EventT0 and an additional 1 ns bias
137  // m_6SampleTime += aStrip.time / tmp_sigmaSquared;
138  // additional change also below: m_6SampleTime /= weightSum instead of m_6SampleTime/=m_charge
139  noise += aStrip.noise * aStrip.noise;
140  }
141 
142  if ((m_charge == 0) || (noise == 0)) {
143  m_stopCreationCluster = true;
144  return;
145  }
146 
147  noise = sqrt(noise);
149  // m_6SampleTime /= weightSum;
150  m_6SampleTimeError = 1. / TMath::Sqrt(weightSum);
151  m_SNR = m_charge / noise;
152 
153 
154  if (clusterSize < m_sizeHeadTail) { // COG, size = 1 or 2
155  m_position /= m_charge;
156  // Compute position error
157  if (clusterSize == 1) {
158  // Add a strip charge equal to the zero-suppression threshold to compute the error
159  double phantomCharge = m_cutAdjacent * m_strips.at(0).noise;
160  m_positionError = pitch * phantomCharge / (m_charge + phantomCharge);
161  } else {
162  double a = m_cutAdjacent;
163  if (m_strips.at(0).noise == 0) {
164  m_stopCreationCluster = true;
165  return;
166  }
167  double sn = m_charge / m_strips.at(0).noise;
168  if (sn == 0) {
169  m_stopCreationCluster = true;
170  return;
171  }
172  m_positionError = a * pitch / sn;
173  }
174  } else { // Head-tail
175  double centreCharge = (m_charge - minStripCharge - maxStripCharge) / (clusterSize - 2);
176  if (centreCharge == 0) {
177  m_stopCreationCluster = true;
178  return;
179  }
180 
181  minStripCharge = (minStripCharge < centreCharge) ? minStripCharge : centreCharge;
182  maxStripCharge = (maxStripCharge < centreCharge) ? maxStripCharge : centreCharge;
183  double minPos = m_isUside ? info.getUCellPosition(minStripCellID) : info.getVCellPosition(minStripCellID);
184  double maxPos = m_isUside ? info.getUCellPosition(maxStripCellID) : info.getVCellPosition(maxStripCellID);
185  m_position = 0.5 * (minPos + maxPos + (maxStripCharge - minStripCharge) / centreCharge * pitch);
186 
187  double sn = centreCharge / m_cutAdjacent / noise;
188  // Rough estimates of Landau noise
189  double landauHead = minStripCharge / centreCharge;
190  double landauTail = maxStripCharge / centreCharge;
191  m_positionError = 0.5 * pitch * sqrt(1.0 / sn / sn +
192  0.5 * landauHead * landauHead +
193  0.5 * landauTail * landauTail);
194  }
195 
196  //Lorentz shift correction - PATCHED
197  //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.
198  const SensorInfo& sensorInfo = dynamic_cast<const SensorInfo&>(VXD::GeoCache::get(m_vxdID));
199 
200  bool isMC = Environment::Instance().isMC();
201 
202  if ((m_vxdID.getLayerNumber() == 3) && ! isMC)
204  else
206 
207  };
208 
210  {
211 
212  bool isGood = false;
213 
214  if (m_stopCreationCluster) {
215  B2WARNING("Something is wrong in the cluster creation, this cluster will not be created!");
216  return false;
217  }
218 
219  if (m_seedCharge > 0 && m_seedSNR >= m_cutSeed && m_SNR >= m_cutCluster)
220  isGood = true;
221 
222  return isGood;
223  };
224 
225 
227  {
228 
229  if (m_timeAlgorithm == 0)
230  return get6SampleCoGTime();
231  else if (m_timeAlgorithm == 1)
232  return get3SampleCoGRawTime();
233  else if (m_timeAlgorithm == 2)
234  return get3SampleELSRawTime();
235  else {
236  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");
237  return 0;
238  }
239  }
240 
242  {
243 
244  if (m_timeAlgorithm == 0)
245  return get6SampleCoGTimeError();
246  else if (m_timeAlgorithm == 1)
247  return get3SampleCoGTimeError();
248  else if (m_timeAlgorithm == 2)
249  return get3SampleELSTimeError();
250  else {
251  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");
252  return 0;
253  }
254  }
255 
257  {
258 
259  //take the MaxSum 3 samples
260  std::vector<float> clustered3s = getMaxSum3Samples().second;
261  auto begin = clustered3s.begin();
262  const auto end = clustered3s.end();
263 
264  //calculate 'raw' CoG3 hit-time
265  constexpr auto stepSize = 16000. / 509; //APV25 clock period = 31.4 ns
266  auto retval = 0., norm = 0.;
267  for (auto step = 0.; begin != end; ++begin, step += stepSize) {
268  norm += static_cast<double>(*begin);
269  retval += static_cast<double>(*begin) * step;
270  }
271  float rawtime = retval / norm;
272 
273  return rawtime;
274  }
275 
277  {
278 
279  //take the MaxSum 3 samples
280  std::vector<float> clustered3s = getMaxSum3Samples().second;
281  const auto begin = clustered3s.begin();
282 
283  //calculate 'raw' ELS hit-time
284  constexpr auto stepSize = 16000. / 509; //APV25 clock period = 31.4 ns
285  constexpr auto tau = 55;//ELS time constant, default55
286  auto num = 2 * stepSize * std::exp(-4 * stepSize / tau) + std::exp(-2 * stepSize / tau) * stepSize / 2 * (*begin - std::exp(
287  -2 * stepSize / tau) * (*(begin + 2))) / (*begin + std::exp(-stepSize / tau) * (*(begin + 1)) / 2);
288  auto denom = 1 - std::exp(-4 * stepSize / tau) - (1 + std::exp(-2 * stepSize / tau) / 2) * (*begin - std::exp(
289  -2 * stepSize / tau) * (*(begin + 2))) / (*begin + std::exp(-stepSize / tau) * (*(begin + 1)) / 2);
290  float rawtime = - num / denom;
291 
292  return rawtime;
293 
294  }
296  {
297 
298  //no obvious way to compute the error yet
299  return 6;
300  }
301 
303  {
304 
305  //no obvious way to compute the error yet
306  return 6;
307  }
308 
309 
311  {
312 
313  if (m_strips.size() == 0)
314  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!");
315 
316  //steps:
317  //1.loop on m_strips
318  //2. access the index of the recodigit from the element of m_strip
319  //3. get the shaperdigit related to the recodigit of index recoDigitIndex
320  //4. sum each sample for each strip accessed in the loop
321  //5. you are done
322 
323  Belle2::SVDShaperDigit::APVFloatSamples returnSamples = {0, 0, 0, 0, 0, 0};
324  //FIXME: the name of the StoreArray of RecoDigits and ShaperDigits
325  // must be taken from the SimpleClusterizer.
326  const StoreArray<SVDRecoDigit> m_storeRecoDigits(m_storeRecoDigitsName.c_str());
327  for (auto istrip : m_strips) {
328  const SVDShaperDigit* shaperdigit = m_storeRecoDigits[istrip.recoDigitIndex]->getRelatedTo<SVDShaperDigit>
329  (m_storeShaperDigitsName.c_str());
330  if (!shaperdigit) B2ERROR("No shaperdigit for strip!?");
331  Belle2::SVDShaperDigit::APVFloatSamples APVsamples = shaperdigit->getSamples();
332  for (int iSample = 0; iSample < static_cast<int>(APVsamples.size()); ++iSample)
333  returnSamples.at(iSample) += APVsamples.at(iSample);
334  }
335 
336  return returnSamples;
337  }
338 
339  std::pair<int, std::vector<float>> SimpleClusterCandidate::getMaxSum3Samples() const
340  {
341 
342  //take the cluster samples
344 
345  //Max Sum selection
346  if (clsSamples.size() < 3) B2ERROR("APV25 samples less than 3!?");
347  std::vector<float> Sum2bin(clsSamples.size() - 1, 0);
348  for (int iBin = 0; iBin < static_cast<int>(clsSamples.size()) - 1; ++iBin)
349  Sum2bin.at(iBin) = clsSamples.at(iBin) + clsSamples.at(iBin + 1);
350  auto itSum = std::max_element(std::begin(Sum2bin), std::end(Sum2bin));
351  int ctrFrame = std::distance(std::begin(Sum2bin), itSum);
352  if (ctrFrame == 0) ctrFrame = 1;
353  std::vector<float> clustered3s = {clsSamples.at(ctrFrame - 1), clsSamples.at(ctrFrame), clsSamples.at(ctrFrame + 1)};
354 
355  return std::make_pair(ctrFrame - 1, clustered3s);
356 
357  }
358 
359 
360  } //SVD namespace
362 } //Belle2 namespace
bool isMC() const
Do we have generated, not real data?
Definition: Environment.cc:55
static Environment & Instance()
Static method to get a reference to the Environment instance.
Definition: Environment.cc:29
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 TVector3 & getLorentzShift(double uCoord, double vCoord) const
Calculate Lorentz shift along a given coordinate in a magnetic field at a given position.
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:66
static GeoCache & getInstance()
Return a reference to the singleton instance.
Definition: GeoCache.cc:213
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
Abstract base class for different kinds of events.
structure containing the relevant informations of eachstrip of the cluster