Project
Loading...
Searching...
No Matches
DigiReco.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
12#include <TMath.h>
13#include "Framework/Logger.h"
16
17namespace o2
18{
19namespace zdc
20{
21
23{
24 LOG(info) << "Initialization of ZDC reconstruction";
25 // Load configuration parameters
26 auto& sopt = ZDCSimParam::Instance();
27 mIsContinuous = sopt.continuous;
28 mNBCAHead = mIsContinuous ? sopt.nBCAheadCont : sopt.nBCAheadTrig;
29
30 if (!mModuleConfig) {
31 LOG(fatal) << "Missing ModuleConfig configuration object";
32 return;
33 }
34
35 mTriggerMask = mModuleConfig->getTriggerMask();
36
38
39 if (mTreeDbg) {
40 // Open debug file
41 LOG(info) << "ZDC DigiReco: opening debug output";
42 mDbg = std::make_unique<TFile>("ZDCRecoDbg.root", "recreate");
43 mTDbg = std::make_unique<TTree>("zdcr", "ZDCReco");
44 mTDbg->Branch("zdcr", "RecEventAux", &mRec);
45 }
46
47 // Update reconstruction parameters
48 // auto& ropt=RecoParamZDC::Instance();
50 ropt.print();
51 mRopt = (o2::zdc::RecoParamZDC*)&ropt;
52
53 // Fill maps to decode the pattern of channels with hit
54 for (int itdc = 0; itdc < o2::zdc::NTDCChannels; itdc++) {
55 // If the reconstruction parameters were not manually set
56 if (ropt.tmod[itdc] < 0 || ropt.tch[itdc] < 0) {
57 int isig = TDCSignal[itdc];
58 for (int im = 0; im < NModules; im++) {
59 for (uint32_t ic = 0; ic < NChPerModule; ic++) {
60 if (mModuleConfig->modules[im].channelID[ic] == isig && mModuleConfig->modules[im].readChannel[ic]) {
61 // ropt.updateFromString(TString::Format("RecoParamZDC.tmod[%d]=%d;",itdc,im));
62 // ropt.updateFromString(TString::Format("RecoParamZDC.tch[%d]=%d;",itdc,ic));
63 ropt.tmod[itdc] = im;
64 ropt.tch[itdc] = ic;
65 // Fill mask to identify TDC channels
66 mTDCMask[itdc] = (0x1 << (4 * im + ic));
67 goto next_itdc;
68 }
69 }
70 }
71 } else {
72 // Fill mask to identify TDC channels
73 mTDCMask[itdc] = (0x1 << (4 * ropt.tmod[itdc] + ropt.tch[itdc]));
74 }
75 next_itdc:;
76 if (mVerbosity > DbgZero) {
77 LOG(info) << "TDC " << itdc << "(" << ChannelNames[TDCSignal[itdc]] << ")"
78 << " mod " << ropt.tmod[itdc] << " ch " << ropt.tch[itdc];
79 }
80 }
81
82 // Signal processing
83 // N.B. Function call overrides other settings for low pass filtering
84 if (mLowPassFilterSet == false) {
85 if (ropt.low_pass_filter < 0) {
86 if (!mRecoConfigZDC) {
87 LOG(fatal) << "Configuration of low pass filtering: missing configuration object and no manual override";
88 } else {
89 ropt.low_pass_filter = mRecoConfigZDC->low_pass_filter;
90 }
91 }
92 mLowPassFilter = ropt.low_pass_filter > 0 ? true : false;
93 }
94 LOG(info) << "Low pass filtering is " << (mLowPassFilter ? "enabled" : "disabled");
95
96 // Full interpolation of waveform (N.B. function call overrides other settings)
97 if (mFullInterpolationSet == false) {
98 if (ropt.full_interpolation < 0) {
99 if (!mRecoConfigZDC) {
100 LOG(fatal) << "Configuration of interpolation: missing configuration object and no manual override";
101 } else {
102 ropt.full_interpolation = mRecoConfigZDC->full_interpolation;
103 }
104 }
105 mFullInterpolation = ropt.full_interpolation > 0 ? true : false;
106 }
107 if (ropt.full_interpolation_min_length >= 2) {
108 // Minimum is 2 consecutive bunch crossings
109 mFullInterpolationMinLength = ropt.full_interpolation_min_length;
110 }
111 if (mVerbosity > DbgZero) {
112 LOG(info) << "Full waveform interpolation is " << (mFullInterpolation ? "enabled" : "disabled") << " min length is " << mFullInterpolationMinLength;
113 }
114
115 if (ropt.triggerCondition == 0) {
116 if (!mRecoConfigZDC) {
117 LOG(fatal) << "Trigger condition: missing configuration object and no manual override";
118 } else {
119 mTriggerCondition = mRecoConfigZDC->triggerCondition;
120 }
121 } else {
122 mTriggerCondition = ropt.triggerCondition;
123 }
124
125 if (mTriggerCondition == 0x1) {
126 LOG(info) << "SINGLE trigger condition enforced in reconstruction";
127 } else if (mTriggerCondition == 0x3) {
128 LOG(info) << "DOUBLE trigger condition enforced in reconstruction";
129 } else if (mTriggerCondition == 0x7) {
130 LOG(info) << "TRIPLE trigger condition enforced in reconstruction";
131 } else {
132 LOG(fatal) << "Unsupported trigger condition in ZDC reconstruction: " << mTriggerCondition;
133 }
134
135 if (mCorrSignalSet == false) {
136 if (ropt.corr_signal < 0) {
137 if (!mRecoConfigZDC) {
138 LOG(fatal) << "Configuration of TDC signal correction: missing configuration object and no manual override";
139 } else {
140 ropt.corr_signal = mRecoConfigZDC->corr_signal;
141 }
142 }
143 mCorrSignal = ropt.corr_signal > 0 ? true : false;
144 }
145 if (mVerbosity > DbgZero) {
146 LOG(info) << "TDC signal correction is " << (mCorrSignal ? "enabled" : "disabled");
147 }
148
149 if (mCorrBackgroundSet == false) {
150 if (ropt.corr_background < 0) {
151 if (!mRecoConfigZDC) {
152 LOG(fatal) << "Configuration of TDC pile-up correction: missing configuration object and no manual override";
153 } else {
154 ropt.corr_background = mRecoConfigZDC->corr_background;
155 }
156 }
157 mCorrBackground = ropt.corr_background > 0 ? true : false;
158 }
159 if (mVerbosity > DbgZero) {
160 LOG(info) << "TDC pile-up correction is " << (mCorrBackground ? "enabled" : "disabled");
161 }
162
163 // Trigger configuration
164 for (int itdc = 0; itdc < o2::zdc::NTDCChannels; itdc++) {
165 // If the reconstruction parameters were not manually set
166 if (ropt.tth[itdc] <= 0) {
167 if (!mRecoConfigZDC) {
168 LOG(fatal) << "Trigger threshold for TDC " << itdc << " missing configuration object and no manual override";
169 } else {
170 ropt.tth[itdc] = mRecoConfigZDC->tth[itdc];
171 }
172 }
173 if (ropt.tsh[itdc] <= 0) {
174 if (!mRecoConfigZDC) {
175 LOG(fatal) << "Trigger shift for TDC " << itdc << " missing configuration object and no manual override";
176 } else {
177 ropt.tsh[itdc] = mRecoConfigZDC->tsh[itdc];
178 }
179 }
180 if (mVerbosity > DbgZero) {
181 LOG(info) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " tth= " << mRopt->tth[itdc] << " tsh= " << mRopt->tsh[itdc];
182 }
183 }
184
185 // Extended search configuration
186 if (ropt.setExtendedSearch == false) {
187 if (mRecoConfigZDC == nullptr) {
188 LOG(fatal) << "Extended search configuration: missing configuration object and no manual override";
189 } else {
190 ropt.doExtendedSearch = mRecoConfigZDC->extendedSearch;
191 }
192 }
193 LOG(info) << "Extended search is " << (mRopt->doExtendedSearch ? "ON" : "OFF");
194
195 // Store hits with in-event pile-up (EvE)
196 if (ropt.setStoreEvPileup == false) {
197 if (mRecoConfigZDC == nullptr) {
198 LOG(fatal) << "Storage of hits with in-event pile-up: missing configuration object and no manual override";
199 } else {
200 ropt.doStoreEvPileup = mRecoConfigZDC->storeEvPileup;
201 }
202 }
203 LOG(info) << "Storage of EvE hits is " << (mRopt->doStoreEvPileup ? "ON" : "OFF");
204
205 // TDC calibration
206 // Recentering
207 for (int itdc = 0; itdc < o2::zdc::NTDCChannels; itdc++) {
208 float fval = ropt.tdc_shift[itdc];
209 // If the reconstruction parameters were not manually set
210 if (fval < 0) {
211 // Check if calibration object is present
212 if (!mTDCParam) {
213 LOG(fatal) << "TDC " << itdc << " missing configuration object and no manual override";
214 } else {
215 // Encode TDC shift
216 fval = mTDCParam->getShift(itdc) / o2::zdc::FTDCVal;
217 }
218 }
219 auto val = std::nearbyint(fval);
220 if (val < kMinShort) {
221 LOG(fatal) << "Shift for TDC " << itdc << " " << val << " is out of range";
222 }
223 if (val > kMaxShort) {
224 LOG(fatal) << "Shift for TDC " << itdc << " " << val << " is out of range";
225 }
226 tdc_shift[itdc] = val;
227 if (mVerbosity > DbgZero) {
228 LOG(info) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " shift= " << tdc_shift[itdc] << " i.s. = " << val * o2::zdc::FTDCVal << " ns";
229 }
230 }
231
232 // Amplitude calibration
233 for (int itdc = 0; itdc < o2::zdc::NTDCChannels; itdc++) {
234 float fval = ropt.tdc_calib[itdc];
235 // If the reconstruction parameters were not manually set
236 if (fval < 0) {
237 // Check if calibration object is present
238 if (!mTDCParam) {
239 LOG(fatal) << "TDC amplitude calibration " << itdc << " missing configuration object and no manual override";
240 } else {
241 fval = mTDCParam->getFactor(itdc);
242 }
243 }
244 if (fval <= 0) {
245 LOG(fatal) << "Correction factor for TDC amplitude " << itdc << " " << fval << " is out of range";
246 }
247 tdc_calib[itdc] = fval;
248 fval = ropt.tdc_offset[itdc];
249 // If the reconstruction parameters were not manually set
250 if (fval == -FInfty) {
251 // Check if calibration object is present
252 if (!mTDCParam) {
253 LOG(fatal) << "TDC offset correction " << itdc << " missing configuration object and no manual override";
254 } else {
255 fval = mTDCParam->getOffset(itdc);
256 }
257 }
258 if (fval <= -ADCRange || fval >= ADCRange) {
259 LOG(fatal) << "TDC offset correction " << itdc << " " << fval << " is out of range";
260 }
261 tdc_offset[itdc] = fval;
262 if (mVerbosity > DbgZero) {
263 LOG(info) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " factor= " << tdc_calib[itdc] << " offset= " << tdc_offset[itdc];
264 }
265 }
266
267 // TDC search zone
268 for (int itdc = 0; itdc < o2::zdc::NTDCChannels; itdc++) {
269 // If the reconstruction parameters were not manually set
270 if (ropt.tdc_search[itdc] <= 0) {
271 if (!mRecoConfigZDC) {
272 LOG(fatal) << "Search zone for TDC " << itdc << " missing configuration object and no manual override";
273 } else {
274 ropt.tdc_search[itdc] = mRecoConfigZDC->tdc_search[itdc];
275 }
276 }
277 if (mVerbosity > DbgZero) {
278 LOG(info) << itdc << " " << ChannelNames[TDCSignal[itdc]] << " search= " << ropt.tdc_search[itdc] << " i.s. = " << ropt.tdc_search[itdc] * o2::zdc::FTDCVal << " ns";
279 }
280 }
281
282 // Energy calibration
283 for (int il = 0; il < ChEnergyCalib.size(); il++) {
284 if (ropt.energy_calib[ChEnergyCalib[il]] > 0) {
285 LOG(info) << "Energy Calibration from command line " << ChannelNames[ChEnergyCalib[il]] << " = " << ropt.energy_calib[ChEnergyCalib[il]];
286 } else if (mEnergyParam && mEnergyParam->energy_calib[ChEnergyCalib[il]] > 0) {
287 ropt.energy_calib[ChEnergyCalib[il]] = mEnergyParam->energy_calib[ChEnergyCalib[il]];
288 LOG(info) << "Energy Calibration from CCDB " << ChannelNames[ChEnergyCalib[il]] << " = " << ropt.energy_calib[ChEnergyCalib[il]];
289 } else {
290 if (ChEnergyCalib[il] == CaloCommonPM[ChEnergyCalib[il]]) {
291 // Is a common PM or a ZEM
292 ropt.energy_calib[ChEnergyCalib[il]] = 1;
293 LOG(warning) << "Default Energy Calibration " << ChannelNames[ChEnergyCalib[il]] << " = " << ropt.energy_calib[ChEnergyCalib[il]];
294 } else {
295 // Is one of the analog sums -> same calibration as common PM
296 // N.B. the calibration for common has already been set in the loop
298 LOG(info) << "SUM Energy Calibration " << ChannelNames[ChEnergyCalib[il]] << " = " << ropt.energy_calib[ChEnergyCalib[il]];
299 }
300 }
301 }
302
303 // Tower calibration (intercalibration of towers)
304 // Array ChTowerCalib defines which channels use this calibration: ZN and ZP towers + ZEM2
305 for (int il = 0; il < ChTowerCalib.size(); il++) {
306 if (ropt.tower_calib[ChTowerCalib[il]] > 0) {
307 LOG(info) << "Tower Calibration from command line " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.tower_calib[ChTowerCalib[il]];
308 } else if (mTowerParam && mTowerParam->tower_calib[ChTowerCalib[il]] > 0) {
309 ropt.tower_calib[ChTowerCalib[il]] = mTowerParam->tower_calib[ChTowerCalib[il]];
310 LOG(info) << "Tower Calibration from CCDB " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.tower_calib[ChTowerCalib[il]];
311 } else {
312 ropt.tower_calib[ChTowerCalib[il]] = 1;
313 LOG(warning) << "Default Tower Calibration " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.tower_calib[ChTowerCalib[il]];
314 }
315 }
316
317 // Tower energy calibration
318 // For the common PM and sum is given by the calibration parameters
319 // for the towers is the product of energy calibration of common PM and tower calibration
320 // It is possible to override from command line
321 for (int il = 0; il < ChTowerCalib.size(); il++) {
322 if (ropt.energy_calib[ChTowerCalib[il]] > 0) {
323 LOG(info) << "Tower Energy Calibration set to " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.energy_calib[ChTowerCalib[il]];
324 } else {
326 if (mVerbosity > DbgZero) {
327 LOG(info) << "Tower Energy Calibration " << ChannelNames[ChTowerCalib[il]] << " = " << ropt.energy_calib[ChTowerCalib[il]];
328 }
329 }
330 }
331
332 // ADC offset
333 for (int ic = 0; ic < NChannels; ic++) {
334 if (ropt.adc_offset[ic] > -FInfty) {
335 LOG(info) << "ADC offset from command line " << ChannelNames[ic] << " = " << ropt.adc_offset[ic];
336 } else if (mEnergyParam && mEnergyParam->adc_offset[ic] > -FInfty) {
337 ropt.adc_offset[ic] = mEnergyParam->adc_offset[ic];
338 if (mVerbosity > DbgZero) {
339 LOG(info) << "ADC offset from CCDB " << ChannelNames[ic] << " = " << ropt.adc_offset[ic];
340 }
341 } else {
342 ropt.adc_offset[ic] = 0;
343 LOG(warning) << "Default ADC offset " << ChannelNames[ic] << " = " << ropt.energy_calib[ic];
344 }
345 }
346
347 // Fill maps channel maps for integration
348 for (int ich = 0; ich < NChannels; ich++) {
349 // If the reconstruction parameters were not manually set
350 if (ropt.amod[ich] < 0 || ropt.ach[ich] < 0) {
351 for (int im = 0; im < NModules; im++) {
352 for (uint32_t ic = 0; ic < NChPerModule; ic++) {
353 if (mModuleConfig->modules[im].channelID[ic] == ich && mModuleConfig->modules[im].readChannel[ic]) {
354 ropt.amod[ich] = im;
355 ropt.ach[ich] = ic;
356 // Fill mask to identify all channels
357 mChMask[ich] = (0x1 << (4 * im + ic));
358 goto next_ich;
359 }
360 }
361 }
362 } else {
363 // Fill mask to identify all channels
364 mChMask[ich] = (0x1 << (4 * ropt.amod[ich] + ropt.ach[ich]));
365 }
366 next_ich:;
367 if (mVerbosity > DbgZero) {
368 LOG(info) << "ADC " << ich << "(" << ChannelNames[ich] << ") mod " << ropt.amod[ich] << " ch " << ropt.ach[ich];
369 }
370 }
371
372 // Integration ranges
373 for (int ich = 0; ich < NChannels; ich++) {
374 // If the reconstruction parameters were not manually set
375 if (ropt.beg_int[ich] == DummyIntRange || ropt.end_int[ich] == DummyIntRange) {
376 if (!mRecoConfigZDC) {
377 LOG(fatal) << "Integration for signal " << ich << " missing configuration object and no manual override";
378 } else {
379 ropt.beg_int[ich] = mRecoConfigZDC->beg_int[ich];
380 ropt.end_int[ich] = mRecoConfigZDC->end_int[ich];
381 }
382 }
383 if (ropt.beg_ped_int[ich] == DummyIntRange || ropt.end_ped_int[ich] == DummyIntRange) {
384 if (!mRecoConfigZDC) {
385 LOG(fatal) << "Integration for pedestal " << ich << " missing configuration object and no manual override";
386 } else {
387 ropt.beg_ped_int[ich] = mRecoConfigZDC->beg_ped_int[ich];
388 ropt.end_ped_int[ich] = mRecoConfigZDC->end_ped_int[ich];
389 }
390 }
391 // Thresholds for pedestal
392 // If the reconstruction parameters were not manually set
393 if (ropt.beg_int[ich] == ADCRange) {
394 if (!mRecoConfigZDC) {
395 LOG(fatal) << "Pedestal threshold high for signal " << ich << " missing configuration object and no manual override";
396 } else {
397 ropt.ped_thr_hi[ich] = mRecoConfigZDC->ped_thr_hi[ich];
398 }
399 }
400 if (ropt.beg_int[ich] == ADCRange) {
401 if (!mRecoConfigZDC) {
402 LOG(fatal) << "Pedestal threshold low for signal " << ich << " missing configuration object and no manual override";
403 } else {
404 ropt.ped_thr_lo[ich] = mRecoConfigZDC->ped_thr_lo[ich];
405 }
406 }
407 if (mVerbosity > DbgZero) {
408 LOG(info) << ChannelNames[ich] << " integration: signal=[" << ropt.beg_int[ich] << ":" << ropt.end_int[ich] << "] pedestal=[" << ropt.beg_ped_int[ich] << ":" << ropt.end_ped_int[ich]
409 << "] thresholds (" << ropt.ped_thr_hi[ich] << ", " << ropt.ped_thr_lo[ich] << ")";
410 }
411 }
412 if (mVerbosity > DbgZero && mTDCCorr != nullptr) {
413 mTDCCorr->print();
414 }
415 // Information about reconstruction configuration
416 if (mLowPassFilter == false) {
417 LOG(warning) << "Low pass filtering of signal is disabled";
418 }
419 if (mCorrSignal == false) {
420 LOG(warning) << "TDC signal correction is disabled";
421 }
422 if (mCorrBackground == false) {
423 LOG(warning) << "TDC pile-up correction is disabled";
424 }
425 if (mPedParam == nullptr) {
426 LOG(warning) << "Missing average pedestals";
427 } else {
428 if (mVerbosity > DbgZero) {
429 mPedParam->print();
430 } else {
431 mPedParam->print(false);
432 }
433 }
434} // init
435
437{
438 if (mTreeDbg) {
439 LOG(info) << "o2::zdc::DigiReco: closing debug output";
440 mTDbg->Write();
441 mTDbg.reset();
442 mDbg->Close();
443 mDbg.reset();
444 }
445
447
448 if (mNLonely > 0) {
449 LOG(warn) << "Detected " << mNLonely << " lonely bunches";
450 for (int ib = 0; ib < o2::constants::lhc::LHCMaxBunches; ib++) {
451 if (mLonely[ib]) {
452 LOGF(warn, "lonely bunch %4d #times=%u #trig=%u", ib, mLonely[ib], mLonelyTrig[ib]);
453 }
454 }
455 }
456 for (int ich = 0; ich < NChannels; ich++) {
457 if (mMissingPed[ich] > 0) {
458 LOGF(error, "Missing pedestal for ch %2d %s: %u", ich, ChannelNames[ich], mMissingPed[ich]);
459 }
460 }
461}
462
464{
465 // Prepare tapered sinc function
466 // Lost reference of first interpolating function
467 // Found problems in implementation: the interpolated function is not derivable in sampled points
468 // tsc/TSN =3.75 (~ 4) and TSL*TSN*sqrt(2)/tsc >> 1 (n. of sigma)
469 // const O2_ZDC_DIGIRECO_FLT tsc = 750;
470 // Now using Kaiser function
471 O2_ZDC_DIGIRECO_FLT beta = TMath::Pi() * mAlpha;
472 O2_ZDC_DIGIRECO_FLT norm = 1. / TMath::BesselI0(beta);
473 constexpr int n = TSL * TSN;
474 for (int tsi = 0; tsi <= n; tsi++) {
476 O2_ZDC_DIGIRECO_FLT fs = 1;
477 if (arg1 != 0) {
478 fs = TMath::Sin(arg1) / arg1;
479 }
480 // First tapering window
481 // O2_ZDC_DIGIRECO_FLT arg2 = O2_ZDC_DIGIRECO_FLT(tsi) / tsc;
482 // O2_ZDC_DIGIRECO_FLT fg = TMath::Exp(-arg2 * arg2);
483 // Kaiser window
485 O2_ZDC_DIGIRECO_FLT fg = norm * TMath::BesselI0(beta * TMath::Sqrt(1. - arg2 * arg2));
486 mTS[n + tsi] = fs * fg;
487 mTS[n - tsi] = mTS[n + tsi]; // Function is even
488 }
489 LOG(info) << "Interpolation numeric precision is " << sizeof(O2_ZDC_DIGIRECO_FLT);
490 LOG(info) << "Interpolation alpha = " << mAlpha;
491}
492
493int DigiReco::process(const gsl::span<const o2::zdc::OrbitData>& orbitdata, const gsl::span<const o2::zdc::BCData>& bcdata, const gsl::span<const o2::zdc::ChannelData>& chdata)
494{
495#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
496 LOG(info) << "________________________________________________________________________________";
497 LOG(info) << __func__;
498#endif
499 // We assume that vectors contain data from a full time frame
500 mOrbitData = orbitdata;
501 mBCData = bcdata;
502 mChData = chdata;
503 mInError = false;
504
505 // Initialization of lookup structure for pedestals
506 mOrbit.clear();
507 int norb = mOrbitData.size();
508 if (mVerbosity >= DbgFull) {
509 LOG(info) << "Dump of pedestal data lookup table";
510 }
511 // TODO: send scalers to aggregator
512 uint32_t scaler[NChannels] = {0};
513 for (int iorb = 0; iorb < norb; iorb++) {
514 mOrbit[mOrbitData[iorb].ir.orbit] = iorb;
515 if (mVerbosity >= DbgFull) {
516 LOG(info) << "mOrbitData[" << mOrbitData[iorb].ir.orbit << "] = " << iorb;
517 }
518 // TODO: add only if orbit is good. Here we check only the individual scaler values
519 for (int ich = 0; ich < NChannels; ich++) {
520 if (mOrbitData[iorb].scaler[ich] <= o2::constants::lhc::LHCMaxBunches) {
521 scaler[ich] += mOrbitData[iorb].scaler[ich];
522 }
523 }
524 }
525 if (mVerbosity > DbgMinimal) {
526 for (int ich = 0; ich < NChannels; ich++) {
527 LOG(info) << ChannelNames[ich] << " cnt: " << scaler[ich];
528 }
529 }
530
531 mNBC = mBCData.size();
532 mReco.clear();
533 mReco.resize(mNBC);
534 // Initialization of reco structure
535 for (int ibc = 0; ibc < mNBC; ibc++) {
536 auto& bcr = mReco[ibc];
537#ifdef O2_ZDC_TDC_C_ARRAY
538 for (int itdc = 0; itdc < NTDCChannels; itdc++) {
539 for (int i = 0; i < MaxTDCValues; i++) {
540 bcr.tdcVal[itdc][i] = kMinShort;
541 bcr.tdcAmp[itdc][i] = kMinShort;
542 }
543 }
544#endif
545 auto& bcd = mBCData[ibc];
546 bcr.ir = bcd.ir;
547 int chEnt = bcd.ref.getFirstEntry();
548 for (int ic = 0; ic < bcd.ref.getEntries(); ic++) {
549 auto& chd = mChData[chEnt];
550 if (chd.id > IdDummy && chd.id < NChannels) {
551 bcr.ref[chd.id] = chEnt;
552 }
553 chEnt++;
554 }
555 }
556
557 // Probably this is not necessary
558 // for(int isig=0; isig<NChannels; isig++){
559 // mReco.pattern[isig]=0;
560 // for(int itb=0; itb<NTimeBinsPerBC; itb++){
561 // mReco.fired[isig][itb]=0;
562 // }
563 // for(int isb=0; isb<mNSB; isb++){
564 // mReco.inter[isig][isb]=0;
565 // }
566 // }
567
568 // Assign interaction record and event information
569 for (int ibc = 0; ibc < mNBC; ibc++) {
570 mReco[ibc].ir = mBCData[ibc].ir;
571 mReco[ibc].channels = mBCData[ibc].channels;
572 mReco[ibc].triggers = mBCData[ibc].triggers;
573 for (int isig = 0; isig < NChannels; isig++) {
574 auto ref = mReco[ibc].ref[isig];
575 if (ref == ZDCRefInitVal) {
576 for (int is = 0; is < NTimeBinsPerBC; is++) {
577 mReco[ibc].data[isig][is] = Int16MaxVal;
578 }
579 } else {
580 for (int is = 0; is < NTimeBinsPerBC; is++) {
581 mReco[ibc].data[isig][is] = mChData[ref].data[is];
582 }
583 }
584 }
585 }
586
587 // Low pass filtering
588 if (mLowPassFilter) {
589 // N.B. At the moment low pass filtering is performed only on TDC
590 // signals and not on the rest of the signals
591 lowPassFilter();
592 } else {
593 // Copy samples
594 for (int itdc = 0; itdc < NTDCChannels; itdc++) {
595 auto isig = TDCSignal[itdc];
596 for (int ibc = 0; ibc < mNBC; ibc++) {
597 auto ref_c = mReco[ibc].ref[isig];
598 if (ref_c != ZDCRefInitVal) {
599 for (int is = 0; is < NTimeBinsPerBC; is++) {
600 mReco[ibc].data[isig][is] = mChData[ref_c].data[is];
601 }
602 }
603 }
604 }
605 }
606
607 if (mFullInterpolation) {
608 // Copy remaining channels
609 for (int isig = 0; isig < NChannels; isig++) {
610 int isig_tdc = TDCSignal[SignalTDC[isig]];
611 if (isig == isig_tdc) {
612 // Already copied
613 continue;
614 }
615 for (int ibc = 0; ibc < mNBC; ibc++) {
616 auto ref_c = mReco[ibc].ref[isig];
617 if (ref_c != ZDCRefInitVal) {
618 for (int is = 0; is < NTimeBinsPerBC; is++) {
619 mReco[ibc].data[isig][is] = mChData[ref_c].data[is];
620 }
621 }
622 }
623 }
624 }
625
626 // Find consecutive bunch crossings by taking into account just the presence
627 // of bunch crossing data and then perform signal interpolation in the identified ranges.
628 // With this definition of "consecutive" bunch crossings gaps in the sample data
629 // may be present, therefore in the reconstruction method we take into account for signals
630 // that do not span the entire range
631 int seq_beg = 0;
632 int seq_end = 0;
633 if (mVerbosity > DbgMinimal) {
634 LOG(info) << "Processing ZDC reconstruction for " << mNBC << " bunch crossings";
635 }
636
637 // TDC reconstruction
638 for (int ibc = 0; ibc < mNBC; ibc++) {
639 auto& ir = mBCData[seq_end].ir;
640 auto bcd = mBCData[ibc].ir.differenceInBC(ir);
641 if (bcd < 0) {
642 LOG(error) << "Bunch order error in TDC reconstruction";
643 for (int ibcdump = 0; ibcdump < mNBC; ibcdump++) {
644 LOG(error) << "mBCData[" << ibcdump << "] @ " << mBCData[ibcdump].ir.orbit << "." << mBCData[ibcdump].ir.bc;
645 }
646 LOG(error) << "Orbit number is not increasing " << mBCData[seq_end].ir.orbit << "." << mBCData[seq_end].ir.bc << " followed by " << mBCData[ibc].ir.orbit << "." << mBCData[ibc].ir.bc;
647 return __LINE__;
648 } else if (bcd > 1) {
649 // Detected a gap
650 int rval = reconstructTDC(seq_beg, seq_end);
651 if (rval) {
652 return rval;
653 }
654
655 seq_beg = ibc;
656 seq_end = ibc;
657 } else if (ibc == (mNBC - 1)) {
658 // Last bunch
659 seq_end = ibc;
660 int rval = reconstructTDC(seq_beg, seq_end);
661 if (rval) {
662 return rval;
663 }
664
665 seq_beg = mNBC;
666 seq_end = mNBC;
667 } else {
668 // Look for another bunch
669 seq_end = ibc;
670 }
671#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
672 // Here in order to avoid mixing information
673 mBCData[ibc].print(mTriggerMask);
674#endif
675 }
676
677 // Apply pile-up correction for TDCs to get corrected TDC amplitudes and values
678 correctTDCPile();
679
680 // ADC reconstruction
681 seq_beg = 0;
682 seq_end = 0;
683 for (int ibc = 0; ibc < mNBC; ibc++) {
684 auto& ir = mBCData[seq_end].ir;
685 auto bcd = mBCData[ibc].ir.differenceInBC(ir);
686 if (bcd < 0) {
687 LOG(error) << "Bunch order error in ADC reconstruction";
688 for (int ibcdump = 0; ibcdump < mNBC; ibcdump++) {
689 LOG(error) << "mBCData[" << ibcdump << "] @ " << mBCData[ibcdump].ir.orbit << "." << mBCData[ibcdump].ir.bc;
690 }
691 LOG(error) << "Orbit number is not increasing " << mBCData[seq_end].ir.orbit << "." << mBCData[seq_end].ir.bc << " followed by " << mBCData[ibc].ir.orbit << "." << mBCData[ibc].ir.bc;
692 return __LINE__;
693 } else if (bcd > 1) {
694 // Detected a gap
695 int rval = reconstruct(seq_beg, seq_end);
696 if (rval != 0) {
697 return rval;
698 }
699 seq_beg = ibc;
700 seq_end = ibc;
701 } else if (ibc == (mNBC - 1)) {
702 // Last bunch
703 seq_end = ibc;
704 int rval = reconstruct(seq_beg, seq_end);
705 if (rval != 0) {
706 return rval;
707 }
708 seq_beg = mNBC;
709 seq_end = mNBC;
710 } else {
711 // Look for another bunch
712 seq_end = ibc;
713 }
714 }
715 return 0;
716} // process
717
718void DigiReco::lowPassFilter()
719{
720 // First attempt to low pass filtering uses the average of three consecutive samples
721 // ringing noise has T~6 ns w.r.t. a sampling period of ~ 2 ns
722 // one should get smoothing of the noise
723#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
724 LOG(info) << "________________________________________________________________________________";
725 LOG(info) << __func__;
726#endif
727 constexpr int MaxTimeBin = NTimeBinsPerBC - 1;
728 for (int itdc = 0; itdc < NTDCChannels; itdc++) {
729 auto isig = TDCSignal[itdc];
730 for (int ibc = 0; ibc < mNBC; ibc++) {
731 // Indexes of current, previous and next recorded bunch crossings
732 auto ref_c = mReco[ibc].ref[isig];
733 uint32_t ref_p = ZDCRefInitVal;
734 uint32_t ref_n = ZDCRefInitVal;
735 int64_t bcd_p = ZDCRefInitVal;
736 int64_t bcd_n = ZDCRefInitVal;
737 if (ibc > 0) { // Is not first bunch in list
738 ref_p = mReco[ibc - 1].ref[isig];
739 bcd_p = mReco[ibc].ir.differenceInBC(mReco[ibc - 1].ir); // b.c. number of (ibc) - b.c. number (ibc-1)
740 }
741 if (ibc < (mNBC - 1)) { // Is not last bunch in list
742 ref_n = mReco[ibc + 1].ref[isig];
743 bcd_n = mReco[ibc + 1].ir.differenceInBC(mReco[ibc].ir); // b.c. number of (ibc+1) - b.c. number (ibc)
744 }
745 if (ref_c != ZDCRefInitVal) { // Should always be true
746 for (int is = 0; is < NTimeBinsPerBC; is++) {
747 int32_t sum = mChData[ref_c].data[is];
748 if (is == 0) {
749 sum += mChData[ref_c].data[1];
750 if (ref_p != ZDCRefInitVal && bcd_p == 1) {
751 // Add last sample of previous bunch crossing
752 sum += mChData[ref_p].data[MaxTimeBin];
753 } else {
754 // As a backup we count twice the first sample
755 sum += mChData[ref_c].data[0];
756 }
757 } else if (is == MaxTimeBin) {
758 sum += mChData[ref_c].data[MaxTimeBin - 1];
759 if (ref_n != ZDCRefInitVal && bcd_n == 1) {
760 // Add first sample of next bunch crossing
761 sum += mChData[ref_n].data[0];
762 } else {
763 // As a backup we count twice the last sample
764 sum += mChData[ref_c].data[MaxTimeBin];
765 }
766 } else {
767 // Not on the bunch boundary
768 sum += mChData[ref_c].data[is - 1];
769 sum += mChData[ref_c].data[is + 1];
770 }
771 // Make the average taking into account rounding and sign
772 bool isNegative = sum < 0;
773 if (isNegative) {
774 sum = -sum;
775 }
776 auto mod = sum % 3;
777 sum = sum / 3;
778 if (mod == 2) {
779 sum++;
780 }
781 if (isNegative) {
782 sum = -sum;
783 }
784 // Store filtered values
785 mReco[ibc].data[isig][is] = sum;
786 }
787 }
788 }
789 }
790}
791
792int DigiReco::reconstructTDC(int ibeg, int iend)
793{
794#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
795 LOG(info) << "________________________________________________________________________________";
796 LOG(info) << __func__ << "(" << ibeg << ", " << iend << ") length=" << iend - ibeg + 1;
797 for (int itdc = 0; itdc < NTDCChannels; itdc++) {
798 mAssignedTDC[itdc] = 0;
799 }
800#endif
801 // Apply differential discrimination
802 for (int itdc = 0; itdc < NTDCChannels; itdc++) {
803 // Check if channel has valid data for consecutive bunches in current bunch range
804 // N.B. there are events recorded from ibeg-iend but we are not sure if it is the
805 // case for every TDC channel
806 int istart = -1, istop = -1;
807 // Loop allows for gaps in the data sequence for each TDC channel
808 for (int ibun = ibeg; ibun <= iend; ibun++) {
809 if (mBCData[ibun].channels & mTDCMask[itdc]) { // TDC channel has data for this event
810 if (istart < 0) {
811 istart = ibun;
812 }
813 istop = ibun;
814 } else { // No data from channel
815 // A gap is detected
816 if (istart >= 0 && (istop - istart) > 0) {
817 // Need data for at least two consecutive bunch crossings
818 int rval = 0;
819 if (mRopt->doExtendedSearch) {
820 rval = processTriggerExtended(itdc, istart, istop);
821 } else {
822 rval = processTrigger(itdc, istart, istop);
823 }
824 if (rval) {
825 return rval;
826 }
827 }
828 istart = -1;
829 istop = -1;
830 }
831 }
832 // Check if there are consecutive bunch crossings at the end of group
833 if (istart >= 0 && (istop - istart) > 0) {
834 int rval = 0;
835 if (mRopt->doExtendedSearch) {
836 rval = processTriggerExtended(itdc, istart, istop);
837 } else {
838 rval = processTrigger(itdc, istart, istop);
839 }
840 if (rval) {
841 return rval;
842 }
843 }
844 }
845 // processTrigger(..) calls interpolate(..) that assigns all TDCs
846 // The following TDC processing stage findSignals(..) assumes that time shift
847 // due to pile-up has been corrected because main-main is assumed to be
848 // in position 0
849 // In case we do full interpolation, we process also the channels that are not
850 // considered in TDC list
851 if (mFullInterpolation) {
852 for (int isig = 0; isig < NChannels; isig++) {
853 int isig_tdc = TDCSignal[SignalTDC[isig]];
854 if (isig == isig_tdc) {
855 // Already computed
856 continue;
857 }
858 // Check if channel has valid data for consecutive bunches in current bunch range
859 // N.B. there are events recorded from ibeg-iend but we are not sure if it is the
860 // case for every channel
861 int istart = -1, istop = -1;
862 // Loop allows for gaps in the data sequence for each TDC channel
863 for (int ibun = ibeg; ibun <= iend; ibun++) {
864 if (mBCData[ibun].channels & mChMask[isig]) { // Channel has data for this event
865 if (istart < 0) {
866 istart = ibun;
867 }
868 istop = ibun;
869 } else { // No data from channel
870 // A gap is detected
871 if (istart >= 0 && (istop - istart + 1) >= mFullInterpolationMinLength) {
872 // Need data for at least mFullInterpolationMinLength (two) consecutive bunch crossings
873 int rval = fullInterpolation(isig, istart, istop);
874 if (rval) {
875 return rval;
876 }
877 }
878 istart = -1;
879 istop = -1;
880 }
881 }
882 // Check if there are mFullInterpolationMinLength consecutive bunch crossings at the end of group
883 if (istart >= 0 && (istop - istart + 1) >= mFullInterpolationMinLength) {
884 int rval = fullInterpolation(isig, istart, istop);
885 if (rval) {
886 return rval;
887 }
888 }
889 }
890 }
891#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
892 printf("Assiged TDCs:");
893 bool hasMult = false;
894 for (int itdc = 0; itdc < NTDCChannels; itdc++) {
895 if (mAssignedTDC[itdc] > 0) {
896 printf(" %s:%d", ChannelNames[TDCSignal[itdc]].data(), mAssignedTDC[itdc]);
897 if (mAssignedTDC[itdc] > 1) {
898 hasMult = true;
899 }
900 }
901 }
902 if (hasMult) {
903 printf(" MULTIPLE_ASSIGNMENTS\n");
904 } else {
905 printf("\n");
906 }
907#endif
908 return 0;
909} // reconstructTDC
910
911int DigiReco::reconstruct(int ibeg, int iend)
912{
913#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
914 LOG(info) << "________________________________________________________________________________";
915 LOG(info) << __func__ << "(" << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc;
916#endif
917 // Process consecutive BCs
918 if (ibeg == iend) {
919 mNLonely++;
920 mLonely[mReco[ibeg].ir.bc]++;
921 if (mBCData[ibeg].triggers != 0x0) {
922 mLonelyTrig[mReco[ibeg].ir.bc]++;
923 }
924 // Cannot reconstruct lonely bunch
925 // LOG(info) << "Lonely bunch " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc;
926 return 0;
927 }
928#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
929 for (int ibun = ibeg; ibun <= iend; ibun++) {
930 printf("%d CH Mask: 0x%08x TDC data for:", ibun, mBCData[ibun].channels);
931 for (int itdc = 0; itdc < NTDCChannels; itdc++) {
932 if (mBCData[ibun].channels & mTDCMask[itdc]) {
933 printf(" %s", ChannelNames[TDCSignal[itdc]].data());
934 } else {
935 printf(" ");
936 }
937 }
938 printf("\n");
939 }
940#endif
941
942 // After pile-up correction, find signals around main-main that satisfy condition on TDC
943 findSignals(ibeg, iend);
944
945 // For each calorimeter that has detects a collision at the time of main-main
946 // collisions we reconstruct integrated charges and fill output tree
947 for (int ich = 0; ich < NChannels; ich++) {
948 // We consder the longest sequence of acquired bunches that can be readout by
949 // the acquisition in case of isolated events (filling scheme with sigle bunches)
951 // Flags to investigate pile-up
952 bool hasFired[NBCReadOut] = {0}; // Channel has a TDC fired
953 bool hasHit[NBCReadOut] = {0}; // Channel has hit
954 bool hasAuto0[NBCReadOut] = {0}; // Module has Auto_0 trigger bit
955 bool hasAutoM[NBCReadOut] = {0}; // Module has Auto_m trigger bit
956 // Initialize info about previous bunches
957 for (int ibp = 1; ibp < 4; ibp++) {
958 int ibun = ibeg - ibp;
959 // For the time being, we cannot access previous time frame (ibun<0)
960 if (ibun < 0) {
961 break;
962 }
963 auto bcd = mBCData[ibeg].ir.differenceInBC(mBCData[ibun].ir);
964 if (bcd < 1) {
965 LOG(error) << "Bunches are not in ascending order: " << mBCData[ibeg].ir.orbit << "." << mBCData[ibeg].ir.bc << " followed by " << mBCData[ibun].ir.orbit << "." << mBCData[ibun].ir.bc;
966 return __LINE__;
967 }
968 if (bcd > 3) {
969 break;
970 }
971 // Assignment is done taking into account bunch crossing difference
972 ref[bcd] = mReco[ibun].ref[ich];
973 // If channel has no waverform data cannot have a hit or trigger bit assigned
974 // because all channels of a module are acquired if trigger condition is
975 // satisfied
976 if (ref[bcd] == ZDCRefInitVal) {
977 continue;
978 }
979 // This condition is not comprehensive of all pile-up sources
980 // chfired: Fired TDC condition related to channel (e.g. AND of TC and SUM @ main-main)
981 hasFired[bcd] = mReco[ibun].chfired[ich];
982 // Information from hardware autotrigger is not restricted to hits in main-main
983 // but it may extend outside the correct bunch for signals near the bunch edges
984 // hasHit refers to a single channel since it is derived from ChannelDataV0::Hit
985 hasHit[bcd] = mBCData[ibun].triggers & mChMask[ich];
986 // hasAuto0 and hasAutoM are derived from autotrigger decisions and therefore
987 // refer to a module (max 4 channels) and not to a single channel
988 ModuleTriggerMapData mt;
989 mt.w = mBCData[ibun].moduleTriggers[mRopt->amod[ich]];
990 hasAuto0[bcd] = mt.f.Auto_0;
991 hasAutoM[bcd] = mt.f.Auto_m;
992#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
993 printf("%2d %s bcd = %d ibun = %d ibeg = %d ref = %3u %s %s %s\n",
994 ich, ChannelNames[ich].data(), bcd, ibun, ibeg, ref[bcd],
995 hasHit[bcd] ? "H" : "-", hasAuto0[bcd] ? "A0" : "--", hasAutoM[bcd] ? "AM" : "--");
996#endif
997 }
998 // Analyze all bunches
999 for (int ibun = ibeg; ibun <= iend; ibun++) {
1000 updateOffsets(ibun); // Get Orbit pedestals
1001 auto& rec = mReco[ibun];
1002 // Check if the corresponding TDC is fired
1003 ref[0] = mReco[ibun].ref[ich];
1004 hasHit[0] = mBCData[ibun].triggers & mChMask[ich];
1005 ModuleTriggerMapData mt;
1006 mt.w = mBCData[ibun].moduleTriggers[mRopt->amod[ich]];
1007 hasAuto0[0] = mt.f.Auto_0;
1008 hasAutoM[0] = mt.f.Auto_m;
1009 if (rec.chfired[ich]) {
1010 // Check if channel data are present in payload
1011 if (ref[0] < ZDCRefInitVal) {
1012 // Energy reconstruction
1013 // Compute event by event pedestal
1014 bool hasEvPed = false;
1015 float evPed = 0;
1016 if (ibun > ibeg) {
1017 auto ref_m = ref[1];
1018 if (mRopt->beg_ped_int[ich] >= 0 || ref_m < ZDCRefInitVal) {
1019 for (int is = mRopt->beg_ped_int[ich]; is <= mRopt->end_ped_int[ich]; is++) {
1020 if (is < 0) {
1021 // Sample is in previous BC
1022 evPed += float(mChData[ref_m].data[is + NTimeBinsPerBC]);
1023 } else {
1024 // Sample is in current BC
1025 evPed += float(mChData[ref[0]].data[is]);
1026 }
1027 }
1028 evPed /= float(mRopt->end_ped_int[ich] - mRopt->beg_ped_int[ich] + 1);
1029 hasEvPed = true;
1030 }
1031 }
1032 // Pile-up detection using trigger information allows to identify
1033 // the presence of a signal in previous bunch and is module-wise
1034
1035 // Detection of pile-up from previous bunch by comparing event pedestal with reference
1036 // (reference can be orbit or QC). If pile-up is detected we use orbit pedestal
1037 // instead of event pedestal
1038 // TODO: pedestal event could have a TM..
1039 if (hasEvPed && (mSource[ich] == PedOr || mSource[ich] == PedQC)) {
1040 auto pedref = mOffset[ich];
1041 if (evPed > pedref && (evPed - pedref) > mRopt->ped_thr_hi[ich]) {
1042 // Anomalous offset (put a warning but use event pedestal)
1043 rec.offPed[ich] = true;
1044 } else if (evPed < pedref && (pedref - evPed) > mRopt->ped_thr_lo[ich]) {
1045 // Possible presence of pile-up (will need to use orbit pedestal)
1046 rec.pilePed[ich] = true;
1047 }
1048 }
1049 float myPed = std::numeric_limits<float>::infinity();
1050 // TODO:
1051 if (hasEvPed && rec.pilePed[ich] == false) {
1052 myPed = evPed;
1053 rec.adcPedEv[ich] = true;
1054 } else if (mSource[ich] == PedOr) {
1055 myPed = mOffset[ich];
1056 rec.adcPedOr[ich] = true;
1057 } else if (mSource[ich] == PedQC) {
1058 myPed = mOffset[ich];
1059 rec.adcPedQC[ich] = true;
1060 } else {
1061 rec.adcPedMissing[ich] = true;
1062 }
1063 if (myPed < std::numeric_limits<float>::infinity()) {
1064 float sum = 0;
1065 for (int is = mRopt->beg_int[ich]; is <= mRopt->end_int[ich]; is++) {
1066 // TODO: pile-up correction
1067 // TODO: manage signal positioned across boundary
1068 sum += (myPed - float(mChData[ref[0]].data[is]));
1069 }
1070 rec.ezdc[ich] = (sum - mRopt->adc_offset[ich]) * mRopt->energy_calib[ich];
1071 } else {
1072 LOGF(warn, "%d.%-4d CH %2d %s missing pedestal", rec.ir.orbit, rec.ir.bc, ich, ChannelNames[ich].data());
1073 }
1074 } else {
1075 // This could arise from memory corruption or in the case when TDC bits are forced to 1
1076 // due to a broken channel. For example Sum is broken and sum TDC is forced to 1
1077 // Take a very small signal that triggers on one module and not the other
1078 // 1) module 0 triggered by ZNATC is autotriggered
1079 // 2) module 1 triggered by ZNATC is not triggered -> Sum is missing
1080 // 3) sum TDC is forced to 1 and therefore the TDC is fired even if data are not present
1081 // 4) you get this error flag in reconstruction
1082 // This should happen only in case of hardware fault and signals near threshold
1083 // This should be mitigated by having a software threshold higher than the hardware one
1084 rec.adcPedMissing[ich] = true;
1085 if (mVerbosity >= DbgMedium) {
1086 LOGF(warn, "%d.%-4d CH %2d %s ADC missing, TDC present", rec.ir.orbit, rec.ir.bc, ich, ChannelNames[ich].data());
1087 }
1088 }
1089 }
1090 // Shift bunches by 1 taking into account bunch crossing difference
1091 // TODO
1092 // This is a simple shift by 1 position
1093 if (ibun != iend) {
1094 for (int ibcr = NBCReadOut - 1; ibcr > 0; ibcr--) {
1095 ref[ibcr] = ref[ibcr - 1];
1096 hasHit[ibcr] = hasHit[ibcr - 1];
1097 hasAuto0[ibcr] = hasAuto0[ibcr - 1];
1098 hasAutoM[ibcr] = hasAutoM[ibcr - 1];
1099 hasFired[ibcr] = hasFired[ibcr - 1];
1100 }
1101 }
1102 } // Loop on bunches
1103 } // Loop on channels
1104 if (mTreeDbg) {
1105 for (int ibun = ibeg; ibun <= iend; ibun++) {
1106 auto& rec = mReco[ibun];
1107 mRec = rec;
1108 mTDbg->Fill();
1109 }
1110 }
1111 return 0;
1112} // reconstruct
1113
1114void DigiReco::updateOffsets(int ibun)
1115{
1116 auto orbit = mBCData[ibun].ir.orbit;
1117 if (orbit == mOffsetOrbit) {
1118 return;
1119 }
1120 mOffsetOrbit = orbit;
1121
1122 // Reset information about pedestal origin
1123 for (int ich = 0; ich < NChannels; ich++) {
1124 mSource[ich] = PedND;
1125 mOffset[ich] = std::numeric_limits<float>::infinity();
1126 }
1127
1128 // Default TDC pedestal is from orbit
1129 // Look for Orbit pedestal offset
1130 std::map<uint32_t, int>::iterator it = mOrbit.find(orbit);
1131 if (it != mOrbit.end()) {
1132 auto& orbitdata = mOrbitData[it->second];
1133 for (int ich = 0; ich < NChannels; ich++) {
1134 auto myped = float(orbitdata.data[ich]) * mModuleConfig->baselineFactor;
1135 if (myped >= ADCMin && myped <= ADCMax) {
1136 // Pedestal information is present for this channel
1137 mOffset[ich] = myped;
1138 mSource[ich] = PedOr;
1139 }
1140 }
1141 }
1142
1143 // Use average "QC" pedestal if orbit pedestals are missing
1144 if (mPedParam != nullptr) {
1145 for (int ich = 0; ich < NChannels; ich++) {
1146 if (mSource[ich] == PedND) {
1147 auto myped = mPedParam->getCalib(ich);
1148 if (myped >= ADCMin && myped <= ADCMax) {
1149 mOffset[ich] = myped;
1150 mSource[ich] = PedQC;
1151 }
1152 }
1153 }
1154 }
1155
1156 for (int ich = 0; ich < NChannels; ich++) {
1157 if (mSource[ich] == PedND) {
1158 mMissingPed[ich]++;
1159 if (mVerbosity > DbgMinimal) {
1160 LOGF(error, "Missing pedestal for ch %2d %s orbit %u ", ich, ChannelNames[ich], mOffsetOrbit);
1161 }
1162 }
1163#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1164 LOGF(info, "Pedestal for ch %2d %s orbit %u %s: %f", ich, ChannelNames[ich], mOffsetOrbit, mSource[ich] == PedOr ? "OR" : (mSource[ich] == PedQC ? "QC" : "??"), mOffset[ich]);
1165#endif
1166 }
1167} // updateOffsets
1168
1169int DigiReco::processTrigger(int itdc, int ibeg, int iend)
1170{
1171#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1172 LOG(info) << __func__ << "(itdc=" << itdc << "[" << ChannelNames[TDCSignal[itdc]] << "], " << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc;
1173#endif
1174 // Extracting TDC information for TDC number itdc, in consecutive bunches from ibeg to iend
1175 int nbun = iend - ibeg + 1;
1176 int maxs2 = NTimeBinsPerBC * nbun - 1;
1177 int shift = mRopt->tsh[itdc];
1178 int thr = mRopt->tth[itdc];
1179
1180 int is1 = 0, is2 = 1;
1181 uint8_t isfired = 0;
1182#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1183 int16_t m[3] = {0};
1184 int16_t s[3] = {0};
1185#endif
1186 int it1 = 0, it2 = 0, ib1 = -1, ib2 = -1;
1187 for (;;) {
1188 // Shift data
1189 isfired = isfired << 1;
1190#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1191 for (int i = 2; i > 0; i--) {
1192 m[i] = m[i - 1];
1193 s[i] = s[i - 1];
1194 }
1195#endif
1196 // Bunches and samples that are used in the difference
1197 int b1 = ibeg + is1 / NTimeBinsPerBC;
1198 int b2 = ibeg + is2 / NTimeBinsPerBC;
1199 int s1 = is1 % NTimeBinsPerBC;
1200 int s2 = is2 % NTimeBinsPerBC;
1201 auto ref_m = mReco[b1].ref[TDCSignal[itdc]]; // reference to minuend
1202 auto ref_s = mReco[b2].ref[TDCSignal[itdc]]; // reference to subtrahend
1203 // Check data consistency before computing difference
1204 if (ref_m == ZDCRefInitVal || ref_s == ZDCRefInitVal) {
1205 if (ref_m == ZDCRefInitVal) {
1206 LOG(error) << __func__ << " @ " << __LINE__ << " Missing information for bunch crossing " << mReco[b1].ir.orbit << "." << mReco[b1].ir.bc << " tdc = " << itdc << " sig = " << TDCSignal[itdc];
1207 }
1208 if (ref_s == ZDCRefInitVal) {
1209 LOG(error) << __func__ << " @ " << __LINE__ << " Missing information for bunch crossing " << mReco[b2].ir.orbit << "." << mReco[b2].ir.bc << " tdc = " << itdc << " sig = " << TDCSignal[itdc];
1210 }
1211 return __LINE__;
1212 }
1213 // Check that bunch crossings are indeed the same or consecutive
1214 auto bcd = mReco[b2].ir.differenceInBC(mReco[b1].ir);
1215 if (bcd != 0 && bcd != 1) {
1216 LOG(error) << __func__ << " @ " << __LINE__ << " Large bunch crossing difference " << mReco[b1].ir.orbit << "." << mReco[b1].ir.bc << " followed by " << mReco[b2].ir.orbit << "." << mReco[b2].ir.bc;
1217 return __LINE__;
1218 }
1219 int diff = mChData[ref_m].data[s1] - mChData[ref_s].data[s2];
1220 // Triple trigger condition
1221#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1222 m[0] = mChData[ref_m].data[s1];
1223 s[0] = mChData[ref_s].data[s2];
1224#endif
1225 if (diff > thr) {
1226 isfired = isfired | 0x1;
1227 if ((isfired & mTriggerCondition) == mTriggerCondition) {
1228 // Fired bit is assigned to the second sample, i.e. to the one that can identify the
1229 // signal peak position
1230 mReco[b2].fired[itdc] |= mMask[s2];
1231#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1232 if (mTriggerCondition == 0x7) {
1233 printf("0x7 TDC %d[%s] Fired @ %u.%u.s%02u (%5d-%5d)=%5d>%2d && (%5d-%5d)=%5d>%2d && (s%02d:%-5d-s%02d:%-5d)=%5d>%2d\n",
1234 itdc, ChannelNames[TDCSignal[itdc]].data(), mReco[b2].ir.orbit, mReco[b2].ir.bc, s2,
1235 m[2], s[2], (m[2] - s[2]), thr,
1236 m[1], s[1], (m[1] - s[1]), thr,
1237 s1, m[0], s2, s[0], diff, thr);
1238 } else if (mTriggerCondition == 0x3) {
1239 printf("0x3 TDC %d[%s] Fired @ %u.%u.s%02u (%5d-%5d)=%5d>%2d && (s%02d:%-5d-s%02d:(%-5d))=%5d>%2d\n",
1240 itdc, ChannelNames[TDCSignal[itdc]].data(), mReco[b2].ir.orbit, mReco[b2].ir.bc, s2,
1241 m[1], s[1], (m[1] - s[1]), thr,
1242 s1, m[0], s2, s[0], diff, thr);
1243 } else if (mTriggerCondition == 0x1) {
1244 printf("0x1 TDC %d[%s] Fired @ %u.%u.s%02u (%d-(%d))=%d>%d && (%d-(%d))=%d>%d && (s%d:%d-s%d:(%d))=%d>%d\n",
1245 itdc, ChannelNames[TDCSignal[itdc]].data(), mReco[b2].ir.orbit, mReco[b2].ir.bc, s2,
1246 s1, m[0], s2, s[0], diff, thr);
1247 }
1248#endif
1249 }
1250 }
1251 if (is2 >= shift) {
1252 is1++;
1253 }
1254 if (is2 < maxs2) {
1255 is2++;
1256 }
1257 if (is1 == maxs2) {
1258 break;
1259 }
1260 }
1261 return interpolate(itdc, ibeg, iend);
1262} // processTrigger
1263
1264int DigiReco::processTriggerExtended(int itdc, int ibeg, int iend)
1265{
1266 auto isig = TDCSignal[itdc];
1267#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1268 LOG(info) << __func__ << "(itdc=" << itdc << "[" << ChannelNames[isig] << "], " << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc;
1269#endif
1270 // Extends search zone at the beginning of sequence. Need pedestal information.
1271 // For simplicity we use information for current bunch/orbit
1272 updateOffsets(ibeg);
1273 if (mSource[isig] == PedND) {
1274 // Fall back to normal trigger
1275 // Message will be produced when computing amplitude (if a hit is found in this bunch)
1276 // In this framework we have a potential undetected inefficiency, however pedestal
1277 // problem is a serious problem and will be noticed anyway
1278 return processTrigger(itdc, ibeg, iend);
1279 }
1280
1281 int nbun = iend - ibeg + 1;
1282 int maxs2 = NTimeBinsPerBC * nbun - 1;
1283 int shift = mRopt->tsh[itdc];
1284 int thr = mRopt->tth[itdc];
1285
1286 int is1 = -shift, is2 = 0;
1287 uint8_t isfired = 0;
1288#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1289 int16_t m[3] = {0};
1290 int16_t s[3] = {0};
1291#endif
1292
1293 int it1 = 0, it2 = 0, ib1 = -1, ib2 = -1;
1294 for (;;) {
1295 // Shift data
1296 isfired = isfired << 1;
1297#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1298 for (int i = 2; i > 0; i--) {
1299 m[i] = m[i - 1];
1300 s[i] = s[i - 1];
1301 }
1302#endif
1303 // Bunches and samples that are used in the difference
1304 int diff = 0;
1305 int b2 = ibeg + is2 / NTimeBinsPerBC;
1306 int s2 = is2 % NTimeBinsPerBC;
1307 auto ref_s = mReco[b2].ref[isig]; // reference to subtrahend
1308 int s1 = is1 % NTimeBinsPerBC;
1309 if (is1 < 0) {
1310 if (ref_s == ZDCRefInitVal) {
1311 LOG(error) << __func__ << " @ " << __LINE__ << " Missing information for bunch crossing " << mReco[b2].ir.orbit << "." << mReco[b2].ir.bc << " sig = " << isig;
1312 return __LINE__;
1313 }
1314 diff = mOffset[isig] - mChData[ref_s].data[s2];
1315#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1316 m[0] = mOffset[isig];
1317 s[0] = mChData[ref_s].data[s2];
1318#endif
1319 } else {
1320 int b1 = ibeg + is1 / NTimeBinsPerBC;
1321 auto ref_m = mReco[b1].ref[TDCSignal[itdc]]; // reference to minuend
1322 // Check data consistency before computing difference
1323 if (ref_m == ZDCRefInitVal || ref_s == ZDCRefInitVal) {
1324 LOG(error) << __func__ << " @ " << __LINE__ << " Missing information for bunch crossing " << mReco[b1].ir.orbit << "." << mReco[b1].ir.bc << " tdc = " << itdc << " sig = " << TDCSignal[itdc];
1325 return __LINE__;
1326 }
1327 // Check that bunch crossings are indeed the same or consecutive
1328 auto bcd = mReco[b2].ir.differenceInBC(mReco[b1].ir);
1329 if (bcd != 0 && bcd != 1) {
1330 LOG(error) << __func__ << ": large bunch crossing difference " << mReco[b1].ir.orbit << "." << mReco[b1].ir.bc << " followed by " << mReco[b2].ir.orbit << "." << mReco[b2].ir.bc;
1331 return __LINE__;
1332 }
1333 diff = mChData[ref_m].data[s1] - mChData[ref_s].data[s2];
1334#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1335 m[0] = mChData[ref_m].data[s1];
1336 s[0] = mChData[ref_s].data[s2];
1337#endif
1338 }
1339 if (diff > thr) {
1340 isfired = isfired | 0x1;
1341 // Check trigger condition
1342 if ((isfired & mTriggerCondition) == mTriggerCondition) {
1343 // Fired bit is assigned to the second sample, i.e. to the one that can identify the
1344 // signal peak position
1345 mReco[b2].fired[itdc] |= mMask[s2];
1346#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1347 if (mTriggerCondition == 0x7) {
1348 printf("0x7E TDC %d[%s] Fired @ %u.%u.s%02u (%5d-%5d)=%5d>%2d && (%5d-%5d)=%5d>%5d && (s%02d:%-5d-s%02d:%-5d)=%-5d>%2d\n",
1349 itdc, ChannelNames[TDCSignal[itdc]].data(), mReco[b2].ir.orbit, mReco[b2].ir.bc, s2,
1350 m[2], s[2], (m[2] - s[2]), thr,
1351 m[1], s[1], (m[1] - s[1]), thr,
1352 s1, m[0], s2, s[0], diff, thr);
1353 } else if (mTriggerCondition == 0x3) {
1354 printf("0x3E TDC %d[%s] Fired @ %u.%u.s%02u (%5d-%5d)=%5d>%2d && (s%02d:%-5d-s%02d:(%-5d))=%-5d>%2d\n",
1355 itdc, ChannelNames[TDCSignal[itdc]].data(), mReco[b2].ir.orbit, mReco[b2].ir.bc, s2,
1356 m[1], s[1], (m[1] - s[1]), thr,
1357 s1, m[0], s2, s[0], diff, thr);
1358 } else if (mTriggerCondition == 0x1) {
1359 printf("0x1E TDC %d[%s] Fired @ %u.%u.s%02u (%5d-(%5d))=%5d>%2d && (%5d-(%5d))=%5d>%2d && (s%d:%5d-s%d:(%5d))=%5d>%2d\n",
1360 itdc, ChannelNames[TDCSignal[itdc]].data(), mReco[b2].ir.orbit, mReco[b2].ir.bc, s2,
1361 s1, m[0], s2, s[0], diff, thr);
1362 }
1363#endif
1364 }
1365 }
1366 is1++;
1367 if (is2 < maxs2) {
1368 is2++;
1369 }
1370 if (is1 == maxs2) {
1371 break;
1372 }
1373 }
1374 return interpolate(itdc, ibeg, iend);
1375} // processTriggerExtended
1376
1377// Interpolation for single point
1378O2_ZDC_DIGIRECO_FLT DigiReco::getPoint(int isig, int ibeg, int iend, int i)
1379{
1380 constexpr int nsbun = TSN * NTimeBinsPerBC; // Total number of interpolated points per bunch crossing
1381 if (i >= mNtot || i < 0) {
1382 LOG(error) << "Error addressing isig=" << isig << " i=" << i << " mNtot=" << mNtot;
1383 mInError = true;
1384 return std::numeric_limits<float>::infinity();
1385 }
1386 // Constant extrapolation at the beginning and at the end of the array
1387 if (i < TSNH) {
1388 // Return value of first sample
1389 return mFirstSample;
1390 } else if (i >= mIlast) {
1391 // Return value of last sample
1392 return mLastSample;
1393 } else {
1394 // Identification of the point to be assigned
1395 int ibun = ibeg + i / nsbun;
1396 // Interpolation between acquired points (N.B. from 0 to mNint)
1397 i = i - TSNH;
1398 int im = i % TSN;
1399 if (im == 0) {
1400 // This is an acquired point
1401 int ip = (i / TSN) % NTimeBinsPerBC;
1402 int ib = ibeg + (i / TSN) / NTimeBinsPerBC;
1403 if (ib != ibun) {
1404 LOG(error) << "ib=" << ib << " ibun=" << ibun;
1405 mInError = true;
1406 return std::numeric_limits<float>::infinity();
1407 }
1408 return mReco[ibun].data[isig][ip]; // Filtered point
1409 // return mChData[mReco[ibun].ref[isig]].data[ip]; // Original point
1410 } else {
1411 // Do the actual interpolation
1413 int ip = i / TSN;
1415 for (int is = TSN - im, ii = ip - TSL + 1; is < NTS; is += TSN, ii++) {
1416 // Default is first point in the array
1417 O2_ZDC_DIGIRECO_FLT yy = mFirstSample;
1418 if (ii > 0) {
1419 if (ii < mNsam) {
1420 int ip = ii % NTimeBinsPerBC;
1421 int ib = ibeg + ii / NTimeBinsPerBC;
1422 yy = mReco[ib].data[isig][ip];
1423 // yy = mChData[mReco[ib].ref[isig]].data[ip];
1424 } else {
1425 // Last acquired point
1426 yy = mLastSample;
1427 }
1428 }
1429 sum += mTS[is];
1430 y += yy * mTS[is];
1431 }
1432 y = y / sum;
1433 return y;
1434 }
1435 }
1436}
1437
1438void DigiReco::setPoint(int isig, int ibeg, int iend, int i)
1439{
1440 // This function needs to be used only if mFullInterpolation is true otherwise the
1441 // vectors are not allocated
1442 if (!mFullInterpolation) {
1443 LOG(fatal) << __func__ << " call with mFullInterpolation = " << mFullInterpolation;
1444 return;
1445 }
1446 constexpr int nsbun = TSN * NTimeBinsPerBC; // Total number of interpolated points per bunch crossing
1447 if (i >= mNtot || i < 0) {
1448 LOG(error) << "Error addressing signal isig=" << isig << " i=" << i << " mNtot=" << mNtot;
1449 mInError = true;
1450 return;
1451 }
1452 // Constant extrapolation at the beginning and at the end of the array
1453 if (i < TSNH) {
1454 // Assign value of first sample
1455 mReco[ibeg].inter[isig][i] = mFirstSample;
1456 } else if (i >= mIlast) {
1457 // Assign value of last sample
1458 int isam = i % nsbun;
1459 mReco[iend].inter[isig][isam] = mLastSample;
1460 } else {
1461 // Identification of the point to be assigned
1462 int ibun = ibeg + i / nsbun;
1463 int isam = i % nsbun;
1464 mReco[ibun].inter[isig][isam] = getPoint(isig, ibeg, iend, i);
1465 }
1466} // setPoint
1467
1468int DigiReco::fullInterpolation(int isig, int ibeg, int iend)
1469{
1470 // Interpolation of signal isig, in consecutive bunches from ibeg to iend
1471 // This function works for all signals and does not evaluate trigger
1472 // You need to call interpolate(int itdc... for the TDC signals
1473#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1474 LOG(info) << __func__ << "(isig=" << isig << "[" << ChannelNames[isig] << "], " << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc;
1475#endif
1476
1477 // TODO: get data from preceding time frame in case there are bunches
1478 // with signal at the beginning of the first orbit of a time frame
1479
1480 constexpr int MaxTimeBin = NTimeBinsPerBC - 1; //< number of samples per BC
1481
1482 // Set data members for interpolation of the current channel
1483 mNbun = iend - ibeg + 1; // Number of adjacent bunches
1484 mNsam = mNbun * NTimeBinsPerBC; // Number of acquired samples
1485 mNtot = mNsam * TSN; // Total number of points in the interpolated arrays
1486 mNint = (mNbun * NTimeBinsPerBC - 1) * TSN; // Total points in the interpolation region (-1)
1487 mIlast = mNtot - TSNH; // Index of last acquired sample
1488
1489 // At this level there should be no need to check if the channel is connected
1490 // since a fatal should have been raised already
1491 for (int ibun = ibeg; ibun <= iend; ibun++) {
1492 auto ref = mReco[ibun].ref[isig];
1493 if (ref == ZDCRefInitVal) {
1494 LOG(error) << __func__ << " @ " << __LINE__ << " Missing information for bunch crossing " << mReco[ibun].ir.orbit << "." << mReco[ibun].ir.bc << " sig = " << isig;
1495 return __LINE__;
1496 }
1497 }
1498
1499 mFirstSample = mReco[ibeg].data[isig][0];
1500 mLastSample = mReco[iend].data[isig][MaxTimeBin];
1501
1502 // Allocate and fill array of interpolated points
1503 for (int ibun = ibeg; ibun <= iend; ibun++) {
1504 mReco[ibun].allocate(isig);
1505 }
1506 for (int i = 0; i < mNtot; i++) {
1507 setPoint(isig, ibeg, iend, i);
1508 }
1509 if (mInError) {
1510 return __LINE__;
1511 }
1512 return 0;
1513}
1514
1515int DigiReco::interpolate(int itdc, int ibeg, int iend)
1516{
1517 // Interpolation of TDC channel itdc, in consecutive bunches from ibeg to iend
1518 int isig = TDCSignal[itdc];
1519
1520#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1521 LOG(info) << __func__ << "(itdc=" << itdc << "[" << ChannelNames[isig] << "], " << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc;
1522#endif
1523
1524 // TODO: get data from preceding time frame in case there are bunches
1525 // with signal at the beginning of the first orbit of a time frame
1526
1527 constexpr int MaxTimeBin = NTimeBinsPerBC - 1; //< number of samples per BC
1528 constexpr int nsbun = TSN * NTimeBinsPerBC; // Total number of interpolated points per bunch crossing
1529
1530 // Set data members for interpolation of the current TDC
1531 mNbun = iend - ibeg + 1; // Number of adjacent bunches
1532 mNsam = mNbun * NTimeBinsPerBC; // Number of acquired samples
1533 mNtot = mNsam * TSN; // Total number of points in the interpolated arrays
1534 mNint = (mNbun * NTimeBinsPerBC - 1) * TSN; // Total points in the interpolation region (-1)
1535 mIlast = mNtot - TSNH; // Index of last acquired sample
1536
1537 constexpr int nsp = 5; // Number of points to be searched
1538
1539 // At this level there should be no need to check if the channel is connected
1540 // since a fatal should have been raised already
1541 for (int ibun = ibeg; ibun <= iend; ibun++) {
1542 auto ref = mReco[ibun].ref[isig];
1543 if (ref == ZDCRefInitVal) {
1544 LOG(error) << __func__ << " @ " << __LINE__ << " Missing information for bunch crossing " << mReco[ibun].ir.orbit << "." << mReco[ibun].ir.bc << " sig = " << isig;
1545 return __LINE__;
1546 }
1547 }
1548
1549 // auto ref_beg = mReco[ibeg].ref[isig];
1550 // auto ref_end = mReco[iend].ref[isig];
1551 // mFirstSample = mChData[ref_beg].data[0]; // Original points
1552 // mLastSample = mChData[ref_end].data[MaxTimeBin]; // Original points
1553
1554 mFirstSample = mReco[ibeg].data[isig][0];
1555 mLastSample = mReco[iend].data[isig][MaxTimeBin];
1556
1557 // mFullInterpolation turns on full interpolation for debugging
1558 // otherwise the interpolation is performed only around actual signal
1559 if (mFullInterpolation) {
1560 for (int ibun = ibeg; ibun <= iend; ibun++) {
1561 mReco[ibun].allocate(isig);
1562 }
1563 for (int i = 0; i < mNtot; i++) {
1564 setPoint(isig, ibeg, iend, i);
1565 }
1566 }
1567 if (mInError) {
1568 return __LINE__;
1569 }
1570 // Looking for a local maximum in a search zone
1571 O2_ZDC_DIGIRECO_FLT amp = std::numeric_limits<float>::infinity(); // Amplitude to be stored
1572 int isam_amp = 0; // Sample at maximum amplitude (relative to beginning of group)
1573 int ip_old = -1, ip_cur = -1, ib_cur = -1; // Current and old points
1574 bool is_searchable = false; // Flag for point in the search zone for maximum amplitude
1575 bool was_searchable = false; // Flag for point in the search zone for maximum amplitude
1576 int ib[nsp] = {-1, -1, -1, -1, -1};
1577 int ip[nsp] = {-1, -1, -1, -1, -1};
1578 // N.B. Points at the extremes are constant therefore no local maximum
1579 // can occur in these two regions
1580 for (int i = 0; i < mNint; i += mInterpolationStep) {
1581 int isam = i + TSNH;
1582 // Check if trigger is fired for this point
1583 // For the moment we don't take into account possible extensions of the search zone
1584 // ip_cur can span several bunches and is used just to identify transitions
1585 ip_cur = isam / TSN;
1586 // Speed up computation
1587 if (ip_cur != ip_old) {
1588 ip_old = ip_cur;
1589 for (int j = 0; j < 5; j++) {
1590 ib[j] = -1;
1591 ip[j] = -1;
1592 }
1593 // There are three possible triple conditions that involve current point (middle is current point)
1594 ip[2] = ip_cur % NTimeBinsPerBC;
1595 ib[2] = ibeg + ip_cur / NTimeBinsPerBC;
1596 ib_cur = ib[2];
1597 if (ip[2] > 0) {
1598 ip[1] = ip[2] - 1;
1599 ib[1] = ib[2];
1600 } else if (ip[2] == 0) {
1601 if (ib[2] > ibeg) {
1602 ib[1] = ib[2] - 1;
1603 ip[1] = MaxTimeBin;
1604 }
1605 }
1606 if (ip[1] > 0) {
1607 ip[0] = ip[1] - 1;
1608 ib[0] = ib[1];
1609 } else if (ip[1] == 0) {
1610 if (ib[1] > ibeg) {
1611 ib[0] = ib[1] - 1;
1612 ip[0] = MaxTimeBin;
1613 }
1614 }
1615 if (ip[2] < MaxTimeBin) {
1616 ip[3] = ip[2] + 1;
1617 ib[3] = ib[2];
1618 } else if (ip[2] == MaxTimeBin) {
1619 if (ib[2] < iend) {
1620 ib[3] = ib[2] + 1;
1621 ip[3] = 0;
1622 }
1623 }
1624 if (ip[3] < MaxTimeBin) {
1625 ip[4] = ip[3] + 1;
1626 ib[4] = ib[3];
1627 } else if (ip[3] == MaxTimeBin) {
1628 if (ib[3] < iend) {
1629 ib[4] = ib[3] + 1;
1630 ip[4] = 0;
1631 }
1632 }
1633 // meet the threshold condition
1634 was_searchable = is_searchable;
1635 // Search conditions with list of allowed patterns
1636 // No need to double check ib[?] and ip[?] because either we assign both or none
1637 uint16_t triggered = 0x0000;
1638 for (int j = 0; j < 5; j++) {
1639 if (ib[j] >= 0 && (mReco[ib[j]].fired[itdc] & mMask[ip[j]]) > 0) {
1640 triggered |= (0x1 << j);
1641 }
1642 }
1643 // Reject conditions:
1644 // 00000
1645 // 10001
1646 // One among 10000 and 00001
1647 // Accept conditions:
1648 constexpr uint16_t accept[14] = {
1649 // 0x01, // 00001 extend search zone before maximum
1650 0x02, // 00010
1651 0x04, // 00100
1652 0x08, // 01000
1653 0x10, // 10000 extend after
1654 0x03, // 00011
1655 0x06, // 00110
1656 0x0c, // 01100
1657 0x18, // 11000
1658 0x07, // 00111
1659 0x0e, // 01110
1660 0x1c, // 11100
1661 0x0f, // 01111
1662 0x1e, // 11110
1663 0x1f // 11111
1664 };
1665 // All other are not correct (->reject)
1666 is_searchable = 0;
1667 if (triggered != 0) {
1668 for (int j = 0; j < 14; j++) {
1669 if (triggered == accept[j]) {
1670 is_searchable = 1;
1671 break;
1672 }
1673 }
1674 }
1675 }
1676 // We do not restrict search zone around expected main-main collision
1677 // because we would like to be able to identify pile-up from collisions
1678 // with satellites
1679 // This is buggy because you can get just one TDC for each search zone
1680 // If more than one signal is present, just the largest one is saved
1681 // To overcome this limitation one should implement more refined analysis
1682 // techniques to perform shape recognition
1683
1684 // If we exit from searching zone
1685 if (was_searchable && !is_searchable) {
1686 if (amp <= ADCMax) {
1687 if (mInterpolationStep > 1) {
1688 // Refine peak search
1689 int sbeg = (isam_amp - TSNH);
1690 int send = (isam_amp + TSNH);
1691 if (sbeg < 0) {
1692 sbeg = 0;
1693 send = sbeg + TSN;
1694 }
1695 if (send > (mNint + TSNH)) {
1696 send = mNint + TSNH;
1697 sbeg = send - TSN;
1698 }
1699 if (sbeg < 0) {
1700 sbeg = 0;
1701 }
1702 for (int spos = sbeg; spos < send; spos++) {
1703 // Perform interpolation for the searched point
1704 O2_ZDC_DIGIRECO_FLT myval = getPoint(isig, ibeg, iend, spos);
1705 // Get local minimum of waveform
1706 if (myval < amp) {
1707 amp = myval;
1708 isam_amp = spos;
1709 }
1710 }
1711 }
1712 // Store identified peak
1713 int ibun = ibeg + isam_amp / nsbun;
1714 updateOffsets(ibun);
1715 // At this level offsets are from Orbit or QC therefore
1716 // the TDC amplitude and time are affected by pile-up from
1717 // previous collisions. Pile up correction needs to be
1718 // performed after all signals have been identified
1719 if (mSource[isig] != PedND) {
1720 amp = mOffset[isig] - amp;
1721 } else {
1722 LOGF(error, "%u.%-4d Missing pedestal for TDC %d %s ", mBCData[ibun].ir.orbit, mBCData[ibun].ir.bc, itdc, ChannelNames[TDCSignal[itdc]]);
1723 amp = std::numeric_limits<float>::infinity();
1724 }
1725 int tdc = isam_amp % nsbun;
1726 assignTDC(ibun, ibeg, iend, itdc, tdc, amp);
1727 }
1728 amp = std::numeric_limits<float>::infinity();
1729 isam_amp = 0;
1730 was_searchable = 0;
1731 }
1732 if (is_searchable) {
1733 int mysam = isam % nsbun;
1734 O2_ZDC_DIGIRECO_FLT myval;
1735 if (mFullInterpolation) {
1736 // Already interpolated
1737 myval = mReco[ib_cur].inter[isig][mysam];
1738 } else {
1739 // Perform interpolation for the searched point
1740 myval = getPoint(isig, ibeg, iend, isam);
1741 }
1742 // Get local minimum of waveform
1743 if (myval < amp) {
1744 amp = myval;
1745 isam_amp = isam;
1746 }
1747 }
1748 } // Loop on interpolated points
1749 if (mInError) {
1750 return __LINE__;
1751 }
1752
1753 // Trigger flag still present at the of the scan
1754 if (is_searchable) {
1755 // Add last identified peak
1756 if (amp <= ADCMax) {
1757 if (mInterpolationStep > 1) {
1758 // Refine peak search
1759 int sbeg = (isam_amp - TSNH);
1760 int send = (isam_amp + TSNH);
1761 if (sbeg < 0) {
1762 sbeg = 0;
1763 send = sbeg + TSN;
1764 }
1765 if (send > (mNint + TSNH)) {
1766 send = mNint + TSNH;
1767 sbeg = send - TSN;
1768 }
1769 if (sbeg < 0) {
1770 sbeg = 0;
1771 }
1772 for (int spos = sbeg; spos < send; spos++) {
1773 // Perform interpolation for the searched point
1774 O2_ZDC_DIGIRECO_FLT myval = getPoint(isig, ibeg, iend, spos);
1775 // Get local minimum of waveform
1776 if (myval < amp) {
1777 amp = myval;
1778 isam_amp = spos;
1779 }
1780 }
1781 }
1782 // Store identified peak
1783 int ibun = ibeg + isam_amp / nsbun;
1784 updateOffsets(ibun);
1785 if (mSource[isig] != PedND) {
1786 amp = mOffset[isig] - amp;
1787 } else {
1788 LOGF(error, "%u.%-4d Missing pedestal for TDC %d %s ", mBCData[ibun].ir.orbit, mBCData[ibun].ir.bc, itdc, ChannelNames[TDCSignal[itdc]]);
1789 amp = std::numeric_limits<float>::infinity();
1790 }
1791 int tdc = isam_amp % nsbun;
1792 assignTDC(ibun, ibeg, iend, itdc, tdc, amp);
1793 }
1794 }
1795 if (mInError) {
1796 return __LINE__;
1797 }
1798 // TODO: add logic to assign TDC in presence of overflow
1799 return 0;
1800} // interpolate
1801
1802void DigiReco::assignTDC(int ibun, int ibeg, int iend, int itdc, int tdc, float amp)
1803{
1804 constexpr int nsbun = TSN * NTimeBinsPerBC; // Total number of interpolated points per bunch crossing
1805 constexpr int tdc_max = nsbun / 2;
1806 constexpr int tdc_min = -tdc_max;
1807
1808 auto& rec = mReco[ibun];
1809
1810 // Flag hit position in sequence
1811 if (ibun == ibeg) {
1812 rec.isBeg[itdc] = true;
1813 }
1814 if (ibun == iend) {
1815 rec.isEnd[itdc] = true;
1816 }
1817
1818 int isig = TDCSignal[itdc];
1819 float TDCVal = tdc;
1820 float TDCAmp = amp;
1821
1822 // Correct for time bias on single signals
1823 float TDCValCorr = 0, TDCAmpCorr = 0;
1824 if (mCorrSignal == false || correctTDCSignal(itdc, tdc, amp, TDCValCorr, TDCAmpCorr, rec.isBeg[itdc], rec.isEnd[itdc]) != 0) {
1825 // Cannot apply amplitude correction for isolated signal -> Flag error condition
1826 rec.tdcSigE[TDCSignal[itdc]] = true;
1827 } else {
1828 TDCVal = TDCValCorr;
1829 // Cannot correct amplitude if pedestal is missing
1830 if (!rec.tdcPedMissing[isig]) {
1831 TDCAmp = TDCAmpCorr;
1832 }
1833 }
1834
1835 // rec.genericE[TDCSignal[itdc]] = true; // Produce fake error
1836
1837 // TDC calibration
1838 TDCVal = TDCVal - tdc_shift[itdc];
1839 if (!rec.tdcPedMissing[isig]) {
1840 // Cannot correct amplitude if pedestal is missing
1841 TDCAmp = (TDCAmp - tdc_offset[itdc]) * tdc_calib[itdc];
1842 }
1843
1844 // Encode amplitude and assign
1845 rec.TDCVal[itdc].push_back(TDCVal);
1846 rec.TDCAmp[itdc].push_back(TDCAmp);
1847 int& ihit = mReco[ibun].ntdc[itdc];
1848#ifdef O2_ZDC_TDC_C_ARRAY
1849 if (ihit < MaxTDCValues) {
1850 rec.tdcVal[itdc][ihit] = TDCVal;
1851 rec.tdcAmp[itdc][ihit] = TDCAmp;
1852 } else {
1853 LOG(error) << rec.ir.orbit << "." << rec.ir.bc << " ibun=" << ibun << " itdc=" << itdc << " tdc=" << tdc << " TDCVal=" << TDCVal * o2::zdc::FTDCVal << " TDCAmp=" << TDCAmp << " OVERFLOW";
1854 }
1855#endif
1856 // Assign info about pedestal subtration
1857 if (mSource[isig] == PedOr) {
1858 rec.tdcPedOr[isig] = true;
1859 } else if (mSource[isig] == PedQC) {
1860 rec.tdcPedQC[isig] = true;
1861 } else if (mSource[isig] == PedEv) {
1862 // In present implementation this never happens
1863 rec.tdcPedEv[isig] = true;
1864 } else {
1865 rec.tdcPedMissing[isig] = true;
1866 }
1867#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1868 LOG(info) << __func__ << " itdc=" << itdc << " " << ChannelNames[isig] << " @ ibun=" << ibun << " " << mReco[ibun].ir.orbit << "." << mReco[ibun].ir.bc << " "
1869 << " tdc=" << tdc << " -> " << TDCValCorr << " shift=" << tdc_shift[itdc] << " -> TDCVal=" << TDCVal << "=" << TDCVal * o2::zdc::FTDCVal
1870 << " mSource[" << isig << "] = " << unsigned(mSource[isig]) << " = " << mOffset[isig]
1871 << " amp=" << amp << " -> " << TDCAmpCorr << " calib=" << tdc_calib[itdc] << " offset=" << tdc_offset[itdc] << " -> TDCAmp=" << TDCAmp
1872 << (ibun == ibeg ? " B" : "") << (ibun == iend ? " E" : "");
1873 mAssignedTDC[itdc]++;
1874#endif
1875 ihit++;
1876} // assignTDC
1877
1878void DigiReco::findSignals(int ibeg, int iend)
1879{
1880 // N.B. findSignals is called after pile-up correction on TDCs
1881#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1882 LOG(info) << __func__ << "(" << ibeg << ", " << iend << "): " << mReco[ibeg].ir.orbit << "." << mReco[ibeg].ir.bc << " - " << mReco[iend].ir.orbit << "." << mReco[iend].ir.bc;
1883#endif
1884 // Identify TDC signals
1885 for (int ibun = ibeg; ibun <= iend; ibun++) {
1886 updateOffsets(ibun); // Get orbit pedestals or run pedestals as a fallback
1887 auto& rec = mReco[ibun];
1888 for (int itdc = 0; itdc < NTDCChannels; itdc++) {
1889#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1890 bool msg = false;
1891 if (rec.fired[itdc] != 0x0) {
1892 msg = true;
1893 printf("%d %u.%-4u TDCDiscr %d [%s] 0x%04hx -> ", ibun, rec.ir.orbit, rec.ir.bc, itdc, ChannelNames[TDCSignal[itdc]].data(), rec.fired[itdc]);
1894 for (int isam = 0; isam < NTimeBinsPerBC; isam++) {
1895 printf("%d", rec.fired[itdc] & mMask[isam] ? 1 : 0);
1896 }
1897 }
1898#endif
1899 rec.pattern[itdc] = 0;
1900 for (int32_t i = 0; i < rec.ntdc[itdc]; i++) {
1901#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1902 msg = true;
1903 printf(" %d TDC A=%5.0f @ T=%5.0f", i, rec.TDCAmp[itdc][i], rec.TDCVal[itdc][i]);
1904#endif
1905 // There is a TDC value in the search zone around main-main position
1906 // NB: by definition main-main collision has zero time
1907 if (std::abs(rec.TDCVal[itdc][i]) < mRopt->tdc_search[itdc]) {
1908 rec.pattern[itdc] = 1;
1909 }
1910#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1911 if (rec.pattern[itdc] == 1) {
1912 printf(" in_r");
1913 } else {
1914 printf(" out_r");
1915 }
1916#endif
1917 }
1918#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1919 if (msg) {
1920 printf("\n");
1921 }
1922#endif
1923 }
1924
1925#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
1926 printf("%d %u.%-4u TDC PATTERN: ", ibun, mReco[ibun].ir.orbit, mReco[ibun].ir.bc);
1927 for (int itdc = 0; itdc < NTDCChannels; itdc++) {
1928 printf("%d", rec.pattern[itdc]);
1929 }
1930 for (int itdc = 0; itdc < NTDCChannels; itdc++) {
1931 printf(" %s", rec.pattern[itdc] ? ChannelNames[TDCSignal[itdc]].data() : " ");
1932 }
1933 printf("\n");
1934#endif
1935
1936 // Check if coincidence of common PM and sum of towers is satisfied
1937 // Missing coincidence can be due for example by PM noise
1938 // TODO: for the moment the map of fired TDC is in RecEventAux
1939 // One should transmit it or introduce a way to recompute while reading back
1940 // the reconstructed events
1941 // Side A
1942 if ((rec.pattern[TDCZNAC] || mRopt->bitset[TDCZNAC]) && (rec.pattern[TDCZNAS] || mRopt->bitset[TDCZNAS])) {
1943 for (int ich = IdZNAC; ich <= IdZNASum; ich++) {
1944 rec.chfired[ich] = true;
1945 }
1946 }
1947 if ((rec.pattern[TDCZPAC] || mRopt->bitset[TDCZPAC]) && (rec.pattern[TDCZPAS] || mRopt->bitset[TDCZPAS])) {
1948 for (int ich = IdZPAC; ich <= IdZPASum; ich++) {
1949 rec.chfired[ich] = true;
1950 }
1951 }
1952 // ZEM1 and ZEM2 are not in coincidence
1953 rec.chfired[IdZEM1] = rec.pattern[TDCZEM1];
1954 rec.chfired[IdZEM2] = rec.pattern[TDCZEM2];
1955 // Side C
1956 if ((rec.pattern[TDCZNCC] || mRopt->bitset[TDCZNCC]) && (rec.pattern[TDCZNCS] || mRopt->bitset[TDCZNCS])) {
1957 for (int ich = IdZNCC; ich <= IdZNCSum; ich++) {
1958 rec.chfired[ich] = true;
1959 }
1960 }
1961 if ((rec.pattern[TDCZPCC] || mRopt->bitset[TDCZPCC]) && (rec.pattern[TDCZPCS] || mRopt->bitset[TDCZPCS])) {
1962 for (int ich = IdZPCC; ich <= IdZPCSum; ich++) {
1963 rec.chfired[ich] = true;
1964 }
1965 }
1966 // TODO: option to use a less restrictive definition of "fired" using for example
1967 // just the autotrigger bits instead of using TDCs
1968#ifndef O2_ZDC_DEBUG
1969 if (mVerbosity >= DbgFull) {
1970 printf("%d %u.%-4u TDC FIRED ", ibun, rec.ir.orbit, rec.ir.bc);
1971 printf("ZNA:%d%d%d%d%d%d ZPA:%d%d%d%d%d%d ZEM:%d%d ZNC:%d%d%d%d%d%d ZPC:%d%d%d%d%d%d\n",
1972 rec.chfired[IdZNAC], rec.chfired[IdZNA1], rec.chfired[IdZNA2], rec.chfired[IdZNA3], rec.chfired[IdZNA4], rec.chfired[IdZNASum],
1973 rec.chfired[IdZPAC], rec.chfired[IdZPA1], rec.chfired[IdZPA2], rec.chfired[IdZPA3], rec.chfired[IdZPA4], rec.chfired[IdZPASum],
1974 rec.chfired[IdZEM1], rec.chfired[IdZEM2],
1975 rec.chfired[IdZNCC], rec.chfired[IdZNC1], rec.chfired[IdZNC2], rec.chfired[IdZNC3], rec.chfired[IdZNC4], rec.chfired[IdZNCSum],
1976 rec.chfired[IdZPCC], rec.chfired[IdZPC1], rec.chfired[IdZPC2], rec.chfired[IdZPC3], rec.chfired[IdZPC4], rec.chfired[IdZPCSum]);
1977 }
1978#endif
1979 } // loop on bunches
1980} // findSignals
1981
1982void DigiReco::correctTDCPile()
1983{
1984 // Pile-up correction for TDCs
1985 // FEE acquires data in two modes: triggered and continuous
1986 // In triggered mode minimum two and up to four bunches are transferred for each ALICE trigger
1987 // In continuous mode two bunches are transferred for each autotrigger
1988 // Reconstruction is performed for consecutive bunches
1989 // There is no issue with gaps for triggered mode because the trigger condition
1990 // A0 || A1 || (A2 && (T0 || TM)) || (A3 && T0) one can have the following sequences
1991 // where: T is autotrigger, A is ALICE trigger, P is a previous bunch, - is skipped
1992 // ---PA A0 || A1
1993 // ---TA A0 || A1
1994 // --TPA A2 && T0
1995 // -TPPA A2 && TM A3 && T0
1996 // On the other hand, in autotrigger mode one can have a gap
1997 // ---PT
1998 // --PTT
1999 // -PTPT
2000 // PT-PT
2001 // therefore we have to look for an interaction outside the range of consecutive bunch
2002 // crossings that is used in reconstruction. Therefore the correction is done outside
2003 // reconstruction loop
2004 // In case TDC correction parameters are missing (e.g. mTDCCorr==0) then
2005 // pile-up is flagged but not corrected for
2006
2007#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
2008 LOG(info) << "________________________________________________________________________________";
2009 LOG(info) << __func__;
2010#endif
2011
2012 // TODO: Perform actual pile-up correction for TDCs.. this is still work in progress..
2013 // For the moment this function has pile-up detection
2014
2015 for (int itdc = 0; itdc < NTDCChannels; itdc++) {
2016 // Queue is empty at first event of the time frame
2017 // TODO: collect information from previous time frame
2018 std::deque<DigiRecoTDC> tdc;
2019 for (int ibc = 0; ibc < mNBC; ibc++) {
2020 // Bunch to be corrected
2021 auto rec = &mReco[ibc];
2022 // Count the number of hits in preceding bunch crossings
2023 // N.B. it is initialized at every bunch crossing
2024 int ntdc[NBCAn] = {0};
2025 for (auto it = tdc.begin(); it != tdc.end(); ++it) {
2026 auto bcd = (rec->ir).differenceInBC((*it).ir);
2027 if (bcd > NBCAn) {
2028 // Remove early events
2029 tdc.pop_front();
2030 } else if (bcd > 0) {
2031 ntdc[bcd - 1]++;
2032 }
2033 }
2034 if (rec->ntdc[itdc] > 1) {
2035 // In-bunch pile-up: cannot correct
2036 rec->tdcPileEvE[TDCSignal[itdc]] = true;
2037 if (mRopt->doStoreEvPileup) {
2038 // Store also multiple hits
2039 for (int ihit = 0; ihit < rec->ntdc[itdc]; ihit++) {
2040 tdc.emplace_back(rec->TDCVal[itdc][ihit], rec->TDCAmp[itdc][ihit], rec->ir);
2041 }
2042 }
2043 } else if (rec->ntdc[itdc] == 1) {
2044 // A single TDC hit is present in current bunch
2045 if (tdc.size() > 0) {
2046 if (mCorrBackground) {
2047 correctTDCBackground(ibc, itdc, tdc);
2048 } else {
2049 // Identify pile-up and assign error flags
2050 std::deque<DigiRecoTDC>::reverse_iterator rit = tdc.rbegin();
2051 // Here we should start the loop on signal bucket position
2052 for (rit = tdc.rbegin(); rit != tdc.rend(); ++rit) {
2053 auto bcd = (rec->ir).differenceInBC((*rit).ir);
2054 // Check if background can be corrected
2055 if (bcd > 0 && bcd <= NBCAn) {
2056 if (ntdc[bcd - 1] > 0) {
2057 // We flag pile-up
2058 if (bcd == 1) {
2059 rec->tdcPileM1E[TDCSignal[itdc]] = true;
2060 } else if (bcd == 2) {
2061 rec->tdcPileM2E[TDCSignal[itdc]] = true;
2062 } else if (bcd == 3) {
2063 rec->tdcPileM3E[TDCSignal[itdc]] = true;
2064 }
2065 }
2066 }
2067 }
2068 }
2069 }
2070 // Add current event at the end of the queue
2071 for (int ihit = 0; ihit < rec->ntdc[itdc]; ihit++) {
2072 tdc.emplace_back(rec->TDCVal[itdc][ihit], rec->TDCAmp[itdc][ihit], rec->ir);
2073 }
2074 } // Single hit in bunch
2075#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
2076 if (rec->tdcPileEvE[TDCSignal[itdc]] || rec->tdcPileM1C[TDCSignal[itdc]] || rec->tdcPileM1E[TDCSignal[itdc]] ||
2077 rec->tdcPileM2C[TDCSignal[itdc]] || rec->tdcPileM2E[TDCSignal[itdc]] || rec->tdcPileM3C[TDCSignal[itdc]] || rec->tdcPileM3E[TDCSignal[itdc]]) {
2078 printf("%d %u.%-4u %s:%s%s%s%s\n", ibc, rec->ir.orbit, rec->ir.bc, ChannelNames[TDCSignal[itdc]].data(),
2079 rec->tdcPileEvE[TDCSignal[itdc]] ? " PileEvE" : "",
2080 rec->tdcPileM1C[TDCSignal[itdc]] ? " PileM1C" : "",
2081 rec->tdcPileM1E[TDCSignal[itdc]] ? " PileM1E" : "",
2082 rec->tdcPileM2C[TDCSignal[itdc]] ? " PileM2C" : "",
2083 rec->tdcPileM2E[TDCSignal[itdc]] ? " PileM2E" : "",
2084 rec->tdcPileM3C[TDCSignal[itdc]] ? " PileM3C" : "",
2085 rec->tdcPileM3E[TDCSignal[itdc]] ? " PileM3E" : "");
2086 }
2087#endif
2088 }
2089 }
2090} // correctTDCPile
2091
2092// #define O2_ZDC_DEBUG_CORR
2093
2094int DigiReco::correctTDCSignal(int itdc, int16_t TDCVal, float TDCAmp, float& fTDCVal, float& fTDCAmp, bool isbeg, bool isend)
2095{
2096 // Correction of single TDC signals
2097 // This function takes into account the position of the signal in the sequence
2098 // TDCVal is before recentering
2099 constexpr int TDCRange = TSN * NTimeBinsPerBC;
2100 constexpr int TDCMax = TDCRange - TSNH - 1;
2101
2102 // Fallback is no correction appliead
2103 fTDCVal = TDCVal;
2104 fTDCAmp = TDCAmp;
2105
2106 if (mTDCCorr == nullptr) {
2107#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
2108 printf("%21s itdc=%d TDC=%d AMP=%d MISSING mTDCCorr\n", __func__, itdc, TDCVal, TDCAmp);
2109#endif
2110 return 1;
2111 }
2112
2113 if (isbeg == false && isend == false) {
2114 // Mid bunch
2115 fTDCAmp = TDCAmp / mTDCCorr->mAFMidC[itdc][0];
2116 fTDCVal = TDCVal - mTDCCorr->mTSMidC[itdc][0];
2117 } else if (isbeg == true) {
2118 {
2119 auto p0 = mTDCCorr->mTSBegC[itdc][0];
2120 auto p1 = mTDCCorr->mTSBegC[itdc][1];
2121 if (TDCVal > TSNH && TDCVal < p0) {
2122 auto diff = TDCVal - p0;
2123 auto p2 = mTDCCorr->mTSBegC[itdc][2];
2124 auto p3 = mTDCCorr->mTSBegC[itdc][3];
2125 fTDCVal = TDCVal - (p1 + p2 * diff + p3 * diff * diff);
2126 } else {
2127 fTDCVal = TDCVal - p1;
2128 }
2129 }
2130 {
2131 auto p0 = mTDCCorr->mAFBegC[itdc][0];
2132 auto p1 = mTDCCorr->mAFBegC[itdc][1];
2133 if (TDCVal > TSNH && TDCVal < p0) {
2134 auto diff = TDCVal - p0;
2135 auto p2 = mTDCCorr->mAFBegC[itdc][2];
2136 auto p3 = mTDCCorr->mAFBegC[itdc][3];
2137 fTDCAmp = TDCAmp / (p1 + p2 * diff + p3 * diff * diff);
2138 } else {
2139 fTDCAmp = TDCAmp / p1;
2140 }
2141 }
2142 } else if (isend == true) {
2143 {
2144 auto p0 = mTDCCorr->mTSEndC[itdc][0];
2145 auto p1 = mTDCCorr->mTSEndC[itdc][1];
2146 if (TDCVal > p0 && TDCVal < TDCMax) {
2147 auto diff = TDCVal - p0;
2148 auto p2 = mTDCCorr->mTSEndC[itdc][2];
2149 auto p3 = mTDCCorr->mTSEndC[itdc][3];
2150 fTDCVal = TDCVal - (p1 + p2 * diff + p3 * diff * diff);
2151 } else {
2152 fTDCVal = TDCVal - p1;
2153 }
2154 }
2155 {
2156 auto p0 = mTDCCorr->mAFEndC[itdc][0];
2157 auto p1 = mTDCCorr->mAFEndC[itdc][1];
2158 if (TDCVal > p0 && TDCVal < TDCMax) {
2159 auto diff = TDCVal - p0;
2160 auto p2 = mTDCCorr->mAFEndC[itdc][2];
2161 auto p3 = mTDCCorr->mAFEndC[itdc][3];
2162 fTDCAmp = TDCAmp / (p1 + p2 * diff + p3 * diff * diff);
2163 } else {
2164 fTDCAmp = TDCAmp / p1;
2165 }
2166 }
2167 } else {
2168#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
2169 printf("%21s itdc=%d TDC=%d AMP=%d LONELY BUNCH\n", __func__, itdc, TDCVal, TDCAmp);
2170#endif
2171 return 1;
2172 }
2173 return 0;
2174} // correctTDCSignal
2175
2176int DigiReco::correctTDCBackground(int ibc, int itdc, std::deque<DigiRecoTDC>& tdc)
2177{
2178 constexpr int TDCRange = TSN * NTimeBinsPerBC;
2179 constexpr int BucketS = TDCRange / NBucket;
2180 constexpr int BucketSH = BucketS / 2;
2181 auto rec = &mReco[ibc];
2182 auto isig = TDCSignal[itdc];
2183 // With this function we are able to correct a single hit in a bunch
2184 // therefore we refer just to TDC hit in position [0]
2185 float TDCValUnc = rec->TDCVal[itdc][0];
2186 float TDCAmpUnc = rec->TDCAmp[itdc][0];
2187#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
2188 auto TDCValUncBck = rec->TDCVal[itdc][0];
2189 auto TDCAmpUncBck = rec->TDCAmp[itdc][0];
2190#endif
2191 float TDCValBest = TDCValUnc;
2192 float TDCAmpBest = TDCAmpUnc;
2193 int TDCSigBest = -1;
2194 float dtime = std::numeric_limits<float>::infinity();
2195 // Try every bucket position
2196 for (int ibuks = 0; ibuks < NBucket; ibuks++) {
2197 std::deque<DigiRecoTDC>::reverse_iterator rit = tdc.rbegin();
2198 // Correct amplitude
2199 float sum[3] = {0};
2200 // Loop on background signals to sum the effects on reconstructed amplitude
2201 int32_t nbkg = 0;
2202 for (rit = tdc.rbegin(); rit != tdc.rend(); ++rit) {
2203 auto bcd = (rec->ir).differenceInBC((*rit).ir);
2204 if (bcd > 0 && bcd <= NBCAn) {
2205 // Flag error if correction object does not exists
2206 if (mTDCCorr == nullptr) {
2207 if (bcd == 1) {
2208 rec->tdcPileM1E[isig] = true;
2209 } else if (bcd == 2) {
2210 rec->tdcPileM2E[isig] = true;
2211 } else if (bcd == 3) {
2212 rec->tdcPileM3E[isig] = true;
2213 }
2214 } else {
2215 int16_t TDCBkgVal = (*rit).val;
2216 int16_t TDCBkgAmp = (*rit).amp;
2217 // Get bucket number for background with floor division (divisor is positive)
2218 int arg1 = TDCBkgVal + BucketSH;
2219 int q1 = arg1 / BucketS;
2220 int r1 = arg1 % BucketS;
2221 if (r1 < 0) {
2222 q1--;
2223 r1 += TSN;
2224 }
2225 int arg2 = q1 + NBKZero;
2226 int q2 = arg2 / NBucket;
2227 int ibukb = arg2 % NBucket;
2228 if (ibukb < 0) {
2229 q2--;
2230 ibukb += NBucket;
2231 }
2232 // Correction parameters for amplitude
2233 int32_t ibun = NBCAn - bcd;
2234 auto p0 = mTDCCorr->mAmpCorr[itdc][ibun][ibukb][ibuks][0];
2235 auto p1 = mTDCCorr->mAmpCorr[itdc][ibun][ibukb][ibuks][1];
2236 auto p2 = mTDCCorr->mAmpCorr[itdc][ibun][ibukb][ibuks][2];
2237#ifdef O2_ZDC_DEBUG_CORR
2238 printf("%+e,%+e,%+e, // as%d_bc%+d_bk%d_sn%d\n", p0, p1, p2, itdc, -bcd, ibukb, ibuks);
2239#endif
2240 // Flag error if parameters are NaN
2241 if (std::isnan(p0) || std::isnan(p1) || std::isnan(p2)) {
2242 if (bcd == 1) {
2243 rec->tdcPileM1E[isig] = true;
2244 } else if (bcd == 2) {
2245 rec->tdcPileM2E[isig] = true;
2246 } else if (bcd == 3) {
2247 rec->tdcPileM3E[isig] = true;
2248 }
2249 } else {
2250 nbkg++;
2251 sum[0] += p0;
2252 sum[1] += p1;
2253 sum[2] += p2 * TDCBkgAmp;
2254 // Flag application of correction and flag error if
2255 // there are multiple signals in a bunch
2256 if (ibuks == 0) { // Make the test just once
2257 if (bcd == 1) {
2258 if (rec->tdcPileM1C[isig]) {
2259 rec->tdcPileM1E[isig] = true;
2260 } else {
2261 rec->tdcPileM1C[isig] = true;
2262 }
2263 } else if (bcd == 2) {
2264 if (rec->tdcPileM2C[isig]) {
2265 rec->tdcPileM2E[isig] = true;
2266 } else {
2267 rec->tdcPileM2C[isig] = true;
2268 }
2269 } else if (bcd == 3) {
2270 if (rec->tdcPileM3C[isig]) {
2271 rec->tdcPileM3E[isig] = true;
2272 } else {
2273 rec->tdcPileM3C[isig] = true;
2274 }
2275 }
2276 }
2277 }
2278 }
2279 }
2280 }
2281 if (mTDCCorr == nullptr) {
2282 // Cannot correct and error conditions has been already set above
2283 return 1;
2284 }
2285 if (nbkg > 0) { // Cross check.. should always be true
2286 float TDCAmpUpd = (TDCAmpUnc - sum[0] - sum[2]) / (1. - float(nbkg) + sum[1]);
2287 // Compute time correction assuming that time shift is additive
2288 float tshift = 0;
2289 for (rit = tdc.rbegin(); rit != tdc.rend(); ++rit) {
2290 auto bcd = (rec->ir).differenceInBC((*rit).ir);
2291 if (bcd > 0 && bcd <= NBCAn) {
2292 int16_t TDCBkgVal = (*rit).val;
2293 int16_t TDCBkgAmp = (*rit).amp;
2294 // Get bucket number for background with floor division (divisor is positive)
2295 int arg1 = TDCBkgVal + BucketSH;
2296 int q1 = arg1 / BucketS;
2297 int r1 = arg1 % BucketS;
2298 if (r1 < 0) {
2299 q1--;
2300 r1 += TSN;
2301 }
2302 int arg2 = q1 + NBKZero;
2303 int q2 = arg2 / NBucket;
2304 int ibukb = arg2 % NBucket;
2305 if (ibukb < 0) {
2306 q2--;
2307 ibukb += NBucket;
2308 }
2309 // Parameters for time correction
2310 int32_t ibun = NBCAn - bcd;
2311 auto p0 = mTDCCorr->mTDCCorr[itdc][ibun][ibukb][ibuks][0];
2312 auto p1 = mTDCCorr->mTDCCorr[itdc][ibun][ibukb][ibuks][1];
2313 auto p2 = mTDCCorr->mTDCCorr[itdc][ibun][ibukb][ibuks][2];
2314#ifdef O2_ZDC_DEBUG_CORR
2315 printf("%+e,%+e,%+e, // ts%d_bc%d_bk%d_sn%d\n", p0, p1, p2, itdc, -bcd, ibukb, ibuks);
2316#endif
2317 // Flag error if parameters are NaN
2318 if (std::isnan(p0) || std::isnan(p1)) {
2319 if (bcd == 1) {
2320 rec->tdcPileM1E[isig] = true;
2321 } else if (bcd == 2) {
2322 rec->tdcPileM2E[isig] = true;
2323 } else if (bcd == 3) {
2324 rec->tdcPileM3E[isig] = true;
2325 }
2326 } else {
2327 tshift += p0 + p1 / (TDCAmpUpd / TDCBkgAmp);
2328#ifdef O2_ZDC_DEBUG_CORR
2329 printf("ibuk = b.%d s.%d = %8.2f ts=%8.2f\n", ibukb, ibuks, TDCAmpUpd, TDCBkgAmp, tshift);
2330#endif
2331 }
2332 }
2333 }
2334 // Update signal arrival time
2335 float TDCValUpd = TDCValUnc - tshift;
2336 float TDCBucket = (ibuks - NBKZero) * BucketS;
2337 // Compare updated arrival time with assumed bucket assignment
2338 // Take into account the possibility that the TDC has been assigned to preceding
2339 // or successive bunch
2340 float mydtime = std::min(std::abs(TDCBucket - TDCValUpd), std::min(std::abs(TDCBucket - TDCValUpd - TDCRange), std::abs(TDCBucket - TDCValUpd + TDCRange)));
2341#ifdef O2_ZDC_DEBUG_CORR
2342 printf("ibuks = %d = %8.2f AS=%8.2f ts=%8.2f TDC %8.2f -> %8.2f delta=%8.2f\n", ibuks, TDCBucket, TDCAmpUpd, tshift, TDCValUnc, TDCValUpd, mydtime);
2343#endif
2344 if (mydtime < dtime) {
2345 dtime = mydtime;
2346 TDCValBest = TDCValUpd;
2347 TDCAmpBest = TDCAmpUpd;
2348 TDCSigBest = ibuks;
2349 }
2350 }
2351 } // Loop on signal bucket position (ibuks)
2352 rec->TDCVal[itdc][0] = TDCValBest;
2353 rec->TDCAmp[itdc][0] = TDCAmpBest;
2354#ifdef ALICEO2_ZDC_DIGI_RECO_DEBUG
2355 if (rec->TDCVal[itdc][0] != TDCValUnc || rec->TDCAmp[itdc][0] != TDCAmpUnc) {
2356 printf("%21s ibc=%d itdc=%d sn = %d", __func__, ibc, itdc, TDCSigBest);
2357 printf(" TDC=%f -> %f", TDCValUncBck, rec->TDCVal[itdc][0]);
2358 printf(" AMP=%f -> %f\n", TDCAmpUncBck, rec->TDCAmp[itdc][0]);
2359 }
2360#endif
2361 return 0;
2362}
2363} // namespace zdc
2364} // namespace o2
uint64_t orbit
Definition RawEventData.h:6
unsigned short int uint16_t
unsigned int uint32_t
std::vector< double > sum
int32_t i
Timeframe settings Average distance in cm of events merged into Randomize distance around average distance of merged events Simulate correct bunch interactions instead of placing only the average number of events A value[n] sets TFlen for[n] collisions in Number of bunches per trainsort Number of bunch trains Instantaneous interaction rate Do not simulate border Total number of collisions to be placed in the interior of all time Do not select random but walk over array of events in stride steps h Event generator settings h configStandalone Use CPU for GPU Force usage of the specified GPU device no CPU fallback Continue processing after an error s
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc Replace constant variables static by constexpr expressions Compile RTC in deterministic with NO_FAST_MATH flags and GPUCA_DETERMINISTIC_MODE define Use RTC to optimize GPU code h configStandalone Processing proc_rtctech Use a file lock to serialize access to the cache folder int32_t
configStandalone rec
configStandalone Reconstruction rec_tpc multiplier for the combined cluster track error during track following area in cm for the search of for z only used if decrease removal by when above this local occupancy rowx Shift of TPC revert cluster flag edge bit distance to edge exceeds this ZOffset for secondary multiple of radius max P of electron K BB bands crossing max P of electron p BB bands crossing max P of electron d BB bands crossing max P of electron t BB bands crossing min accepted dEdxMaxTPC of the track Additive extra cluster error for Y2 if edge flag set Additive extra cluster error for Y2 if single set Additive extra cluster error for Y2 if or single set Additive extra cluster error for Z2 if or single set Extra errors to add to track when crossing depending on addErrorsCECrossing Inner portion of y range in sector that is not used in searching for extrapolated track candidates factor2YS for track merging factor2K for track merging Margin in cm of Y position when rejecting edge clusters based on uncorrected track Y Max fraction of shared clusters for tracklet Except pad from cluster finding if total number of charges in a fragment is above this Except pad from cluster finding if number of consecutive charges in a fragment is above this Threshold where a timebin is considered disabling the noisy pad check for that pad Treat signal above this minimum as saturated Smoothing factor for the exponential Highly Ionising Particle tail filter Number of timebins to use for the averaging Add additional custom track errors when crossing relative as fraction of Do N fit passes in final fit of< 0:reject at max -n hits") AddOptionRTC(rejectIFCLowRadiusCluster, uint8_t, 1, "", 0, "Reject clusters that get the IFC mask error during refit") AddOptionRTC(dEdxTruncLow, uint8_t, 2, "", 0, "Low truncation threshold, fraction of 128") AddOptionRTC(dEdxTruncHigh, uint8_t, 77, "", 0, "High truncation threshold, fraction of 128") AddOptionRTC(extrapolationTracking, int8_t, 1, "", 0, "Enable Extrapolation Tracking(prolong tracks to adjacent sectors to find short segments)") AddOptionRTC(disableRefitAttachment, uint8_t, 0, "", 0, "Bitmask to disable certain attachment steps during refit(1:attachment, 2:propagation, 4:loop following, 8:mirroring)") AddOptionRTC(rejectionStrategy, uint8_t, o2::gpu::GPUSettings::RejectionStrategyA, "", 0, "Enable rejection of TPC clusters for compression(0=no, 1=strategy A, 2=strategy B)") AddOptionRTC(mergeLoopersAfterburner, uint8_t, 1, "", 0, "Run afterburner for additional looper merging") AddOptionRTC(compressionTypeMask, uint8_t, o2::gpu::GPUSettings::CompressionFull, "", 0, "TPC Compression mode bits(1=truncate charge/width LSB, 2=differences, 4=track-model)") AddOptionRTC(compressionSortOrder, uint8_t, o2::gpu::GPUSettings::SortTime, "", 0, "Sort order of TPC compression(0=time, 1=pad, 2=Z-time-pad, 3=Z-pad-time, 4=no sorting(use incoming order))") AddOptionRTC(sigBitsCharge, uint8_t, 4, "", 0, "Number of significant bits for TPC cluster charge in compression mode 1") AddOptionRTC(sigBitsWidth, uint8_t, 3, "", 0, "Number of significant bits for TPC cluster width in compression mode 1") AddOptionRTC(dropLoopers, uint8_t, 0, "", 0, "Drop looping tracks starting from second loop") AddOptionRTC(mergerInterpolateErrors, uint8_t, 1, "", 0, "Use interpolation instead of extrapolation for chi2 based cluster rejection") AddOptionRTC(mergerInterpolateRejectAlsoOnCurrentPosition, uint8_t, 1, "", 0, "When using mergerInterpolateErrors, reject based on chi2 twice computed with interpolated and current track position starting from NDF > mergerNonInterpolateRejectMinNDF Merge tracks accross the central electrode Enable PID response Add sub threshold clusters in TPC dEdx computation OR mask of TPC flags that will reject the cluster in alternative dEdx Reject edge clusters based on uncorrected track Y during track fit Increase decrease removal by when on this number of pads from the edge h configStandalone Reconstruction rec_trd Max chi2 for TRD tracklets to be matched to a track Chi2 cut for strict matching mode Number of sigmas for ITS TPC track time error estimate Addition to search road around track prolongation along Y in cm Optimal tracklet rphi resolution in maximum chi2 per attached tracklet for TRD tracks take into account the full likelihood of the slope including exponential tails Tracks with less attached tracklets are discarded after the tracking Post trigger Pile up integration time in BCs fits all iterations but the last one in projections Use material lookup table for TPC refit Apply workarounds to avoid cyclic merge should not be needed tpc dyn configStandalone Processing proc_rtc true
configStandalone Reconstruction rec_tpc float
constexpr int p2()
constexpr int p1()
constexpr to accelerate the coordinates changing
char error[CURL_ERROR_SIZE]
uint32_t j
Definition RawData.h:0
ZDC reconstruction parameters.
void prepareInterpolation()
Definition DigiReco.cxx:463
int process(const gsl::span< const o2::zdc::OrbitData > &orbitdata, const gsl::span< const o2::zdc::BCData > &bcdata, const gsl::span< const o2::zdc::ChannelData > &chdata)
Definition DigiReco.cxx:493
GLdouble n
Definition glcorearb.h:1982
const GLfloat * m
Definition glcorearb.h:4066
GLuint GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat GLfloat s1
Definition glcorearb.h:5034
GLint y
Definition glcorearb.h:270
GLuint GLfloat * val
Definition glcorearb.h:1582
GLint ref
Definition glcorearb.h:291
std::array< int, 23 > p3
std::array< int, 24 > p0
std::mt19937 mt(rd())
struct o2::upgrades_utils::@482 zdc
structure to keep FT0 information
constexpr int IdZNCSum
constexpr int IdZPC4
constexpr int IdZPA2
constexpr int NModules
Definition Constants.h:68
constexpr int IdZNA3
constexpr int IdZNA1
constexpr int DummyIntRange
Definition Constants.h:303
const int TDCSignal[NTDCChannels]
Definition Constants.h:181
constexpr int16_t Int16MaxVal
Definition Constants.h:56
constexpr int IdZPA1
constexpr int IdZPCSum
constexpr int IdZNC2
constexpr int IdZEM1
constexpr int NBucket
Definition Constants.h:119
constexpr std::array< int, 17 > ChTowerCalib
Definition Constants.h:290
constexpr float FInfty
Definition Constants.h:77
float O2_ZDC_DIGIRECO_FLT
Definition DigiReco.h:49
constexpr int NTimeBinsPerBC
Definition Constants.h:53
constexpr uint32_t ZDCRefInitVal
Definition Constants.h:91
constexpr int NChPerModule
Definition Constants.h:69
constexpr std::array< int, 10 > ChEnergyCalib
Definition Constants.h:286
constexpr int NTDCChannels
Definition Constants.h:90
constexpr int IdZNCC
constexpr int IdZPAC
const int SignalTDC[NChannels]
Definition Constants.h:195
constexpr int NChannels
Definition Constants.h:65
constexpr int IdZPC2
constexpr int NBCAn
Definition Constants.h:123
constexpr int NBCReadOut
Definition Constants.h:54
constexpr int IdZPA4
constexpr int DbgFull
Definition Constants.h:210
constexpr int NBKZero
Definition Constants.h:120
constexpr int IdZNC1
constexpr int IdZNC3
constexpr int TSN
Definition Constants.h:94
constexpr int IdZPCC
constexpr int ADCRange
Definition Constants.h:76
constexpr int NTS
Definition Constants.h:96
constexpr int IdZPC1
constexpr int IdZPA3
constexpr int DbgMinimal
Definition Constants.h:208
constexpr int IdZNC4
constexpr int IdZEM2
constexpr int IdZNA2
constexpr int TSL
Definition Constants.h:93
constexpr int DbgZero
Definition Constants.h:207
constexpr int IdZNASum
constexpr int IdDummy
constexpr int ADCMin
Definition Constants.h:76
constexpr int IdZPC3
constexpr int MaxTDCValues
Definition Constants.h:89
constexpr int IdZNA4
constexpr int IdZNAC
constexpr std::string_view ChannelNames[]
Definition Constants.h:147
constexpr int DbgMedium
Definition Constants.h:209
constexpr int TSNH
Definition Constants.h:95
constexpr int ADCMax
Definition Constants.h:76
constexpr int IdZPASum
constexpr float FTDCVal
Definition Constants.h:103
constexpr std::array< int, NChannels > CaloCommonPM
Definition Constants.h:296
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
uint32_t orbit
LHC orbit.
void print(bool printall=true) const
float getCalib(uint32_t ich) const
uint32_t getTriggerMask() const
std::array< Module, MaxNModules > modules
int32_t beg_ped_int[NChannels]
float ped_thr_hi[NChannels]
int32_t beg_int[NChannels]
int32_t tsh[NTDCChannels]
int32_t tth[NTDCChannels]
int32_t end_int[NChannels]
float ped_thr_lo[NChannels]
int32_t end_ped_int[NChannels]
int tdc_search[NTDCChannels]
int32_t amod[NChannels]
float energy_calib[NChannels]
float tdc_shift[NTDCChannels]
int32_t tmod[NTDCChannels]
float tdc_calib[NTDCChannels]
float ped_thr_hi[NChannels]
float adc_offset[NChannels]
float tdc_offset[NTDCChannels]
int32_t ach[NChannels]
int32_t end_int[NChannels]
bool bitset[NTDCChannels]
float tdc_search[NTDCChannels]
int32_t tsh[NTDCChannels]
int32_t beg_int[NChannels]
float ped_thr_lo[NChannels]
int32_t tth[NTDCChannels]
int32_t end_ped_int[NChannels]
float tower_calib[NChannels]
int32_t tch[NTDCChannels]
int32_t beg_ped_int[NChannels]
float energy_calib[NChannels]
float adc_offset[NChannels]
std::array< std::array< std::array< std::array< std::array< float, NFParA >, NBucket >, NBucket >, NBCAn >, NTDCChannels > mAmpCorr
Definition ZDCTDCCorr.h:33
std::array< std::array< float, NParExtC >, NTDCChannels > mTSBegC
Definition ZDCTDCCorr.h:35
std::array< std::array< float, NParExtC >, NTDCChannels > mTSEndC
Definition ZDCTDCCorr.h:37
std::array< std::array< std::array< std::array< std::array< float, NFParT >, NBucket >, NBucket >, NBCAn >, NTDCChannels > mTDCCorr
Definition ZDCTDCCorr.h:32
std::array< std::array< float, NParMidC >, NTDCChannels > mAFMidC
Definition ZDCTDCCorr.h:39
void print() const
std::array< std::array< float, NParExtC >, NTDCChannels > mAFEndC
Definition ZDCTDCCorr.h:40
std::array< std::array< float, NParMidC >, NTDCChannels > mTSMidC
Definition ZDCTDCCorr.h:36
std::array< std::array< float, NParExtC >, NTDCChannels > mAFBegC
Definition ZDCTDCCorr.h:38
static void print()
Definition ZDCTDCData.h:35
float getOffset(uint32_t ich) const
float getFactor(uint32_t ich) const
float getShift(uint32_t ich) const
float tower_calib[NChannels]
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
std::vector< ChannelData > channels
uint64_t const void const *restrict const msg
Definition x9.h:153