Project
Loading...
Searching...
No Matches
Clusterer.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
14#include <memory>
15#include "TDecompBK.h"
16
17#include "PHOSReconstruction/Clusterer.h" // for LOG
21
22#include <fairlogger/Logger.h> // for LOG
23
24using namespace o2::phos;
25
27
28//____________________________________________________________________________
30{
31 if (!mPHOSGeom) {
33 }
36 LOG(info) << "Clusterizer parameters";
38 LOG(info) << "mLogWeight = " << sp.mLogWeight;
39 LOG(info) << "mDigitMinEnergy = " << sp.mDigitMinEnergy;
40 LOG(info) << "mClusteringThreshold = " << sp.mClusteringThreshold;
41 LOG(info) << "mLocalMaximumCut = " << sp.mLocalMaximumCut;
42 LOG(info) << "mUnfoldMaxSize = " << sp.mUnfoldMaxSize;
43 LOG(info) << "mUnfoldClusters = " << sp.mUnfoldClusters;
44 LOG(info) << "mUnfogingEAccuracy = " << sp.mUnfogingEAccuracy;
45 LOG(info) << "mUnfogingXZAccuracy = " << sp.mUnfogingXZAccuracy;
46 LOG(info) << "mUnfogingChi2Accuracy = " << sp.mUnfogingChi2Accuracy;
47 LOG(info) << "mNMaxIterations = " << sp.mNMaxIterations;
48}
49//____________________________________________________________________________
50void Clusterer::process(gsl::span<const Digit> digits, gsl::span<const TriggerRecord> dtr,
52 std::vector<Cluster>& clusters, std::vector<CluElement>& cluelements, std::vector<TriggerRecord>& trigRec,
54{
55 clusters.clear(); // final out list of clusters
56 cluelements.clear();
57 cluelements.reserve(digits.size());
58 trigRec.clear();
59 cluMC.clear();
60 mProcessMC = (dmc != nullptr);
61
62 for (const auto& tr : dtr) {
63 int indexStart = clusters.size(); // final out list of clusters
64
65 // Convert digits to cluelements
66 int firstDigitInEvent = tr.getFirstEntry();
67 int lastDigitInEvent = firstDigitInEvent + tr.getNumberOfObjects();
68 mFirstElememtInEvent = cluelements.size();
69 mCluEl.clear();
70 mTrigger.clear();
71 for (int i = firstDigitInEvent; i < lastDigitInEvent; i++) {
72 const Digit& digitSeed = digits[i];
73 short absId = digitSeed.getAbsId();
74 if (digitSeed.isTRU()) {
75 mTrigger.emplace_back(digitSeed);
76 continue;
77 }
78 if (isBadChannel(absId)) {
79 continue;
80 }
81 float energy = calibrate(digitSeed.getAmplitude(), absId, digitSeed.isHighGain());
82 if (energy < o2::phos::PHOSSimParams::Instance().mDigitMinEnergy) {
83 continue;
84 }
85 float x = 0., z = 0.;
87 mCluEl.emplace_back(absId, digitSeed.isHighGain(), energy, calibrateT(digitSeed.getTime(), absId, digitSeed.isHighGain(), tr.getBCData().bc),
88 x, z, digitSeed.getLabel(), 1.);
89 }
90 mLastElementInEvent = cluelements.size();
91
92 // Collect digits to clusters
93 makeClusters(clusters, cluelements);
94
95 LOG(debug) << "Found clusters from " << indexStart << " to " << clusters.size();
96 trigRec.emplace_back(tr.getBCData(), indexStart, clusters.size() - indexStart);
97 }
98 if (mProcessMC) {
99 evalLabels(clusters, cluelements, dmc, cluMC);
100 }
101}
102//____________________________________________________________________________
103void Clusterer::processCells(gsl::span<const Cell> cells, gsl::span<const TriggerRecord> ctr,
105 std::vector<Cluster>& clusters, std::vector<CluElement>& cluelements, std::vector<TriggerRecord>& trigRec,
107{
108 // Transform input Cells to digits and run standard recontruction
109 clusters.clear(); // final out list of clusters
110 cluelements.clear();
111 cluelements.reserve(cells.size());
112 trigRec.clear();
113 cluMC.clear();
114 mProcessMC = (dmc != nullptr);
115 miCellLabel = 0;
116 for (const auto& tr : ctr) {
117 int firstCellInEvent = tr.getFirstEntry();
118 int lastCellInEvent = firstCellInEvent + tr.getNumberOfObjects();
119 int indexStart = clusters.size(); // final out list of clusters
120 // convert cells to cluelements
121 mFirstElememtInEvent = cluelements.size();
122 mCluEl.clear();
123 mTrigger.clear();
124 for (int i = firstCellInEvent; i < lastCellInEvent; i++) {
125 const Cell c = cells[i];
126 short absId = c.getAbsId();
127 if (c.getTRU()) {
128 mTrigger.emplace_back(c.getTRUId(), c.getEnergy(), c.getTime(), 0);
129 continue;
130 }
131 if (isBadChannel(absId)) {
132 continue;
133 }
134 float energy = calibrate(c.getEnergy(), absId, c.getHighGain());
135 if (energy < o2::phos::PHOSSimParams::Instance().mDigitMinEnergy) {
136 continue;
137 }
138 float x = 0., z = 0.;
140 mCluEl.emplace_back(absId, c.getHighGain(), energy, calibrateT(c.getTime(), absId, c.getHighGain(), tr.getBCData().bc),
141 x, z, i, 1.);
142 }
143 mLastElementInEvent = cluelements.size();
144 makeClusters(clusters, cluelements);
145 trigRec.emplace_back(tr.getBCData(), indexStart, clusters.size() - indexStart);
146 }
147 if (mProcessMC) {
148 evalLabels(clusters, cluelements, dmc, cluMC);
149 }
150}
151//____________________________________________________________________________
152void Clusterer::makeClusters(std::vector<Cluster>& clusters, std::vector<CluElement>& cluelements)
153{
154 // A cluster is defined as a list of neighbour digits (as defined in Geometry::areNeighbours)
155 // Cluster contains first and (next-to) last index of the combined list of clusterelements, so
156 // add elements to final list and mark element in internal list as used (zero energy)
157
158 int iFirst = 0; // first index of digit which potentially can be a part of cluster
159 int n = mCluEl.size();
160 for (int i = iFirst; i < n; i++) {
161 if (mCluEl[i].energy == 0) { // already used
162 continue;
163 }
164
165 CluElement& digitSeed = mCluEl[i];
166
167 // is this digit so energetic that start cluster?
168 Cluster* clu = nullptr;
169 int iDigitInCluster = 0;
171 // start new cluster
172 clusters.emplace_back();
173 clu = &(clusters.back());
174 clu->setFirstCluEl(cluelements.size());
175 cluelements.emplace_back(digitSeed);
176 digitSeed.energy = 0;
177 iDigitInCluster = 1;
178 } else {
179 continue;
180 }
181 // Now scan remaining digits in list to find neigbours of our seed
182 int index = 0;
183 while (index < iDigitInCluster) { // scan over digits already in cluster
184 short digitSeedAbsId = cluelements.at(clu->getFirstCluEl() + index).absId;
185 index++;
186 for (int j = iFirst; j < n; j++) {
187 if (mCluEl[j].energy == 0) {
188 continue; // look through remaining digits
189 }
190 CluElement& digitN = mCluEl[j];
191
192 // call (digit,digitN) in THAT oder !!!!!
193 Int_t ineb = Geometry::areNeighbours(digitSeedAbsId, digitN.absId);
194 switch (ineb) {
195 case -1: // too early (e.g. previous module), do not look before j at subsequent passes
196 iFirst = j;
197 break;
198 case 0: // not a neighbour
199 break;
200 case 1: // are neighbours
201 cluelements.emplace_back(digitN);
202 digitN.energy = 0;
203 iDigitInCluster++;
204 break;
205 case 2: // too far from each other
206 default:
207 break;
208 } // switch
209 }
210 } // loop over cluster
211 clu->setLastCluEl(cluelements.size());
212
213 // Unfold overlapped clusters
214 // Split clusters with several local maxima if necessary
215 if (o2::phos::PHOSSimParams::Instance().mUnfoldClusters &&
216 clu->getMultiplicity() < o2::phos::PHOSSimParams::Instance().mUnfoldMaxSize) { // Do not unfold huge clusters
217 makeUnfolding(*clu, clusters, cluelements);
218 } else {
219 evalAll(*clu, cluelements);
220 if (clu->getEnergy() < 1.e-4) { // remove cluster and belonging to it elements
221 for (int i = clu->getMultiplicity(); i--;) {
222 cluelements.pop_back();
223 }
224 clusters.pop_back();
225 }
226 }
227
228 } // energy theshold
229}
230//__________________________________________________________________________
231void Clusterer::makeUnfolding(Cluster& clu, std::vector<Cluster>& clusters, std::vector<CluElement>& cluelements)
232{
233 // Split cluster if several local maxima are found
234 if (clu.getNExMax() > -1) { // already unfolded
235 return;
236 }
237
238 char nMax = getNumberOfLocalMax(clu, cluelements);
239 if (nMax > 1) {
240 unfoldOneCluster(clu, nMax, clusters, cluelements);
241 } else {
242 clu.setNExMax(nMax); // Only one local maximum
243 evalAll(clu, cluelements);
244 if (clu.getEnergy() < 1.e-4) { // remove cluster and belonging to it elements
245 for (int i = clu.getMultiplicity(); i--;) {
246 cluelements.pop_back();
247 }
248 clusters.pop_back();
249 }
250 }
251}
252//____________________________________________________________________________
253void Clusterer::unfoldOneCluster(Cluster& iniClu, char nMax, std::vector<Cluster>& clusters, std::vector<CluElement>& cluelements)
254{
255 // Performs the unfolding of a cluster with nMax overlapping showers
256 // Parameters: iniClu cluster to be unfolded
257 // nMax number of local maxima found (this is the number of new clusters)
258 // digitId: index of digits, corresponding to local maxima
259 // maxAtEnergy: energies of digits, corresponding to local maxima
260
261 // Take initial cluster and calculate local coordinates of digits
262 // To avoid multiple re-calculation of same parameters
263 short mult = iniClu.getMultiplicity();
264 std::vector<std::vector<float>> eInClusters(mult, std::vector<float>(nMax));
265 uint32_t firstCE = iniClu.getFirstCluEl();
266 uint32_t lastCE = iniClu.getLastCluEl();
267
268 mProp.reserve(mult * nMax);
269
270 for (int iclu = nMax; iclu--;) {
271 CluElement& ce = cluelements[mMaxAt[iclu]];
272 mxMax[iclu] = ce.localX;
273 mzMax[iclu] = ce.localZ;
274 meMax[iclu] = ce.energy;
275 mxMaxPrev[iclu] = mxMax[iclu];
276 mzMaxPrev[iclu] = mzMax[iclu];
277 }
278
279 TMatrixDSym B(nMax);
280 TVectorD C(nMax);
281 TDecompBK bk(nMax);
282
283 // Try to decompose cluster to contributions
284 int nIterations = 0;
285 bool insuficientAccuracy = true;
286 double chi2Previous = 1.e+6;
287 double step = 0.2;
288 while (insuficientAccuracy && nIterations < o2::phos::PHOSSimParams::Instance().mNMaxIterations) {
289 insuficientAccuracy = false; // will be true if at least one parameter changed too much
290 B.Zero();
291 C.Zero();
292 mProp.clear();
293 double chi2 = 0.;
294 for (int iclu = nMax; iclu--;) {
295 mA[iclu] = 0;
296 mxB[iclu] = 0;
297 mzB[iclu] = 0;
298 }
299 // Fill matrix and vector
300 for (uint32_t idig = firstCE; idig < lastCE; idig++) {
301 CluElement& ce = cluelements[idig];
302 double sumA = 0.;
303 for (int iclu = nMax; iclu--;) {
304 double lx = ce.localX - mxMax[iclu];
305 double lz = ce.localZ - mzMax[iclu];
306 double r2 = lx * lx + lz * lz;
307 double deriv = 0;
308 double ss = showerShape(r2, deriv);
309 mfij[iclu] = ss;
310 mfijr[iclu] = deriv;
311 mfijx[iclu] = deriv * ce.localX; // derivatives
312 mfijz[iclu] = deriv * ce.localZ;
313 sumA += ss * meMax[iclu];
314 C(iclu) += ce.energy * ss;
315 }
316 double dE = ce.energy - sumA;
317 chi2 += dE * dE;
318 for (int iclu = 0; iclu < nMax; iclu++) {
319 for (int jclu = iclu; jclu < nMax; jclu++) {
320 B(iclu, jclu) += mfij[iclu] * mfij[jclu];
321 }
322 mA[iclu] += mfijr[iclu] * dE;
323 mxB[iclu] += mfijx[iclu] * dE;
324 mzB[iclu] += mfijz[iclu] * dE;
325 mProp[(idig - firstCE) * nMax + iclu] = mfij[iclu] * meMax[iclu] / sumA;
326 }
327 }
328 if (nIterations > 0 && chi2 > chi2Previous) { // too big step
329 step = 0.5 * step;
330 for (int iclu = nMax; iclu--;) {
331 mxMax[iclu] = mxMaxPrev[iclu] + step * mdx[iclu];
332 mzMax[iclu] = mzMaxPrev[iclu] + step * mdz[iclu];
333 }
334 nIterations++;
335 insuficientAccuracy = true;
336 continue;
337 }
338 // Good iteration, move further
339 step = 0.2;
340 chi2Previous = chi2;
341 for (int iclu = nMax; iclu--;) {
342 mxMaxPrev[iclu] = mxMax[iclu];
343 mzMaxPrev[iclu] = mzMax[iclu];
344 }
345
346 // calculate next step using derivative
347 // fill remaning part of B
348 for (int iclu = 1; iclu < nMax; iclu++) {
349 for (int jclu = 0; jclu < iclu; jclu++) {
350 B(iclu, jclu) = B(jclu, iclu);
351 }
352 }
353 for (int iclu = nMax; iclu--;) {
354 if (mA[iclu] != 0) {
355 mdx[iclu] = mxB[iclu] / mA[iclu] - mxMaxPrev[iclu];
356 mdz[iclu] = mzB[iclu] / mA[iclu] - mzMaxPrev[iclu];
357 }
358 }
359
360 for (int iclu = nMax; iclu--;) {
361 // a-la Fletcher-Rivs algorithm
362 mdx[iclu] += 0.2 * mdxprev[iclu];
363 mdz[iclu] += 0.2 * mdzprev[iclu];
364 mdxprev[iclu] = mdx[iclu];
365 mdzprev[iclu] = mdz[iclu];
366 insuficientAccuracy |= fabs(step * mdx[iclu]) > o2::phos::PHOSSimParams::Instance().mUnfogingXZAccuracy;
367 insuficientAccuracy |= fabs(step * mdz[iclu]) > o2::phos::PHOSSimParams::Instance().mUnfogingXZAccuracy;
368 mxMax[iclu] = mxMaxPrev[iclu] + step * mdx[iclu];
369 mzMax[iclu] = mzMaxPrev[iclu] + step * mdz[iclu];
370 }
371 // now exact solution for amplitudes
372 bk.SetMatrix(B);
373 if (bk.Decompose()) {
374 if (bk.Solve(C)) {
375 for (int iclu = 0; iclu < nMax; iclu++) {
376 meMax[iclu] = C(iclu);
377 // double eOld = meMax[iclu];
378 // insuficientAccuracy|=fabs(meMax[iclu]-eOld)> meMax[iclu]*o2::phos::PHOSSimParams::Instance().mUnfogingEAccuracy ;
379 }
380 } else {
381 // LOG(warning) << "Failed to decompose matrix of size " << int(nMax) << " Clusters mult=" << lastCE-firstCE;
382 }
383 } else {
384 // LOG(warning) << "Failed to decompose matrix of size " << int(nMax);
385 }
386 insuficientAccuracy &= (chi2 > o2::phos::PHOSSimParams::Instance().mUnfogingChi2Accuracy * nMax);
387 nIterations++;
388 }
389
390 // Iterations finished, put first new cluster into place of mother one, others to the end of list
391 for (int iclu = 0; iclu < nMax; iclu++) {
392 // copy cluElements to the final list
393 int start = cluelements.size();
394 int nce = 0;
395 for (uint32_t idig = firstCE; idig < lastCE; idig++) {
396 CluElement& el = cluelements[idig];
397 float ei = el.energy * mProp[(idig - firstCE) * nMax + iclu];
399 cluelements.emplace_back(el);
400 cluelements.back().energy = ei;
401 cluelements.back().fraction = mProp[(idig - firstCE) * nMax + iclu];
402 nce++;
403 }
404 }
405 if (iclu == 0) { // replace parent
406 iniClu.setNExMax(nMax);
407 iniClu.setFirstCluEl(start);
408 iniClu.setLastCluEl(start + nce);
409 evalAll(iniClu, cluelements);
410 if (iniClu.getEnergy() < 1.e-4) { // remove cluster and belonging to it elements
411 for (int i = iniClu.getMultiplicity(); i--;) {
412 cluelements.pop_back();
413 }
414 clusters.pop_back();
415 }
416 } else {
417 clusters.emplace_back();
418 Cluster& clu = clusters.back();
419 clu.setNExMax(nMax);
421 clu.setLastCluEl(start + nce);
422 evalAll(clu, cluelements);
423 if (clu.getEnergy() < 1.e-4) { // remove cluster and belonging to it elements
424 for (int i = clu.getMultiplicity(); i--;) {
425 cluelements.pop_back();
426 }
427 clusters.pop_back();
428 }
429 }
430 }
431}
432
433//____________________________________________________________________________
434void Clusterer::evalLabels(std::vector<Cluster>& clusters, std::vector<CluElement>& cluElements,
437{
438
439 int labelIndex = cluMC.getIndexedSize();
440 auto clu = clusters.begin();
441
442 while (clu != clusters.end()) {
443 // Calculate list of primaries
444 // loop over entries in digit MCTruthContainer
445 for (uint32_t id = clu->getFirstCluEl(); id < clu->getLastCluEl(); id++) {
446 CluElement& ll = cluElements[id];
447 int i = ll.label; // index
448 float sc = ll.fraction;
449 gsl::span<const MCLabel> spDigList = dmc->getLabels(i);
450 if (spDigList.size() == 0 || spDigList.begin()->isFake()) {
451 continue;
452 }
453 gsl::span<MCLabel> spCluList = cluMC.getLabels(labelIndex); // get updated list
454 auto digL = spDigList.begin();
455 while (digL != spDigList.end()) {
456 if (digL->isFake()) {
457 digL++;
458 continue;
459 }
460 bool merged = false;
461 auto cluL = spCluList.begin();
462 while (cluL != spCluList.end()) {
463 if (*digL == *cluL) {
464 (*cluL).add(*digL, sc);
465 merged = true;
466 break;
467 }
468 ++cluL;
469 }
470 if (!merged) { // just add label
471 if (sc == 1.) {
472 cluMC.addElement(labelIndex, (*digL));
473 } else { // rare case of unfolded clusters
474 MCLabel tmpL = (*digL);
475 tmpL.scale(sc);
476 cluMC.addElement(labelIndex, tmpL);
477 }
478 }
479 ++digL;
480 }
481 }
482 labelIndex++;
483 ++clu;
484 }
485}
486//____________________________________________________________________________
487double Clusterer::showerShape(double r2, double& deriv)
488{
489 // Shape of the shower (see PHOS TDR)
490 // we neglect dependence on the incident angle.
491
492 // const float width = 1. / (2. * 2.32 * 2.32 * 2.32 * 2.32 * 2.32 * 2.32);
493 // const float width = 1. / (2. * 2.32 * 2.32 * 2.32 * 2.32 );
494 // return TMath::Exp(-r2 * r2 * width);
495 if (r2 == 0.) {
496 deriv = 0;
497 return 1.;
498 }
499 double r4 = r2 * r2;
500 double r295 = TMath::Power(r2, 2.95 / 2.);
501 double a = 2.32 + 0.26 * r4;
502 double b = 31.645570 + 2.0632911 * r295;
503 double s = TMath::Exp(-r4 * ((a + b) / (a * b)));
504 deriv = -2. * s * r2 * (2.32 / (a * a) + (0.54161392 * r295 + 31.645570) / (b * b));
505 return s;
506}
507
508//____________________________________________________________________________
509void Clusterer::evalAll(Cluster& clu, std::vector<CluElement>& cluel) const
510{
511 // position, energy, coreEnergy, dispersion, time,
512
513 // Calculates the center of gravity in the local PHOS-module coordinates
514 // Note that correction for non-perpendicular incidence will be applied later
515 // when vertex will be known.
516 float fullEnergy = 0.;
517 float time = 0.;
518 float eMax = 0.;
519 uint32_t iFirst = clu.getFirstCluEl(), iLast = clu.getLastCluEl();
520 clu.setModule(Geometry::absIdToModule(cluel[iFirst].absId));
522 for (uint32_t i = iFirst; i < iLast; i++) {
523 float ei = cluel[i].energy;
524 if (ei < eMin) {
525 continue;
526 }
527 fullEnergy += ei;
528 if (ei > eMax) {
529 time = cluel[i].time;
530 eMax = ei;
531 }
532 }
533 clu.setEnergy(fullEnergy);
534 if (fullEnergy <= 0) {
535 return;
536 }
537 // Calculate time as time in the digit with maximal energy
539
540 float localPosX = 0., localPosZ = 0.;
541 float wtot = 0.;
542 float invE = 1. / fullEnergy;
543 for (uint32_t i = iFirst; i < iLast; i++) {
544 CluElement& ce = cluel[i];
545 if (ce.energy < eMin) {
546 continue;
547 }
548 float w = std::max(0.f, o2::phos::PHOSSimParams::Instance().mLogWeight + std::log(ce.energy * invE));
549 localPosX += ce.localX * w;
550 localPosZ += ce.localZ * w;
551 wtot += w;
552 }
553 if (wtot > 0) {
554 wtot = 1. / wtot;
555 localPosX *= wtot;
556 localPosZ *= wtot;
557 }
558 clu.setLocalPosition(localPosX, localPosZ);
559
560 // Dispersion, core energy
561 float coreRadius2 = o2::phos::PHOSSimParams::Instance().mCoreR;
562 coreRadius2 *= coreRadius2;
563 float coreE = 0.;
564 float dispersion = 0.;
565 float dxx = 0., dxz = 0., dzz = 0., lambdaLong = 0., lambdaShort = 0.;
566 for (uint32_t i = iFirst; i < iLast; i++) {
567 CluElement& ce = cluel[i];
568 float ei = ce.energy;
569 if (ei < eMin) {
570 continue;
571 }
572 float x = ce.localX - localPosX;
573 float z = ce.localZ - localPosZ;
574 float distance = x * x + z * z;
575
576 float w = std::max(0.f, o2::phos::PHOSSimParams::Instance().mLogWeight + std::log(ei * invE));
577 dispersion += w * distance;
578 dxx += w * x * x;
579 dzz += w * z * z;
580 dxz += w * x * z;
581 if (distance < coreRadius2) {
582 coreE += ei;
583 }
584 }
585 clu.setCoreEnergy(coreE);
586 // dispersion NB! wtot here already inverse
587 dispersion *= wtot;
588
589 dxx *= wtot;
590 dzz *= wtot;
591 dxz *= wtot;
592
593 lambdaLong = 0.5 * (dxx + dzz) + std::sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz);
594 if (lambdaLong > 0) {
595 lambdaLong = std::sqrt(lambdaLong);
596 }
597
598 lambdaShort = 0.5 * (dxx + dzz) - std::sqrt(0.25 * (dxx - dzz) * (dxx - dzz) + dxz * dxz);
599 if (lambdaShort > 0) { // To avoid exception if numerical errors lead to negative lambda.
600 lambdaShort = std::sqrt(lambdaShort);
601 } else {
602 lambdaShort = 0.;
603 }
604
605 if (dispersion >= 0) {
606 clu.setDispersion(std::sqrt(dispersion));
607 } else {
608 clu.setDispersion(0.);
609 }
610 clu.setElipsAxis(lambdaShort, lambdaLong);
611
612 // Test trigger
613 char relId[3];
614 Geometry::relPosToRelId(clu.module(), localPosX, localPosZ, relId);
615
616 for (auto& trd : mTrigger) {
617 char trurelid[3];
618 short trtype = trd.is2x2Tile() ? 0 : 1;
619 Geometry::truAbsToRelNumbering(trd.getAbsId(), trtype, trurelid);
620
621 // Trigger tile coordinates of lower left corner (smallest x,z)
622 int dx = relId[1] - trurelid[1];
623 int dz = relId[2] - trurelid[2];
624 if (trtype == 0) { // 2x2
625 if (dx >= 0 && dx < 2 && dz >= 0 && dz < 2) {
626 clu.setFiredTrigger(trd.isHighGain());
627 break;
628 }
629 } else { // 4x4
630 if (dx >= 0 && dx < 4 && dz >= 0 && dz < 4) {
631 clu.setFiredTrigger(trd.isHighGain());
632 break;
633 }
634 }
635 }
636}
637//____________________________________________________________________________
638char Clusterer::getNumberOfLocalMax(Cluster& clu, std::vector<CluElement>& cluel)
639{
640 // Calculates the number of local maxima in the cluster using LocalMaxCut as the minimum
641 // energy difference between maximum and surrounding digits
642
645 mIsLocalMax.clear();
647
648 uint32_t iFirst = clu.getFirstCluEl(), iLast = clu.getLastCluEl();
649 for (uint32_t i = iFirst; i < iLast; i++) {
650 mIsLocalMax.push_back(cluel[i].energy > cluSeed);
651 }
652
653 for (uint32_t i = iFirst; i < iLast - 1; i++) {
654 for (uint32_t j = i + 1; j < iLast; j++) {
655
656 if (Geometry::areNeighbours(cluel[i].absId, cluel[j].absId) == 1) {
657 if (cluel[i].energy > cluel[j].energy) {
658 mIsLocalMax[j - iFirst] = false;
659 // but may be digit too is not local max ?
660 if (cluel[j].energy > cluel[i].energy - locMaxCut) {
661 mIsLocalMax[i - iFirst] = false;
662 }
663 } else {
664 mIsLocalMax[i - iFirst] = false;
665 // but may be digitN is not local max too?
666 if (cluel[i].energy > cluel[j].energy - locMaxCut) {
667 mIsLocalMax[j - iFirst] = false;
668 }
669 }
670 } // if areneighbours
671 } // digit j
672 } // digit i
673
674 int iDigitN = 0;
675 for (std::size_t i = 0; i < mIsLocalMax.size(); i++) {
676 if (mIsLocalMax[i]) {
677 mMaxAt[iDigitN] = i + iFirst;
678 iDigitN++;
679 if (iDigitN >= NLOCMAX) { // Note that size of output arrays is limited:
680 static int nAlarms = 0;
681 if (nAlarms++ < 5) {
682 LOG(alarm) << "Too many local maxima, cluster multiplicity " << mIsLocalMax.size();
683 }
684 return -2;
685 }
686 }
687 }
688
689 return iDigitN;
690}
int16_t time
Definition RawEventData.h:4
int32_t i
Definition of the PHOS cluster finder.
ClassImp(Clusterer)
uint32_t j
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
std::ostringstream debug
Definition B.h:16
A container to hold and manage MC truth information/labels.
gsl::span< TruthElement > getLabels(uint32_t dataindex)
void addElement(uint32_t dataindex, TruthElement const &element, bool noElement=false)
short getAbsId() const
Definition Cell.cxx:44
Contains PHOS cluster parameters.
Definition Cluster.h:39
float getEnergy() const
Definition Cluster.h:56
uint32_t getFirstCluEl() const
Definition Cluster.h:104
void setFirstCluEl(uint32_t first)
Definition Cluster.h:106
void setCoreEnergy(float ec)
Definition Cluster.h:60
int getMultiplicity() const
Definition Cluster.h:86
void setNExMax(char nmax=1)
Definition Cluster.h:89
void setDispersion(float d)
Definition Cluster.h:63
void setFiredTrigger(char t)
Definition Cluster.h:99
void setLocalPosition(float posX, float posZ)
Definition Cluster.h:81
char getNExMax() const
Definition Cluster.h:90
void setModule(char mod)
Definition Cluster.h:93
void setEnergy(float e)
Definition Cluster.h:57
void setLastCluEl(uint32_t last)
Definition Cluster.h:107
void setElipsAxis(float lambdaShort, float lambdaLong)
Definition Cluster.h:71
char module() const
Definition Cluster.h:92
uint32_t getLastCluEl() const
Definition Cluster.h:105
void setTime(float t)
Definition Cluster.h:96
static constexpr short NLOCMAX
Definition Clusterer.h:105
void makeUnfolding(Cluster &clu, std::vector< Cluster > &clusters, std::vector< o2::phos::CluElement > &cluel)
bool isBadChannel(short absId)
Definition Clusterer.h:91
void processCells(gsl::span< const Cell > digits, gsl::span< const TriggerRecord > dtr, const o2::dataformats::MCTruthContainer< MCLabel > *dmc, std::vector< Cluster > &clusters, std::vector< CluElement > &cluel, std::vector< TriggerRecord > &rigRec, o2::dataformats::MCTruthContainer< MCLabel > &cluMC)
int mLastElementInEvent
Range of digits from one event.
Definition Clusterer.h:118
std::array< double, NLOCMAX > mfijz
transient variable for derivative calculation
Definition Clusterer.h:134
std::array< int, NLOCMAX > mMaxAt
indexes of local maxima
Definition Clusterer.h:138
char getNumberOfLocalMax(Cluster &clu, std::vector< CluElement > &cluel)
std::array< float, NLOCMAX > meMax
currecnt amplitude in unfoding
Definition Clusterer.h:123
void evalLabels(std::vector< Cluster > &clusters, std::vector< CluElement > &cluel, const o2::dataformats::MCTruthContainer< MCLabel > *dmc, o2::dataformats::MCTruthContainer< MCLabel > &cluMC)
float calibrateT(float time, short absId, bool isHighGain, int bc)
Definition Clusterer.h:68
std::array< float, NLOCMAX > mdz
step on current minimization iteration
Definition Clusterer.h:127
void process(gsl::span< const Digit > digits, gsl::span< const TriggerRecord > dtr, const o2::dataformats::MCTruthContainer< MCLabel > *dmc, std::vector< Cluster > &clusters, std::vector< CluElement > &cluel, std::vector< TriggerRecord > &rigRec, o2::dataformats::MCTruthContainer< MCLabel > &cluMC)
Definition Clusterer.cxx:50
int mFirstElememtInEvent
Range of digits from one event.
Definition Clusterer.h:117
std::array< float, NLOCMAX > mdzprev
step on previoud minimization iteration
Definition Clusterer.h:129
double showerShape(double r2, double &deriv)
std::array< double, NLOCMAX > mxB
transient variable for derivative calculation
Definition Clusterer.h:131
void makeClusters(std::vector< Cluster > &clusters, std::vector< o2::phos::CluElement > &cluel)
std::array< float, NLOCMAX > mdxprev
step on previoud minimization iteration
Definition Clusterer.h:128
std::array< double, NLOCMAX > mfij
transient variable for derivative calculation
Definition Clusterer.h:136
Geometry * mPHOSGeom
packed shifts for 14 ddls
Definition Clusterer.h:111
std::vector< Digit > mTrigger
internal vector of clusters
Definition Clusterer.h:116
void unfoldOneCluster(Cluster &iniClu, char nMax, std::vector< Cluster > &clusters, std::vector< CluElement > &cluelements)
std::array< float, NLOCMAX > mdx
step on current minimization iteration
Definition Clusterer.h:126
std::vector< CluElement > mCluEl
! Bad map, Clusterizer not owner
Definition Clusterer.h:115
float calibrate(float amp, short absId, bool isHighGain)
Definition Clusterer.h:59
std::array< double, NLOCMAX > mA
transient variable for derivative calculation
Definition Clusterer.h:130
std::vector< float > mProp
proportion of clusters in the current digit
Definition Clusterer.h:120
std::array< float, NLOCMAX > mxMax
current maximum coordinate
Definition Clusterer.h:121
std::array< double, NLOCMAX > mzB
transient variable for derivative calculation
Definition Clusterer.h:132
void evalAll(Cluster &clu, std::vector< CluElement > &cluel) const
std::vector< bool > mIsLocalMax
transient array for local max finding
Definition Clusterer.h:137
std::array< double, NLOCMAX > mfijr
transient variable for derivative calculation
Definition Clusterer.h:135
std::array< float, NLOCMAX > mzMax
in the unfolding procedure
Definition Clusterer.h:122
std::array< double, NLOCMAX > mfijx
transient variable for derivative calculation
Definition Clusterer.h:133
std::array< float, NLOCMAX > mxMaxPrev
coordunates at previous step
Definition Clusterer.h:124
std::array< float, NLOCMAX > mzMaxPrev
coordunates at previous step
Definition Clusterer.h:125
short getAbsId() const
Absolute sell id.
Definition Digit.h:106
float getAmplitude() const
Energy deposited in a cell.
Definition Digit.h:113
bool isHighGain() const
Checks if this digit is produced in High Gain or Low Gain channels.
Definition Digit.h:121
int getLabel() const
index of entry in MCLabels array
Definition Digit.h:128
bool isTRU() const
Definition Digit.h:103
float getTime() const
time measured in digit w.r.t. photon to PHOS arrival
Definition Digit.h:117
static void relPosToRelId(short module, float x, float z, char *relId)
Definition Geometry.cxx:226
static char absIdToModule(short absId)
Definition Geometry.cxx:151
static int areNeighbours(short absId1, short absId2)
Definition Geometry.cxx:159
static void absIdToRelPosInModule(short absId, float &x, float &z)
Definition Geometry.cxx:198
static bool truAbsToRelNumbering(short truId, short trigType, char *relid)
Definition Geometry.cxx:83
static Geometry * GetInstance()
Definition Geometry.h:63
void scale(float s)
Definition MCLabel.h:43
GLdouble n
Definition glcorearb.h:1982
GLint GLenum GLint x
Definition glcorearb.h:403
GLuint index
Definition glcorearb.h:781
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLsizei GLsizei GLfloat distance
Definition glcorearb.h:5506
GLuint start
Definition glcorearb.h:469
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLubyte GLubyte GLubyte GLubyte w
Definition glcorearb.h:852
GLuint id
Definition glcorearb.h:650
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
float mUnfogingChi2Accuracy
critical chi2/NDF
float mCoreR
Radius to caluclate core energy.
bool mUnfoldClusters
To perform cluster unfolding.
float mLogWeight
Cutoff used in log. weight calculation.
int mUnfoldMaxSize
maximal number of cells in cluster to be unfolded
float mDigitMinEnergy
Minimal energy of digits to be used in cluster (GeV)
float mClusteringThreshold
Minimal energy of digit to start clustering (GeV)
float mUnfogingXZAccuracy
Accuracy of position calculation in unfolding procedure (cm)
float mLocalMaximumCut
Minimal height of local maximum over neighbours.
float mUnfogingEAccuracy
Accuracy of energy calculation in unfoding prosedure (GeV)
int mNMaxIterations
Maximal number of iterations in unfolding procedure.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
Cluster clu
std::vector< Cluster > clusters
std::vector< Cell > cells
std::vector< Digit > digits