Project
Loading...
Searching...
No Matches
ClusterFactory.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
13#include <array>
14#include <gsl/span>
15#include "Rtypes.h"
23#include "EMCALBase/Geometry.h"
24#include "MathUtils/Cartesian.h"
25
27
28using namespace o2::emcal;
29
30template <class InputType>
31ClusterFactory<InputType>::ClusterFactory(gsl::span<const o2::emcal::Cluster> clustersContainer, gsl::span<const InputType> inputsContainer, gsl::span<const int> cellsIndices)
32{
33 setContainer(clustersContainer, inputsContainer, cellsIndices);
34}
35
36template <class InputType>
38{
39 mClustersContainer = gsl::span<const o2::emcal::Cluster>();
40 mInputsContainer = gsl::span<const InputType>();
41 mCellsIndices = gsl::span<int>();
42 mLookUpInit = false;
43 mCellLabelContainer = gsl::span<const o2::emcal::CellLabel>();
44}
45
48//____________________________________________________________________________
49template <class InputType>
51{
52 if (clusterIndex >= mClustersContainer.size()) {
53 throw ClusterRangeException(clusterIndex, mClustersContainer.size());
54 }
55 if (!mGeomPtr) {
57 }
58
59 o2::emcal::AnalysisCluster clusterAnalysis;
60 clusterAnalysis.setID(clusterIndex);
61
62 int firstCellIndex = mClustersContainer[clusterIndex].getCellIndexFirst();
63 int nCells = mClustersContainer[clusterIndex].getNCells();
64
65 gsl::span<const int> inputsIndices = gsl::span<const int>(&mCellsIndices[firstCellIndex], nCells);
66
67 // First calculate the index of input with maximum amplitude and get
68 // the supermodule number where it sits.
69
70 auto [inputIndMax, inputEnergyMax, cellAmp, shared] = getMaximalEnergyIndex(inputsIndices);
71
72 short towerId = mInputsContainer[inputIndMax].getTower();
73
74 float exoticTime = mInputsContainer[inputIndMax].getTimeStamp();
75
76 float fCross = 0.;
77
78 try {
79 clusterAnalysis.setIsExotic(isExoticCell(towerId, inputEnergyMax, exoticTime, fCross));
80 clusterAnalysis.setFCross(fCross);
81 } catch (UninitLookUpTableException& e) {
82 LOG(error) << e.what();
83 }
84
85 clusterAnalysis.setIndMaxInput(inputIndMax);
86
87 clusterAnalysis.setE(cellAmp);
88
89 mSuperModuleNumber = mGeomPtr->GetSuperModuleNumber(towerId);
90
91 clusterAnalysis.setNCells(inputsIndices.size());
92
93 std::vector<unsigned short> cellsIdices;
94
95 bool addClusterLabels = ((clusterLabel != nullptr) && (mCellLabelContainer.size() > 0));
96 for (auto cellIndex : inputsIndices) {
97 cellsIdices.push_back(cellIndex);
98 if (addClusterLabels) {
99 for (size_t iLabel = 0; iLabel < mCellLabelContainer[cellIndex].GetLabelSize(); iLabel++) {
100 if (mCellLabelContainer[cellIndex].GetAmplitudeFraction(iLabel) <= 0.f) {
101 continue; // skip 0 entries
102 }
103 clusterLabel->addValue(mCellLabelContainer[cellIndex].GetLabel(iLabel),
104 mCellLabelContainer[cellIndex].GetAmplitudeFraction(iLabel) * mInputsContainer[cellIndex].getEnergy());
105 }
106 }
107 }
108 if (addClusterLabels) {
109 clusterLabel->orderLabels();
110 clusterLabel->normalize(cellAmp);
111 }
112
113 clusterAnalysis.setCellsIndices(cellsIdices);
114
115 // evaluate global and local position
116 evalGlobalPosition(inputsIndices, clusterAnalysis);
117 evalLocalPosition(inputsIndices, clusterAnalysis);
118
119 // evaluate shower parameters
120 evalElipsAxis(inputsIndices, clusterAnalysis);
121 evalDispersion(inputsIndices, clusterAnalysis);
122
123 // evaluate number of local maxima
124 evalNExMax(inputsIndices, clusterAnalysis);
125
126 evalCoreEnergy(inputsIndices, clusterAnalysis);
127 evalTime(inputsIndices, clusterAnalysis);
128
129 // TODO to be added at a later stage
130 // evalPrimaries(inputsIndices, clusterAnalysis);
131 // evalParents(inputsIndices, clusterAnalysis);
132
133 // TODO to be added at a later stage
134 // Called last because it sets the global position of the cluster?
135 // Do not call it when recalculating clusters out of standard reconstruction
136 // if (!mJustCluster)
137 // evalLocal2TrackingCSTransform();
138
139 return clusterAnalysis;
140}
141
145//____________________________________________________________________________
146template <class InputType>
147void ClusterFactory<InputType>::evalDispersion(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
148{
149 double d = 0., wtot = 0.;
150 int nstat = 0;
151
152 // Calculates the dispersion in cell units
153 double etaMean = 0.0, phiMean = 0.0;
154
155 // Calculate mean values
156 for (auto iInput : inputsIndices) {
157
158 if (clusterAnalysis.E() > 0 && mInputsContainer[iInput].getEnergy() > 0) {
159 auto [nSupMod, nModule, nIphi, nIeta] = mGeomPtr->GetCellIndex(mInputsContainer[iInput].getTower());
160 auto [iphi, ieta] = mGeomPtr->GetCellPhiEtaIndexInSModule(nSupMod, nModule, nIphi, nIeta);
161
162 // In case of a shared cluster, index of SM in C side, columns start at 48 and ends at 48*2
163 // C Side impair SM, nSupMod%2=1; A side pair SM nSupMod%2=0
164 if (mSharedCluster && nSupMod % 2) {
165 ieta += EMCAL_COLS;
166 }
167
168 double etai = (double)ieta;
169 double phii = (double)iphi;
170 double w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
171
172 if (w > 0.0) {
173 phiMean += phii * w;
174 etaMean += etai * w;
175 wtot += w;
176 }
177 }
178 }
179
180 if (wtot > 0) {
181 phiMean /= wtot;
182 etaMean /= wtot;
183 } else {
184 LOG(error) << Form("Wrong weight %f\n", wtot);
185 }
186
187 // Calculate dispersion
188 for (auto iInput : inputsIndices) {
189
190 if (clusterAnalysis.E() > 0 && mInputsContainer[iInput].getEnergy() > 0) {
191 auto [nSupMod, nModule, nIphi, nIeta] = mGeomPtr->GetCellIndex(mInputsContainer[iInput].getTower());
192 auto [iphi, ieta] = mGeomPtr->GetCellPhiEtaIndexInSModule(nSupMod, nModule, nIphi, nIeta);
193
194 // In case of a shared cluster, index of SM in C side, columns start at 48 and ends at 48*2
195 // C Side impair SM, nSupMod%2=1; A side pair SM, nSupMod%2=0
196 if (mSharedCluster && nSupMod % 2) {
197 ieta += EMCAL_COLS;
198 }
199
200 double etai = (double)ieta;
201 double phii = (double)iphi;
202 double w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
203
204 if (w > 0.0) {
205 nstat++;
206 d += w * ((etai - etaMean) * (etai - etaMean) + (phii - phiMean) * (phii - phiMean));
207 }
208 }
209 }
210
211 if (wtot > 0 && nstat > 1) {
212 d /= wtot;
213 } else {
214 d = 0.;
215 }
216
217 clusterAnalysis.setDispersion(TMath::Sqrt(d));
218}
219
222//____________________________________________________________________________
223template <class InputType>
224void ClusterFactory<InputType>::evalLocalPosition(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
225{
226
227 int nstat = 0;
228
229 double dist = tMaxInCm(double(clusterAnalysis.E()));
230
231 double clXYZ[3] = {0., 0., 0.}, clRmsXYZ[3] = {0., 0., 0.}, xyzi[3], wtot = 0., w = 0.;
232
233 for (auto iInput : inputsIndices) {
234
235 try {
236 mGeomPtr->RelPosCellInSModule(mInputsContainer[iInput].getTower(), dist).GetCoordinates(xyzi[0], xyzi[1], xyzi[2]);
237 } catch (InvalidCellIDException& e) {
238 LOG(error) << e.what();
239 continue;
240 }
241
242 // Temporal patch, due to mapping problem, need to swap "y" in one of the 2 SM, although no effect in position calculation. GCB 05/2010
243 if (mSharedCluster && mSuperModuleNumber != mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower())) {
244 xyzi[1] *= -1;
245 }
246
247 if (mLogWeight > 0.0) {
248 w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
249 } else {
250 w = mInputsContainer[iInput].getEnergy(); // just energy
251 }
252
253 if (w > 0.0) {
254 wtot += w;
255 nstat++;
256
257 for (int i = 0; i < 3; i++) {
258 clXYZ[i] += (w * xyzi[i]);
259 clRmsXYZ[i] += (w * xyzi[i] * xyzi[i]);
260 }
261 } // w > 0
262 } // dig loop
263
264 // cout << " wtot " << wtot << endl;
265
266 if (wtot > 0) {
267 // xRMS = TMath::Sqrt(x2m - xMean*xMean);
268 for (int i = 0; i < 3; i++) {
269 clXYZ[i] /= wtot;
270
271 if (nstat > 1) {
272 clRmsXYZ[i] /= (wtot * wtot);
273 clRmsXYZ[i] = clRmsXYZ[i] - clXYZ[i] * clXYZ[i];
274
275 if (clRmsXYZ[i] > 0.0) {
276 clRmsXYZ[i] = TMath::Sqrt(clRmsXYZ[i]);
277 } else {
278 clRmsXYZ[i] = 0;
279 }
280 } else {
281 clRmsXYZ[i] = 0;
282 }
283 }
284 } else {
285 for (int i = 0; i < 3; i++) {
286 clXYZ[i] = clRmsXYZ[i] = -1.;
287 }
288 }
289
290 clusterAnalysis.setLocalPosition(math_utils::Point3D<float>(clXYZ[0], clXYZ[1], clXYZ[2]));
291}
292
295//____________________________________________________________________________
296template <class InputType>
297void ClusterFactory<InputType>::evalGlobalPosition(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
298{
299
300 int i = 0, nstat = 0;
301
302 double dist = tMaxInCm(double(clusterAnalysis.E()));
303
304 double clXYZ[3] = {0., 0., 0.}, clRmsXYZ[3] = {0., 0., 0.}, lxyzi[3], xyzi[3], wtot = 0., w = 0.;
305
306 for (auto iInput : inputsIndices) {
307
308 // get the local coordinates of the cell
309 try {
310 mGeomPtr->RelPosCellInSModule(mInputsContainer[iInput].getTower(), dist).GetCoordinates(lxyzi[0], lxyzi[1], lxyzi[2]);
311 } catch (InvalidCellIDException& e) {
312 LOG(error) << e.what();
313 continue;
314 }
315
316 // Now get the global coordinate
317 mGeomPtr->GetGlobal(lxyzi, xyzi, mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower()));
318
319 if (mLogWeight > 0.0) {
320 w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
321 } else {
322 w = mInputsContainer[iInput].getEnergy(); // just energy
323 }
324
325 if (w > 0.0) {
326 wtot += w;
327 nstat++;
328
329 for (i = 0; i < 3; i++) {
330 clXYZ[i] += (w * xyzi[i]);
331 clRmsXYZ[i] += (w * xyzi[i] * xyzi[i]);
332 }
333 }
334 }
335
336 // cout << " wtot " << wtot << endl;
337
338 if (wtot > 0) {
339 // xRMS = TMath::Sqrt(x2m - xMean*xMean);
340 for (i = 0; i < 3; i++) {
341 clXYZ[i] /= wtot;
342
343 if (nstat > 1) {
344 clRmsXYZ[i] /= (wtot * wtot);
345 clRmsXYZ[i] = clRmsXYZ[i] - clXYZ[i] * clXYZ[i];
346
347 if (clRmsXYZ[i] > 0.0) {
348 clRmsXYZ[i] = TMath::Sqrt(clRmsXYZ[i]);
349 } else {
350 clRmsXYZ[i] = 0;
351 }
352 } else {
353 clRmsXYZ[i] = 0;
354 }
355 }
356 } else {
357 for (i = 0; i < 3; i++) {
358 clXYZ[i] = clRmsXYZ[i] = -1.;
359 }
360 }
361
362 clusterAnalysis.setGlobalPosition(math_utils::Point3D<float>(clXYZ[0], clXYZ[1], clXYZ[2]));
363}
364
367//____________________________________________________________________________
368template <class InputType>
369void ClusterFactory<InputType>::evalLocalPositionFit(double deff, double mLogWeight,
370 double phiSlope, gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
371{
372 int i = 0, nstat = 0;
373 double clXYZ[3] = {0., 0., 0.}, clRmsXYZ[3] = {0., 0., 0.}, xyzi[3], wtot = 0., w = 0.;
374
375 for (auto iInput : inputsIndices) {
376
377 try {
378 mGeomPtr->RelPosCellInSModule(mInputsContainer[iInput].getTower(), deff).GetCoordinates(xyzi[0], xyzi[1], xyzi[2]);
379 } catch (InvalidCellIDException& e) {
380 LOG(error) << e.what();
381 continue;
382 }
383
384 if (mLogWeight > 0.0) {
385 w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
386 } else {
387 w = mInputsContainer[iInput].getEnergy(); // just energy
388 }
389
390 if (w > 0.0) {
391 wtot += w;
392 nstat++;
393
394 for (i = 0; i < 3; i++) {
395 clXYZ[i] += (w * xyzi[i]);
396 clRmsXYZ[i] += (w * xyzi[i] * xyzi[i]);
397 }
398 }
399 } // loop
400
401 // cout << " wtot " << wtot << endl;
402
403 if (wtot > 0) {
404 // xRMS = TMath::Sqrt(x2m - xMean*xMean);
405 for (i = 0; i < 3; i++) {
406 clXYZ[i] /= wtot;
407
408 if (nstat > 1) {
409 clRmsXYZ[i] /= (wtot * wtot);
410 clRmsXYZ[i] = clRmsXYZ[i] - clXYZ[i] * clXYZ[i];
411
412 if (clRmsXYZ[i] > 0.0) {
413 clRmsXYZ[i] = TMath::Sqrt(clRmsXYZ[i]);
414 } else {
415 clRmsXYZ[i] = 0;
416 }
417 } else {
418 clRmsXYZ[i] = 0;
419 }
420 }
421 } else {
422 for (i = 0; i < 3; i++) {
423 clXYZ[i] = clRmsXYZ[i] = -1.;
424 }
425 }
426
427 // clRmsXYZ[i] ??
428
429 if (phiSlope != 0.0 && mLogWeight > 0.0 && wtot) {
430 // Correction in phi direction (y - coords here); Aug 16;
431 // May be put to global level or seperate method
432 double ycorr = clXYZ[1] * (1. + phiSlope);
433
434 // printf(" y %f : ycorr %f : slope %f \n", clXYZ[1], ycorr, phiSlope);
435 clXYZ[1] = ycorr;
436 }
437
438 clusterAnalysis.setLocalPosition(math_utils::Point3D<float>(clXYZ[0], clXYZ[1], clXYZ[2]));
439}
440
445//_____________________________________________________________________________
446template <class InputType>
447void ClusterFactory<InputType>::getDeffW0(const double esum, double& deff, double& w0)
448{
449 double e = 0.0;
450 const double kdp0 = 9.25147, kdp1 = 1.16700; // Hard coded now
451 const double kwp0 = 4.83713, kwp1 = -2.77970e-01, kwp2 = 4.41116;
452
453 // No extrapolation here
454 e = esum < 0.5 ? 0.5 : esum;
455 e = e > 100. ? 100. : e;
456
457 deff = kdp0 + kdp1 * TMath::Log(e);
458 w0 = kwp0 / (1. + TMath::Exp(kwp1 * (e + kwp2)));
459}
460
468//______________________________________________________________________________
469template <class InputType>
470void ClusterFactory<InputType>::evalCoreEnergy(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
471{
472
473 float coreEnergy = 0.;
474
475 if (!clusterAnalysis.getLocalPosition().Mag2()) {
476 evalLocalPosition(inputsIndices, clusterAnalysis);
477 }
478
479 double phiPoint = clusterAnalysis.getLocalPosition().Phi();
480 double etaPoint = clusterAnalysis.getLocalPosition().Eta();
481 for (auto iInput : inputsIndices) {
482
483 auto [eta, phi] = mGeomPtr->EtaPhiFromIndex(mInputsContainer[iInput].getTower());
484 phi = phi * TMath::DegToRad();
485
486 double distance = TMath::Sqrt((eta - etaPoint) * (eta - etaPoint) + (phi - phiPoint) * (phi - phiPoint));
487
488 if (distance < mCoreRadius) {
489 coreEnergy += mInputsContainer[iInput].getEnergy();
490 }
491 }
492 clusterAnalysis.setCoreEnergy(coreEnergy);
493}
494
497//____________________________________________________________________________
498template <class InputType>
499void ClusterFactory<InputType>::evalNExMax(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
500{
501 // Pre-compute cell indices and energies for all cells in cluster to avoid multiple expensive geometry lookups
502 const size_t n = inputsIndices.size();
503 std::vector<short> rows;
504 std::vector<short> columns;
505 std::vector<double> energies;
506
507 rows.reserve(n);
508 columns.reserve(n);
509 energies.reserve(n);
510
511 for (auto iInput : inputsIndices) {
512 auto [nSupMod, nModule, nIphi, nIeta] = mGeomPtr->GetCellIndex(mInputsContainer[iInput].getTower());
513
514 // get a nice topological indexing that is done in exactly the same way as used by the clusterizer
515 // this way we can handle the shared cluster cases correctly
516 const auto [row, column] = mGeomPtr->GetTopologicalRowColumn(nSupMod, nModule, nIphi, nIeta);
517
518 rows.push_back(row);
519 columns.push_back(column);
520 energies.push_back(mInputsContainer[iInput].getEnergy());
521 }
522
523 // Now find local maxima using pre-computed data
524 int nExMax = 0;
525 for (size_t i = 0; i < n; i++) {
526 // this cell is assumed to be local maximum unless we find a higher energy cell in the neighborhood
527 bool isExMax = true;
528
529 // loop over all other cells in cluster
530 for (size_t j = 0; j < n; j++) {
531 if (i == j)
532 continue;
533
534 // adjacent cell is any cell with adjacent phi or eta index
535 if (std::abs(rows[i] - rows[j]) <= 1 &&
536 std::abs(columns[i] - columns[j]) <= 1) {
537
538 // if there is a cell with higher energy than the current cell, it is not a local maximum
539 if (energies[j] > energies[i]) {
540 isExMax = false;
541 break;
542 }
543 }
544 }
545 if (isExMax) {
546 nExMax++;
547 }
548 }
549 clusterAnalysis.setNExMax(nExMax);
550}
551
555//____________________________________________________________________________
556template <class InputType>
557void ClusterFactory<InputType>::evalElipsAxis(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
558{
559 double wtot = 0.;
560 double x = 0.;
561 double z = 0.;
562 double dxx = 0.;
563 double dzz = 0.;
564 double dxz = 0.;
565
566 std::array<float, 2> lambda;
567
568 for (auto iInput : inputsIndices) {
569
570 auto [nSupMod, nModule, nIphi, nIeta] = mGeomPtr->GetCellIndex(mInputsContainer[iInput].getTower());
571 auto [iphi, ieta] = mGeomPtr->GetCellPhiEtaIndexInSModule(nSupMod, nModule, nIphi, nIeta);
572
573 // In case of a shared cluster, index of SM in C side, columns start at 48 and ends at 48*2
574 // C Side impair SM, nSupMod%2=1; A side pair SM, nSupMod%2=0
575 if (mSharedCluster && nSupMod % 2) {
576 ieta += EMCAL_COLS;
577 }
578
579 double etai = (double)ieta;
580 double phii = (double)iphi;
581
582 double w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
583 // clusterAnalysis.E() summed amplitude of inputs, i.e. energy of cluster
584 // Gives smaller value of lambda than log weight
585 // w = mEnergyList[iInput] / clusterAnalysis.E(); // Nov 16, 2006 - try just energy
586
587 dxx += w * etai * etai;
588 x += w * etai;
589 dzz += w * phii * phii;
590 z += w * phii;
591
592 dxz += w * etai * phii;
593
594 wtot += w;
595 }
596
597 if (wtot > 0) {
598 dxx /= wtot;
599 x /= wtot;
600 dxx -= x * x;
601 dzz /= wtot;
602 z /= wtot;
603 dzz -= z * z;
604 dxz /= wtot;
605 dxz -= x * z;
606
607 lambda[0] = 0.5 * (dxx + dzz) + TMath::Sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz);
608
609 if (lambda[0] > 0) {
610 lambda[0] = TMath::Sqrt(lambda[0]);
611 } else {
612 lambda[0] = 0;
613 }
614
615 lambda[1] = 0.5 * (dxx + dzz) - TMath::Sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz);
616
617 if (lambda[1] > 0) { // To avoid exception if numerical errors lead to negative lambda.
618 lambda[1] = TMath::Sqrt(lambda[1]);
619 } else {
620 lambda[1] = 0.;
621 }
622 } else {
623 lambda[0] = 0.;
624 lambda[1] = 0.;
625 }
626
627 clusterAnalysis.setM02(lambda[0] * lambda[0]);
628 clusterAnalysis.setM20(lambda[1] * lambda[1]);
629}
630
633//____________________________________________________________________________
634template <class InputType>
635std::tuple<int, float, float, bool> ClusterFactory<InputType>::getMaximalEnergyIndex(gsl::span<const int> inputsIndices) const
636{
637
638 float energy = 0.;
639 int mid = 0;
640 float cellAmp = 0;
641 int iSupMod0 = -1;
642 bool shared = false;
643 for (auto iInput : inputsIndices) {
644 if (iInput >= mInputsContainer.size()) {
645 throw CellIndexRangeException(iInput, mInputsContainer.size());
646 }
647 cellAmp += mInputsContainer[iInput].getEnergy();
648 if (iSupMod0 == -1) {
649 iSupMod0 = mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower());
650 } else if (iSupMod0 != mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower())) {
651 shared = true;
652 }
653 if (mInputsContainer[iInput].getEnergy() > energy) {
654 energy = mInputsContainer[iInput].getEnergy();
655 mid = iInput;
656 }
657 } // loop on cluster inputs
658
659 return std::make_tuple(mid, energy, cellAmp, shared);
660}
661
664//____________________________________________________________________________
665template <class InputType>
666bool ClusterFactory<InputType>::isExoticCell(short towerId, float ecell, float const exoticTime, float& fCross) const
667{
668 if (ecell < mExoticCellMinAmplitude) {
669 return false; // do not reject low energy cells
670 }
671
672 // if the look up table is not set yet (mostly due to a reset call) then set it up now.
673 if (!getLookUpInit()) {
675 }
676
677 float eCross = getECross(towerId, ecell, exoticTime);
678 fCross = 1.f - eCross / ecell;
679
680 if (fCross > mExoticCellFraction) {
681 LOG(debug) << "EXOTIC CELL id " << towerId << ", eCell " << ecell << ", eCross " << eCross << ", 1-eCross/eCell " << 1 - eCross / ecell;
682 return true;
683 }
684
685 return false;
686}
687
690//____________________________________________________________________________
691template <class InputType>
692float ClusterFactory<InputType>::getECross(short towerId, float energy, float const exoticTime) const
693{
694 auto [iSM, iMod, iIphi, iIeta] = mGeomPtr->GetCellIndex(towerId);
695 auto [iphi, ieta] = mGeomPtr->GetCellPhiEtaIndexInSModule(iSM, iMod, iIphi, iIeta);
696
697 // Get close cells index, energy and time, not in corners
698
699 short towerId1 = -1;
700 short towerId2 = -1;
701
702 if (iphi < o2::emcal::EMCAL_ROWS - 1) {
703 try {
704 towerId1 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi + 1, ieta);
705 } catch (InvalidCellIDException& e) {
706 towerId1 = -1 * e.getCellID();
707 }
708 }
709 if (iphi > 0) {
710 try {
711 towerId2 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi - 1, ieta);
712 } catch (InvalidCellIDException& e) {
713 towerId2 = -1 * e.getCellID();
714 }
715 }
716
717 // In case of cell in eta = 0 border, depending on SM shift the cross cell index
718
719 short towerId3 = -1;
720 short towerId4 = -1;
721
722 if (ieta == o2::emcal::EMCAL_COLS - 1 && !(iSM % 2)) {
723 try {
724 towerId3 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM + 1, iphi, 0);
725 } catch (InvalidCellIDException& e) {
726 towerId3 = -1 * e.getCellID();
727 }
728 try {
729 towerId4 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta - 1);
730 } catch (InvalidCellIDException& e) {
731 towerId4 = -1 * e.getCellID();
732 }
733 } else if (ieta == 0 && iSM % 2) {
734 try {
735 towerId3 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta + 1);
736 } catch (InvalidCellIDException& e) {
737 towerId3 = -1 * e.getCellID();
738 }
739 try {
740 towerId4 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM - 1, iphi, o2::emcal::EMCAL_COLS - 1);
741 } catch (InvalidCellIDException& e) {
742 towerId4 = -1 * e.getCellID();
743 }
744 } else {
745 if (ieta < o2::emcal::EMCAL_COLS - 1) {
746 try {
747 towerId3 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta + 1);
748 } catch (InvalidCellIDException& e) {
749 towerId3 = -1 * e.getCellID();
750 }
751 }
752 if (ieta > 0) {
753 try {
754 towerId4 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta - 1);
755 } catch (InvalidCellIDException& e) {
756 towerId4 = -1 * e.getCellID();
757 }
758 }
759 }
760
761 LOG(debug) << "iSM " << iSM << ", towerId " << towerId << ", a " << towerId1 << ", b " << towerId2 << ", c " << towerId3 << ", e " << towerId3;
762
763 short index1 = (towerId1 > -1) ? mLoolUpTowerToIndex.at(towerId1) : -1;
764 short index2 = (towerId2 > -1) ? mLoolUpTowerToIndex.at(towerId2) : -1;
765 short index3 = (towerId3 > -1) ? mLoolUpTowerToIndex.at(towerId3) : -1;
766 short index4 = (towerId4 > -1) ? mLoolUpTowerToIndex.at(towerId4) : -1;
767
768 std::array<std::pair<float, float>, 4> cellData = {
769 {{(index1 > -1) ? mInputsContainer[index1].getEnergy() : 0., (index1 > -1) ? mInputsContainer[index1].getTimeStamp() : 0.},
770 {(index2 > -1) ? mInputsContainer[index2].getEnergy() : 0., (index2 > -1) ? mInputsContainer[index2].getTimeStamp() : 0.},
771 {(index3 > -1) ? mInputsContainer[index3].getEnergy() : 0., (index3 > -1) ? mInputsContainer[index3].getTimeStamp() : 0.},
772 {(index4 > -1) ? mInputsContainer[index4].getEnergy() : 0., (index4 > -1) ? mInputsContainer[index4].getTimeStamp() : 0.}}};
773
774 for (auto& cell : cellData) {
775 if (std::abs(exoticTime - cell.second) > mExoticCellDiffTime) {
776 cell.first = 0;
777 }
778 }
779
780 float w1 = 1, w2 = 1, w3 = 1, w4 = 1;
781 if (mUseWeightExotic) {
782 w1 = GetCellWeight(cellData[0].first, energy);
783 w2 = GetCellWeight(cellData[1].first, energy);
784 w3 = GetCellWeight(cellData[2].first, energy);
785 w4 = GetCellWeight(cellData[3].first, energy);
786 }
787
788 if (cellData[0].first < mExoticCellInCrossMinAmplitude || w1 <= 0) {
789 cellData[0].first = 0;
790 }
791 if (cellData[1].first < mExoticCellInCrossMinAmplitude || w2 <= 0) {
792 cellData[1].first = 0;
793 }
794 if (cellData[2].first < mExoticCellInCrossMinAmplitude || w3 <= 0) {
795 cellData[2].first = 0;
796 }
797 if (cellData[3].first < mExoticCellInCrossMinAmplitude || w4 <= 0) {
798 cellData[3].first = 0;
799 }
800
801 return cellData[0].first + cellData[1].first + cellData[2].first + cellData[3].first;
802}
803
806//____________________________________________________________________________
807template <class InputType>
808float ClusterFactory<InputType>::GetCellWeight(float eCell, float eCluster) const
809{
810 if (eCell > 0 && eCluster > 0) {
811 if (mLogWeight > 0) {
812 return std::max(0.f, mLogWeight + std::log(eCell / eCluster));
813 } else {
814 return std::log(eCluster / eCell);
815 }
816 } else {
817 return 0.;
818 }
819}
820
823//____________________________________________________________________________
824template <class InputType>
825int ClusterFactory<InputType>::getMultiplicityAtLevel(float H, gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
826{
827 int multipl = 0;
828 for (auto iInput : inputsIndices) {
829 if (mInputsContainer[iInput].getEnergy() > H * clusterAnalysis.E()) {
830 multipl++;
831 }
832 }
833
834 return multipl;
835}
836
839//____________________________________________________________________________
840template <class InputType>
841void ClusterFactory<InputType>::evalTime(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
842{
843 float maxE = 0;
844 unsigned short maxAt = 0;
845 for (auto iInput : inputsIndices) {
846 if (mInputsContainer[iInput].getEnergy() > maxE) {
847 maxE = mInputsContainer[iInput].getEnergy();
848 maxAt = iInput;
849 }
850 }
851
852 clusterAnalysis.setClusterTime(mInputsContainer[maxAt].getTimeStamp());
853}
854
858//_____________________________________________________________________
859template <class InputType>
860double ClusterFactory<InputType>::tMaxInCm(const double e, const int key) const
861{
862 const double ca = 4.82; // shower max parameter - first guess; ca=TMath::Log(1000./8.07)
863 double tmax = 0.; // position of electromagnetic shower max in cm
864
865 const double x0 = 1.31; // radiation lenght (cm)
866
867 if (e > 0.1) {
868 tmax = TMath::Log(e) + ca;
869 if (key == 0) {
870 tmax += 0.5;
871 } else {
872 tmax -= 0.5;
873 }
874 tmax *= x0; // convert to cm
875 }
876
877 return tmax;
878}
879
882//______________________________________________________________________________
883template <class InputType>
885{
886 return (2. * TMath::ATan(TMath::Exp(-arg)));
887}
888
891//______________________________________________________________________________
892template <class InputType>
894{
895 return (-1 * TMath::Log(TMath::Tan(0.5 * arg)));
896}
897
898template <class InputType>
899ClusterFactory<InputType>::ClusterIterator::ClusterIterator(const ClusterFactory& factory, int clusterIndex, bool forward) : mClusterFactory(factory),
900 mCurrentCluster(),
901 mClusterID(clusterIndex),
902 mForward(forward)
903{
904 mCurrentCluster = mClusterFactory.buildCluster(mClusterID);
905}
906
907template <class InputType>
909{
910 return &mClusterFactory == &rhs.mClusterFactory && mClusterID == rhs.mClusterID && mForward == rhs.mForward;
911}
912
913template <class InputType>
915{
916 if (mForward) {
917 mClusterID++;
918 } else {
919 mClusterID--;
920 }
921 mCurrentCluster = mClusterFactory.buildCluster(mClusterID);
922 return *this;
923}
924
925template <class InputType>
927{
928 auto tmp = *this;
929 ++(*this);
930 return tmp;
931}
932
933template <class InputType>
935{
936 if (mForward) {
937 mClusterID--;
938 } else {
939 mClusterID++;
940 }
941 mCurrentCluster = mClusterFactory.buildCluster(mClusterID);
942 return *this;
943}
944
945template <class InputType>
947{
948 auto tmp = *this;
949 --(*this);
950 return tmp;
951}
952
std::ostringstream debug
int32_t i
uint32_t j
Definition RawData.h:0
StringRef key
Cluster class for kinematic cluster parametersported from AliVCluster in AliRoot.
void setNExMax(unsigned char nExMax)
void setGlobalPosition(math_utils::Point3D< float > x)
Set the cluster global position.
void setFCross(float fCross)
void setCoreEnergy(float energy)
math_utils::Point3D< float > getLocalPosition() const
void setCellsIndices(const std::vector< unsigned short > &array)
Set the array of cell indices.
void setIndMaxInput(const int ind)
void setClusterTime(float time)
void setLocalPosition(math_utils::Point3D< float > x)
ClusterIterator & operator--()
Prefix decrementation operator.
ClusterIterator(const ClusterFactory &factory, int clusterIndex, bool forward)
Constructor, initializing the iterator.
bool operator==(const ClusterIterator &rhs) const
Check for equalness.
ClusterIterator & operator++()
Prefix incrementation operator.
Exception handling uninitialized look up table.
const char * what() const noexcept final
Access to error message of the exception.
EMCal clusters factory Ported from class AliEMCALcluster.
void reset()
Reset containers.
std::tuple< int, float, float, bool > getMaximalEnergyIndex(gsl::span< const int > inputsIndices) const
Finds the maximum energy in the cluster and computes the Summed amplitude of digits/cells.
float GetCellWeight(float eCell, float eCluster) const
return weight of cell for shower shape calculation
float thetaToEta(float arg) const
Converts Theta (Radians) to Eta (Radians)
void evalNExMax(gsl::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
Calculate the number of local maxima in the cluster.
float getECross(short absID, float energy, float const exoticTime) const
Calculate the energy in the cross around the energy of a given cell.
void evalGlobalPosition(gsl::span< const int > inputsIndices, AnalysisCluster &cluster) const
Calculates the center of gravity in the global ALICE coordinates.
void evalLocalPosition(gsl::span< const int > inputsIndices, AnalysisCluster &cluster) const
Calculates the center of gravity in the local EMCAL-module coordinates.
Double_t tMaxInCm(const Double_t e=0.0, const int key=0) const
static void getDeffW0(const Double_t esum, Double_t &deff, Double_t &w0)
void evalTime(gsl::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
Time is set to the time of the digit with the maximum energy.
int getMultiplicityAtLevel(float level, gsl::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
Calculates the multiplicity of digits/cells with energy larger than level*energy.
ClusterFactory()=default
Dummy constructor.
void evalLocalPositionFit(Double_t deff, Double_t w0, Double_t phiSlope, gsl::span< const int > inputsIndices, AnalysisCluster &cluster) const
evaluates local position of clusters in SM
void evalElipsAxis(gsl::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
void evalCoreEnergy(gsl::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
void evalDispersion(gsl::span< const int > inputsIndices, AnalysisCluster &clusterAnalysis) const
float etaToTheta(float arg) const
Converts Eta (Radians) to Theta (Radians)
bool isExoticCell(short towerId, float ecell, float const exoticTime, float &fCross) const
Look to cell neighbourhood and reject if it seems exotic.
AnalysisCluster buildCluster(int index, o2::emcal::ClusterLabel *clusterLabel=nullptr) const
evaluates cluster parameters: position, shower shape, primaries ...
cluster class for MC particle IDs and their respective energy fraction
void orderLabels()
Sort the labels and energy fraction in descending order (largest energy fraction to smallest)
void normalize(float factor)
Normalize the energy fraction.
void addValue(int label, float energyFraction)
Add label and energy fraction to the.
Exception handling non-existing cell IDs.
int getCellID() const noexcept
Access to cell ID raising the exception.
const char * what() const noexcept final
Access to error message of the exception.
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
GLsizei GLsizei GLfloat distance
Definition glcorearb.h:5506
GLuint GLfloat x0
Definition glcorearb.h:5034
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
@ EMCAL_ROWS
Number of rows per module for EMCAL.
Definition Constants.h:25
@ EMCAL_COLS
Number of columns per module for EMCAL.
Definition Constants.h:26
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
std::vector< int > row
std::vector< ReadoutWindowData > rows