Project
Loading...
Searching...
No Matches
CaloRawFitter.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 <cassert>
15#include <numeric>
16#include <gsl/span>
17
18// ROOT sytem
19#include "TMath.h"
20
21#include <fairlogger/Logger.h>
26
27using namespace o2::emcal;
28
29int CaloRawFitter::getErrorNumber(CaloRawFitter::RawFitterError_t fiterror)
30{
31 switch (fiterror) {
33 return 0;
35 return 1;
37 return 2;
39 return 3;
41 return 4;
42 };
43 // Silence compiler warnings for false positives
44 // can never enter here due to usage of enum class
45 return -1;
46}
47
49{
50 assert(fiterror < getNumberOfErrorTypes());
51 switch (fiterror) {
52 case 0:
54 case 1:
56 case 2:
58 case 3:
60 case 4:
62 };
63 // Silence the compiler warning for false positives
64 // Since we catch invalid codes via the assert we can
65 // never reach here. Since it is an enum class we need
66 // to choose one error code here. Pick the first error
67 // code instead.
69}
70
72{
73 switch (fiterror) {
75 return "SampleUninitalized";
77 return "NoConvergence";
79 return "Chi2Error";
81 return "BunchRejected";
83 return "LowSignal";
84 };
85 // Silence compiler warnings for false positives
86 // can never enter here due to usage of enum class
87 return "Unknown";
88}
89
91{
92 switch (fiterror) {
94 return "sample uninitalized";
96 return "No convergence";
98 return "Chi2 error";
100 return "Bunch rejected";
102 return "Low signal";
103 };
104 // Silence compiler warnings for false positives
105 // can never enter here due to usage of enum class
106 return "Unknown";
107}
108
110{
111 switch (fiterror) {
113 return "Sample for fit not initialzied or bunch length is 0";
115 return "Fit of the raw bunch was not successful";
117 return "Chi2 of the fit could not be determined";
119 return "Calo bunch could not be selected";
121 return "No ADC value above threshold found";
122 };
123 // Silence compiler warnings for false positives
124 // can never enter here due to usage of enum class
125 return "Unknown error code";
126}
127
128// Default constructor
129CaloRawFitter::CaloRawFitter(const char* name, const char* nameshort) : mMinTimeIndex(-1),
130 mMaxTimeIndex(-1),
131 mAmpCut(4),
132 mNsamplePed(3),
133 mIsZerosupressed(true),
134 mName(name),
135 mNameShort(nameshort),
136 mAlgo(FitAlgorithm::NONE),
137 mL1Phase(0),
138 mAmp(0)
139{
140}
141
143{
144
145 if ((min > max) || min > constants::EMCAL_MAXTIMEBINS || max > constants::EMCAL_MAXTIMEBINS) {
146 LOG(warn) << "Attempt to set Invalid time bin range (Min , Max) = (" << min << ", " << max << "), Ingored";
147 } else {
150 }
151}
152
153unsigned short CaloRawFitter::getMaxAmplitudeBunch(const gsl::span<unsigned short> data) const
154{
155 return *std::max_element(data.begin(), data.end());
156}
157
158std::tuple<int, int> CaloRawFitter::findPeakRegion(const gsl::span<double> adcValues, short indexMaxADC, int threshold) const
159{
160
161 int first(0), last(0);
162 int tmpfirst = indexMaxADC;
163 int tmplast = indexMaxADC;
164 double prevFirst = adcValues[indexMaxADC];
165 double prevLast = adcValues[indexMaxADC];
166 bool firstJump = false;
167 bool lastJump = false;
168
169 while ((tmpfirst >= 0) && (adcValues[tmpfirst] >= threshold) && (!firstJump)) {
170 // jump check:
171 if (tmpfirst != indexMaxADC) { // neighbor to maxindex can share peak with maxindex
172 if (adcValues[tmpfirst] >= prevFirst) {
173 firstJump = true;
174 }
175 }
176 prevFirst = adcValues[tmpfirst];
177 tmpfirst--;
178 }
179
180 while ((tmplast < adcValues.size()) && (adcValues[tmplast] >= threshold) && (!lastJump)) {
181 // jump check:
182 if (tmplast != indexMaxADC) { // neighbor to maxindex can share peak with maxindex
183 if (adcValues[tmplast] >= prevLast) {
184 lastJump = true;
185 }
186 }
187 prevLast = adcValues[tmplast];
188 tmplast++;
189 }
190
191 // we keep one pre- or post- sample if we can (as in online)
192 // check though if we ended up on a 'jump', or out of bounds: if so, back up
193 if (firstJump || tmpfirst < 0) {
194 tmpfirst++;
195 }
196 if (lastJump || tmplast >= adcValues.size()) {
197 tmplast--;
198 }
199
200 first = tmpfirst;
201 last = tmplast;
202
203 return std::make_tuple(first, last);
204}
205
206std::tuple<float, std::array<double, constants::EMCAL_MAXTIMEBINS>> CaloRawFitter::reverseAndSubtractPed(const Bunch& bunch) const
207{
208 std::array<double, constants::EMCAL_MAXTIMEBINS> outarray;
209 int length = bunch.getBunchLength();
210 const gsl::span<const uint16_t> sig(bunch.getADC());
211
212 double ped = mIsZerosupressed ? 0. : evaluatePedestal(sig, length);
213
214 for (int i = 0; i < length; i++) {
215 outarray[i] = sig[length - i - 1] - ped;
216 }
217
218 return std::make_tuple(ped, outarray);
219}
220
221double CaloRawFitter::evaluatePedestal(const gsl::span<const uint16_t> data, std::optional<int> length) const
222{
223 if (!mNsamplePed) {
225 }
226 if (data.size() < mNsamplePed) {
227 return 0.;
228 }
229 return static_cast<double>(std::accumulate(data.begin(), data.begin() + mNsamplePed, 0)) / mNsamplePed;
230}
231
232std::tuple<short, int> CaloRawFitter::getMaxAmplitudeBunch(const Bunch& bunch) const
233{
234 short maxADC = -1;
235 int maxIndex = -1;
236 const std::vector<uint16_t>& sig = bunch.getADC();
237
238 for (int i = 0; i < bunch.getBunchLength(); i++) {
239 if (sig[i] > maxADC) {
240 maxADC = sig[i];
241 maxIndex = i;
242 }
243 }
244
245 return std::make_tuple(maxADC, bunch.getBunchLength() - 1 - maxIndex + bunch.getStartTime());
246}
247
249{
250 short maxADC = -1;
251 int indexMax = -1;
252 const std::vector<uint16_t>& sig = bunch.getADC();
253
254 for (int i = 0; i < bunch.getBunchLength(); i++) {
255 if (sig[i] > maxADC) {
256 maxADC = sig[i];
257 indexMax = i;
258 }
259 }
260
261 bool isBunchEdge = false;
262 if (indexMax == 0 || indexMax == (bunch.getBunchLength() - 1)) {
263 isBunchEdge = true;
264 }
265
266 return isBunchEdge;
267}
268
269std::tuple<short, short, short> CaloRawFitter::selectMaximumBunch(const gsl::span<const Bunch>& bunchvector)
270{
271 short bunchindex = -1;
272 short indexMaxInBunch(0), maxADCallBunches(-1);
273
274 for (unsigned int i = 0; i < bunchvector.size(); i++) {
275 auto [maxADC, maxIndex] = getMaxAmplitudeBunch(bunchvector[i]); // CRAP PTH, bug fix, trouble if more than one bunches
276 if (isInTimeRange(maxIndex, mMaxTimeIndex, mMinTimeIndex)) {
277 if (maxADC > maxADCallBunches) {
278 bunchindex = i;
279 indexMaxInBunch = maxIndex;
280 maxADCallBunches = maxADC;
281 }
282 }
283 }
284
285 if (bunchindex >= 0) {
286 // reject bunch if the max. ADC value is at the edges of a bunch
287 if (isMaxADCBunchEdge(bunchvector[bunchindex])) {
289 }
290 }
291
292 return std::make_tuple(bunchindex, indexMaxInBunch, maxADCallBunches);
293}
294
295bool CaloRawFitter::isInTimeRange(int indexMaxADC, int maxtime, int mintime) const
296{
297 if ((mintime < 0 && maxtime < 0) || maxtime < 0) {
298 return true;
299 }
300
301 return (indexMaxADC < maxtime) && (indexMaxADC > mintime) ? true : false;
302}
303
304double CaloRawFitter::calculateChi2(double amp, double time,
305 int first, int last,
306 double adcErr, double tau) const
307{
308 if (first == last || first < 0) { // signal consists of single sample, chi2 estimate (0) not too well defined..
309 // or, first is negative, the indices are not valid
311 }
312
313 int nsamples = last - first + 1;
314
315 double chi2 = 0;
316
317 for (int i = 0; i < nsamples; i++) {
318 int x = first + i; // timebin
319 double xx = (x - time + tau) / tau; // help variable
320 double f = 0.0;
321
322 if (xx > 0) {
323 f = amp * xx * xx * TMath::Exp(2 * (1 - xx));
324 }
325
326 double dy = mReversed[x] - f;
327 chi2 += dy * dy;
328 }
329
330 if (adcErr > 0.0) { // weight chi2
331 chi2 /= (adcErr * adcErr);
332 }
333
334 return chi2;
335}
336std::tuple<int, int, float, short, short, float, int, int> CaloRawFitter::preFitEvaluateSamples(const gsl::span<const Bunch> bunchvector, int adcThreshold)
337{
338
339 int nsamples(0), first(0), last(0), indexMaxADCRReveresed(0);
340 double peakADC(0.), pedestal(0.);
341
342 // Reset buffer for reversed bunch, no matter whether the bunch could be selected or not
343 mReversed.fill(0);
344
345 // select the bunch with the highest amplitude unless any time constraints is set
346 for (unsigned int i = 0; i < bunchvector.size(); i++) {
347 if (bunchvector[i].getBunchLength() > bunchvector[i].getADC().size()) {
349 }
350 }
351 auto [bunchindex, indexMaxADC, adcMAX] = selectMaximumBunch(bunchvector);
352
353 // something valid was found, and non-zero amplitude
354 if (bunchindex >= 0) {
355 if (adcMAX >= adcThreshold) {
356 // use more convenient numbering and possibly subtract pedestal
357
358 int bunchlength = bunchvector[bunchindex].getBunchLength();
359 const std::vector<uint16_t>& sig = bunchvector[bunchindex].getADC();
360
361 if (!mIsZerosupressed) {
362 pedestal = evaluatePedestal(sig, bunchlength);
363 }
364
365 int testindexReverse = -1;
366 for (int i = 0; i < bunchlength; i++) {
367 mReversed[i] = sig[bunchlength - i - 1] - pedestal;
368 if (mReversed[i] > peakADC) {
369 peakADC = mReversed[i];
370 testindexReverse = i;
371 }
372 }
373
374 if (peakADC >= adcThreshold) // possibly significant signal
375 {
376 // select array around max to possibly be used in fit
377 indexMaxADCRReveresed = indexMaxADC - bunchvector[bunchindex].getStartTime();
378 std::tie(first, last) = findPeakRegion(gsl::span<double>(&mReversed[0], bunchvector[bunchindex].getBunchLength()), indexMaxADCRReveresed, adcThreshold);
379
380 // sanity check: maximum should not be in first or last bin
381 // if we should do a fit
382 if (first != indexMaxADCRReveresed && last != indexMaxADCRReveresed) {
383 // calculate how many samples we have
384 nsamples = last - first + 1;
385 }
386 }
387 } else {
389 }
390 } else {
392 }
393
394 return std::make_tuple(nsamples, bunchindex, peakADC, adcMAX, indexMaxADCRReveresed, pedestal, first, last);
395}
396
397std::ostream& o2::emcal::operator<<(std::ostream& stream, const CaloRawFitter::RawFitterError_t error)
398{
400 return stream;
401}
int16_t time
Definition RawEventData.h:4
int32_t i
std::vector< uint16_t > nsamples
Definition testDigit.cxx:38
ALTRO bunch information.
Definition Bunch.h:40
uint8_t getStartTime() const
Get the start time bin.
Definition Bunch.h:83
const std::vector< uint16_t > & getADC() const
Get range of ADC values in the bunch.
Definition Bunch.h:72
uint8_t getBunchLength() const
Get the length of the bunch (number of time bins)
Definition Bunch.h:76
static constexpr int getNumberOfErrorTypes() noexcept
Get the number of raw fit error types supported.
CaloRawFitter(const char *name, const char *nameshort)
Constructor.
bool isMaxADCBunchEdge(const Bunch &bunch) const
Check if the max. ADC value is at the edge of a bunch.
std::tuple< short, short, short > selectMaximumBunch(const gsl::span< const Bunch > &bunchvector)
We select the bunch with the highest amplitude unless any time constraints is set.
static const char * getErrorTypeTitle(RawFitterError_t fiterror)
Get the title connected to the fit error type.
std::tuple< int, int, float, short, short, float, int, int > preFitEvaluateSamples(const gsl::span< const Bunch > bunchvector, int adcThreshold)
Method to do the selection of what should possibly be fitted.
int mMaxTimeIndex
The timebin of the max signal value must be between fMinTimeIndex and fMaxTimeIndex.
std::array< double, constants::EMCAL_MAXTIMEBINS > mReversed
Reversed sequence of samples (pedestalsubtracted)
std::tuple< short, int > getMaxAmplitudeBunch(const Bunch &bunchx) const
Get the maximum amplitude and its index of a bunch array.
bool isInTimeRange(int indexMaxADC, int maxtime, int mintime) const
Check if the index of the max ADC vaue is within accepted time range.
double evaluatePedestal(const gsl::span< const uint16_t > data, std::optional< int > length) const
Calculate the pedestal from the ADC values in a bunch.
static const char * getErrorTypeDescription(RawFitterError_t fiterror)
Get the description connected to the fit error type.
std::tuple< int, int > findPeakRegion(const gsl::span< double > adcValues, short indexMaxADC, int threshold) const
Find region constrainded by its closest minima around the main peak.
std::tuple< float, std::array< double, constants::EMCAL_MAXTIMEBINS > > reverseAndSubtractPed(const Bunch &bunch) const
Time sample comes in reversed order, revers them back Subtract the baseline based on content of altro...
double calculateChi2(double amp, double time, int first, int last, double adcErr=1, double tau=2.35) const
Calculates the chi2 of the fit.
RawFitterError_t
Error codes for failures in raw fitter procedure.
@ LOW_SIGNAL
No ADC value above threshold found.
@ SAMPLE_UNINITIALIZED
Samples not initialized or length is 0.
@ CHI2_ERROR
Chi2 cannot be determined (usually due to insufficient amount of samples)
static const char * getErrorTypeName(RawFitterError_t fiterror)
Get the name connected to the fit error type.
static RawFitterError_t intToErrorType(unsigned int fiterror)
Convert numeric representation of error type to RawFitterError_t.
void setTimeConstraint(int min, int max)
The require time range if the maximum ADC value is between min and max (timebin)
bool mIsZerosupressed
Wether or not the data is zeros supressed, by default its assumed that the baseline is also subtracte...
int mMinTimeIndex
The timebin of the max signal value must be between fMinTimeIndex and fMaxTimeIndex.
int mNsamplePed
Number of samples used for pedestal calculation (first in bunch)
GLint GLenum GLint x
Definition glcorearb.h:403
GLsizeiptr size
Definition glcorearb.h:659
GLuint const GLchar * name
Definition glcorearb.h:781
GLint first
Definition glcorearb.h:399
GLdouble f
Definition glcorearb.h:310
GLboolean * data
Definition glcorearb.h:298
GLuint GLsizei GLsizei * length
Definition glcorearb.h:790
GLuint GLuint stream
Definition glcorearb.h:1806
std::ostream & operator<<(std::ostream &stream, const Cell &cell)
Stream operator for EMCAL cell.
Definition Cell.cxx:355
constexpr size_t min
constexpr size_t max
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"