Belle II Software prerelease-10-00-00a
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 {
27
28 namespace SVD {
29
30 SimpleClusterCandidate::SimpleClusterCandidate(VxdID vxdID, bool isUside, int sizeHeadTail, double cutSeed, double cutAdjacent,
31 double cutCluster, int timeAlgorithm)
32 : m_storeShaperDigitsName("SVDShaperDigits")
33 , m_storeRecoDigitsName("SVDRecoDigits")
34 , m_strips(4)
35 , m_cutSeed(cutSeed)
36 , m_cutAdjacent(cutAdjacent)
37 , m_cutCluster(cutCluster)
38 , m_sizeHeadTail(sizeHeadTail)
39 , m_timeAlgorithm(timeAlgorithm)
40 , m_charge(0)
41 , m_chargeError(0)
42 , m_seedCharge(0)
43 , m_6SampleTime(0)
45 , m_position(0)
47 , m_SNR(0)
48 , m_seedSNR(0)
49 , m_seedIndex(-1)
50 , m_vxdID(vxdID)
51 , m_isUside(isUside)
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_storeShaperDigitsName(storeShaperDigitsName)
57 , m_storeRecoDigitsName(storeRecoDigitsName)
58 , m_strips(4)
59 , m_cutSeed(cutSeed)
60 , m_cutAdjacent(cutAdjacent)
61 , m_cutCluster(cutCluster)
62 , m_sizeHeadTail(sizeHeadTail)
63 , m_timeAlgorithm(timeAlgorithm)
64 , m_charge(0)
65 , m_chargeError(0)
66 , m_seedCharge(0)
67 , m_6SampleTime(0)
69 , m_position(0)
71 , m_SNR(0)
72 , m_seedSNR(0)
73 , m_seedIndex(-1)
74 , m_vxdID(vxdID)
75 , m_isUside(isUside)
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 for 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?
static Environment & Instance()
Static method to get a reference to the Environment instance.
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.
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
vector containing the strips in the cluster
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...
float m_chargeError
Error on Charge of the cluster.
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 facilitate easy access to sensor information of the VXD like coordinate transformations or p...
Definition GeoCache.h:39
const SensorInfoBase & getSensorInfo(Belle2::VxdID id) const
Return a reference 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
double sqrt(double a)
sqrt for double
Definition beamHelpers.h:28
Namespace to encapsulate code needed for simulation and reconstrucion of the SVD.
Abstract base class for different kinds of events.
STL namespace.
structure containing the relevant information of eachstrip of the cluster