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 try {
77 clusterAnalysis.setIsExotic(isExoticCell(towerId, inputEnergyMax, exoticTime));
78 } catch (UninitLookUpTableException& e) {
79 LOG(error) << e.what();
80 }
81
82 clusterAnalysis.setIndMaxInput(inputIndMax);
83
84 clusterAnalysis.setE(cellAmp);
85
86 mSuperModuleNumber = mGeomPtr->GetSuperModuleNumber(towerId);
87
88 clusterAnalysis.setNCells(inputsIndices.size());
89
90 std::vector<unsigned short> cellsIdices;
91
92 bool addClusterLabels = ((clusterLabel != nullptr) && (mCellLabelContainer.size() > 0));
93 for (auto cellIndex : inputsIndices) {
94 cellsIdices.push_back(cellIndex);
95 if (addClusterLabels) {
96 for (size_t iLabel = 0; iLabel < mCellLabelContainer[cellIndex].GetLabelSize(); iLabel++) {
97 if (mCellLabelContainer[cellIndex].GetAmplitudeFraction(iLabel) <= 0.f) {
98 continue; // skip 0 entries
99 }
100 clusterLabel->addValue(mCellLabelContainer[cellIndex].GetLabel(iLabel),
101 mCellLabelContainer[cellIndex].GetAmplitudeFraction(iLabel) * mInputsContainer[cellIndex].getEnergy());
102 }
103 }
104 }
105 if (addClusterLabels) {
106 clusterLabel->orderLabels();
107 clusterLabel->normalize(cellAmp);
108 }
109
110 clusterAnalysis.setCellsIndices(cellsIdices);
111
112 // evaluate global and local position
113 evalGlobalPosition(inputsIndices, clusterAnalysis);
114 evalLocalPosition(inputsIndices, clusterAnalysis);
115
116 // evaluate shower parameters
117 evalElipsAxis(inputsIndices, clusterAnalysis);
118 evalDispersion(inputsIndices, clusterAnalysis);
119
120 evalCoreEnergy(inputsIndices, clusterAnalysis);
121 evalTime(inputsIndices, clusterAnalysis);
122
123 // TODO to be added at a later stage
124 // evalPrimaries(inputsIndices, clusterAnalysis);
125 // evalParents(inputsIndices, clusterAnalysis);
126
127 // TODO to be added at a later stage
128 // Called last because it sets the global position of the cluster?
129 // Do not call it when recalculating clusters out of standard reconstruction
130 // if (!mJustCluster)
131 // evalLocal2TrackingCSTransform();
132
133 return clusterAnalysis;
134}
135
139//____________________________________________________________________________
140template <class InputType>
141void ClusterFactory<InputType>::evalDispersion(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
142{
143 double d = 0., wtot = 0.;
144 int nstat = 0;
145
146 // Calculates the dispersion in cell units
147 double etaMean = 0.0, phiMean = 0.0;
148
149 // Calculate mean values
150 for (auto iInput : inputsIndices) {
151
152 if (clusterAnalysis.E() > 0 && mInputsContainer[iInput].getEnergy() > 0) {
153 auto [nSupMod, nModule, nIphi, nIeta] = mGeomPtr->GetCellIndex(mInputsContainer[iInput].getTower());
154 auto [iphi, ieta] = mGeomPtr->GetCellPhiEtaIndexInSModule(nSupMod, nModule, nIphi, nIeta);
155
156 // In case of a shared cluster, index of SM in C side, columns start at 48 and ends at 48*2
157 // C Side impair SM, nSupMod%2=1; A side pair SM nSupMod%2=0
158 if (mSharedCluster && nSupMod % 2) {
159 ieta += EMCAL_COLS;
160 }
161
162 double etai = (double)ieta;
163 double phii = (double)iphi;
164 double w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
165
166 if (w > 0.0) {
167 phiMean += phii * w;
168 etaMean += etai * w;
169 wtot += w;
170 }
171 }
172 }
173
174 if (wtot > 0) {
175 phiMean /= wtot;
176 etaMean /= wtot;
177 } else {
178 LOG(error) << Form("Wrong weight %f\n", wtot);
179 }
180
181 // Calculate dispersion
182 for (auto iInput : inputsIndices) {
183
184 if (clusterAnalysis.E() > 0 && mInputsContainer[iInput].getEnergy() > 0) {
185 auto [nSupMod, nModule, nIphi, nIeta] = mGeomPtr->GetCellIndex(mInputsContainer[iInput].getTower());
186 auto [iphi, ieta] = mGeomPtr->GetCellPhiEtaIndexInSModule(nSupMod, nModule, nIphi, nIeta);
187
188 // In case of a shared cluster, index of SM in C side, columns start at 48 and ends at 48*2
189 // C Side impair SM, nSupMod%2=1; A side pair SM, nSupMod%2=0
190 if (mSharedCluster && nSupMod % 2) {
191 ieta += EMCAL_COLS;
192 }
193
194 double etai = (double)ieta;
195 double phii = (double)iphi;
196 double w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
197
198 if (w > 0.0) {
199 nstat++;
200 d += w * ((etai - etaMean) * (etai - etaMean) + (phii - phiMean) * (phii - phiMean));
201 }
202 }
203 }
204
205 if (wtot > 0 && nstat > 1) {
206 d /= wtot;
207 } else {
208 d = 0.;
209 }
210
211 clusterAnalysis.setDispersion(TMath::Sqrt(d));
212}
213
216//____________________________________________________________________________
217template <class InputType>
218void ClusterFactory<InputType>::evalLocalPosition(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
219{
220
221 int nstat = 0;
222
223 double dist = tMaxInCm(double(clusterAnalysis.E()));
224
225 double clXYZ[3] = {0., 0., 0.}, clRmsXYZ[3] = {0., 0., 0.}, xyzi[3], wtot = 0., w = 0.;
226
227 for (auto iInput : inputsIndices) {
228
229 try {
230 mGeomPtr->RelPosCellInSModule(mInputsContainer[iInput].getTower(), dist).GetCoordinates(xyzi[0], xyzi[1], xyzi[2]);
231 } catch (InvalidCellIDException& e) {
232 LOG(error) << e.what();
233 continue;
234 }
235
236 // 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
237 if (mSharedCluster && mSuperModuleNumber != mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower())) {
238 xyzi[1] *= -1;
239 }
240
241 if (mLogWeight > 0.0) {
242 w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
243 } else {
244 w = mInputsContainer[iInput].getEnergy(); // just energy
245 }
246
247 if (w > 0.0) {
248 wtot += w;
249 nstat++;
250
251 for (int i = 0; i < 3; i++) {
252 clXYZ[i] += (w * xyzi[i]);
253 clRmsXYZ[i] += (w * xyzi[i] * xyzi[i]);
254 }
255 } // w > 0
256 } // dig loop
257
258 // cout << " wtot " << wtot << endl;
259
260 if (wtot > 0) {
261 // xRMS = TMath::Sqrt(x2m - xMean*xMean);
262 for (int i = 0; i < 3; i++) {
263 clXYZ[i] /= wtot;
264
265 if (nstat > 1) {
266 clRmsXYZ[i] /= (wtot * wtot);
267 clRmsXYZ[i] = clRmsXYZ[i] - clXYZ[i] * clXYZ[i];
268
269 if (clRmsXYZ[i] > 0.0) {
270 clRmsXYZ[i] = TMath::Sqrt(clRmsXYZ[i]);
271 } else {
272 clRmsXYZ[i] = 0;
273 }
274 } else {
275 clRmsXYZ[i] = 0;
276 }
277 }
278 } else {
279 for (int i = 0; i < 3; i++) {
280 clXYZ[i] = clRmsXYZ[i] = -1.;
281 }
282 }
283
284 clusterAnalysis.setLocalPosition(math_utils::Point3D<float>(clXYZ[0], clXYZ[1], clXYZ[2]));
285}
286
289//____________________________________________________________________________
290template <class InputType>
291void ClusterFactory<InputType>::evalGlobalPosition(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
292{
293
294 int i = 0, nstat = 0;
295
296 double dist = tMaxInCm(double(clusterAnalysis.E()));
297
298 double clXYZ[3] = {0., 0., 0.}, clRmsXYZ[3] = {0., 0., 0.}, lxyzi[3], xyzi[3], wtot = 0., w = 0.;
299
300 for (auto iInput : inputsIndices) {
301
302 // get the local coordinates of the cell
303 try {
304 mGeomPtr->RelPosCellInSModule(mInputsContainer[iInput].getTower(), dist).GetCoordinates(lxyzi[0], lxyzi[1], lxyzi[2]);
305 } catch (InvalidCellIDException& e) {
306 LOG(error) << e.what();
307 continue;
308 }
309
310 // Now get the global coordinate
311 mGeomPtr->GetGlobal(lxyzi, xyzi, mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower()));
312
313 if (mLogWeight > 0.0) {
314 w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
315 } else {
316 w = mInputsContainer[iInput].getEnergy(); // just energy
317 }
318
319 if (w > 0.0) {
320 wtot += w;
321 nstat++;
322
323 for (i = 0; i < 3; i++) {
324 clXYZ[i] += (w * xyzi[i]);
325 clRmsXYZ[i] += (w * xyzi[i] * xyzi[i]);
326 }
327 }
328 }
329
330 // cout << " wtot " << wtot << endl;
331
332 if (wtot > 0) {
333 // xRMS = TMath::Sqrt(x2m - xMean*xMean);
334 for (i = 0; i < 3; i++) {
335 clXYZ[i] /= wtot;
336
337 if (nstat > 1) {
338 clRmsXYZ[i] /= (wtot * wtot);
339 clRmsXYZ[i] = clRmsXYZ[i] - clXYZ[i] * clXYZ[i];
340
341 if (clRmsXYZ[i] > 0.0) {
342 clRmsXYZ[i] = TMath::Sqrt(clRmsXYZ[i]);
343 } else {
344 clRmsXYZ[i] = 0;
345 }
346 } else {
347 clRmsXYZ[i] = 0;
348 }
349 }
350 } else {
351 for (i = 0; i < 3; i++) {
352 clXYZ[i] = clRmsXYZ[i] = -1.;
353 }
354 }
355
356 clusterAnalysis.setGlobalPosition(math_utils::Point3D<float>(clXYZ[0], clXYZ[1], clXYZ[2]));
357}
358
361//____________________________________________________________________________
362template <class InputType>
363void ClusterFactory<InputType>::evalLocalPositionFit(double deff, double mLogWeight,
364 double phiSlope, gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
365{
366 int i = 0, nstat = 0;
367 double clXYZ[3] = {0., 0., 0.}, clRmsXYZ[3] = {0., 0., 0.}, xyzi[3], wtot = 0., w = 0.;
368
369 for (auto iInput : inputsIndices) {
370
371 try {
372 mGeomPtr->RelPosCellInSModule(mInputsContainer[iInput].getTower(), deff).GetCoordinates(xyzi[0], xyzi[1], xyzi[2]);
373 } catch (InvalidCellIDException& e) {
374 LOG(error) << e.what();
375 continue;
376 }
377
378 if (mLogWeight > 0.0) {
379 w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
380 } else {
381 w = mInputsContainer[iInput].getEnergy(); // just energy
382 }
383
384 if (w > 0.0) {
385 wtot += w;
386 nstat++;
387
388 for (i = 0; i < 3; i++) {
389 clXYZ[i] += (w * xyzi[i]);
390 clRmsXYZ[i] += (w * xyzi[i] * xyzi[i]);
391 }
392 }
393 } // loop
394
395 // cout << " wtot " << wtot << endl;
396
397 if (wtot > 0) {
398 // xRMS = TMath::Sqrt(x2m - xMean*xMean);
399 for (i = 0; i < 3; i++) {
400 clXYZ[i] /= wtot;
401
402 if (nstat > 1) {
403 clRmsXYZ[i] /= (wtot * wtot);
404 clRmsXYZ[i] = clRmsXYZ[i] - clXYZ[i] * clXYZ[i];
405
406 if (clRmsXYZ[i] > 0.0) {
407 clRmsXYZ[i] = TMath::Sqrt(clRmsXYZ[i]);
408 } else {
409 clRmsXYZ[i] = 0;
410 }
411 } else {
412 clRmsXYZ[i] = 0;
413 }
414 }
415 } else {
416 for (i = 0; i < 3; i++) {
417 clXYZ[i] = clRmsXYZ[i] = -1.;
418 }
419 }
420
421 // clRmsXYZ[i] ??
422
423 if (phiSlope != 0.0 && mLogWeight > 0.0 && wtot) {
424 // Correction in phi direction (y - coords here); Aug 16;
425 // May be put to global level or seperate method
426 double ycorr = clXYZ[1] * (1. + phiSlope);
427
428 // printf(" y %f : ycorr %f : slope %f \n", clXYZ[1], ycorr, phiSlope);
429 clXYZ[1] = ycorr;
430 }
431
432 clusterAnalysis.setLocalPosition(math_utils::Point3D<float>(clXYZ[0], clXYZ[1], clXYZ[2]));
433}
434
439//_____________________________________________________________________________
440template <class InputType>
441void ClusterFactory<InputType>::getDeffW0(const double esum, double& deff, double& w0)
442{
443 double e = 0.0;
444 const double kdp0 = 9.25147, kdp1 = 1.16700; // Hard coded now
445 const double kwp0 = 4.83713, kwp1 = -2.77970e-01, kwp2 = 4.41116;
446
447 // No extrapolation here
448 e = esum < 0.5 ? 0.5 : esum;
449 e = e > 100. ? 100. : e;
450
451 deff = kdp0 + kdp1 * TMath::Log(e);
452 w0 = kwp0 / (1. + TMath::Exp(kwp1 * (e + kwp2)));
453}
454
462//______________________________________________________________________________
463template <class InputType>
464void ClusterFactory<InputType>::evalCoreEnergy(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
465{
466
467 float coreEnergy = 0.;
468
469 if (!clusterAnalysis.getLocalPosition().Mag2()) {
470 evalLocalPosition(inputsIndices, clusterAnalysis);
471 }
472
473 double phiPoint = clusterAnalysis.getLocalPosition().Phi();
474 double etaPoint = clusterAnalysis.getLocalPosition().Eta();
475 for (auto iInput : inputsIndices) {
476
477 auto [eta, phi] = mGeomPtr->EtaPhiFromIndex(mInputsContainer[iInput].getTower());
478 phi = phi * TMath::DegToRad();
479
480 double distance = TMath::Sqrt((eta - etaPoint) * (eta - etaPoint) + (phi - phiPoint) * (phi - phiPoint));
481
482 if (distance < mCoreRadius) {
483 coreEnergy += mInputsContainer[iInput].getEnergy();
484 }
485 }
486 clusterAnalysis.setCoreEnergy(coreEnergy);
487}
488
492//____________________________________________________________________________
493template <class InputType>
494void ClusterFactory<InputType>::evalElipsAxis(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
495{
496 double wtot = 0.;
497 double x = 0.;
498 double z = 0.;
499 double dxx = 0.;
500 double dzz = 0.;
501 double dxz = 0.;
502
503 std::array<float, 2> lambda;
504
505 for (auto iInput : inputsIndices) {
506
507 auto [nSupMod, nModule, nIphi, nIeta] = mGeomPtr->GetCellIndex(mInputsContainer[iInput].getTower());
508 auto [iphi, ieta] = mGeomPtr->GetCellPhiEtaIndexInSModule(nSupMod, nModule, nIphi, nIeta);
509
510 // In case of a shared cluster, index of SM in C side, columns start at 48 and ends at 48*2
511 // C Side impair SM, nSupMod%2=1; A side pair SM, nSupMod%2=0
512 if (mSharedCluster && nSupMod % 2) {
513 ieta += EMCAL_COLS;
514 }
515
516 double etai = (double)ieta;
517 double phii = (double)iphi;
518
519 double w = TMath::Max(0., mLogWeight + TMath::Log(mInputsContainer[iInput].getEnergy() / clusterAnalysis.E()));
520 // clusterAnalysis.E() summed amplitude of inputs, i.e. energy of cluster
521 // Gives smaller value of lambda than log weight
522 // w = mEnergyList[iInput] / clusterAnalysis.E(); // Nov 16, 2006 - try just energy
523
524 dxx += w * etai * etai;
525 x += w * etai;
526 dzz += w * phii * phii;
527 z += w * phii;
528
529 dxz += w * etai * phii;
530
531 wtot += w;
532 }
533
534 if (wtot > 0) {
535 dxx /= wtot;
536 x /= wtot;
537 dxx -= x * x;
538 dzz /= wtot;
539 z /= wtot;
540 dzz -= z * z;
541 dxz /= wtot;
542 dxz -= x * z;
543
544 lambda[0] = 0.5 * (dxx + dzz) + TMath::Sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz);
545
546 if (lambda[0] > 0) {
547 lambda[0] = TMath::Sqrt(lambda[0]);
548 } else {
549 lambda[0] = 0;
550 }
551
552 lambda[1] = 0.5 * (dxx + dzz) - TMath::Sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz);
553
554 if (lambda[1] > 0) { // To avoid exception if numerical errors lead to negative lambda.
555 lambda[1] = TMath::Sqrt(lambda[1]);
556 } else {
557 lambda[1] = 0.;
558 }
559 } else {
560 lambda[0] = 0.;
561 lambda[1] = 0.;
562 }
563
564 clusterAnalysis.setM02(lambda[0] * lambda[0]);
565 clusterAnalysis.setM20(lambda[1] * lambda[1]);
566}
567
570//____________________________________________________________________________
571template <class InputType>
572std::tuple<int, float, float, bool> ClusterFactory<InputType>::getMaximalEnergyIndex(gsl::span<const int> inputsIndices) const
573{
574
575 float energy = 0.;
576 int mid = 0;
577 float cellAmp = 0;
578 int iSupMod0 = -1;
579 bool shared = false;
580 for (auto iInput : inputsIndices) {
581 if (iInput >= mInputsContainer.size()) {
582 throw CellIndexRangeException(iInput, mInputsContainer.size());
583 }
584 cellAmp += mInputsContainer[iInput].getEnergy();
585 if (iSupMod0 == -1) {
586 iSupMod0 = mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower());
587 } else if (iSupMod0 != mGeomPtr->GetSuperModuleNumber(mInputsContainer[iInput].getTower())) {
588 shared = true;
589 }
590 if (mInputsContainer[iInput].getEnergy() > energy) {
591 energy = mInputsContainer[iInput].getEnergy();
592 mid = iInput;
593 }
594 } // loop on cluster inputs
595
596 return std::make_tuple(mid, energy, cellAmp, shared);
597}
598
601//____________________________________________________________________________
602template <class InputType>
603bool ClusterFactory<InputType>::isExoticCell(short towerId, float ecell, float const exoticTime) const
604{
605 if (ecell < mExoticCellMinAmplitude) {
606 return false; // do not reject low energy cells
607 }
608
609 // if the look up table is not set yet (mostly due to a reset call) then set it up now.
610 if (!getLookUpInit()) {
612 }
613
614 float eCross = getECross(towerId, ecell, exoticTime);
615
616 if (1 - eCross / ecell > mExoticCellFraction) {
617 LOG(debug) << "EXOTIC CELL id " << towerId << ", eCell " << ecell << ", eCross " << eCross << ", 1-eCross/eCell " << 1 - eCross / ecell;
618 return true;
619 }
620
621 return false;
622}
623
626//____________________________________________________________________________
627template <class InputType>
628float ClusterFactory<InputType>::getECross(short towerId, float energy, float const exoticTime) const
629{
630 auto [iSM, iMod, iIphi, iIeta] = mGeomPtr->GetCellIndex(towerId);
631 auto [iphi, ieta] = mGeomPtr->GetCellPhiEtaIndexInSModule(iSM, iMod, iIphi, iIeta);
632
633 // Get close cells index, energy and time, not in corners
634
635 short towerId1 = -1;
636 short towerId2 = -1;
637
638 if (iphi < o2::emcal::EMCAL_ROWS - 1) {
639 try {
640 towerId1 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi + 1, ieta);
641 } catch (InvalidCellIDException& e) {
642 towerId1 = -1 * e.getCellID();
643 }
644 }
645 if (iphi > 0) {
646 try {
647 towerId2 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi - 1, ieta);
648 } catch (InvalidCellIDException& e) {
649 towerId2 = -1 * e.getCellID();
650 }
651 }
652
653 // In case of cell in eta = 0 border, depending on SM shift the cross cell index
654
655 short towerId3 = -1;
656 short towerId4 = -1;
657
658 if (ieta == o2::emcal::EMCAL_COLS - 1 && !(iSM % 2)) {
659 try {
660 towerId3 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM + 1, iphi, 0);
661 } catch (InvalidCellIDException& e) {
662 towerId3 = -1 * e.getCellID();
663 }
664 try {
665 towerId4 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta - 1);
666 } catch (InvalidCellIDException& e) {
667 towerId4 = -1 * e.getCellID();
668 }
669 } else if (ieta == 0 && iSM % 2) {
670 try {
671 towerId3 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta + 1);
672 } catch (InvalidCellIDException& e) {
673 towerId3 = -1 * e.getCellID();
674 }
675 try {
676 towerId4 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM - 1, iphi, o2::emcal::EMCAL_COLS - 1);
677 } catch (InvalidCellIDException& e) {
678 towerId4 = -1 * e.getCellID();
679 }
680 } else {
681 if (ieta < o2::emcal::EMCAL_COLS - 1) {
682 try {
683 towerId3 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta + 1);
684 } catch (InvalidCellIDException& e) {
685 towerId3 = -1 * e.getCellID();
686 }
687 }
688 if (ieta > 0) {
689 try {
690 towerId4 = mGeomPtr->GetAbsCellIdFromCellIndexes(iSM, iphi, ieta - 1);
691 } catch (InvalidCellIDException& e) {
692 towerId4 = -1 * e.getCellID();
693 }
694 }
695 }
696
697 LOG(debug) << "iSM " << iSM << ", towerId " << towerId << ", a " << towerId1 << ", b " << towerId2 << ", c " << towerId3 << ", e " << towerId3;
698
699 short index1 = (towerId1 > -1) ? mLoolUpTowerToIndex.at(towerId1) : -1;
700 short index2 = (towerId2 > -1) ? mLoolUpTowerToIndex.at(towerId2) : -1;
701 short index3 = (towerId3 > -1) ? mLoolUpTowerToIndex.at(towerId3) : -1;
702 short index4 = (towerId4 > -1) ? mLoolUpTowerToIndex.at(towerId4) : -1;
703
704 std::array<std::pair<float, float>, 4> cellData = {
705 {{(index1 > -1) ? mInputsContainer[index1].getEnergy() : 0., (index1 > -1) ? mInputsContainer[index1].getTimeStamp() : 0.},
706 {(index2 > -1) ? mInputsContainer[index2].getEnergy() : 0., (index2 > -1) ? mInputsContainer[index2].getTimeStamp() : 0.},
707 {(index3 > -1) ? mInputsContainer[index3].getEnergy() : 0., (index3 > -1) ? mInputsContainer[index3].getTimeStamp() : 0.},
708 {(index4 > -1) ? mInputsContainer[index4].getEnergy() : 0., (index4 > -1) ? mInputsContainer[index4].getTimeStamp() : 0.}}};
709
710 for (auto& cell : cellData) {
711 if (std::abs(exoticTime - cell.second) > mExoticCellDiffTime) {
712 cell.first = 0;
713 }
714 }
715
716 float w1 = 1, w2 = 1, w3 = 1, w4 = 1;
717 if (mUseWeightExotic) {
718 w1 = GetCellWeight(cellData[0].first, energy);
719 w2 = GetCellWeight(cellData[1].first, energy);
720 w3 = GetCellWeight(cellData[2].first, energy);
721 w4 = GetCellWeight(cellData[3].first, energy);
722 }
723
724 if (cellData[0].first < mExoticCellInCrossMinAmplitude || w1 <= 0) {
725 cellData[0].first = 0;
726 }
727 if (cellData[1].first < mExoticCellInCrossMinAmplitude || w2 <= 0) {
728 cellData[1].first = 0;
729 }
730 if (cellData[2].first < mExoticCellInCrossMinAmplitude || w3 <= 0) {
731 cellData[2].first = 0;
732 }
733 if (cellData[3].first < mExoticCellInCrossMinAmplitude || w4 <= 0) {
734 cellData[3].first = 0;
735 }
736
737 return cellData[0].first + cellData[1].first + cellData[2].first + cellData[3].first;
738}
739
742//____________________________________________________________________________
743template <class InputType>
744float ClusterFactory<InputType>::GetCellWeight(float eCell, float eCluster) const
745{
746 if (eCell > 0 && eCluster > 0) {
747 if (mLogWeight > 0) {
748 return std::max(0.f, mLogWeight + std::log(eCell / eCluster));
749 } else {
750 return std::log(eCluster / eCell);
751 }
752 } else {
753 return 0.;
754 }
755}
756
759//____________________________________________________________________________
760template <class InputType>
761int ClusterFactory<InputType>::getMultiplicityAtLevel(float H, gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
762{
763 int multipl = 0;
764 for (auto iInput : inputsIndices) {
765 if (mInputsContainer[iInput].getEnergy() > H * clusterAnalysis.E()) {
766 multipl++;
767 }
768 }
769
770 return multipl;
771}
772
775//____________________________________________________________________________
776template <class InputType>
777void ClusterFactory<InputType>::evalTime(gsl::span<const int> inputsIndices, AnalysisCluster& clusterAnalysis) const
778{
779 float maxE = 0;
780 unsigned short maxAt = 0;
781 for (auto iInput : inputsIndices) {
782 if (mInputsContainer[iInput].getEnergy() > maxE) {
783 maxE = mInputsContainer[iInput].getEnergy();
784 maxAt = iInput;
785 }
786 }
787
788 clusterAnalysis.setClusterTime(mInputsContainer[maxAt].getTimeStamp());
789}
790
794//_____________________________________________________________________
795template <class InputType>
796double ClusterFactory<InputType>::tMaxInCm(const double e, const int key) const
797{
798 const double ca = 4.82; // shower max parameter - first guess; ca=TMath::Log(1000./8.07)
799 double tmax = 0.; // position of electromagnetic shower max in cm
800
801 const double x0 = 1.31; // radiation lenght (cm)
802
803 if (e > 0.1) {
804 tmax = TMath::Log(e) + ca;
805 if (key == 0) {
806 tmax += 0.5;
807 } else {
808 tmax -= 0.5;
809 }
810 tmax *= x0; // convert to cm
811 }
812
813 return tmax;
814}
815
818//______________________________________________________________________________
819template <class InputType>
821{
822 return (2. * TMath::ATan(TMath::Exp(-arg)));
823}
824
827//______________________________________________________________________________
828template <class InputType>
830{
831 return (-1 * TMath::Log(TMath::Tan(0.5 * arg)));
832}
833
834template <class InputType>
835ClusterFactory<InputType>::ClusterIterator::ClusterIterator(const ClusterFactory& factory, int clusterIndex, bool forward) : mClusterFactory(factory),
836 mCurrentCluster(),
837 mClusterID(clusterIndex),
838 mForward(forward)
839{
840 mCurrentCluster = mClusterFactory.buildCluster(mClusterID);
841}
842
843template <class InputType>
845{
846 return &mClusterFactory == &rhs.mClusterFactory && mClusterID == rhs.mClusterID && mForward == rhs.mForward;
847}
848
849template <class InputType>
851{
852 if (mForward) {
853 mClusterID++;
854 } else {
855 mClusterID--;
856 }
857 mCurrentCluster = mClusterFactory.buildCluster(mClusterID);
858 return *this;
859}
860
861template <class InputType>
863{
864 auto tmp = *this;
865 ++(*this);
866 return tmp;
867}
868
869template <class InputType>
871{
872 if (mForward) {
873 mClusterID--;
874 } else {
875 mClusterID++;
876 }
877 mCurrentCluster = mClusterFactory.buildCluster(mClusterID);
878 return *this;
879}
880
881template <class InputType>
883{
884 auto tmp = *this;
885 --(*this);
886 return tmp;
887}
888
int32_t i
std::ostringstream debug
StringRef key
Cluster class for kinematic cluster parametersported from AliVCluster in AliRoot.
void setGlobalPosition(math_utils::Point3D< float > x)
Set the cluster global position.
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)
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.
bool isExoticCell(short towerId, float ecell, float const exoticTime) const
Look to cell neighbourhood and reject if it seems exotic.
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)
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.
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"