Project
Loading...
Searching...
No Matches
WaveformCalibQueue.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 "Framework/Logger.h"
14
15namespace o2
16{
17namespace zdc
18{
19
21{
22 mCfg = cfg;
23 int ifirst = mCfg->getFirst();
24 int ilast = mCfg->getLast();
25 if (ifirst > 0 || ilast < 0 || ilast < ifirst) {
26 LOGF(fatal, "WaveformCalibQueue configure error with ifirst=%d ilast=%d", ifirst, ilast);
27 }
28 mFirst = ifirst;
29 mLast = ilast;
30 mN = ilast - ifirst + 1;
31 mPk = -mFirst;
32 mPeak = peak(mPk);
33 mNP = mN * NIS;
34 for (int32_t isig = 0; isig < NChannels; isig++) {
35 mTimeLow[isig] = std::nearbyint(cfg->cutTimeLow[SignalTDC[isig]] / FTDCVal);
36 mTimeHigh[isig] = std::nearbyint(cfg->cutTimeHigh[SignalTDC[isig]] / FTDCVal);
37 }
38}
39
40// appends an event to the queue with the request that there are at most
41// mN consecutive bunches
42// The TDC conditions are checked and returned in output
44{
45 auto& toadd = ev.ir;
46 // If queue is empty insert event
47 if (mIR.size() == 0) {
48 appendEv(ev);
49 return 0;
50 }
51 // Check last element
52 auto& last = mIR.back();
53 // If BC are not consecutive, clear queue
54 if (toadd.differenceInBC(last) > 1) {
55#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
56 LOG(info) << "WaveformCalibQueue::" << __func__ << " gap detected. Clearing " << mIR.size() << " bc";
57#endif
58 clear();
59 }
60 // If queue is not empty and is too long remove first element
61 while (mIR.size() >= mN) {
62 pop();
63 }
64 // If BC are consecutive or cleared queue append element
65 appendEv(ev);
66 if (mIR.size() == mN) {
67#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
68 LOG(info) << "WaveformCalibQueue::" << __func__ << " processing " << mIR.size() << " bcs";
69#endif
70 uint32_t mask = 0;
71 for (int32_t itdc = 0; itdc < NTDCChannels; itdc++) {
72 // Check which channels satisfy the condition on TDC
73 bool tdccond = true;
74 for (int i = 0; i < mN; i++) {
75 int n = mNTDC[itdc].at(i);
76 if (i == mPk) {
77 if (n != 1) {
78 tdccond = false;
79 break;
80 } else {
81 auto tdca = mTDCA[itdc].at(i);
82 auto tdcv = mTDCP[itdc].at(i);
83 if (tdca < mCfg->cutLow[itdc] || tdca > mCfg->cutHigh[itdc] || tdcv < mCfg->cutTimeLow[itdc] || tdcv > mCfg->cutTimeHigh[itdc]) {
84 tdccond = false;
85 break;
86 }
87 }
88 } else {
89 if (n != 0) {
90 tdccond = false;
91 break;
92 }
93 }
94 }
95 if (tdccond) {
96 mask = mask | (0x1 << itdc);
97 }
98 }
99 return mask;
100 } else {
101 // #ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
102 // LOG(info) << "WaveformCalibQueue::" << __func__ << " IR size = " << mIR.size() << " != " << mN;
103 // #endif
104 return 0;
105 }
106}
107
109{
110#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
111 LOGF(info, "WaveformCalibQueue::%s %u.%04u", __func__, ev.ir.orbit, ev.ir.bc);
112#endif
113 mIR.push_back(ev.ir);
114 mEntry.push_back(ev.getNextEntry() - 1);
115
116 auto& curb = ev.getCurB();
117 int firstw, nw;
118 curb.getRefW(firstw, nw);
119 mFirstW.push_back(firstw);
120 mNW.push_back(nw);
121
122 // Note: pile-up messages are computed only for the 10 TDCs
123 for (int isig = 0; isig < NChannels; isig++) {
124 mHasInfos[isig].push_back(false);
125 }
126 if (ev.getNInfo() > 0) {
127 // Need clean data (no messages)
128 auto& decodedInfo = ev.getDecodedInfo();
129 for (uint16_t info : decodedInfo) {
130 uint8_t ch = (info >> 10) & 0x1f;
131 uint16_t code = info & 0x03ff;
132 auto& last = mHasInfos[ch].back();
133 last = true;
134 }
135 // if (mVerbosity > DbgMinimal) {
136 // ev.print();
137 // }
138 }
139 // TDC channels are used to select reconstructed waveforms
140 for (int32_t itdc = 0; itdc < NTDCChannels; itdc++) {
141 int ich = o2::zdc::TDCSignal[itdc];
142 int nhit = ev.NtdcV(itdc);
143 if (ev.NtdcA(itdc) != nhit) {
144 LOGF(error, "Mismatch in TDC %d data Val=%d Amp=%d\n", itdc, ev.NtdcV(itdc), ev.NtdcA(ich));
145 mNTDC[itdc].push_back(0);
146 mTDCA[itdc].push_back(0);
147 mTDCP[itdc].push_back(0);
148 } else if (nhit == 0) {
149 mNTDC[itdc].push_back(0);
150 mTDCA[itdc].push_back(0);
151 mTDCP[itdc].push_back(0);
152 } else {
153 // Store single TDC entry
154 mNTDC[itdc].push_back(nhit);
155 mTDCA[itdc].push_back(ev.tdcA(itdc, 0));
156 mTDCP[itdc].push_back(ev.tdcV(itdc, 0));
157 }
158 }
159}
160
161int WaveformCalibQueue::hasData(int isig, const gsl::span<const o2::zdc::ZDCWaveform>& wave)
162{
163 int ipk = -1;
164 int ipkb = -1;
165 float min = std::numeric_limits<float>::infinity();
166 for (int ib = 0; ib < mN; ib++) {
167 int ifound = false;
168#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
169 LOG(info) << "WaveformCalibQueue::" << __func__ << " mNW[" << ib << "] = " << mNW[ib] << " mFirstW = " << mFirstW[ib];
170#endif
171 for (int iw = 0; iw < mNW[ib]; iw++) {
172 auto& mywave = wave[iw + mFirstW[ib]];
173 if (mywave.ch() == isig) {
174 ifound = true;
175 for (int ip = 0; ip < NIS; ip++) {
176 if (mywave.inter[ip] < min) {
177 ipkb = ib;
178 ipk = ip;
179 min = mywave.inter[ip];
180 }
181 }
182 }
183 }
184 // Need to have consecutive data for all bunches
185 if (!ifound) {
186 return -1;
187 }
188 }
189 if (ipkb != mPk) {
190 return -1;
191 } else {
192 int ipos = NTimeBinsPerBC * TSN * ipkb + ipk;
193#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
194 LOG(info) << "WaveformCalibQueue::" << __func__ << " isig = " << isig << " ipkb " << ipkb << " ipk " << ipk << " min " << min;
195#endif
196 return ipos;
197 }
198}
199
200// Checks if waveform has available data and adds it to summary data
201// a compensation of the time jitter
202int WaveformCalibQueue::addData(int isig, const gsl::span<const o2::zdc::ZDCWaveform>& wave, WaveformCalibData& data)
203{
204#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
205 LOG(info) << "WaveformCalibQueue::" << __func__ << " isig=" << isig << " " << ChannelNames[isig] << " tdcid=" << SignalTDC[isig] << " tdc_sig=" << TDCSignal[SignalTDC[isig]] << " " << ChannelNames[TDCSignal[SignalTDC[isig]]];
206#endif
207 int ipkb = -1; // Bunch where peak is found
208 int ipk = -1; // peak position within bunch
209 float min = std::numeric_limits<float>::infinity();
210 float max = -std::numeric_limits<float>::infinity();
211 bool hasInfos = false;
212 for (int ib = 0; ib < mN; ib++) {
213 bool ifound = false;
214 // #ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
215 // LOG(info) << "mNW[" << ib << "/" << mN << "] = " << mNW[ib] << " mFirstW = " << mFirstW[ib];
216 // #endif
217 if (mHasInfos[isig][ib] || mHasInfos[TDCSignal[SignalTDC[isig]]][ib]) {
218#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
219 LOG(info) << "HasInfos on ib = " << ib << " tdcid=" << SignalTDC[isig] << " tdc_sig=" << TDCSignal[SignalTDC[isig]] << " " << mHasInfos[isig][ib] << " " << mHasInfos[TDCSignal[SignalTDC[isig]]][ib];
220#endif
221 hasInfos = true;
222 }
223 for (int iw = 0; iw < mNW[ib]; iw++) {
224 // Signal shouldn't have info messages. We check also corresponding TDC signal for pile-up information
225 // TODO: relax this condition to avoid to check pedestal messages since pedestal is subtracted
226 // when converting waveform calibration object into SimConfig object
227 auto& mywave = wave[iw + mFirstW[ib]];
228 if (mywave.ch() == isig) {
229 ifound = true;
230 for (int ip = 0; ip < NIS; ip++) {
231 if (mywave.inter[ip] < min) {
232 ipkb = ib;
233 ipk = ip;
234 min = mywave.inter[ip];
235 }
236 if (mywave.inter[ip] > max) {
237 max = mywave.inter[ip];
238 }
239 }
240 }
241 }
242#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
243 LOG(info) << " isig=" << isig << " mNW[" << ib << "] = " << mNW[ib] << " mFirstW = " << mFirstW[ib] << " ifound=" << ifound << " hasInfos=" << hasInfos;
244#endif
245 // Need to have consecutive data for all bunches
246 if (!ifound || hasInfos) {
247 return -1;
248 }
249 }
250 if (ipkb != mPk) {
251#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
252 LOG(info) << " isig = " << isig << " ipkb " << ipkb << " != mPk " << mPk << " SKIP";
253#endif
254 return -1;
255 } else {
256#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
257 LOG(info) << " isig = " << isig << " ADDING DATA";
258#endif
259 int ppos = NIS * ipkb + ipk;
260 int itdc = SignalTDC[isig];
261 if (isig != TDCSignal[itdc]) {
262 // Additional checks for towers
263 float amp = max - min;
264 if (amp < mCfg->cutLow[isig] || amp > mCfg->cutHigh[isig]) {
265 // No warning messages for amplitude cuts on towers
266#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
267 LOG(info) << " isig = " << isig << " amplitude " << amp << " not in range " << mCfg->cutLow[isig] << " : " << mCfg->cutHigh[isig];
268#endif
269 return -1;
270 }
271 if ((ppos - mPeak) < mTimeLow[itdc] || (ppos - mPeak) > mTimeHigh[itdc]) {
272 if (mVerbosity > DbgMinimal) {
273 // Put a warning message for a signal out of time
274 LOGF(warning, "%d.%04d Signal %2d peak position %d-%d=%d is outside allowed range [%d:%d]", mIR[mPk].orbit, mIR[mPk].bc, isig, ppos, mPeak, ppos - mPeak, mTimeLow[isig], mTimeHigh[isig]);
275 }
276 return -1;
277 }
278 }
279 int ipos = mPeak - ppos;
280 data.addEntry(isig);
281 // Restrict validity range because of signal jitter
282 data.setFirstValid(isig, ipos);
283 // We know that points are consecutive
284 for (int ib = 0; ib < mN; ib++) {
285 for (int iw = 0; iw < mNW[ib]; iw++) {
286 auto& mywave = wave[iw + mFirstW[ib]];
287 if (mywave.ch() == isig) {
288 for (int ip = 0; ip < NIS; ip++) {
289 if (ipos >= 0 && ipos < mNP) {
290 // We don't use incapsulation because this section is called too many times
291 data.mWave[isig].mData[ipos] += mywave.inter[ip];
292 }
293 ipos++;
294 }
295 }
296 }
297 }
298 ipos--;
299 // Restrict validity range because of signal jitter
300 data.setLastValid(isig, ipos);
301#ifdef O2_ZDC_WAVEFORMCALIB_DEBUG
302 LOG(info) << "WaveformCalibQueue::" << __func__ << " isig = " << isig << " ipkb " << ipkb << " ipk " << ipk << " min " << min << " range=[" << data.getFirstValid(isig) << ":" << ppos << ":" << data.getLastValid(isig) << "]";
303#endif
304 return ipos;
305 }
306}
307
309{
310 int n = mIR.size();
311 printf("WaveformCalibQueue::print() %d consecutive bunches\n", n);
312 for (int i = 0; i < n; i++) {
313 printf("%d.%04d mEntry=%d mFirstW=%d mNW=%d waveforms\n", mIR[i].orbit, mIR[i].bc, mEntry[i], mFirstW[i], mNW[i]);
314 bool printed = false;
315 for (int j = 0; j < NChannels; j++) {
316 if (mHasInfos[j][i] != 0) {
317 if (!printed) {
318 printf("mHasInfos:");
319 printed = true;
320 }
321 printf(" %2d=%d", j, mHasInfos[j][i] != 0);
322 }
323 }
324 if (printed) {
325 printf("\n");
326 printed = false;
327 }
328 for (int j = 0; j < NTDCChannels; j++) {
329 if (mNTDC[j][i] > 0) {
330 if (!printed) {
331 printf("mNTDC:");
332 printed = true;
333 }
334 printf(" %2d=%6u", j, mNTDC[j][i]);
335 }
336 }
337 if (printed) {
338 printf("\n");
339 printed = false;
340 }
341 for (int j = 0; j < NTDCChannels; j++) {
342 if (mNTDC[j][i] > 0) {
343 if (!printed) {
344 printf("mTDCA:");
345 printed = true;
346 }
347 printf(" %2d=%6.1f", j, mTDCA[j][i]);
348 }
349 }
350 if (printed) {
351 printf("\n");
352 printed = false;
353 }
354 for (int j = 0; j < NTDCChannels; j++) {
355 if (mNTDC[j][i] > 0) {
356 if (!printed) {
357 printf("mTDCP:");
358 printed = true;
359 }
360 printf(" %2d=%6.1f", j, mTDCP[j][i]);
361 }
362 }
363 if (printed) {
364 printf("\n");
365 }
366 }
367}
368
370{
371 LOG(info) << "WaveformCalibQueue::" << __func__;
372 LOGF(info, "mFirst=%d mLast=%d mPk=%d mN=%d mPeak=%d/mNP=%d", mFirst, mLast, mPk, mN, mPeak, mNP);
373 for (int isig = 0; isig < NChannels; isig++) {
374 LOGF(info, "ch%02d pos [%d:%d]", isig, mTimeLow[isig], mTimeHigh[isig]);
375 }
376}
377
378} // namespace zdc
379} // namespace o2
uint64_t orbit
Definition RawEventData.h:6
uint64_t bc
Definition RawEventData.h:5
int32_t i
uint32_t j
Definition RawData.h:0
Waveform calibration intermediate data queue.
GLdouble n
Definition glcorearb.h:1982
GLboolean * data
Definition glcorearb.h:298
GLint GLuint mask
Definition glcorearb.h:291
struct o2::upgrades_utils::@463 zdc
structure to keep FT0 information
const int TDCSignal[NTDCChannels]
Definition Constants.h:181
constexpr int NTimeBinsPerBC
Definition Constants.h:53
constexpr int NTDCChannels
Definition Constants.h:90
const int SignalTDC[NChannels]
Definition Constants.h:195
constexpr int NChannels
Definition Constants.h:65
constexpr int TSN
Definition Constants.h:94
constexpr int DbgMinimal
Definition Constants.h:208
constexpr int NIS
Definition Constants.h:97
constexpr std::string_view ChannelNames[]
Definition Constants.h:147
constexpr float FTDCVal
Definition Constants.h:103
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
uint32_t orbit
LHC orbit.
uint16_t bc
bunch crossing ID of interaction
void getRefW(int &firstw, int &nw)
Definition BCRecData.h:130
BCRecData & getCurB()
int NtdcV(uint8_t ich) const
float tdcV(uint8_t ich, uint64_t ipos) const
o2::InteractionRecord ir
float tdcA(uint8_t ich, uint64_t ipos) const
int NtdcA(uint8_t ich) const
const std::vector< uint16_t > & getDecodedInfo()
NElem getNInfo() const
double cutTimeHigh[NTDCChannels]
TDC cut low.
double cutHigh[NChannels]
Amplitude cut low.
double cutTimeLow[NTDCChannels]
Minimum entries to compute waveform.
const WaveformCalibConfig * mCfg
int addData(int isig, const gsl::span< const o2::zdc::ZDCWaveform > &wave, WaveformCalibData &data)
std::deque< int32_t > mFirstW
std::deque< float > mTDCP[NTDCChannels]
int mTimeHigh[NChannels]
Cut on position difference low.
void appendEv(RecEventFlat &ev)
int mVerbosity
Cut on position difference high.
std::deque< o2::InteractionRecord > mIR
std::deque< uint32_t > mNTDC[NTDCChannels]
uint32_t append(RecEventFlat &ev)
std::deque< float > mTDCA[NTDCChannels]
std::deque< bool > mHasInfos[NChannels]
int hasData(int isig, const gsl::span< const o2::zdc::ZDCWaveform > &wave)
std::deque< int32_t > mEntry
void configure(const WaveformCalibConfig *cfg)
constexpr size_t min
constexpr size_t max
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"