Project
Loading...
Searching...
No Matches
Digits2Raw.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 <string>
13#include <TFile.h>
14#include <TTree.h>
15#include <TRandom.h>
16#include <TMath.h>
17#include "ZDCBase/Constants.h"
23#include "Framework/Logger.h"
24
25using namespace o2::zdc;
26
27//______________________________________________________________________________
28void Digits2Raw::processDigits(const std::string& outDir, const std::string& fileDigitsName)
29{
30 auto& sopt = ZDCSimParam::Instance();
31 mIsContinuous = sopt.continuous;
32
33 if (!mModuleConfig) {
34 LOG(fatal) << "Missing ModuleConfig configuration object";
35 return;
36 }
37
38 if (!mSimCondition) {
39 LOG(fatal) << "Missing SimCondition configuration object";
40 return;
41 }
42
43 if (mNEmpty < 0) {
44 LOG(fatal) << "Bunch crossing map is not initialized";
45 return;
46 }
47
48 if (mNEmpty == 0) {
49 LOG(warning) << "Bunch crossing map has zero clean empty bunches";
50 }
51
52 setTriggerMask();
53
54 std::string outd = outDir;
55 if (outd.back() != '/') {
56 outd += '/';
57 }
58
59 mLinkID = uint32_t(0);
60 mCruID = uint16_t(0);
61 mFLPID = uint16_t(0);
62 mEndPointID = uint32_t(0);
63 // TODO: assign FeeID from configuration object
64 // N.B. Now the electronics has the possibility to reconfigure FEE ID in order to match
65 // what is expected from simulation. The FEE ID should never change in the future
66 for (int ilink = 0; ilink < NLinks; ilink++) {
67 uint64_t FeeID = uint64_t(ilink);
68 std::string outFileLink = o2::utils::Str::concat_string(outDir, "/", "ZDC");
69 if (mFileFor != "all") {
70 outFileLink += fmt::format("_{}", mFLP);
71 if (mFileFor != "flp") {
72 outFileLink += fmt::format("_cru{}_{}", mCruID, mEndPointID);
73 if (mFileFor != "cruendpoint") {
74 outFileLink += fmt::format("_lnk{}_feeid{}", ilink, FeeID);
75 if (mFileFor != "link") {
76 LOG(fatal) << "Not supported output file splitting: " << mFileFor;
77 throw std::runtime_error("invalid option provided for file grouping");
78 }
79 }
80 }
81 }
82 outFileLink += ".raw";
83 mWriter.registerLink(FeeID, mCruID, mLinkID, mEndPointID, outFileLink);
84 }
85
86 std::unique_ptr<TFile> digiFile(TFile::Open(fileDigitsName.c_str()));
87 if (!digiFile || digiFile->IsZombie()) {
88 LOG(fatal) << "Failed to open input digits file " << fileDigitsName;
89 return;
90 }
91
92 TTree* digiTree = (TTree*)digiFile->Get("o2sim");
93 if (!digiTree) {
94 LOG(fatal) << "Failed to get digits tree";
95 return;
96 }
97
98 if (digiTree->GetBranch("ZDCDigitBC")) {
99 digiTree->SetBranchAddress("ZDCDigitBC", &mzdcBCDataPtr);
100 } else {
101 LOG(fatal) << "Branch ZDCDigitBC is missing";
102 return;
103 }
104
105 if (digiTree->GetBranch("ZDCDigitCh")) {
106 digiTree->SetBranchAddress("ZDCDigitCh", &mzdcChDataPtr);
107 } else {
108 LOG(fatal) << "Branch ZDCDigitCh is missing";
109 return;
110 }
111
112 if (digiTree->GetBranch("ZDCDigitOrbit")) {
113 digiTree->SetBranchAddress("ZDCDigitOrbit", &mzdcPedDataPtr);
114 } else {
115 LOG(fatal) << "Branch ZDCDigitOrbit is missing";
116 return;
117 }
118
119 if (digiTree->GetBranchStatus("ZDCDigitLabels")) {
120 digiTree->SetBranchStatus("ZDCDigitLabel*", 0);
121 }
122 int nBCadd = 0;
123 // TODO: fix the conversion logic
124 // If first stored bunch is not in first digitized orbit the empty orbits
125 // at the beginning of the simulation are not converted to raw data
126 // If last orbits are empty they are not inserted in raw data
127 // Logic is not tested if digiTree has more than one entry
128 // The resulting file has less orbits. However the missing orbits have no signals
129 // and threefore are not used in reconstruction -> this fix has low priority
130 for (int ient = 0; ient < digiTree->GetEntries(); ient++) {
131 digiTree->GetEntry(ient);
132 mNbc = mzdcBCData.size();
133 if (mVerbosity > 0) {
134 LOG(info) << "Entry " << ient << ": processing " << mNbc << " BCs stored";
135 }
136 for (int ibc = 0; ibc < mNbc; ibc++) {
137 mBCD = mzdcBCData[ibc];
138 convertDigits(ibc);
139 writeDigits();
140 // Detect last event or orbit change and insert last bunch
141 if (ibc == (mNbc - 1)) {
142 // For last event we need to close last orbit (if it is needed)
143 if (mzdcBCData[ibc].ir.bc != 3563) {
144 if (mVerbosity > 1) {
145 LOG(info) << "Closing last orbit " << mzdcBCData[ibc].ir.orbit;
146 }
147 insertLastBunch(ibc, mzdcBCData[ibc].ir.orbit);
148 writeDigits();
149 nBCadd++;
150 }
151 } else {
152 auto this_orbit = mzdcBCData[ibc].ir.orbit;
153 auto next_orbit = mzdcBCData[ibc + 1].ir.orbit;
154 // If current bunch is last bunch in the orbit we don't insert it again
155 if (mzdcBCData[ibc].ir.bc == 3563) {
156 this_orbit = this_orbit + 1;
157 }
158 // We may need to insert more than one orbit
159 for (auto orbit = this_orbit; orbit < next_orbit; orbit++) {
160 if (mVerbosity > 1) {
161 LOG(info) << "Inserting last bunch for orbit " << orbit;
162 }
163 insertLastBunch(ibc, orbit);
164 writeDigits();
165 nBCadd++;
166 }
167 }
168 }
169 LOG(info) << "Entry " << ient << " Converted BCs: " << mNbc << " + added@3563:" << nBCadd << " = " << mNbc + nBCadd;
170 }
171 digiFile->Close();
172}
173
174//______________________________________________________________________________
175void Digits2Raw::setTriggerMask()
176{
177 mTriggerMask = 0;
178 mPrintTriggerMask = "";
179 for (int32_t im = 0; im < NModules; im++) {
180 if (im > 0) {
181 mPrintTriggerMask += " ";
182 }
183 mPrintTriggerMask += std::to_string(im);
184 mPrintTriggerMask += "[";
185 for (uint32_t ic = 0; ic < NChPerModule; ic++) {
186 if (mModuleConfig->modules[im].trigChannel[ic]) {
187 uint32_t tmask = 0x1 << (im * NChPerModule + ic);
188 mTriggerMask = mTriggerMask | tmask;
189 mPrintTriggerMask += "T";
190 } else {
191 mPrintTriggerMask += " ";
192 }
193 }
194 mPrintTriggerMask += "]";
195#ifdef O2_ZDC_DEBUG
196 uint32_t mytmask = mTriggerMask >> (im * NChPerModule);
197 printf("Trigger mask for module %d 0123 %s%s%s%s\n", im,
198 mytmask & 0x1 ? "T" : "N",
199 mytmask & 0x2 ? "T" : "N",
200 mytmask & 0x4 ? "T" : "N",
201 mytmask & 0x8 ? "T" : "N");
202#endif
203 }
204 printf("trigger_mask=0x%08x %s", mTriggerMask, mPrintTriggerMask.data());
205}
206
207//______________________________________________________________________________
208inline void Digits2Raw::resetSums(uint32_t orbit)
209{
210 for (int32_t im = 0; im < NModules; im++) {
211 for (int32_t ic = 0; ic < NChPerModule; ic++) {
212 mScalers[im][ic] = 0;
213 mSumPed[im][ic] = 0;
214 mPed[im][ic] = 0;
215 }
216 }
217 mLatestOrbit = orbit;
218 mLastNEmpty = 0;
219}
220
221//______________________________________________________________________________
222inline void Digits2Raw::updatePedestalReference(int bc)
223{
224 // Compute or update baseline reference
225 // In the last BC we copy what is stored in the digits
226 if (bc == 3563) {
227 int io = 0;
228 for (; io < mzdcPedData.size(); io++) {
229 uint32_t orbit = mBCD.ir.orbit;
230 if (orbit == mzdcPedData[io].ir.orbit) {
231 break;
232 }
233 }
234 if (io == mzdcPedData.size()) {
235 LOG(fatal) << "Cannot find orbit";
236 }
237 for (int32_t im = 0; im < NModules; im++) {
238 for (int32_t ic = 0; ic < NChPerModule; ic++) {
239 // Identify connected channel
240 auto id = mModuleConfig->modules[im].channelID[ic];
241 mPed[im][ic] = *((uint16_t*)&mzdcPedData[io].data[id]);
242 }
243 }
244 } else if (mEmpty[bc] > 0 && mEmpty[bc] != mLastNEmpty) {
245 // For the preceding bunch crossing we make-up the fields in a random walk
246 // fashion like in the hardware. The result however cannot be coherent with
247 // what is stored in the last bunch
248 for (int32_t im = 0; im < NModules; im++) {
249 for (int32_t ic = 0; ic < NChPerModule; ic++) {
250 // Identify connected channel
251 auto id = mModuleConfig->modules[im].channelID[ic];
252 auto base_m = mSimCondition->channels[id].pedestal; // Average pedestal
253 auto base_s = mSimCondition->channels[id].pedestalFluct; // Baseline oscillations
254 auto base_n = mSimCondition->channels[id].pedestalNoise; // Electronic noise
255 double deltan = mEmpty[bc] - mLastNEmpty;
256 // We assume to have a fluctuation every two bunch crossings
257 // Will need to tune this parameter
258 double k = 2.;
259 mSumPed[im][ic] += gRandom->Gaus(12. * deltan * base_m, 12. * k * base_s * TMath::Sqrt(deltan / k));
260 // Adding in quadrature the RMS of pedestal electronic noise
261 mSumPed[im][ic] += gRandom->Gaus(0, base_n * TMath::Sqrt(12. * deltan));
262 double myped = mSumPed[im][ic] / double(mEmpty[bc]) / 12.; // Average current pedestal
263 myped = TMath::Nint(myped / mModuleConfig->baselineFactor); // Convert into digitized pedestal
264 int16_t theped = myped;
265 // Correct for overflow and underflow
266 if (myped < -32768) {
267 theped = -32768;
268 }
269 if (myped > 32767) {
270 myped = 32767;
271 }
272 mPed[im][ic] = *((uint16_t*)&theped);
273 }
274 }
275 mLastNEmpty = mEmpty[bc];
276 }
277}
278
279//______________________________________________________________________________
280inline void Digits2Raw::resetOutputStructure(uint16_t bc, uint32_t orbit, bool is_dummy)
281{
282 // Increment scalers and reset output structure
283 for (uint32_t im = 0; im < NModules; im++) {
284 for (uint32_t ic = 0; ic < NChPerModule; ic++) {
285 // Fixed words
286 mZDC.data[im][ic].w[0][0] = Id_w0;
287 mZDC.data[im][ic].w[0][1] = 0;
288 mZDC.data[im][ic].w[0][2] = 0;
289 mZDC.data[im][ic].w[0][3] = 0;
290 mZDC.data[im][ic].w[1][0] = Id_w1;
291 mZDC.data[im][ic].w[1][1] = 0;
292 mZDC.data[im][ic].w[1][2] = 0;
293 mZDC.data[im][ic].w[1][3] = 0;
294 mZDC.data[im][ic].w[2][0] = Id_w2;
295 mZDC.data[im][ic].w[2][1] = 0;
296 mZDC.data[im][ic].w[2][2] = 0;
297 mZDC.data[im][ic].w[2][3] = 0;
298 // Module and channel numbers
299 mZDC.data[im][ic].f.board = im;
300 mZDC.data[im][ic].f.ch = ic;
301 // Orbit and bunch crossing
302 mZDC.data[im][ic].f.orbit = orbit;
303 mZDC.data[im][ic].f.bc = bc;
304 // If channel is hit in current bunch crossing
305 if (!is_dummy) {
306 if (mBCD.triggers & (0x1 << (im * NChPerModule + ic))) {
307 mScalers[im][ic]++; // increment scalers
308 mZDC.data[im][ic].f.Hit = 1; // flag bunch crossing
309 }
310 }
311 mZDC.data[im][ic].f.hits = mScalers[im][ic];
312 mZDC.data[im][ic].f.offset = mPed[im][ic];
313 }
314 }
315}
316
317//______________________________________________________________________________
318inline void Digits2Raw::assignTriggerBits(int ibc, uint16_t bc, uint32_t orbit, bool is_dummy)
319{
320 // Triggers refer to the HW trigger conditions (32 possible channels)
321 // Autotrigger, current bunch crossing
322 ModuleTriggerMapData triggers;
323 // Autotrigger and ALICE trigger bits are zero for a dummy bunch crossing
324 if (!is_dummy) {
325 for (uint32_t im = 0; im < NModules; im++) {
326 triggers.w = mzdcBCData[ibc].moduleTriggers[im];
327 for (uint32_t ic = 0; ic < NChPerModule; ic++) {
328 mZDC.data[im][ic].f.Alice_0 = triggers.f.Alice_0;
329 mZDC.data[im][ic].f.Alice_1 = triggers.f.Alice_1;
330 mZDC.data[im][ic].f.Alice_2 = triggers.f.Alice_2;
331 mZDC.data[im][ic].f.Alice_3 = triggers.f.Alice_3;
332 mZDC.data[im][ic].f.Auto_m = triggers.f.Auto_m;
333 mZDC.data[im][ic].f.Auto_0 = triggers.f.Auto_0;
334 mZDC.data[im][ic].f.Auto_1 = triggers.f.Auto_1;
335 mZDC.data[im][ic].f.Auto_2 = triggers.f.Auto_2;
336 mZDC.data[im][ic].f.Auto_3 = triggers.f.Auto_3;
337 }
338 }
339 }
340}
341
342//______________________________________________________________________________
343void Digits2Raw::insertLastBunch(int ibc, uint32_t orbit)
344{
345 // Inserting last bunch in the orbit. This is not present in digits because information is stored in the
346 // OrbitData structure
347
348 // Orbit and bunch crossing identifiers
349 uint16_t bc = 3563;
350
351 // Reset scalers at orbit change
352 if (orbit != mLatestOrbit) {
353 resetSums(orbit);
354 }
355
356 updatePedestalReference(bc);
357
358 // Dummy bunch -> Do not increment scalers but reset output structure
359 resetOutputStructure(bc, orbit, true);
360
361 // Compute autotrigger bits and assign ALICE trigger bits
362 assignTriggerBits(ibc, bc, orbit, true);
363
364 // Insert payload for all channels
365 for (int32_t im = 0; im < NModules; im++) {
366 for (uint32_t ic = 0; ic < NChPerModule; ic++) {
367 if (mModuleConfig->modules[im].readChannel[ic]) {
368 auto id = mModuleConfig->modules[im].channelID[ic];
369 auto base_m = mSimCondition->channels[id].pedestal; // Average pedestal
370 auto base_s = mSimCondition->channels[id].pedestalFluct; // Baseline oscillations
371 auto base_n = mSimCondition->channels[id].pedestalNoise; // Electronic noise
372 double base = gRandom->Gaus(base_m, base_s);
373 double val = base + gRandom->Gaus(0, base_n);
374 mZDC.data[im][ic].f.s00 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
375 val = base + gRandom->Gaus(0, base_n);
376 mZDC.data[im][ic].f.s01 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
377 val = base + gRandom->Gaus(0, base_n);
378 mZDC.data[im][ic].f.s02 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
379 val = base + gRandom->Gaus(0, base_n);
380 mZDC.data[im][ic].f.s03 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
381 val = base + gRandom->Gaus(0, base_n);
382 mZDC.data[im][ic].f.s04 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
383 val = base + gRandom->Gaus(0, base_n);
384 mZDC.data[im][ic].f.s05 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
385 val = base + gRandom->Gaus(0, base_n);
386 mZDC.data[im][ic].f.s06 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
387 val = base + gRandom->Gaus(0, base_n);
388 mZDC.data[im][ic].f.s07 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
389 val = base + gRandom->Gaus(0, base_n);
390 mZDC.data[im][ic].f.s08 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
391 val = base + gRandom->Gaus(0, base_n);
392 mZDC.data[im][ic].f.s09 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
393 val = base + gRandom->Gaus(0, base_n);
394 mZDC.data[im][ic].f.s10 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
395 val = base + gRandom->Gaus(0, base_n);
396 mZDC.data[im][ic].f.s11 = val < ADCMax ? (val > ADCMin ? val : ADCMin) : ADCMax;
397 }
398 }
399 }
400} // insertLastBunch
401
402//______________________________________________________________________________
403void Digits2Raw::convertDigits(int ibc)
404{
405 // Creating raw data from a bunch crossing that is actually present in digits
406
407 // Orbit and bunch crossing identifiers
408 uint16_t bc = mBCD.ir.bc;
409 uint32_t orbit = mBCD.ir.orbit;
410
411 // Reset scalers at orbit change
412 if (orbit != mLatestOrbit) {
413 resetSums(orbit);
414 }
415
416 updatePedestalReference(bc);
417
418 // Not a dummy bunch -> Reset output structure and eventually flag hits and increment scalers
419 resetOutputStructure(bc, orbit, false);
420
421 // Compute autotrigger bits and assign ALICE trigger bits
422 assignTriggerBits(ibc, bc, orbit, false);
423
424 if (mVerbosity > 0) {
425 mBCD.print(mTriggerMask);
426 }
427
428 int chEnt = mBCD.ref.getFirstEntry();
429 for (int ic = 0; ic < mBCD.ref.getEntries(); ic++) {
430 const auto& chd = mzdcChData[chEnt++];
431 if (mVerbosity > 0) {
432 chd.print();
433 }
434 uint16_t bc = mBCD.ir.bc;
435 uint32_t orbit = mBCD.ir.orbit;
436 // Look for channel ID in digits and store channel (just one copy in output)
437 // This is a limitation of software but we are not supposed to acquire the
438 // same signal twice anyway
439 for (int32_t im = 0; im < NModules; im++) {
440 for (uint32_t ic = 0; ic < NChPerModule; ic++) {
441 if (mModuleConfig->modules[im].channelID[ic] == chd.id &&
442 mModuleConfig->modules[im].readChannel[ic]) {
443 int32_t is = 0;
444 mZDC.data[im][ic].f.s00 = chd.data[is++];
445 mZDC.data[im][ic].f.s01 = chd.data[is++];
446 mZDC.data[im][ic].f.s02 = chd.data[is++];
447 mZDC.data[im][ic].f.s03 = chd.data[is++];
448 mZDC.data[im][ic].f.s04 = chd.data[is++];
449 mZDC.data[im][ic].f.s05 = chd.data[is++];
450 mZDC.data[im][ic].f.s06 = chd.data[is++];
451 mZDC.data[im][ic].f.s07 = chd.data[is++];
452 mZDC.data[im][ic].f.s08 = chd.data[is++];
453 mZDC.data[im][ic].f.s09 = chd.data[is++];
454 mZDC.data[im][ic].f.s10 = chd.data[is++];
455 mZDC.data[im][ic].f.s11 = chd.data[is++];
456 break;
457 }
458 }
459 }
460 }
461}
462
463//______________________________________________________________________________
464void Digits2Raw::writeDigits()
465{
466 constexpr static int data_size = sizeof(uint32_t) * NWPerGBTW;
467 constexpr static gsl::span<char> empty;
468 // Local interaction record (true and empty bunches)
469 o2::InteractionRecord ir(mZDC.data[0][0].f.bc, mZDC.data[0][0].f.orbit);
470 for (uint32_t im = 0; im < o2::zdc::NModules; im++) {
471 // Check if module has been filled with data
472 // N.B. All channels are initialized if module is supposed to be readout
473 // Trigger bits are the same for all the channels connected to a module
474 bool TM = mZDC.data[im][0].f.Auto_m;
475 bool T0 = mZDC.data[im][0].f.Auto_0;
476 bool T1 = mZDC.data[im][0].f.Auto_1;
477 bool T2 = mZDC.data[im][0].f.Auto_2;
478 bool T3 = mZDC.data[im][0].f.Auto_3;
479 bool A0 = mZDC.data[im][0].f.Alice_0;
480 bool A1 = mZDC.data[im][0].f.Alice_1;
481 bool A2 = mZDC.data[im][0].f.Alice_2;
482 bool A3 = mZDC.data[im][0].f.Alice_3;
483 bool tcond_continuous = T0 || T1;
484 bool tcond_triggered = A0 || A1 || (A2 && (T0 || TM)) || (A3 && T0);
485 bool tcond_last = mZDC.data[im][0].f.bc == 3563;
486 // Condition to write GBT data
487 bool addedChData[NChPerModule] = {false, false, false, false};
488 if (tcond_triggered || (mIsContinuous && tcond_continuous) || (mZDC.data[im][0].f.bc == 3563)) {
489 for (uint32_t ic = 0; ic < o2::zdc::NChPerModule; ic++) {
490 uint64_t FeeID = 2 * im + ic / 2;
491 if (mModuleConfig->modules[im].readChannel[ic]) {
492 for (int32_t iw = 0; iw < o2::zdc::NWPerBc; iw++) {
493 if (mEnablePadding) {
494 gsl::span<char> payload{reinterpret_cast<char*>(&mZDC.data[im][ic].w[iw][0]), data_size};
495 mWriter.addData(FeeID, mCruID, mLinkID, mEndPointID, ir, payload);
496 } else {
497 gsl::span<char> payload{reinterpret_cast<char*>(&mZDC.data[im][ic].w[iw][0]), PayloadPerGBTW};
498 o2::zdc::Digits2Raw::print_gbt_word((const uint32_t*)&mZDC.data[im][ic].w[iw][0]);
499 mWriter.addData(FeeID, mCruID, mLinkID, mEndPointID, ir, payload);
500 }
501 }
502 addedChData[ic] = true;
503 }
504 }
505 }
506 // All links are registered, we add explicitly zero payload
507 if (addedChData[0] == false && addedChData[1] == false) {
508 uint64_t FeeID = 2 * im;
509 mWriter.addData(FeeID, mCruID, mLinkID, mEndPointID, ir, empty);
510 }
511 if (addedChData[2] == false && addedChData[3] == false) {
512 uint64_t FeeID = 2 * im + 1;
513 mWriter.addData(FeeID, mCruID, mLinkID, mEndPointID, ir, empty);
514 }
515 if (mVerbosity > 1) {
516 if (tcond_continuous) {
517 printf("M%d Cont. T0=%d || T1=%d\n", im, T0, T1);
518 }
519 if (tcond_triggered) {
520 printf("M%d Trig. %s A0=%d || A1=%d || (A2=%d && (T0=%d || TM=%d))=%d || (A3=%d && T0=%d )=%d\n", im, mIsContinuous ? "CM" : "TM", A0, A1, A2, T0, TM, A2 && (T0 || TM), A3, T0, A3 && T0);
521 }
522 if (mZDC.data[im][0].f.bc == 3563) {
523 printf("M%d is last BC\n", im);
524 }
525 if (tcond_triggered || (mIsContinuous && tcond_continuous) || (mZDC.data[im][0].f.bc == 3563)) {
526 for (uint32_t ic = 0; ic < o2::zdc::NChPerModule; ic++) {
527 if (mModuleConfig->modules[im].readChannel[ic]) {
528 for (int32_t iw = 0; iw < o2::zdc::NWPerBc; iw++) {
529 print_gbt_word(&mZDC.data[im][ic].w[iw][0], mModuleConfig);
530 }
531 }
532 }
533 } else {
534 if (mVerbosity > 2) {
535 printf("orbit %9u bc %4u M%d SKIP\n", mZDC.data[im][0].f.orbit, mZDC.data[im][0].f.bc, im);
536 }
537 }
538 }
539 }
540}
541
542//______________________________________________________________________________
543void Digits2Raw::print_gbt_word(const uint32_t* word, const ModuleConfig* moduleConfig)
544{
545 if (word == nullptr) {
546 printf("NULL\n");
547 return;
548 }
549 union {
550 uint16_t uns;
551 int16_t sig;
552 } word16;
553 unsigned __int128 val = word[2];
554 val = val << 32;
555 val = val | word[1];
556 val = val << 32;
557 val = val | word[0];
558 static uint32_t last_orbit = 0, last_bc = 0;
559
560 ULong64_t lsb = val;
561 ULong64_t msb = val >> 64;
562 uint32_t a = word[0];
563 uint32_t b = word[1];
564 uint16_t c = *((uint16_t*)&word[2]);
565 // printf("\nGBTW: %04x %08x %08x\n",c,b,a);
566 if ((a & 0x3) == 0) {
567 uint32_t myorbit = (val >> 48) & 0xffffffff;
568 uint32_t mybc = (val >> 36) & 0xfff;
569 if (myorbit != last_orbit || mybc != last_bc) {
570 printf("Orbit %9u bc %4u\n", myorbit, mybc);
571 last_orbit = myorbit;
572 last_bc = mybc;
573 }
574 printf("%04x %08x %08x ", c, b, a);
575 uint32_t hits = (val >> 24) & 0xfff;
576 word16.uns = (lsb >> 8) & 0xffff;
577 // float foffset = word16.sig * (moduleConfig == nullptr ? 1 : moduleConfig->baselineFactor);
578 uint32_t board = (lsb >> 2) & 0xf;
579 uint32_t ch = (lsb >> 6) & 0x3;
580 printf("orbit %9u bc %4u hits %4u offset %+6i Board %2u Ch %1u", myorbit, mybc, hits, word16.sig, board, ch);
581 // printf("orbit %9u bc %4u hits %4u offset %+9.3f Board %2u Ch %1u", myorbit, mybc, hits, foffset, board, ch);
582 if (board >= NModules) {
583 printf(" ERROR with board");
584 }
585 if (ch >= NChPerModule) {
586 printf(" ERROR with ch");
587 }
588 if (moduleConfig) {
589 auto id = moduleConfig->modules[board].channelID[ch];
590 if (id >= 0 && id < NChannels) {
591 printf(" %s", ChannelNames[id].data());
592 } else {
593 printf(" error with ch id");
594 }
595 }
596 } else if ((a & 0x3) == 1) {
597 printf("%04x %08x %08x ", c, b, a);
598 printf(" %s %s %s %s ", a & 0x10 ? "A0" : " ", a & 0x20 ? "A1" : " ", a & 0x40 ? "A2" : " ", a & 0x80 ? "A3" : " ");
599 printf("0-5 ");
600 int16_t s[6];
601 val = val >> 8;
602 for (int32_t i = 0; i < 6; i++) {
603 s[i] = val & 0xfff;
604 if (s[i] > ADCMax) {
605 s[i] = s[i] - ADCRange;
606 }
607 val = val >> 12;
608 }
609 printf(" %5d %5d %5d %5d %5d %5d%s%s", s[0], s[1], s[2], s[3], s[4], s[5], (a & 0x4) ? " DLOSS" : "", (a & 0x8) ? " ERROR" : "");
610 } else if ((a & 0x3) == 2) {
611 printf("%04x %08x %08x ", c, b, a);
612 printf("%s %s %s %s %s %s ", a & 0x4 ? "H" : " ", a & 0x8 ? "TM" : " ", a & 0x10 ? "T0" : " ", a & 0x20 ? "T1" : " ", a & 0x40 ? "T2" : " ", a & 0x80 ? "T3" : " ");
613 printf("6-b ");
614 int16_t s[6];
615 val = val >> 8;
616 for (int32_t i = 0; i < 6; i++) {
617 s[i] = val & 0xfff;
618 if (s[i] > ADCMax) {
619 s[i] = s[i] - ADCRange;
620 }
621 val = val >> 12;
622 }
623 printf(" %5d %5d %5d %5d %5d %5d", s[0], s[1], s[2], s[3], s[4], s[5]);
624 } else if ((a & 0x3) == 3) {
625 printf("%04x %08x %08x ", c, b, a);
626 printf("HB ");
627 }
628 printf("\n");
629}
630
631//______________________________________________________________________________
632void Digits2Raw::emptyBunches(std::bitset<3564>& bunchPattern)
633{
634 // Check if mModuleConfig object has list of empty bunches
635 if (mModuleConfig->nBunchAverage <= 0) {
636 LOG(fatal) << "nBunchAverage = " << mModuleConfig->nBunchAverage;
637 }
638
639 // Analyze the list of empty bunches that is provided
640 mNEmpty = 0;
641 int ib = 0;
642 uint64_t one = 0x1;
643 for (int i = 0; i < mModuleConfig->NWMap; i++) {
644 uint64_t val = mModuleConfig->emptyMap[i];
645 for (int j = 0; j < 64; j++) {
646 if ((val & (one << j)) != 0) { // Empty bunch
647 mNEmpty++;
648 mEmpty[ib] = mNEmpty;
649 } else { // Not empty
650 mEmpty[ib] = mNEmpty;
651 }
652 ib++;
653 }
654 }
655
656 // No list is provided: we prepare a list from collision context
657 if (mNEmpty == 0) {
658 const int LHCMaxBunches = o2::constants::lhc::LHCMaxBunches;
659 for (int32_t ib = 0; ib < LHCMaxBunches; ib++) {
660 int mb = (ib + 31) % o2::constants::lhc::LHCMaxBunches; // beam gas from back of calorimeter (31 b.c. before)
661 int m1 = (ib + 1) % o2::constants::lhc::LHCMaxBunches; // previous bunch (next is colliding)
662 int cb = ib; // current bunch crossing
663 int p1 = (ib - 1 + o2::constants::lhc::LHCMaxBunches) % o2::constants::lhc::LHCMaxBunches; // colliding + 1 (-1 is colliding)
664 int p2 = (ib - 2 + o2::constants::lhc::LHCMaxBunches) % o2::constants::lhc::LHCMaxBunches; // colliding + 2 (-2 is colliding)
665 int p3 = (ib - 3 + o2::constants::lhc::LHCMaxBunches) % o2::constants::lhc::LHCMaxBunches; // colliding + 3 (-3 is colliding)
666 int p4 = (ib - 4 + o2::constants::lhc::LHCMaxBunches) % o2::constants::lhc::LHCMaxBunches; // colliding + 4 (-4 is colliding)
667 if (bunchPattern[mb] || bunchPattern[m1] || bunchPattern[ib] || bunchPattern[p1] || bunchPattern[p2] || bunchPattern[p3]) {
668 mEmpty[ib] = mNEmpty;
669 } else {
670 mNEmpty++;
671 mEmpty[ib] = mNEmpty;
672 }
673 if (mNEmpty == mModuleConfig->nBunchAverage) {
674 break;
675 }
676 }
677 }
678
679 // Check if there is a mismatch between requested and actual list
680 if (mNEmpty != 0 && mNEmpty != mModuleConfig->nBunchAverage) {
681 LOG(fatal) << "Mismatch with empty map mNEmpty = " << mNEmpty << " nBunchAverage = " << mModuleConfig->nBunchAverage;
682 }
683 LOG(info) << "There are " << mNEmpty << " clean empty bunches";
684}
uint64_t orbit
Definition RawEventData.h:6
uint64_t bc
Definition RawEventData.h:5
int32_t i
constexpr int p2()
constexpr int p1()
constexpr to accelerate the coordinates changing
uint32_t one
Definition RawData.h:4
uint32_t j
Definition RawData.h:0
uint32_t c
Definition RawData.h:2
converts digits to raw format
void addData(uint16_t feeid, uint16_t cru, uint8_t lnk, uint8_t endpoint, const IR &ir, const gsl::span< char > data, bool preformatted=false, uint32_t trigger=0, uint32_t detField=0)
LinkData & registerLink(uint16_t fee, uint16_t cru, uint8_t link, uint8_t endpoint, std::string_view outFileName)
void processDigits(const std::string &outDir, const std::string &fileDigitsName)
Prepare list of clean empty bunches for baseline evaluation.
void emptyBunches(std::bitset< 3564 > &bunchPattern)
static void print_gbt_word(const uint32_t *word, const ModuleConfig *moduleConfig=nullptr)
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
GLboolean * data
Definition glcorearb.h:298
GLuint GLfloat * val
Definition glcorearb.h:1582
GLboolean GLboolean GLboolean GLboolean a
Definition glcorearb.h:1233
GLuint id
Definition glcorearb.h:650
constexpr int LHCMaxBunches
constexpr int FeeID[2]
FEE_ID in RDH.
Definition Constants.h:125
constexpr int NModules
Definition Constants.h:68
constexpr int NChPerModule
Definition Constants.h:69
constexpr int NWPerGBTW
constexpr unsigned short Id_w1
constexpr int NChannels
Definition Constants.h:65
constexpr int ADCRange
Definition Constants.h:76
constexpr int PayloadPerGBTW
constexpr int NWPerBc
Definition Constants.h:72
constexpr unsigned short Id_w2
constexpr unsigned short Id_w0
constexpr int ADCMin
Definition Constants.h:76
constexpr int NLinks
Definition Constants.h:70
constexpr std::string_view ChannelNames[]
Definition Constants.h:147
constexpr int ADCMax
Definition Constants.h:76
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
void empty(int)
uint32_t orbit
LHC orbit.
uint16_t bc
bunch crossing ID of interaction
static std::string concat_string(Ts const &... ts)
uint32_t triggers
Definition BCData.h:60
o2::dataformats::RangeRefComp< 6 > ref
Definition BCData.h:55
void print(uint32_t triggerMask=0, int diff=0) const
Definition BCData.cxx:18
o2::InteractionRecord ir
Definition BCData.h:56
EventChData data[NModules][NChPerModule]
std::array< uint64_t, NWMap > emptyMap
static constexpr int NWMap
std::array< Module, MaxNModules > modules
std::array< ChannelSimCondition, NChannels > channels
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
o2::InteractionRecord ir(0, 0)
struct ChannelDataV0 f
UInt_t w[NWPerBc][NWPerGBTW]
struct ModuleTriggerMap f
Definition BCData.h:48