Project
Loading...
Searching...
No Matches
CaloRawFitterGS.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
15#include <gsl/span>
16#include <cmath>
17#include <TMath.h>
18
21
22using namespace o2::phos;
29
31{
33 // prepare fitting arrays, once per lifetime
35 ma0[0] = 0.;
36 ma1[0] = 0.;
37 ma2[0] = 0.;
38 ma3[0] = 0.;
39 ma4[0] = 0.;
40 for (int i = 1; i < NMAXSAMPLES; i++) {
41 double xi = k * i;
42 mexp[i] = exp(-xi);
43 double s = mexp[i] * mexp[i];
44 ma0[i] = ma0[i - 1] + s;
45 ma1[i] = ma1[i - 1] + s * xi;
46 ma2[i] = ma2[i - 1] + s * xi * xi;
47 ma3[i] = ma3[i - 1] + s * xi * xi * xi;
48 ma4[i] = ma4[i - 1] + s * xi * xi * xi * xi;
49 }
50}
51
52CaloRawFitterGS::FitStatus CaloRawFitterGS::evaluate(gsl::span<short unsigned int> signal)
53{
54
55 // Pedestal analysis mode
56 if (mPedestalRun) {
57 int nPed = signal.size();
58 mAmp = 0.;
59 mTime = 0.;
60 for (auto a : signal) {
61 mAmp += a;
62 mTime += a * a;
63 }
64 if (nPed > 0) {
65 mAmp /= nPed;
66 mTime = mTime / nPed - mAmp * mAmp;
67 if (mTime > 0.) {
68 mTime = sqrt(mTime);
69 }
70 }
71 mOverflow = false;
72 mStatus = kOK;
73 return kOK;
74 }
75
77 // Extract amplitude and time
78 mStatus = evalFit(signal);
79 return mStatus;
80}
81
82CaloRawFitterGS::FitStatus CaloRawFitterGS::evalFit(gsl::span<short unsigned int> signal)
83{
84 // Calculate signal parameters (energy, time, quality) from array of samples
85 // Fit with semi-gaus function with free parameters time and amplitude
86 // Signal overflows if there are at least 3 samples of the same amplitude above 900
87
88 // Calculate signal parameters (energy, time, quality) from array of samples
89 // Energy is a maximum sample minus pedestal 9
90 // Time is the first time bin
91 // Signal overflows is there are at least 3 samples of the same amplitude above 900
92
93 int nSamples = signal.size();
94 if (nSamples == 0) {
95 mAmp = 0;
96 mTime = 0.;
97 mChi2 = 0.;
98 return kEmptyBunch;
99 }
100 if (nSamples == 1) {
101 mAmp = signal[0];
102 mTime = 0.;
103 mChi2 = 1.;
104 return kOK;
105 }
106
107 mOverflow = false;
108
109 // if pedestal should be subtracted first evaluate it
110 float pedMean = 0;
111 int nPed = 0;
112 if (mPedSubtract) {
113 // remember inverse time order
114 for (auto it = signal.rbegin(); (nPed < mPreSamples) && it != signal.rend(); ++it) {
115 nPed++;
116 pedMean += *it;
117 }
118 if (nPed > 0) {
119 pedMean /= nPed;
120 }
121 nSamples -= mPreSamples;
122 if (nSamples <= 0) { // empty bunch left
123 mAmp = 0;
124 mTime = 0.;
125 mChi2 = 0.;
126 return kEmptyBunch;
127 }
128 }
129
130 float maxSample = 0.; // maximal sample value
131 int nMax = 0; // number of consequitive maximal samples
132 bool spike = false; // spike in previoud signal bin?
133 short ap = -1, app = -1; // remember previous values to evaluate spikes
134 double b0 = 0., b1 = 0., b2 = 0., y2 = 0.; // fit coeficients
135 double sa0 = 0., sa1 = 0., sa2 = 0., sa3 = 0., sa4 = 0.; // corrections in case of overflow
136
137 int firstS = nSamples;
138 int j = TMath::Min(nSamples, NMAXSAMPLES - 1);
139 for (int i = 1; i <= j; i++) {
140 short a = signal[firstS - i] - pedMean; // remember inverse order of samples
141 float xi = i * mDecTime;
142 if (a > maxSample) {
143 maxSample = a;
144 nMax = 1;
145 } else {
146 if (a == maxSample) {
147 nMax++;
148 }
149 }
150 // check if there was a spike in previous step?
151 if (app > 0 && ap > 0) {
152 spike = (ap - a > mSpikeThreshold) && (ap - app > mSpikeThreshold);
153 }
154 if (spike) { // Try to recover: subtract last point contribution and replace by average of "app" and "a"
155 float atmp = 0.5 * (app + a);
156 float xiprev = xi - mDecTime;
157 float st = (atmp - ap) * mexp[i - 1];
158 b0 += st;
159 b1 += st * xiprev;
160 b2 += st * xiprev * xiprev;
161 y2 += atmp * atmp - ap * ap;
162 ap = a;
163 } else {
164 app = ap;
165 ap = a;
166 }
167 // Check if in saturation
168 if (maxSample > 900 && nMax >= 3) {
169 // Remove overflow points from the fit
170 if (!mOverflow) { // first time in this sample: remove two previous points
171 sa0 = ma0[i] - ma0[i - 2]; // can not appear at i<2
172 sa1 = ma1[i] - ma1[i - 2];
173 sa2 = ma2[i] - ma2[i - 2];
174 sa3 = ma3[i] - ma3[i - 2];
175 sa4 = ma4[i] - ma4[i - 2];
176 float st = ap * mexp[i - 1];
177 float xiprev = xi - mDecTime;
178 b0 -= st;
179 b1 -= st * xiprev;
180 b2 -= st * xiprev * xiprev;
181 y2 -= ap * ap;
182 st = app * mexp[i - 2];
183 xiprev -= mDecTime;
184 b0 -= st;
185 b1 -= st * xiprev;
186 b2 -= st * xiprev * xiprev;
187 y2 -= ap * ap;
188 }
189 mOverflow = true;
190 }
191 if (!mOverflow) {
192 // to calculate time
193 float st = a * mexp[i];
194 b0 += st;
195 b1 += st * xi;
196 b2 += st * xi * xi;
197 y2 += a * a;
198 } else { // do not add current point and subtract contributions to amx[] arrays
199 sa0 = ma0[i] - ma0[i - 1]; // can not appear at i<2
200 sa1 = ma1[i] - ma1[i - 1];
201 sa2 = ma2[i] - ma2[i - 1];
202 sa3 = ma3[i] - ma3[i - 1];
203 sa4 = ma4[i] - ma4[i - 1];
204 }
205 } // Scanned full
206
207 // too small amplitude, assing max to max Amp and time to zero and do not calculate height
208 if (maxSample < mMinTimeCalc) {
209 mAmp = maxSample;
210 mTime = 0.;
211 mChi2 = 0.;
212 return kOK;
213 }
214
215 if (mOverflow && b0 == 0) { // strong overflow, no reasonable counts, can not extract anything
216 mAmp = 0.;
217 mTime = 0.;
218 mChi2 = 900.;
219 return kOverflow;
220 }
221
222 // calculate time, amp and chi2
223 double a, b, c, d, e; // Polinomial coefficients
224 if (!mOverflow) {
225 a = ma1[j] * b0 - ma0[j] * b1;
226 b = ma0[j] * b2 + 2. * ma1[j] * b1 - 3. * ma2[j] * b0;
227 c = 3. * (ma3[j] * b0 - ma1[j] * b2);
228 d = 3. * ma2[j] * b2 - ma4[j] * b0 - 2. * ma3[j] * b1;
229 e = ma4[j] * b1 - ma3[j] * b2;
230 } else { // account removed points in overflow
231 a = (ma1[j] - sa1) * b0 - (ma0[j] - sa0) * b1;
232 b = (ma0[j] - sa0) * b2 + 2. * (ma1[j] - sa1) * b1 - 3. * (ma2[j] - sa2) * b0;
233 c = 3. * ((ma3[j] - sa3) * b0 - (ma1[j] - sa1) * b2);
234 d = 3. * (ma2[j] - sa2) * b2 - (ma4[j] - sa4) * b0 - 2. * (ma3[j] - sa4) * b1;
235 e = (ma4[j] - sa4) * b1 - (ma3[j] - sa3) * b2;
236 }
237
238 // Find zero of 4-order polinomial
239 // first use linear extrapolation to reach correct root of four
240 double z = -1.;
241 if (ma0[j] * b1 - ma1[j] * b0 != 0) {
242 z = (ma1[j] * b1 - ma2[j] * b0) / (ma0[j] * b1 - ma1[j] * b0) - 1.; // linear fit + offset
243 }
244 double q = 0., dq = 0., ddq = 0., lq = 0., dz = 0.1;
245 double z2 = z * z;
246 double z3 = z2 * z;
247 double z4 = z2 * z2;
248 q = a * z4 + b * z3 + c * z2 + d * z + e; // polinomial
249 dq = 4. * a * z3 + 3. * b * z2 + 2. * c * z + d; // Derivative
250 ddq = 12. * a * z2 + 6. * b * z + 2. * c; // Second derivative
251 if (dq != 0.) {
252 lq = q * ddq / (dq * dq);
253 }
254 // dz = -q/dq ; // Newton ~7 terations
255 // dz =-(1+0.5*lq)*q/dq ; // Chebyshev ~3 iterations to reach |q|<1.e-11
256 double ttt = dq * (1. - 0.5 * lq); // Halley’s method ~3 iterations, a bit more precise
257 if (ttt != 0) {
258 dz = -q / ttt;
259 } else {
260 dz = 0.1; // step off saddle point
261 }
262 int it = 0;
263 while (TMath::Abs(q) > 0.0001 && (++it < 15)) {
264 z += dz;
265 z2 = z * z;
266 z3 = z2 * z;
267 z4 = z2 * z2;
268 q = a * z4 + b * z3 + c * z2 + d * z + e;
269 dq = 4. * a * z3 + 3. * b * z2 + 2. * c * z + d;
270 ddq = 12. * a * z2 + 6. * b * z + 2. * c;
271 if (dq != 0) {
272 lq = q * ddq / (dq * dq);
273 ttt = dq * (1. - 0.5 * lq);
274 // dz = -q/dq ; //Newton
275 // dz =-(1+0.5*lq)*q/dq ; //Chebyshev
276 if (ttt != 0) {
277 dz = -q / ttt; // Halley’s
278 } else {
279 dz = -q / dq;
280 }
281 } else {
282 dz = 0.5 * dz; // step off saddle point
283 }
284 }
285
286 // check that result is reasonable
287 double denom = ma4[j] - 4. * ma3[j] * z + 6. * ma2[j] * z * z - 4. * ma1[j] * z * z * z + ma0[j] * z * z * z * z;
288 if (denom != 0.) {
289 mAmp = 4. * exp(-2 - z) * (b2 - 2. * b1 * z + b0 * z * z) / denom;
290 } else {
291 mAmp = 0.;
292 }
293
294 if ((TMath::Abs(q) < mQAccuracy) && (mAmp < 1.2 * maxSample)) { // converged and estimated amplitude is not mush larger than Max
295 mTime = z / mDecTime;
296 mChi2 = (y2 - 0.25 * exp(2. + z) * mAmp * (b2 - 2 * b1 * z + b0 * z2)) / nSamples;
297 return kOK;
298 } else { // too big difference, fit failed
299 mAmp = maxSample;
300 mTime = 0; // First count in sample
301 mChi2 = 999.;
302 return kFitFailed;
303 }
304}
uint64_t exp(uint64_t base, uint8_t exp) noexcept
int32_t i
const GPUTPCGMMerger::trackCluster & b1
uint32_t j
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
benchmark::State & st
FitStatus evaluate(gsl::span< short unsigned int > signal) final
Evaluation Amplitude and TOF.
FitStatus evalFit(gsl::span< short unsigned int > signal)
static constexpr int NMAXSAMPLES
float mAmp
amplitude of last processed sample
bool mOverflow
is last sample saturated
bool mPedSubtract
should one evaluate and subtract pedestals
float mTime
time of last processed sample
float mChi2
chi2 calculated in last fit
bool mPedestalRun
analyze as pedestal run
FitStatus mStatus
status of last evaluated sample: -1: not yet evaluated; 0: OK; 1: overflow; 2: too large RMS; 3: sing...
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLdouble GLdouble GLdouble z
Definition glcorearb.h:843
float mSampleDecayTime
Time parameter in Gamma2 function (1/tau, 100.e-9/2.1e-6)