Skip to content

Commit 675b5c9

Browse files
mfasDadavidrohr
authored andcommitted
[EMCAL-686] Implement error handling in Raw fitter
Error handling is now exception-based, where the errors thrown are defined as error codes in enum class, and not inherit from std::exception. Raw fitter errors are caught in the RawToCellConverterSpec and pushed to the error container which is pushed to the QC. Futhermore a faulty 0 check was found in the CaloRawFitterGamma2 in the parabola fit where the numeric check for 0 is replaced by DBL_EPSILON.
1 parent f95a06d commit 675b5c9

9 files changed

Lines changed: 179 additions & 83 deletions

File tree

Detectors/EMCAL/reconstruction/include/EMCALReconstruction/AltroDecoder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ class AltroDecoderError : public std::exception
6464
/// \return the error type
6565
static ErrorType_t intToErrorType(int errornumber);
6666

67+
/// \brief Get the number of error types handled by the AltroDecoderError
68+
/// \return Number of error types
69+
static constexpr int getNumberOfErrorTypes() noexcept { return 8; }
70+
6771
/// \brief Access to the error type connected to the erro
6872
/// \return Error type
6973
const ErrorType_t getErrorType() const noexcept { return mErrorType; }

Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitter.h

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,38 @@ class CaloRawFitter
3939
{
4040

4141
public:
42+
/**
43+
* \enum RawFitterError_t
44+
* \brief Error codes for failures in raw fitter procedure
45+
*/
46+
enum class RawFitterError_t {
47+
SAMPLE_UNINITIALIZED, ///< Samples not initialized or length is 0
48+
FIT_ERROR, ///< Fit procedure failed
49+
CHI2_ERROR, ///< Chi2 cannot be determined (usually due to insufficient amount of samples)
50+
BUNCH_NOT_OK ///< Bunch selection failed
51+
};
52+
53+
/// \brief Create error message for a given error type
54+
/// \param fiterror Fit error type
55+
/// \return Error message connected to the error type
56+
static std::string createErrorMessage(RawFitterError_t fiterror);
57+
58+
/// \brief Convert error type to numeric representation
59+
/// \param fiterror Fit error type
60+
/// \return Numeric representation of the raw fitter error
61+
static int getErrorNumber(RawFitterError_t fiterror);
62+
63+
/// \brief Get the number of raw fit error types supported
64+
/// \return Number of error types (4)
65+
static constexpr int getNumberOfErrorTypes() noexcept { return 4; }
66+
4267
/// \brief Constructor
4368
CaloRawFitter(const char* name, const char* nameshort);
4469

4570
/// \brief Destructor
4671
virtual ~CaloRawFitter() = default;
4772

48-
virtual CaloFitResults evaluate(const std::vector<Bunch>& bunchvector,
73+
virtual CaloFitResults evaluate(const gsl::span<const Bunch> bunchvector,
4974
std::optional<unsigned int> altrocfg1,
5075
std::optional<unsigned int> altrocfg2) = 0;
5176

@@ -58,7 +83,7 @@ class CaloRawFitter
5883
/// \return pedestal,
5984
/// \return first time bin,
6085
/// \return last time bin,
61-
std::tuple<int, int, float, short, short, float, int, int> preFitEvaluateSamples(const std::vector<Bunch>& bunchvector,
86+
std::tuple<int, int, float, short, short, float, int, int> preFitEvaluateSamples(const gsl::span<const Bunch> bunchvector,
6287
std::optional<unsigned int> altrocfg1, std::optional<unsigned int> altrocfg2, int acut);
6388

6489
/// \brief The require time range if the maximum ADC value is between min and max (timebin)
@@ -103,7 +128,7 @@ class CaloRawFitter
103128
/// \return The index of the array with the maximum aplitude
104129
/// \return The bin where we have a maximum amp
105130
/// \return The maximum ADC signal
106-
std::tuple<short, short, short> selectBunch(const std::vector<Bunch>& bunchvector);
131+
std::tuple<short, short, short> selectBunch(const gsl::span<const Bunch>& bunchvector);
107132

108133
/// \brief Selection of subset of data from one bunch that will be used for fitting or Peak finding.
109134
/// Go to the left and right of index of the maximum time bin
@@ -113,7 +138,7 @@ class CaloRawFitter
113138
std::tuple<int, int> selectSubarray(const gsl::span<double> data, short maxindex, int cut) const;
114139

115140
/// \brief Pedestal evaluation if not zero suppressed
116-
float evaluatePedestal(const std::vector<uint16_t>& data, std::optional<int> length) const;
141+
float evaluatePedestal(const gsl::span<const uint16_t> data, std::optional<int> length) const;
117142

118143
/// \brief Calculates the chi2 of the fit
119144
///

Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitterGamma2.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ class CaloRawFitterGamma2 final : public CaloRawFitter
5252
int getNiterationsMax() { return mNiterationsMax; }
5353

5454
/// \brief Evaluation Amplitude and TOF
55-
/// return Container with the fit results (amp, time, chi2, ...)
56-
CaloFitResults evaluate(const std::vector<Bunch>& bunchvector,
55+
/// \param
56+
/// \throw RawFitterError_t::FIT_ERROR in case the peak fit failed
57+
/// \return Container with the fit results (amp, time, chi2, ...)
58+
CaloFitResults evaluate(const gsl::span<const Bunch> bunchvector,
5759
std::optional<unsigned int> altrocfg1,
5860
std::optional<unsigned int> altrocfg2) final;
5961

@@ -62,12 +64,22 @@ class CaloRawFitterGamma2 final : public CaloRawFitter
6264
int mNiterationsMax = 15; ///< max number of iteraions
6365

6466
/// \brief Fits the raw signal time distribution
65-
/// \return chi2, fit status.
66-
std::tuple<float, bool> doFit_1peak(int firstTimeBin, int nSamples, float& ampl, float& time);
67+
/// \param firstTimeBin First timebin in the ALTRO bunch
68+
/// \param nSamples Number of time samples of the ALTRO bunch
69+
/// \param[in] ampl Initial guess of the amplitude for the fit
70+
/// \param[out] ampl Amplitude result of the peak fit
71+
/// \param[in] time Initial guess of the time for the fit
72+
/// \param[out] time Time result of the peak fit
73+
/// \return chi2 of the fit
74+
/// \throw RawFitterError_t::FIT_ERROR in case of fit errors (insufficient number of time samples, matrix diagonalization error, ...)
75+
float doFit_1peak(int firstTimeBin, int nSamples, float& ampl, float& time);
6776

6877
/// \brief Fits the raw signal time distribution
78+
/// \param maxTimeBin Time bin of the max. amplitude
6979
/// \return the fit parameters: amplitude, time.
70-
std::tuple<float, float> doParabolaFit(int x) const;
80+
///
81+
/// Fit performed as parabola fit to the signal
82+
std::tuple<float, float> doParabolaFit(int maxTimeBin) const;
7183

7284
ClassDefNV(CaloRawFitterGamma2, 1);
7385
}; // End of CaloRawFitterGamma2

Detectors/EMCAL/reconstruction/include/EMCALReconstruction/CaloRawFitterStandard.h

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,27 @@ class CaloRawFitterStandard final : public CaloRawFitter
5050
~CaloRawFitterStandard() final = default;
5151

5252
/// \brief Approximate response function of the EMCal electronics.
53-
/// \param x: bin
54-
/// \param par: function parameters
53+
/// \param x bin
54+
/// \param par function parameters
5555
/// \return double with signal for a given time bin
5656
static double rawResponseFunction(double* x, double* par);
5757

5858
/// \brief Evaluation Amplitude and TOF
59-
/// return Container with the fit results (amp, time, chi2, ...)
60-
CaloFitResults evaluate(const std::vector<Bunch>& bunchvector,
59+
/// \param bunchvector Calo bunches for the tower and event
60+
/// \param altrocfg1 ALTRO config register 1 from RCU trailer
61+
/// \param altrocfg2 ALTRO config register 2 from RCU trailer
62+
/// \return Container with the fit results (amp, time, chi2, ...)
63+
/// \throw RawFitterError_t in case the fit failed (including all possible errors from upstream)
64+
CaloFitResults evaluate(const gsl::span<const Bunch> bunchvector,
6165
std::optional<unsigned int> altrocfg1,
6266
std::optional<unsigned int> altrocfg2) final;
6367

64-
/// \brief Fits the raw signal time distribution
65-
/// \return the fit parameters: amplitude, time, chi2, fit status.
66-
std::tuple<float, float, float, bool> fitRaw(int firstTimeBin, int lastTimeBin) const;
68+
/// \brief Fits the raw signal time distribution using TMinuit
69+
/// \param firstTimeBin First timebin of the ALTRO bunch
70+
/// \param lastTimeBin Last timebin of the ALTRO bunch
71+
/// \return the fit parameters: amplitude, time, chi2
72+
/// \throw RawFitter_t::FIT_ERROR in case the fit failed (insufficient number of samples or fit error from MINUIT)
73+
std::tuple<float, float, float> fitRaw(int firstTimeBin, int lastTimeBin) const;
6774

6875
private:
6976
ClassDefNV(CaloRawFitterStandard, 1);

Detectors/EMCAL/reconstruction/macros/RawFitterTESTs.C

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,14 @@ void RawFitterTESTs(const char* filename = "")
9797
std::cout << "processing next channel idx " << chan.getChannelIndex() << ", " << chan.getHardwareAddress() << std::endl;
9898
// define the conatiner for the fit results, and perform the raw fitting using the stadnard raw fitter
9999
continue;
100-
o2::emcal::CaloFitResults fitResults = RawFitter.evaluate(chan.getBunches(), 0, 0);
100+
try {
101+
o2::emcal::CaloFitResults fitResults = RawFitter.evaluate(chan.getBunches(), 0, 0);
101102

102-
// print the fit output
103-
std::cout << "The Time is : " << fitResults.getTime() << " And the Amplitude is : " << fitResults.getAmp() << std::endl;
103+
// print the fit output
104+
std::cout << "The Time is : " << fitResults.getTime() << " And the Amplitude is : " << fitResults.getAmp() << std::endl;
105+
} catch (o2::emcal::CaloRawFitter::RawFitterError_t& fiterror) {
106+
std::cerr << "Error processing raw fit: " << o2::emcal::CaloRawFitter::createErrorMessage(fiterror) << std::endl;
107+
}
104108
}
105109
}
106110
}

Detectors/EMCAL/reconstruction/src/CaloRawFitter.cxx

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,40 @@
2525

2626
using namespace o2::emcal;
2727

28+
std::string CaloRawFitter::createErrorMessage(CaloRawFitter::RawFitterError_t errorcode)
29+
{
30+
switch (errorcode) {
31+
case RawFitterError_t::SAMPLE_UNINITIALIZED:
32+
return "Sample for fit not initialzied or bunch length is 0";
33+
case RawFitterError_t::FIT_ERROR:
34+
return "Fit of the raw bunch was not successful";
35+
case RawFitterError_t::CHI2_ERROR:
36+
return "Chi2 of the fit could not be determined";
37+
case RawFitterError_t::BUNCH_NOT_OK:
38+
return "Calo bunch could not be selected";
39+
};
40+
// Silence compiler warnings for false positives
41+
// can never enter here due to usage of enum class
42+
return "Unknown error code";
43+
}
44+
45+
int CaloRawFitter::getErrorNumber(CaloRawFitter::RawFitterError_t fiterror)
46+
{
47+
switch (fiterror) {
48+
case RawFitterError_t::SAMPLE_UNINITIALIZED:
49+
return 0;
50+
case RawFitterError_t::FIT_ERROR:
51+
return 1;
52+
case RawFitterError_t::CHI2_ERROR:
53+
return 2;
54+
case RawFitterError_t::BUNCH_NOT_OK:
55+
return 3;
56+
};
57+
// Silence compiler warnings for false positives
58+
// can never enter here due to usage of enum class
59+
return -1;
60+
}
61+
2862
//Default constructor
2963
CaloRawFitter::CaloRawFitter(const char* name, const char* nameshort) : mMinTimeIndex(-1),
3064
mMaxTimeIndex(-1),
@@ -108,7 +142,7 @@ std::tuple<float, std::array<double, constants::EMCAL_MAXTIMEBINS>> CaloRawFitte
108142
{
109143
std::array<double, constants::EMCAL_MAXTIMEBINS> outarray;
110144
int length = bunch.getBunchLength();
111-
const std::vector<uint16_t>& sig = bunch.getADC();
145+
const gsl::span<const uint16_t> sig(bunch.getADC());
112146

113147
double ped = evaluatePedestal(sig, length);
114148

@@ -119,8 +153,11 @@ std::tuple<float, std::array<double, constants::EMCAL_MAXTIMEBINS>> CaloRawFitte
119153
return std::make_tuple(ped, outarray);
120154
}
121155

122-
float CaloRawFitter::evaluatePedestal(const std::vector<uint16_t>& data, std::optional<int> length) const
156+
float CaloRawFitter::evaluatePedestal(const gsl::span<const uint16_t> data, std::optional<int> length) const
123157
{
158+
if (!mNsamplePed) {
159+
throw RawFitterError_t::SAMPLE_UNINITIALIZED;
160+
}
124161
double tmp = 0;
125162

126163
if (mIsZerosupressed == false) {
@@ -173,15 +210,15 @@ bool CaloRawFitter::checkBunchEdgesForMax(const Bunch& bunch) const
173210
return bunchOK;
174211
}
175212

176-
std::tuple<short, short, short> CaloRawFitter::selectBunch(const std::vector<Bunch>& bunchvector)
213+
std::tuple<short, short, short> CaloRawFitter::selectBunch(const gsl::span<const Bunch>& bunchvector)
177214
{
178215
short bunchindex = -1;
179216
short maxall = -1;
180217
int indx = -1;
181218
short maxampbin(0), maxamplitude(0);
182219

183220
for (unsigned int i = 0; i < bunchvector.size(); i++) {
184-
short max = maxAmp(bunchvector.at(i), indx); // CRAP PTH, bug fix, trouble if more than one bunches
221+
short max = maxAmp(bunchvector[i], indx); // CRAP PTH, bug fix, trouble if more than one bunches
185222
if (isInTimeRange(indx, mMaxTimeIndex, mMinTimeIndex)) {
186223
if (max > maxall) {
187224
maxall = max;
@@ -193,9 +230,9 @@ std::tuple<short, short, short> CaloRawFitter::selectBunch(const std::vector<Bun
193230
}
194231

195232
if (bunchindex >= 0) {
196-
bool bunchOK = checkBunchEdgesForMax(bunchvector.at(bunchindex));
233+
bool bunchOK = checkBunchEdgesForMax(bunchvector[bunchindex]);
197234
if (!bunchOK) {
198-
bunchindex = -1;
235+
throw RawFitterError_t::BUNCH_NOT_OK;
199236
}
200237
}
201238

@@ -217,7 +254,7 @@ double CaloRawFitter::calculateChi2(double amp, double time,
217254
{
218255
if (first == last || first < 0) { // signal consists of single sample, chi2 estimate (0) not too well defined..
219256
// or, first is negative, the indices are not valid
220-
return -1;
257+
throw RawFitterError_t::CHI2_ERROR;
221258
}
222259

223260
int nsamples = last - first + 1;
@@ -243,7 +280,7 @@ double CaloRawFitter::calculateChi2(double amp, double time,
243280

244281
return chi2;
245282
}
246-
std::tuple<int, int, float, short, short, float, int, int> CaloRawFitter::preFitEvaluateSamples(const std::vector<Bunch>& bunchvector,
283+
std::tuple<int, int, float, short, short, float, int, int> CaloRawFitter::preFitEvaluateSamples(const gsl::span<const Bunch> bunchvector,
247284
std::optional<unsigned int> altrocfg1, std::optional<unsigned int> altrocfg2, int acut)
248285
{
249286

@@ -261,8 +298,8 @@ std::tuple<int, int, float, short, short, float, int, int> CaloRawFitter::preFit
261298
//std::tie(ped, mReversed) = reverseAndSubtractPed((bunchvector.at(index)), altrocfg1, altrocfg2);
262299
//maxf = (float)*std::max_element(mReversed.begin(), mReversed.end());
263300

264-
int length = bunchvector.at(index).getBunchLength();
265-
const std::vector<uint16_t>& sig = bunchvector.at(index).getADC();
301+
int length = bunchvector[index].getBunchLength();
302+
const std::vector<uint16_t>& sig = bunchvector[index].getADC();
266303

267304
ped = evaluatePedestal(sig, length);
268305

@@ -276,8 +313,8 @@ std::tuple<int, int, float, short, short, float, int, int> CaloRawFitter::preFit
276313
if (maxf >= acut) // possibly significant signal
277314
{
278315
// select array around max to possibly be used in fit
279-
maxrev = maxampindex - bunchvector.at(index).getStartTime();
280-
std::tie(first, last) = selectSubarray(gsl::span<double>(&mReversed[0], bunchvector.at(index).getBunchLength()), maxrev, acut);
316+
maxrev = maxampindex - bunchvector[index].getStartTime();
317+
std::tie(first, last) = selectSubarray(gsl::span<double>(&mReversed[0], bunchvector[index].getBunchLength()), maxrev, acut);
281318

282319
// sanity check: maximum should not be in first or last bin
283320
// if we should do a fit

0 commit comments

Comments
 (0)