Belle II Software development
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
20using namespace std;
21
22namespace 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)) {
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
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) {
167 return;
168 }
169 double sn = m_charge / m_strips.at(0).noise;
170 if (sn == 0) {
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) {
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::getInstance().getSensorInfo(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
217 B2WARNING("Something is wrong in the cluster creation, this cluster will not be created!");
218 return false;
219 }
220
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
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.
STL namespace.
structure containing the relevant informations of eachstrip of the cluster