Project
Loading...
Searching...
No Matches
ClusterFinderGEM.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
19
21
22#include <algorithm>
23#include <cstring>
24#include <iterator>
25#include <limits>
26#include <numeric>
27#include <set>
28#include <stdexcept>
29#include <string>
30
31#include <TH2I.h>
32#include <TAxis.h>
33#include <TMath.h>
34#include <TRandom.h>
35
36// GG
37#include "PadOriginal.h"
38#include "ClusterOriginal.h"
40// ??? <<<<<<< HEAD
42// #include "mathiesonFit.h"
43// =======
44// #include "MathiesonOriginal.h"
47#include "mathUtil.h"
48#include "mathieson.h"
49#include "InspectModel.h"
50// >>>>>>> 12c0a2e670... High-level Refactoring
51
52#define VERBOSE 1
53
54namespace o2
55{
56namespace mch
57{
58
59extern ClusterConfig clusterConfig;
60
61//_________________________________________________________________________________________________
63 : mMathiesons(std::make_unique<MathiesonOriginal[]>(2)), mPreCluster(std::make_unique<ClusterOriginal>())
64{
66
67 // Mathieson function for station 1
68 mMathiesons[0].setPitch(0.21);
69 mMathiesons[0].setSqrtKx3AndDeriveKx2Kx4(0.7000);
70 mMathiesons[0].setSqrtKy3AndDeriveKy2Ky4(0.7550);
71
72 // Mathieson function for other stations
73 mMathiesons[1].setPitch(0.25);
74 mMathiesons[1].setSqrtKx3AndDeriveKx2Kx4(0.7131);
75 mMathiesons[1].setSqrtKy3AndDeriveKy2Ky4(0.7642);
76 // GG
77 // init Mathieson
79 nPads = 0;
80 xyDxy = nullptr;
81 cathode = nullptr;
82 saturated = nullptr;
83 padCharge = nullptr;
84 DEId = -1;
85 currentBC = 0xFFFFFFFF;
86 currentOrbit = 0xFFFFFFFF;
87 currentPreClusterID = 0;
88}
89
90//_________________________________________________________________________________________________
91void ClusterFinderGEM::init(int _mode, bool run2Config)
92{
94 // ??? Not used
95 mode = _mode;
96 // Run 2 case (default)
97 // 4.f * 0.22875f;
101 //
102 // ClusterResolution
107 if (!run2Config) {
108 // Run 3 case
111 //
112 // Cluster resolution (for the tracking)
117 }
118 // Inv ??? LOG(info) << "Init lowestPadCharge = " << clusterConfig.minChargeOfPads ;
119}
120//_________________________________________________________________________________________________
122{
123 // std::cout << " [GEM] deinit " << std::endl;
125}
126
127//_________________________________________________________________________________________________
128
130
131/* Trace
132ClusterFinderGEM::~ClusterFinderGEM()
133{
134 std::cout << " [ClusterFinderGEM] Delete " << std::endl;
135}
136*/
137
138//_________________________________________________________________________________________________
140{
141
142 // std::cout << " [GEM] Reset hits/mClusters.size=" << mClusters.size() << std::endl;
143
144 // GEM part
146 // Inv ??? freeMemoryPadProcessing();
147 mClusters.clear();
148 mUsedDigits.clear();
149}
150
152{
153 nPads = 0;
154 DEId = -1;
155 if (xyDxy != nullptr) {
156 delete[] xyDxy;
157 xyDxy = nullptr;
158 };
159 if (cathode != nullptr) {
160 delete[] cathode;
161 cathode = nullptr;
162 };
163 if (padCharge != nullptr) {
164 delete[] padCharge;
165 padCharge = nullptr;
166 };
167 if (saturated != nullptr) {
168 delete[] saturated;
169 saturated = nullptr;
170 };
171}
172
173//_________________________________________________________________________________________________
174void ClusterFinderGEM::dumpPreCluster(ClusterDump* dumpFile, gsl::span<const Digit> digits, uint16_t bunchCrossing, uint32_t orbit, uint32_t iPreCluster)
175{
177 // GG mPrecluster defined in other MCHPreClustering/PreClusterFinder.h
178 mSegmentation = &mapping::segmentation(digits[0].getDetID());
179
180 // GG
181 // Allocation
182 nPads = digits.size();
183 double xyDxy[nPads * 4];
184 Mask_t saturated[nPads];
185 Mask_t cathode[nPads];
186 double padCharge[nPads];
187 // use to store in the dump file
188 uint32_t padADC[nPads];
189 DEId = digits[0].getDetID();
190 double* xPad = getX(xyDxy, nPads);
191 double* yPad = getY(xyDxy, nPads);
192 double* dxPad = getDX(xyDxy, nPads);
193 double* dyPad = getDY(xyDxy, nPads);
194
195 for (int iDigit = 0; iDigit < digits.size(); ++iDigit) {
196 const auto& digit = digits[iDigit];
197 int padID = digit.getPadID();
198
199 double x = mSegmentation->padPositionX(padID);
200 double y = mSegmentation->padPositionY(padID);
201 double dx = mSegmentation->padSizeX(padID) / 2.;
202 double dy = mSegmentation->padSizeY(padID) / 2.;
203 uint32_t adc = digit.getADC();
204 double charge = mADCToCharge(adc);
205 bool isSaturated = digit.isSaturated();
206 int plane = mSegmentation->isBendingPad(padID) ? 0 : 1;
207
208 if (charge <= 0.) {
209 throw std::runtime_error("The precluster contains a digit with charge <= 0");
210 }
211
212 // GG
213 // Initialisation for GEM processing
214 xPad[iDigit] = x;
215 yPad[iDigit] = y;
216 dxPad[iDigit] = dx;
217 dyPad[iDigit] = dy;
218 padCharge[iDigit] = charge;
219 saturated[iDigit] = isSaturated;
220 cathode[iDigit] = plane;
221 padADC[iDigit] = adc;
222 }
223 // GG Store in dump file
224 uint32_t N = digits.size();
225 // std::cout << " [GEM] Dump PreCluster " << dumpFile->getName() << ", size=" << N << std::endl;
226
227 if ((N != 0)) {
228 // Replace 0, by 0xFFFFFFFF
229 uint32_t header[6] = {(uint32_t)(bunchCrossing), (orbit), iPreCluster, (0), N, (uint32_t)(DEId)};
230 dumpFile->dumpUInt32(0, 6, header);
231 dumpFile->dumpFloat64(0, N, xPad);
232 dumpFile->dumpFloat64(0, N, yPad);
233 dumpFile->dumpFloat64(0, N, dxPad);
234 dumpFile->dumpFloat64(0, N, dyPad);
235 dumpFile->dumpFloat64(0, N, padCharge);
236 dumpFile->dumpInt16(0, N, saturated);
237 dumpFile->dumpInt16(0, N, cathode);
238 dumpFile->dumpUInt32(0, N, padADC);
239 }
240}
241
242//_________________________________________________________________________________________________
243void ClusterFinderGEM::dumpClusterResults(ClusterDump* dumpFile, const std::vector<Cluster>& clusters, size_t startIdx, uint16_t bunchCrossing, uint32_t orbit, uint32_t iPreCluster)
244{
245 // Dump result
246 // Dump hits from iNewCluster to mClusters.size()
247 uint32_t N = clusters.size() - startIdx;
248 // struct ClusterStruct {
249 // float x; ///< cluster position along x
250 // float y; ///< cluster position along y
251 // float z; ///< cluster position along z
252 // float ex; ///< cluster resolution along x
253 // float ey; ///< cluster resolution along y
254 // uint32_t uid; ///< cluster unique ID
255 // uint32_t firstDigit; ///< index of first associated digit in the ordered vector of digits
256 // uint32_t nDigits; ///< number of digits attached to this cluster
257 //
258 // Header
259 // std::cout << " [GEM] Dump Cluster " << dumpFile->getName() << ", size=" << N << " start=" << startIdx << std::endl;
260
261 uint32_t header[6] = {(uint32_t)(bunchCrossing), (orbit), iPreCluster, (0), N, 0};
262 dumpFile->dumpUInt32(0, 6, header);
263 //
264 double x[N], y[N];
265 double ex[N], ey[N];
266 uint32_t uid[N];
267 uint32_t firstDigit[N], nDigits[N];
268 int i = 0;
269 for (int n = startIdx; n < clusters.size(); ++n, i++) {
270 Cluster hit = clusters[n];
271 x[i] = hit.x;
272 y[i] = hit.y;
273 ex[i] = hit.ex;
274 ey[i] = hit.ey;
275 uid[i] = hit.uid;
276 firstDigit[i] = hit.firstDigit;
277 nDigits[i] = hit.nDigits;
278 }
279 if (N > 0) {
280 dumpFile->dumpFloat64(0, N, x);
281 dumpFile->dumpFloat64(0, N, y);
282 dumpFile->dumpFloat64(0, N, ex);
283 dumpFile->dumpFloat64(0, N, ey);
284 dumpFile->dumpUInt32(0, N, uid);
285 dumpFile->dumpUInt32(0, N, firstDigit);
286 dumpFile->dumpUInt32(0, N, nDigits);
287 // dumpFile->flush();
288 }
289}
290
291/* Invalid
292//_________________________________________________________________________________________________
293// void ClusterFinderGEM::saveStatistics(ClusterDump* dumpFile, gsl::span<const Digit> digits, const std::vector<Cluster>& clusters, size_t startIdx, uint16_t bunchCrossing, uint32_t orbit, uint32_t iPreCluster)
294void ClusterFinderGEM::saveStatistics(uint32_t orbit, uint16_t bunchCrossing, uint32_t iPreCluster, uint16_t nPads, uint16_t nbrClusters, uint16_t DEId, double duration)
295{
296 statStream << iPreCluster << " " << bunchCrossing << " " << orbit << " "
297 << nPads << " " << nbrClusters << " " << DEId << " " << duration << std::endl;
298}
299*/
300
301//_________________________________________________________________________________________________
302void ClusterFinderGEM::fillGEMInputData(gsl::span<const Digit>& digits, uint16_t bunchCrossing, uint32_t orbit, uint32_t iPreCluster)
303{
305 // GG mPrecluster defined in other MCHPreClustering/PreClusterFinder.h
306 mPreCluster->clear();
307 mSegmentation = &mapping::segmentation(digits[0].getDetID());
308
309 // GG
310 // Allocation
311 nPads = digits.size();
312 xyDxy = new double[nPads * 4];
313 saturated = new Mask_t[nPads];
314 cathode = new Mask_t[nPads];
315 padCharge = new double[nPads];
316 // use to store in the dump file
317 uint32_t padADC[nPads];
318 DEId = digits[0].getDetID();
319 double* xPad = getX(xyDxy, nPads);
320 double* yPad = getY(xyDxy, nPads);
321 double* dxPad = getDX(xyDxy, nPads);
322 double* dyPad = getDY(xyDxy, nPads);
323
324 for (int iDigit = 0; iDigit < digits.size(); ++iDigit) {
325 const auto& digit = digits[iDigit];
326 int padID = digit.getPadID();
327
328 double x = mSegmentation->padPositionX(padID);
329 double y = mSegmentation->padPositionY(padID);
330 double dx = mSegmentation->padSizeX(padID) / 2.;
331 double dy = mSegmentation->padSizeY(padID) / 2.;
332 uint32_t adc = digit.getADC();
333 // float charge(0.);
334 // std::memcpy(&charge, &adc, sizeof(adc));
335 double charge = mADCToCharge(adc);
336 bool isSaturated = digit.isSaturated();
337 int plane = mSegmentation->isBendingPad(padID) ? 0 : 1;
338
339 if (charge <= 0.) {
340 throw std::runtime_error("The precluster contains a digit with charge <= 0");
341 }
342 // std::cout << x << ", " << y << ", " << dx << ", " << dy << ", " << charge << ", " << isSaturated << std::endl;
343 mPreCluster->addPad(x, y, dx, dy, charge, isSaturated, plane, iDigit, PadOriginal::kZero);
344 // GG
345 // Initialisation for GEM processing
346 xPad[iDigit] = x;
347 yPad[iDigit] = y;
348 dxPad[iDigit] = dx;
349 dyPad[iDigit] = dy;
350 padCharge[iDigit] = charge;
351 saturated[iDigit] = isSaturated;
352 cathode[iDigit] = plane;
353 padADC[iDigit] = adc;
354 }
355}
356
357//_________________________________________________________________________________________________
358void ClusterFinderGEM::setClusterResolution(Cluster& cluster) const
359{
362
363 if (cluster.getChamberId() < 4) {
364
365 // do not consider mono-cathode clusters in stations 1 and 2
368 } else {
369
370 // find pads below the cluster
371 int padIDNB(-1), padIDB(-1);
372 bool padsFound = mSegmentation->findPadPairByPosition(cluster.x, cluster.y, padIDB, padIDNB);
373
374 // look for these pads (if any) in the list of digits associated to this cluster
375 auto itPadNB = mUsedDigits.end();
376 if (padsFound || mSegmentation->isValid(padIDNB)) {
377 itPadNB = std::find_if(mUsedDigits.begin() + cluster.firstDigit, mUsedDigits.end(),
378 [padIDNB](const Digit& digit) { return digit.getPadID() == padIDNB; });
379 }
380 auto itPadB = mUsedDigits.end();
381 if (padsFound || mSegmentation->isValid(padIDB)) {
382 itPadB = std::find_if(mUsedDigits.begin() + cluster.firstDigit, mUsedDigits.end(),
383 [padIDB](const Digit& digit) { return digit.getPadID() == padIDB; });
384 }
385
386 // set the cluster resolution accordingly
387 cluster.ex = (itPadNB == mUsedDigits.end()) ? clusterConfig.SBadClusterResolutionX
388 : clusterConfig.SDefaultClusterResolutionX;
389 cluster.ey = (itPadB == mUsedDigits.end()) ? clusterConfig.SBadClusterResolutionY
390 : clusterConfig.SDefaultClusterResolutionY;
391 }
392}
393
394//_________________________________________________________________________________________________
395void ClusterFinderGEM::findClusters(gsl::span<const Digit> digits,
396 uint16_t bunchCrossing, uint32_t orbit, uint32_t iPreCluster)
397{
400 // std::cout << " [GEM] preCluster digit size=" << digits.size() << std::endl;
401 // skip preclusters with only 1 digit
402 if (digits.size() < 2) {
403 return;
404 }
405 uint32_t nPreviousCluster = mClusters.size();
407 printf("----------------------------------------\n");
408 std::cout << " [GEM] PreCluster BC=" << bunchCrossing
409 << ", orbit = " << orbit
410 << ", iPreCluster, = " << iPreCluster
411 << std::endl;
412 printf("----------------------------------------\n");
413 }
414 // std::cout << " [GEM] hits/mClusters.size=" << mClusters.size() << std::endl;
415
416 // set the Mathieson function to be used
417 // GG Inv mMathieson = (digits[0].getDetID() < 300) ? &mMathiesons[0] : &mMathiesons[1];
418
419 // reset the current precluster being processed
420 // GG Set the Precluster (pads , ....)
421 fillGEMInputData(digits, bunchCrossing, orbit, iPreCluster);
422
423 // GG process clusters
424 int chId = DEId / 100;
425 int nbrOfHits = ::clusterProcess(xyDxy, cathode, saturated, padCharge, chId, nPads);
426 double theta[nbrOfHits * 5];
427 Groups_t thetaToGroup[nbrOfHits];
429 collectSeeds(theta, thetaToGroup, nbrOfHits);
430 // std::cout << " [GEM] Seeds found by GEM " << nbrOfHits << " / nPads = " << nPads << std::endl;
431 double* muX = getMuX(theta, nbrOfHits);
432 double* muY = getMuY(theta, nbrOfHits);
433 double* w = getW(theta, nbrOfHits);
434 // Find subClusters with there seeds
435 //
437 Groups_t padToCathGrp[nPads];
438 collectGroupMapping(padToCathGrp, nPads);
439 // vectorPrintShort( "padToCathGrp ???", padToCathGrp, nPads);
440 // Take care the number of groups can be !=
441 // between thetaToGroup
442 Groups_t nCathGrp = vectorMaxShort(padToCathGrp, nPads);
443 int nPadStored = 0;
444 // Index of the first store digit of the group
445 uint32_t firstDigit;
446 // For all the cath groups
447 for (int g = 1; g < (nCathGrp + 1); g++) {
448 int i = 0;
449 firstDigit = mUsedDigits.size();
450 for (const auto& pad : *mPreCluster) {
451 // Store the pad belonging to the cath-group
452 if (padToCathGrp[i] == g) {
453 mUsedDigits.emplace_back(digits[pad.digitIndex()]);
454 nPadStored++;
455 }
456 i++;
457 }
458 // n digits for the considered group
459 uint32_t nDigits = mUsedDigits.size() - firstDigit;
460 // For all the seeds or hits
461 for (int s = 0; s < nbrOfHits; s++) {
462 // Store the hit belonging to the cath-group
463 if (thetaToGroup[s] == g) {
464 double x = muX[s];
465 double y = muY[s];
466 /*
467 // ??? Do something for the mathieson factors
468 double dx, dy;
469 // ??? value of chID
470 // ??? To do later
471 if (chId <= 4) {
472 dx = SDefaultClusterResolutionX;
473 dy = SDefaultClusterResolutionY;
474 } else {
475 // Find the associated pads
476 // set the cluster resolution accordingly
477 // cluster.ex = (NBPad) ? SBadClusterResolutionX : SDefaultClusterResolutionX;
478 // cluster.ey = (BPad) ? SBadClusterResolutionY : SDefaultClusterResolutionY;
479 // ???
480 dx = SDefaultClusterResolutionX;
481 dy = SDefaultClusterResolutionY;
482 }
483 */
484 // ??? uint32_t uid = Cluster::buildUniqueId(digits[0].getDetID() / 100 - 1, digits[0].getDetID(), thetaToGroup[s]);
485 uint32_t uid = Cluster::buildUniqueId(digits[0].getDetID() / 100 - 1, digits[0].getDetID(), nPreviousCluster + s);
486 // Debug
487 /*
488 std::cout << "nPreviousCluster=" << nPreviousCluster << ", s=" << ", uid=" << uid << std::endl;
489 */
490 mClusters.push_back({
491 static_cast<float>(x), static_cast<float>(y), 0.0, // x, y, z
492 static_cast<float>(0), static_cast<float>(0), // x, y resolution
493 uid, // uid
494 firstDigit, nDigits // firstDigit, nDigits
495 });
496 setClusterResolution(mClusters[mClusters.size() - 1]);
497 // Debug
498 int iNewCluster = mClusters.size() - 1;
499 /*
500 std::cout << "iNewCluster=" << iNewCluster << ", DEId=" << digits[0].getDetID()
501 << ", x" << mClusters[iNewCluster].x << ", y" << mClusters[iNewCluster].y << ", z" << mClusters[iNewCluster].z
502 << "uid=" << mClusters[iNewCluster].uid << std::endl;
503 */
504 }
505 }
506 }
507
508 // std::cout << " [GEM] Finished preCluster " << digits.size() << std::endl;
511}
512
513} // namespace mch
514} // namespace o2
Clustering and fifting parameters.
Definition of the cluster used by the original cluster finder algorithm.
Configurable parameters for MCH clustering.
int16_t charge
Definition RawEventData.h:5
uint64_t orbit
Definition RawEventData.h:6
unsigned short int uint16_t
unsigned int uint32_t
std::vector< std::string > header
int32_t i
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered saturated
Original definition of the Mathieson function.
Definition of the pad used by the original cluster finder algorithm.
void dumpInt16(int ifile, long size, const int16_t *data)
void dumpUInt32(int ifile, long size, const uint32_t *data)
void dumpFloat64(int ifile, long size, const double_t *data)
void fillGEMInputData(gsl::span< const Digit > &digits, uint16_t bunchCrossing, uint32_t orbit, uint32_t iPreCluster)
void findClusters(gsl::span< const Digit > digits, uint16_t bunchCrossing, uint32_t orbit, uint32_t iPreCluster)
void dumpPreCluster(ClusterDump *dumpFile, gsl::span< const Digit > digits, uint16_t bunchCrossing, uint32_t orbit, uint32_t iPreCluster)
void init(int mode, bool run2Config)
void dumpClusterResults(ClusterDump *dumpFile, const std::vector< Cluster > &clusters, size_t startIdx, uint16_t bunchCrossing, uint32_t orbit, uint32_t iPreCluster)
cluster for internal use
Original Mathieson function.
@ kZero
pad "basic" state
Definition PadOriginal.h:36
double padPositionX(int dePadIndex) const
double padSizeY(int dePadIndex) const
bool findPadPairByPosition(double x, double y, int &bpad, int &nbpad) const
bool isBendingPad(int dePadIndex) const
double padPositionY(int dePadIndex) const
double padSizeX(int dePadIndex) const
bool isValid(int dePadIndex) const
int clusterProcess(const double *xyDxyi, const o2::mch::Mask_t *cathi, const o2::mch::Mask_t *saturated, const double *zi, int chId, int nPads)
GLboolean GLboolean g
Definition glcorearb.h:1233
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
GLint y
Definition glcorearb.h:270
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
O2MCHMAPPINGIMPL3_EXPORT const Segmentation & segmentation(int detElemId)
void initMathieson(int useSpline_, int useCache_)
Definition mathieson.cxx:73
double * getMuY(double *theta, int K)
short Groups_t
double * getDX(double *xyDxy, int N)
void collectSeeds(double *theta, o2::mch::Groups_t *thetaToGroup, int K)
void cleanClusterResults()
double * getX(double *xyDxy, int N)
double * getY(double *xyDxy, int N)
void initClusterConfig()
short Mask_t
double * getMuX(double *theta, int K)
double * getW(double *theta, int K)
double * getDY(double *xyDxy, int N)
ClusterConfig clusterConfig
void collectGroupMapping(Mask_t *padToMGrp, int nPads)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
float SBadClusterResolutionX
bad (e.g. mono-cathode) cluster resolution in x direction (cm)
float SBadClusterResolutionY
bad (e.g. mono-cathode) cluster resolution in y direction (cm)
@ info
Describes main steps and high level behaviors.
float SDefaultClusterResolutionY
default cluster resolution in y direction (cm)
float SDefaultClusterResolutionX
default cluster resolution in x direction (cm)
cluster minimal structure
Definition Cluster.h:31
float ey
cluster resolution along y
Definition Cluster.h:36
int getChamberId() const
Return the chamber ID (0..), part of the unique ID.
Definition Cluster.h:60
uint32_t firstDigit
index of first associated digit in the ordered vector of digits
Definition Cluster.h:38
uint32_t uid
cluster unique ID
Definition Cluster.h:37
uint32_t nDigits
number of digits attached to this cluster
Definition Cluster.h:39
float y
cluster position along y
Definition Cluster.h:33
float x
cluster position along x
Definition Cluster.h:32
float ex
cluster resolution along x
Definition Cluster.h:35
std::vector< Cluster > clusters
std::vector< Digit > digits
ArrayADC adc