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