ATLAS Offline Software
Loading...
Searching...
No Matches
TileRawChannelBuilderMF.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2023 CERN for the benefit of the ATLAS collaboration
3*/
4
5// small hack to enable datapool usage
7// Tile includes
14
15// Atlas includes
18
19// Gaudi includes
20#include "Gaudi/Property.h"
21
22// lang include
23#include <algorithm>
24#include <cmath>
25
26
27// for matrix treatment
28#include "CLHEP/Matrix/Matrix.h"
29
33TileRawChannelBuilderMF::TileRawChannelBuilderMF(const std::string& type, const std::string& name,
34 const IInterface *parent)
35 : TileRawChannelBuilder(type, name, parent)
36 , m_nSamples(0)
38 , m_maxTime(0.0)
39 , m_minTime(0.0)
40{
41
42 //declare interfaces
43 declareInterface<TileRawChannelBuilder>(this);
44 declareInterface<TileRawChannelBuilderMF>(this);
45
46 m_rawChannelContainerKey = "TileRawChannelMF";
47
48 //declare properties
49 declareProperty("AmplitudeCorrection", m_correctAmplitude = false);
50 declareProperty("PedestalMode", m_pedestalMode = 1);
51 declareProperty("DefaultPedestal", m_defaultPedestal = 0.0);
52 declareProperty("MF", m_MF = 0);
53 declareProperty("MaxIterations", m_maxIterations = 5);
54 declareProperty("BestPhase", m_bestPhase = false);
55 declareProperty("TimeFromCOF", m_timeFromCOF = false);
56}
57
63
68
69 ATH_MSG_INFO("TileRawChannelBuilderMF::initialize()");
70
72
73 // Initialize arrays for ped estimation
74 memset(m_chPedCounter, 0, sizeof(m_chPedCounter));
75 memset(m_chPed, 0, sizeof(m_chPed));
76
77 // init in superclass
79
80 // bits 12-15 - various options
81 if (m_correctAmplitude) m_bsflags |= 0x2000;
82 if (m_maxIterations > 1) m_bsflags |= 0x4000;
83 if (m_bestPhase) m_bsflags |= 0x8000;
84
85 m_nSamples = m_tileInfo->NdigitSamples();
86 m_t0SamplePosition = m_tileInfo->ItrigSample();
89
91 //=== get TileCondToolOfc
92 ATH_CHECK(m_tileCondToolOfc.retrieve());
93
94
95 if (m_bestPhase) {
96 //=== get TileToolTiming
97 // TileToolTiming can be disabled in the TileRawChannelBuilder
98 if (!m_tileToolTiming.isEnabled()) {
99 m_tileToolTiming.enable();
100 }
101 ATH_CHECK(m_tileToolTiming.retrieve());
102 }
103
104 //=== get TileCondToolNoiseSample
106
107 ATH_MSG_DEBUG("TileRawChannelBuilderMF::initialize() completed successfully");
108
109 return StatusCode::SUCCESS;
110}
111
116
117 ATH_MSG_DEBUG("Finalizing");
118
119 return StatusCode::SUCCESS;
120}
121
122TileRawChannel* TileRawChannelBuilderMF::rawChannel(const TileDigits* tiledigits, const EventContext& ctx) {
123
124 ++m_chCounter;
125 int i, j, row, col;
126 unsigned int k;
127 double MFchi2 = 0.;
128
129 const HWIdentifier adcId = tiledigits->adc_HWID();
130 int gain = m_tileHWID->adc(adcId);
131 int ros = m_tileHWID->ros(adcId);
132 int drawer = m_tileHWID->drawer(adcId);
133 int channel = m_tileHWID->channel(adcId);
134 unsigned int drawerIdx = TileCalibUtils::getDrawerIdx(ros, drawer);
135
136 ATH_MSG_VERBOSE("Running Matched Filter for TileRawChannel with HWID " << m_tileHWID->to_string(adcId));
137
138 /* get pedestal value assumed for reconstruction */
139 //double digSigma = m_tileInfo->DigitsResolution(gain);
140 // new way to get channel-dependent sigma:
141 // but we lost difference between sigma used in digitization and
142 // sigma assumed in reconstruction - it's the same sigma now
143 //double digSigma = m_tileInfo->DigitsPedSigma(adcId);
144 /* Get vector of time-slice amplitudes. */
145 m_digits = tiledigits->samples();
146 double amp_ch = 0; // Fitted amplitude of RC (to be returned from Filtering code).
147 double cof[7] = { 0., 0., 0., 0., 0., 0., 0. };
148 float ped_ch = 0; // Ped retrieved from m_tileToolNoiseSample.
149 double chisq_ch = 0.; // Chisq resulting from Filtering.
150 double t_ch = 0.; // Fitted time to be supplied by Filtering code
151 double amp_norm = 0.; // Normalization factor for MF method
152 double amp_mf = 0.;
153 float ped_aux = 0;
154 float rms_aux = 0;
155 float phase = 0;
156 int err = 0; //error for matrix handling
157
158 float mindig, maxdig;
159
160 // to treat issues discussed...
161 if (are3FF(mindig, maxdig)) {
162
163 ped_ch = 0.;
164 if (mindig > 2046.99)
165 chisq_ch = 9999.;
166 else
167 chisq_ch = 0.;
168
169 } else {
170
171 if (m_bestPhase) phase = (float) -m_tileToolTiming->getSignalPhase(drawerIdx, channel, gain);
172 rms_aux = m_tileToolNoiseSample->getHfn(drawerIdx, channel, gain, TileRawChannelUnit::ADCcounts, ctx);
173
174 switch (m_pedestalMode) {
175
176 case -1:
177 // use ped estimated from data based on the conditions value
178 ped_aux = m_tileToolNoiseSample->getPed(drawerIdx, channel, gain, TileRawChannelUnit::ADCcounts, ctx);
179 /*rms_aux = m_tileToolNoiseSample->getHfn(drawerIdx, channel, gain, TileRawChannelUnit::ADCcounts, ctx); */
180
181 if (m_chPedCounter[ros][drawer][channel][gain] < 200) {
182
183 if ((m_digits[0] < (ped_aux + 10)) && (m_digits[0] > (ped_aux - 10))) {
184
185 ++m_chPedCounter[ros][drawer][channel][gain];
186 m_chPed[ros][drawer][channel][gain] += m_digits[0];
187
188 }
189 }
190
191 if (m_chPedCounter[ros][drawer][channel][gain] > 0) {
192 ped_ch = m_chPed[ros][drawer][channel][gain] / m_chPedCounter[ros][drawer][channel][gain];
193 } else {
194 ped_ch = ped_aux;
195 }
196 break;
197
198 case 0:
199 // use fixed pedestal from jobOptions
200 ped_ch = m_defaultPedestal;
201 break;
202
203 default:
204 // use pedestal from conditions DB
205 ped_ch = m_tileToolNoiseSample->getPed(drawerIdx, channel, gain, TileRawChannelUnit::ADCcounts, ctx);
206 break;
207
208 }
209
210 // begin COF iteration for amplitude greater than m_ampMinThresh (15 ADC) and within +/- bunch spacing/2
211 int n = 7;
212 CLHEP::HepMatrix A(n, n, 0);
213 int t=0;
214 double signalModel[7]={};
215 bool goodEne = true;
216 t_ch = -phase;
217 for (int it = 0; it < m_maxIterations; it++) {
218
219 float ofcPhase(-t_ch);
221 if (m_tileCondToolOfc->getOfcWeights(drawerIdx, channel, gain, ofcPhase, true, weights, ctx).isFailure()) {
222 ATH_MSG_ERROR("getOfcWeights fails.");
223 return nullptr;
224 }
225
226 t_ch = -ofcPhase;
227
228 double g[9] = {0};
229 double b[9] = {0};
230 double dg[9] = {0};
231
232 for (k = 0; k < m_digits.size(); ++k) {
233 b[k] = weights.w_b[k];
234 g[k] = weights.g[k];
235 dg[k] = weights.dg[k];
236 if (it == 0) {
237 amp_mf += g[k] * (m_digits[k] - ped_ch); // matched filter
238 amp_norm += g[k] * g[k]; // matched filter calibration for amp estimation
239 }
240 }
241
242 if (it == 0) amp_mf = amp_mf / amp_norm; // pure MF (for muon receiver board simulation)
243
244 // build deconvolution matrix (keep OOT signals "in-time")
245 if (it == 0) {
246 t = 4;
247 for (row = 0; row < n; row++) {
248 t -= 1;
249 for (col = 0; col < n; col++) {
250 if (((col + t) > 6) || ((col + t) < 0)) {
251 A[row][col] = 0.0;
252 } else {
253 A[row][col] = g[col + t];
254 }
255
256 }
257 }
258 } else {
259 for (col = 0; col < n; col++) {
260 A[3][col] = g[col];
261 }
262 }
263
264 // apply deconvolution for pileup handling
265 CLHEP::HepMatrix B(n, n, 0);
266 err = 0;
267 B = A;
268 B.invert(err);
269
270 double xDecon[7] = { 0, 0, 0, 0, 0, 0, 0 };
271 for (j = 0; j < n; ++j) {
272 for (i = 0; i < n; ++i) {
273 xDecon[j] += (m_digits[i] - ped_ch) * B[i][j];
274 }
275 }
276
277 // build the pile-up threshold based on deconvolution noise and test whether pileup is present
278 double thr[7] = { 0, 0, 0, 0, 0, 0, 0 };
279 for (j = 0; j < n; ++j) {
280 for (i = 0; i < n; ++i) {
281 thr[j] += (rms_aux * rms_aux) * (B[i][j] * B[i][j]);
282 }
283 thr[j] = sqrt(thr[j]);
284 }
285
286 // apply the pile-up threshold to detect OOT signals
287 int pileupDet[7] = { 0, 0, 0, 1, 0, 0, 0 };
288 int constraint = 1;
289 for (i = 0; i < n; ++i) {
290 if (i == 3) continue;
291 if ((ros == 1) || (ros == 2)) { // test 4*noise RMS from deconvolution matrix for barrel cells (low occupancy)
292 if (xDecon[i] > 4 * thr[i]) {
293 pileupDet[i] = 1;
294 constraint += 1;
295 }
296 } else if ((ros == 3) || (ros == 4)) { // test 3*noise RMS from deconvolution matrix for extended barrel cells (higher occupancy)
297 if (xDecon[i] > 3 * thr[i]) {
298 pileupDet[i] = 1;
299 constraint += 1;
300 }
301 }
302
303 }
304
305 // apply second step COF
306 int allBCtrig = 0; // test if all BCs were triggered by decovolution, and if not, we can include the derivative for timing estimation
307 if (m_timeFromCOF) {
308 if (constraint < 7)
309 constraint += 1; // this line is to include the derivative in second step of COF, for the time estimation
310 else
311 allBCtrig = 1;
312 }
313
314 CLHEP::HepMatrix H(constraint, n, 0);
315
316 t = 4;
317 int rowAux = 0;
318 for (row = 0; row < n; row++) {
319 t -= 1;
320 if (pileupDet[row] == 0) continue;
321 for (col = 0; col < n; col++) {
322 if (((col + t) > 6) || ((col + t) < 0)) {
323 H[rowAux][col] = 0.0;
324 } else {
325 H[rowAux][col] = g[col + t];
326 }
327
328 }
329 rowAux += 1;
330 }
331
332 // including the derivative to better estimate the time if we have less than 7 signals detected by DM
333 if (m_timeFromCOF) {
334 if (rowAux < 7) {
335 for (col = 0; col < n; col++) {
336 H[rowAux][col] = dg[col];
337 }
338 }
339 }
340
341 CLHEP::HepMatrix tH(n, constraint, 0);
342 CLHEP::HepMatrix resultH(constraint, n, 0);
343 CLHEP::HepMatrix multH(constraint, constraint, 0);
344 tH = H.T();
345 multH = H * tH;
346 err = 0;
347 multH.invert(err);
348 resultH = multH * H;
349 for (j = 0; j < n; j++) { // initialize signal model to be built from COF amplitude estimates
350 signalModel[j] = 0.0;
351 cof[j] = 0.0;
352 }
353 int r = 0;
354 int iBC3 = 0; // variable to be used in case of amplitude correction (m_correctAmplitude)
355 if (m_MF == 1) {
356 cof[3] = amp_mf;
357 for (j = 0; j < n; j++) {
358 signalModel[j] += cof[3] * A[3][j];
359 }
360 } else {
361 for (i = 0; i < n; ++i) {
362 if (pileupDet[i] == 0) continue;
363 if (i == 3) iBC3 = r;
364 for (j = 0; j < n; j++) {
365 cof[i] += (m_digits[j] - ped_ch) * resultH[r][j];
366 }
367 for (j = 0; j < n; j++) {
368 signalModel[j] += cof[i] * A[i][j];
369 }
370 r++;
371 }
372 }
373
374 // computation of the timing, instead of taking the b weights from OF2, which are also not optimized for pileup
375 double t_aux = 0.0;
376 if (m_timeFromCOF) {
377 for (j = 0; j < n; j++) {
378 if (allBCtrig == 0)
379 t_aux += (m_digits[j] - ped_ch) * (-resultH[rowAux][j]); // negative to be consistent
380 else
381 t_aux += m_digits[j] * b[j]; // use OF2 b weights (no need to subtract the pedestal), in the case all 7 BC are triggered by deconvolution
382 }
383 } else {
384 for (j = 0; j < n; j++) {
385 t_aux += m_digits[j] * b[j]; // use b weights from OF2 to calculate time
386 }
387 }
388
389 amp_ch = cof[3]; // with COF, the amp_ch may be deprecated
390
391 goodEne = (fabs(cof[3]) > 1.0e-04);
392 if (goodEne) {
393 t_aux /= cof[3];
394 t_ch += t_aux;
395 } else {
396 t_ch = amp_ch = 0.0;
397 for (i = 0; i < n; ++i) {
398 cof[i] = 0.0;
399 }
400 }
401
402 // condition for amplitude and time correction using iterative mode
403 if ((m_maxIterations > 1) && ((cof[3] < m_ampMinThresh) || (t_ch < m_timeMinThresh || t_ch > m_timeMaxThresh)))
404 break;
405
406 // amplitude correction for central BC (same as parabolic correction)
407 if (m_correctAmplitude && cof[3] > m_ampMinThresh && t_ch > m_timeMinThresh && t_ch < m_timeMaxThresh) {
408 double correction = 0.0;
409 ofcPhase = -t_ch;
410 if (m_tileCondToolOfcOnFly->getOfcWeights(drawerIdx, channel, gain, ofcPhase, true, weights, ctx).isFailure()) {
411 ATH_MSG_ERROR("getOfcWeights fails.");
412 return nullptr;
413 }
414 for (j = 0; j < n; ++j) {
415 correction += weights.g[j] * resultH[iBC3][j];
416 }
417 cof[3] += (1 - correction) * cof[3];
418 }
419
420 } //end of COF iteration
421
422 t_ch += phase;
423
424 if (t_ch < m_minTime) t_ch = m_minTime;
425 if (t_ch > m_maxTime) t_ch = m_maxTime;
426
427 if (m_calibrateEnergy) {
428 amp_ch = m_tileToolEmscale->doCalibCis(drawerIdx, channel, gain, amp_ch);
429 for (i = 0; i < n; ++i) {
430 cof[i] = m_tileToolEmscale->doCalibCis(drawerIdx, channel, gain, cof[i]);
431 }
432 }
433
434 // we know that time is zero here, put negative chi^2 to indicate that
435 for (k = 0; k < m_digits.size(); ++k) {
436 double dqf = (signalModel[k] - (m_digits[k] - ped_ch));
437 MFchi2 += dqf * dqf;
438 }
439 chisq_ch = sqrt(MFchi2);
440
441 if (fabs(chisq_ch) > 1.0e-04 || goodEne) {
442 if (msgLvl(MSG::VERBOSE)) {
443 msg(MSG::VERBOSE) << "MFtime=" << t_ch << endmsg;
444 msg(MSG::VERBOSE) << "MFped=" << ped_ch << endmsg;
445 msg(MSG::VERBOSE) << "MFchi2=" << chisq_ch << endmsg;
446 }
447 } else {
448 if (msgLvl(MSG::VERBOSE)) {
449 msg(MSG::VERBOSE) << "MFtime=" << t_ch << endmsg;
450 msg(MSG::VERBOSE) << "MFped=" << ped_ch << endmsg;
451 msg(MSG::VERBOSE) << "MFchi2=" << chisq_ch << " ... assuming 0.0" << endmsg;
452 }
453 chisq_ch = 0.0;
454 }
455
456 }
457
458 // TileRawChannel *rawCh = new TileRawChannel(adcId,amp_ch,t_ch,chisq_ch);
460 TileRawChannel *rawCh = tileRchPool.nextElementPtr();
461 float times[7] = { (float)t_ch, -75, -50, -25, 25, 50, 75};
462 rawCh->assign (adcId,
463 std::begin(cof), std::end(cof),
464 std::begin(times), std::end(times),
465 &chisq_ch, &chisq_ch+1,
466 ped_ch);
467
468 // correct order of amplitudes
469 rawCh->setAmplitude(cof[3], 0);
470 rawCh->setAmplitude(cof[0], 1);
471 rawCh->setAmplitude(cof[1], 2);
472 rawCh->setAmplitude(cof[2], 3);
473
474 ATH_MSG_VERBOSE("Creating RawChannel" << " a=" << amp_ch << " t=" << t_ch << " q=" << chisq_ch);
475
476 if (m_correctTime && (t_ch != 0 && t_ch < m_maxTime && t_ch > m_minTime)) {
477 t_ch -= m_tileToolTiming->getSignalPhase(drawerIdx, channel, t_ch);
478 rawCh->insertTime(t_ch);
479 ATH_MSG_VERBOSE("Correcting time, new time=" << rawCh->time());
480
481 }
482
483 if (TileID::HIGHGAIN == gain) {
484 ++m_nChH;
485 m_RChSumH += amp_ch;
486 } else {
487 ++m_nChL;
488 m_RChSumL += amp_ch;
489 }
490
491 return rawCh;
492}
493
494bool TileRawChannelBuilderMF::are3FF(float &dmin, float &dmax) {
495 bool allSaturated = true;
496 bool jump = false;
497
498 unsigned int nSamp = m_digits.size();
499 if (nSamp) {
500 dmin = dmax = m_digits[0];
501
502 for (unsigned int i = 1; i < nSamp; ++i) {
503 float dig = m_digits[i];
504 if (dig > dmax)
505 dmax = dig;
506 else if (dig < dmin) dmin = dig;
507 }
508 allSaturated = (dmin > m_ADCmaxMinusEps);
509
510 // FIXME:: set these 2 parameters from JobOptions
511 // FIXME:: move this method to base class
512 const float epsilon = 2.1; // allow 1 count fluctuations around const value
513 const float delta = 99.9; // consider jumps by 100 counts only
514 const float level0 = 39.9; // jump from this level to zero is bad
515 const float level1 = 99.9; // jump from this level to m_i_ADCmax is bad
516
517 if (!allSaturated && (dmax - dmin) > delta) {
518 float abovemin = dmax;
519 float belowmax = dmin;
520 unsigned int nmin = 0;
521 unsigned int nmax = 0;
522 //unsigned int pmin = nSamp;
523 unsigned int pmax = nSamp;
524 for (unsigned int i = 0; i < nSamp; ++i) {
525 float smp = m_digits[i];
526 if (smp - dmin < epsilon) {
527 ++nmin;
528 //pmin = i;
529 }
530 if (dmax - smp < epsilon) {
531 ++nmax;
532 pmax = i;
533 }
534 if (smp < abovemin && smp > dmin) {
535 abovemin = smp;
536 }
537 if (smp > belowmax && smp < dmax) {
538 belowmax = smp;
539 }
540 }
541
542 if (dmin < 0.01 && dmax > m_ADCmaxMinusEps) { // jump from zero to saturation
543 jump = true;
544 } else if (dmin < 0.01 && abovemin > level0 && nmin > 1) { // at least two samples at zero, others - above pedestal
545 jump = true;
546 } else if (dmax > m_ADCmaxMinusEps && belowmax < level1 && nmax > 1) { // at least two saturated. others - close to pedestal
547 jump = true;
548 } else if (nmax + nmin == nSamp) {
549 if (nmax > 1 && nmin > 1) { // at least 2 samples at two distinct levels
550 jump = true;
551 } else if (nmax == 1) {
552 if (pmax > 0 && pmax < nSamp - 1) { // jump up in one sample, but not at the edge
553 jump = true;
554 }
555 } else if (nmin == 1) { // jump down in one sample
556 jump = true;
557 }
558 }
559 }
560
561 ATH_MSG_VERBOSE( " TileRawChannelBuilderMF::Are3FF()"
562 << " mindig= " << dmin
563 << " maxdig= " << dmax
564 << " allSat= " << allSaturated
565 << " jump= " << jump);
566
567 if (jump) {
568 dmin = dmax = 4095.; // this is needed to set bad quality from Opt Filter later
569 }
570
571 } else {
572 dmin = dmax = 0.0;
573 }
574
575 return (allSaturated || jump);
576}
577
#define endmsg
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_DEBUG(x)
Helpers for checking error return status codes and reporting errors.
#define H(x, y, z)
Definition MD5.cxx:114
const int nmax(200)
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T, V, H > &t)
bool msgLvl(const MSG::Level lvl) const
a typed memory pool that saves time spent allocation small object.
Definition DataPool.h:63
pointer nextElementPtr()
obtain the next available element in pool by pointer pool is resized if its limit has been reached On...
static unsigned int getDrawerIdx(unsigned int ros, unsigned int drawer)
Returns a drawer hash.
const std::vector< float > & samples() const
Definition TileDigits.h:58
TileRawChannelBuilderMF(const std::string &type, const std::string &name, const IInterface *parent)
Standard constructor.
double m_maxTime
max allowed time = 25*(m_nSamples-1)/2
int m_t0SamplePosition
position of peak sample = (m_nSamples-1)/2
bool are3FF(float &dmin, float &dmax)
Checks that all the samples are 0x3FF (as sent by the DSP when no data arrives)
virtual StatusCode initialize() override
Initialize.
ToolHandle< ITileCondToolOfc > m_tileCondToolOfc
virtual TileRawChannel * rawChannel(const TileDigits *digits, const EventContext &ctx) override
Builder virtual method to be implemented by subclasses.
ToolHandle< TileCondToolNoiseSample > m_tileToolNoiseSample
double m_minTime
min allowed time = -25*(m_nSamples-1)/2
int m_maxIterations
maximum number of iteration to perform
bool m_correctAmplitude
If true, resulting amplitude is corrected when using weights for tau=0 without iteration.
ToolHandle< ITileCondToolOfc > m_tileCondToolOfcOnFly
int m_nSamples
number of samples in the data
virtual StatusCode finalize() override
Finalize.
ToolHandle< TileCondToolTiming > m_tileToolTiming
float m_timeMinThresh
correct amplitude is time is above time min threshold
float m_ampMinThresh
correct amplitude if it's above amplitude threshold (in ADC counts)
float m_timeMaxThresh
correct amplitude is time is below time max threshold
virtual StatusCode initialize()
Initializer.
ToolHandle< TileCondToolEmscale > m_tileToolEmscale
SG::WriteHandleKey< TileRawChannelContainer > m_rawChannelContainerKey
TileRawChannelBuilder(const std::string &type, const std::string &name, const IInterface *parent)
Constructor.
void assign(const HWIdentifier &id, float amplitude, float time, float quality, float ped=0.0)
void insertTime(float time)
float time(int ind=0) const
void setAmplitude(float a, int ind=0)
HWIdentifier adc_HWID(void) const
Definition TileRawData.h:53
int r
Definition globals.cxx:22
hold the test vectors and ease the comparison
MsgStream & msg
Definition testRead.cxx:32