Belle II Software development
CDCTriggerUnpackerModule.cc
1/**************************************************************************
2 * basf2 (Belle II Analysis Software Framework) *
3 * Author: The Belle II Collaboration *
4 * *
5 * See git log for contributors and copyright holders. *
6 * This file is licensed under LGPL-3.0, see LICENSE.md. *
7 **************************************************************************/
8
9#include <trg/cdc/modules/unpacker/CDCTriggerUnpackerModule.h>
10#include <framework/core/ModuleParam.templateDetails.h>
11#include <trg/cdc/dbobjects/CDCTriggerNeuroConfig.h>
12
13#include <array>
14#include <bitset>
15#include <string>
16#include <numeric>
17#include <algorithm>
18
19using namespace Belle2;
20using namespace CDCTriggerUnpacker;
21
22
23//-----------------------------------------------------------------
24// Register the Module
25//-----------------------------------------------------------------
26REG_MODULE(CDCTriggerUnpacker);
27
28//-----------------------------------------------------------------
29// Implementation
30//-----------------------------------------------------------------
31
32constexpr std::array<int, 9> CDCTriggerUnpackerModule::nMergers;
33using dataWord = std::bitset<wordWidth>;
34
35namespace Belle2 {
40 //-----------------------------------------------------------------
41 // Definition of Subtriggers
42 //-----------------------------------------------------------------
43 /*
44 * To implement an unpacker for a new subtrigger module,
45 * 1. Declare a new struct, inherit from SubTrigger
46 * 2. Hold the pointers to the bitstream(s)
47 * 3. declare as many variables as needed
48 * 4. Implement the virtual methods reserve() and unpack()
49 * 5. Instantiate it in initialize() (one object for one UT3)
50 * 6. Push them back to m_subTrigger
51 */
52
54 struct Merger : SubTrigger {
56 Merger(StoreArray<MergerBits>* inArrayPtr, const std::string& inName,
57 unsigned inEventWidth, unsigned inOffset,
58 int inHeaderSize, const std::vector<int>& inNodeID, const std::vector<int>& inNodeID_pcie40,
59 unsigned inNInnerMergers, int& inDelay,
60 int& inCnttrg,
61 int inDebugLevel) :
62 SubTrigger(inName, inEventWidth, inOffset,
63 inHeaderSize, inNodeID, inNodeID_pcie40, inDelay, inCnttrg, inDebugLevel),
64 arrayPtr(inArrayPtr),
65 nInnerMergers(inNInnerMergers) {};
66
70 unsigned nInnerMergers;
72 void reserve(int subDetectorId, std::array<int, nFinesse> nWords, bool pciedata) override
73 {
74 int iNode_i = 0;
75 int iFinesse_i = 0;
76 if (pciedata) {
77 iNode_i = iNode_pcie40;
78 iFinesse_i = iFinesse_pcie40;
79 } else {
80 iNode_i = iNode;
81 iFinesse_i = iFinesse;
82 }
83
84 if (subDetectorId != iNode_i) {
85 return;
86 }
87 if (nWords[iFinesse_i] < headerSize) {
88 return;
89 }
90 size_t nClocks = (nWords[iFinesse_i] - headerSize) / eventWidth;
91 size_t entries = arrayPtr->getEntries();
92 if (entries == 0) {
93 for (unsigned i = 0; i < nClocks; ++i) {
94 arrayPtr->appendNew();
95 }
96 B2DEBUG(20, name << ": " << nClocks << " clocks");
97 } else if (entries != nClocks) {
98 B2DEBUG(20, "Number of clocks in " << name << " conflicts with others!");
99 }
100 };
101
103 void unpack(int subDetectorId,
104 std::array<int*, 48> data32tab,
105 std::array<int, 48> nWords,
106 bool pciedata) override
107 {
108 int iNode_i = 0;
109 int iFinesse_i = 0;
110 if (pciedata) {
111 iNode_i = iNode_pcie40;
112 iFinesse_i = iFinesse_pcie40;
113 } else {
114 iNode_i = iNode;
115 iFinesse_i = iFinesse;
116 }
117
118 if (subDetectorId != iNode_i) {
119 return;
120 }
121 if (nWords[iFinesse_i] < headerSize) {
122 B2DEBUG(20, "The module " << name << " does not have enough data (" <<
123 nWords[iFinesse_i] << "). Nothing will be unpacked.");
124 // TODO: need to clear the output bitstream because we return early here
125 return;
126 }
127 // make bitstream
128 // loop over all clocks
129 for (int i = headerSize; i < nWords[iFinesse_i]; i += eventWidth) {
130 int iclock = (i - headerSize) / eventWidth;
131 auto mergerClock = (*arrayPtr)[iclock];
132 B2DEBUG(100, "clock " << iclock);
133 // loop over all mergers
134 for (unsigned j = offset; j < eventWidth; ++j) {
135 int iMerger = (eventWidth - j - 1) / 8 + nInnerMergers;
136 int pos = (eventWidth - j - 1) % 8;
137 dataWord word(data32tab[iFinesse_i][i + j]);
138 for (int k = 0; k < wordWidth; ++k) {
139 mergerClock->m_signal[iMerger].set(pos * wordWidth + k, word[k]);
140 }
141 }
142 }
143 if (debugLevel >= 300) {
144 printBuffer(data32tab[iFinesse_i] + headerSize, eventWidth);
145 B2DEBUG(20, "");
146 printBuffer(data32tab[iFinesse_i] + headerSize + eventWidth, eventWidth);
147 }
148 for (int i = 0; i < std::accumulate(nMergers.begin(), nMergers.end(), 0); ++i) {
149 B2DEBUG(99, (*arrayPtr)[0]->m_signal[i].to_string());
150 }
151 }
152 };
153
159 const std::string& inName, unsigned inEventWidth, unsigned inOffset,
160 unsigned inHeaderSize, const std::vector<int>& inNodeID, const std::vector<int>& inNodeID_pcie40,
161 unsigned inNumTS, int& inDelay,
162 int& inCnttrg,
163 int inDebugLevel) :
164 SubTrigger(inName, inEventWidth, inOffset / wordWidth, inHeaderSize, inNodeID, inNodeID_pcie40,
165 inDelay, inCnttrg, inDebugLevel),
166 inputArrayPtr(inArrayPtr), outputArrayPtr(outArrayPtr),
167 iTracker(std::stoul(inName.substr(inName.length() - 1))),
168 numTS(inNumTS), offsetBitWidth(inOffset) {};
169
175 unsigned iTracker;
177 unsigned numTS;
180
189 void reserve(int subDetectorId, std::array<int, nFinesse> nWords, bool pciedata) override
190 {
191 int iNode_i = 0;
192 int iFinesse_i = 0;
193 if (pciedata) {
194 iNode_i = iNode_pcie40;
195 iFinesse_i = iFinesse_pcie40;
196 } else {
197 iNode_i = iNode;
198 iFinesse_i = iFinesse;
199 }
200
201 size_t nClocks = (nWords[iFinesse_i] - headerSize) / eventWidth;
202 size_t entries = inputArrayPtr->getEntries();
203 if (subDetectorId == iNode_i) {
204 if (entries == 0) {
205 for (unsigned i = 0; i < nClocks; ++i) {
206 TSFOutputBitStream* inputClock = inputArrayPtr->appendNew();
207 T2DOutputBitStream* outputClock = outputArrayPtr->appendNew();
208 // fill bitstreams for all trackers with zeros
209 for (unsigned j = 0; j < nTrackers; ++j) {
210 for (unsigned iAxialTSF = 0; iAxialTSF < nAxialTSF; ++iAxialTSF) {
211 inputClock->m_signal[iAxialTSF][j].fill(zero_val);
212 }
213 outputClock->m_signal.at(j).fill(zero_val);
214 }
215 }
216 B2DEBUG(20, name << ": " << nClocks << " clocks");
217 } else if (entries != nClocks) {
218 B2DEBUG(20, "Number of clocks in " << name << " conflicts with others!");
219 }
220 }
221 };
222
231 void unpack(int subDetectorId,
232 std::array<int*, 48> data32tab,
233 std::array<int, 48> nWords,
234 bool pciedata) override
235 {
236 int iNode_i = 0;
237 int iFinesse_i = 0;
238 if (pciedata) {
239 iNode_i = iNode_pcie40;
240 iFinesse_i = iFinesse_pcie40;
241 } else {
242 iNode_i = iNode;
243 iFinesse_i = iFinesse;
244 }
245
246 if (subDetectorId != iNode_i) {
247 return;
248 }
249 // Recently, the content of the last clock appears at the beginning.
250 // Now we decide whether we will change the order of the clocks
251 // based on the 127MHz counter on the 2nd half of the first word [15:0]
252 int ccShift = 0;
253 using halfDataWord = std::bitset<16>;
254 std::vector<halfDataWord> counters;
255 counters.reserve(inputArrayPtr->getEntries());
256 for (int iclock = 0; iclock < inputArrayPtr->getEntries(); ++iclock) {
257 counters.emplace_back(data32tab[iFinesse_i]
258 [headerSize + eventWidth * iclock] & 0xffff);
259 B2DEBUG(100, "iclock " << iclock << " --> " << counters.at(iclock).to_ulong() << " : " << std::hex << counters.at(iclock));
260 }
261 bool counter_correct_error = false;
262 while (counters.at(1).to_ulong() - counters.at(0).to_ulong() != 4) {
263 std::rotate(counters.begin(), counters.begin() + 1, counters.end());
264 ccShift++;
265 // 2019,0410 This situation, looks like clockcounter shifted 6 bits left, was first seen in exp5 data.
266 // Later it has been understood that it is due to data from a dummy BRAM buffer, which is supposed to be used for suppressed data only.
267 // The data header is 0xbbbb instead of 0xdddd.
268 // getHeader in the CDCTriggerUnpackerModule.h is modified to skip this kind event.
269 // 2019,0419 unfortunately, clockcounter found disorder since expt 7, run 2553, after update of B2L firmware to replace the b2dly with trigger counter.
270 // for that run, it seems the problem happens only at 2D1, 2D2, and 2D3.
271 if (ccShift >= inputArrayPtr->getEntries()) {
272 B2DEBUG(90, "PHYSJG: clock counter rotation over one cycle: " << ccShift);
273 for (const auto& c : counters) {
274 B2DEBUG(90, "" << c.to_ulong() << " : " << std::hex << c);
275 }
276 counter_correct_error = true;
277 break;
278 }
279 }
280 if (counter_correct_error) {
281 B2DEBUG(20, "PHYSJG: " << name << " too many clock counter rotation corrections: " << ccShift << " data object skipped.");
282 // maybe implement an option for user to decide if this data block should be kept or not?!
283 return;
284 }
285 if (! std::is_sorted(counters.begin(), counters.end(),
286 [](halfDataWord i, halfDataWord j) {
287 return (j.to_ulong() - i.to_ulong() == 4);
288 })) {
289 B2DEBUG(20, "clock counters are still out of order");
290 for (const auto& c : counters) {
291 B2DEBUG(90, "" << c.to_ulong());
292 }
293 }
294 // This could happen when the clock counter is over 1279 and roll back to 0, since only 48 clock counter will be in the data.
295 if (ccShift) {
296 B2DEBUG(15, "shifting the first " << ccShift <<
297 " clock(s) to the end for " << name);
298 }
299
300 // get event body information
301 // make bitstream
302 // loop over all clocks
303 for (int i = headerSize; i < nWords[iFinesse_i]; i += eventWidth) {
304 int iclock = (i - headerSize) / eventWidth - ccShift;
305 if (iclock < 0) {
306 iclock += inputArrayPtr->getEntries();
307 }
308 auto inputClock = (*inputArrayPtr)[iclock];
309 auto outputClock = (*outputArrayPtr)[iclock];
310 // clear output bitstream
311 outputClock->m_signal.at(iTracker).fill(zero_val);
312 B2DEBUG(90, "unpacker clock " << iclock);
313 if (debugLevel >= 300) {
314 printBuffer(data32tab[iFinesse_i] + headerSize + eventWidth * iclock,
315 eventWidth);
316 }
317 // get the clock counters
318 std::array<dataWord, 2> ccword({
319 data32tab[iFinesse_i][i + 2], data32tab[iFinesse_i][i + 3]
320 });
321 // fill input
322 // Careful! this iTSF is (8 - iSL) / 2
323 for (unsigned iTSF = 0; iTSF < nAxialTSF; ++iTSF) {
324 // clear input bitstream
325 inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker].fill(zero_val);
326
327 if (firmwareVersion < "18012600") {
328 /*
329 data_b2l_r <=
330 x"dddd" & cntr125M(15 downto 0) &
331 cc(4) & cc(3) & cc(2) & cc(1) & cc(0) &
332 ccError &
333 -- 82
334 tsfs(4)(209 downto 0) &
335 tsfs(3)(209 downto 0) &
336 tsfs(2)(209 downto 0) &
337 tsfs(1)(209 downto 0) &
338 tsfs(0)(209 downto 0) &
339 */
340 // fill the clock counters
341 for (unsigned pos = 0; pos < clockCounterWidth; ++pos) {
342 const int j = (pos + iTSF * clockCounterWidth) / wordWidth;
343 const int k = (pos + iTSF * clockCounterWidth) % wordWidth;
344 /* The index behaves differently in each containers
345 Here is an example of a 64-bit wide MSB data
346 |-------- smaller index in the firmware ----->
347
348 data in the firmware/VHDL std_logic_vector(63 downto 0)
349 63 62 61 60 ... 01 00
350
351 data in B2L/RawTRG (when using std::bitset<32> for a word)
352 (31 30 29 28 ... 01 00) (31 30 29 28 ... 01 00)
353 |------ word 0 -------| |------ word 1 -------|
354
355 XSim / Bitstream of std::array<char, N> / std::string
356 00 01 02 03 ... 62 63
357 */
358 // Here we are filling std::array<char, N>, which has reversed order
359 // to std::bitset, so there is a - sign in [wordWidth - k]
360 inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker][pos] =
361 std_logic(ccword[j][wordWidth - k]);
362 }
363 // fill the TS hit
364 offsetBitWidth = 82;
365 for (unsigned pos = 0; pos < numTS * lenTS; ++pos) {
366 const int j = (offsetBitWidth + pos + iTSF * numTS * lenTS) / wordWidth;
367 const int k = (offsetBitWidth + pos + iTSF * numTS * lenTS) % wordWidth;
368 dataWord word(data32tab[iFinesse_i][i + j]);
369 // MSB (leftmost) in firmware -> smallest index in Bitstream's
370 // std::array (due to XSIM) -> largest index in std::bitset
371 // so the index is reversed in this assignment
372 inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker]
373 [clockCounterWidth + pos] = std_logic(word[wordWidth - 1 - k]);
374 }
375 } else {
376 /*
377 x"dddd" & (15 downto 11 => '0') & revoclk &
378 cntr125M(15 downto 0) &
379 (15 downto 5 => '0') & ccError &
380 -- 64
381 cc(4) & tsfs(4)(209 downto 0) &
382 cc(3) & tsfs(3)(209 downto 0) &
383 cc(2) & tsfs(2)(209 downto 0) &
384 cc(1) & tsfs(1)(209 downto 0) &
385 cc(0) & tsfs(0)(209 downto 0) &
386 */
387 // fill the cc and TS hit
388 offsetBitWidth = 64;
389 unsigned TSFWidth = clockCounterWidth + numTS * lenTS;
390 for (unsigned pos = 0; pos < TSFWidth; ++pos) {
391 const int j = (offsetBitWidth + pos + iTSF * TSFWidth) / wordWidth;
392 const int k = (offsetBitWidth + pos + iTSF * TSFWidth) % wordWidth;
393 dataWord word(data32tab[iFinesse_i][i + j]);
394 inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker][pos] =
395 std_logic(word[wordWidth - 1 - k]);
396 }
397 }
398 if (debugLevel >= 100) {
399 display_hex(inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker]);
400 }
401 }
402 // fill output
403 if (firmwareVersion < "18012600") {
404 /*
405 -- 1132
406 Main_out(731 downto 0) &
407 */
408 const int outputOffset = nAxialTSF * numTS * lenTS;
409 const int oldtrackWidth = 6;
410 for (unsigned pos = 0; pos < 732; ++pos) {
411 const int j = (offsetBitWidth + pos + outputOffset) / wordWidth;
412 const int k = (offsetBitWidth + pos + outputOffset) % wordWidth;
413 dataWord word(data32tab[iFinesse_i][i + j]);
414 outputClock->m_signal.at(iTracker).at(clockCounterWidth + oldtrackWidth + pos)
415 = std_logic(word[wordWidth - 1 - k]);
416 }
417 } else {
418 /*
419 -- 1159
420 old_track(5 downto 0) &
421 Main_out(731 downto 0) &
422 */
423 //const int outputOffset = 1159;
424 const int outputOffset = offsetBitWidth + nAxialTSF * numTS * lenTS + 45; //1159 with numTS=10 , 1684 with numTS=15
425 for (unsigned pos = 0; pos < T2DOutputWidth; ++pos) {
426 const int j = (pos + outputOffset) / wordWidth;
427 const int k = (pos + outputOffset) % wordWidth;
428 dataWord word(data32tab[iFinesse_i][i + j]);
429 try {
430 outputClock->m_signal.at(iTracker).at(clockCounterWidth + pos)
431 = std_logic(word[wordWidth - 1 - k]);
432 } catch (const std::out_of_range& e) {
433 B2DEBUG(20, "Out-of-range access to outputClock->m_signal.at(iTracker).at(clockCounterWidth + pos)"
434 << LogVar("iTracker", iTracker)
435 << LogVar("clockCounterWidth", clockCounterWidth)
436 << LogVar("post", pos));
437 break;
438 }
439 }
440 }
441 if (debugLevel >= 100) {
442 display_hex(outputClock->m_signal.at(iTracker));
443 }
444 }
445 }
446 };
447
449 template <int bitwidth, typename T_bitstream>
450 struct Neuro : SubTrigger {
453 const std::string& inName, unsigned inEventWidth, unsigned inOffset,
454 unsigned inHeaderSize, const std::vector<int>& inNodeID, const std::vector<int>& inNodeID_pcie40, int& inDelay,
455 int& inCnttrg,
456 int inDebugLevel) :
457 SubTrigger(inName, inEventWidth, inOffset / wordWidth, inHeaderSize, inNodeID, inNodeID_pcie40,
458 inDelay, inCnttrg, inDebugLevel),
459 ArrayPtr(arrPtr),
460 iTracker(std::stoul(inName.substr(inName.length() - 1))),
461 offsetBitWidth(inOffset) {};
462
466 unsigned iTracker;
469
470 void reserve(int subDetectorId, std::array<int, nFinesse> nWords, bool pciedata) override
471 {
472 int iNode_i = 0;
473 int iFinesse_i = 0;
474 if (pciedata) {
475 iNode_i = iNode_pcie40;
476 iFinesse_i = iFinesse_pcie40;
477 } else {
478 iNode_i = iNode;
479 iFinesse_i = iFinesse;
480 }
481
482 size_t nClocks = (nWords[iFinesse_i] - headerSize) / eventWidth;
483 size_t entries = ArrayPtr->getEntries();
484 if (subDetectorId == iNode_i) {
485 if (entries == 0) {
486 for (unsigned i = 0; i < nClocks; ++i) {
487 T_bitstream* nnclock = ArrayPtr->appendNew();
488 // fill bitstreams for all trackers with zeros
489 for (unsigned j = 0; j < nTrackers; ++j) {
490 nnclock->m_signal[j].fill(zero_val);
491 }
492 }
493 B2DEBUG(20, name << ": " << nClocks << " clocks");
494 } else if (entries != nClocks) {
495 B2DEBUG(20, "Number of clocks in " << name << " conflicts with others!");
496 }
497 }
498 };
499
500 void unpack(int subDetectorId,
501 std::array<int*, nFinesse> data32tab,
502 std::array<int, nFinesse> nWords,
503 bool pciedata) override
504 {
505 int iNode_i = 0;
506 int iFinesse_i = 0;
507 if (pciedata) {
508 iNode_i = iNode_pcie40;
509 iFinesse_i = iFinesse_pcie40;
510 } else {
511 iNode_i = iNode;
512 iFinesse_i = iFinesse;
513 }
514
515 if (subDetectorId != iNode_i) {
516 return;
517 }
518 // make bitstream
519 // loop over all clocks
520 for (int i = headerSize; i < nWords[iFinesse_i]; i += eventWidth) {
521 int iclock = (i - headerSize) / eventWidth;
522 auto nnclock = (*ArrayPtr)[iclock];
523 B2DEBUG(20, "clock " << iclock);
524 if (debugLevel >= 300) {
525 printBuffer(data32tab[iFinesse_i] + headerSize + eventWidth * iclock,
526 eventWidth);
527 }
528 // fill output
529 for (unsigned pos = 0; pos < bitwidth; ++pos) {
530 const int j = (offsetBitWidth + pos) / wordWidth;
531 const int k = (offsetBitWidth + pos) % wordWidth;
532 std::bitset<wordWidth> word(data32tab[iFinesse_i][i + j]);
533 nnclock->m_signal[iTracker][pos] = std_logic(word[wordWidth - 1 - k]);
534 }
535 if (debugLevel >= 100) {
536 display_hex(nnclock->m_signal[iTracker]);
537 }
538 }
539 }
540 };
541
542};
543
545{
546 // Set module properties
547 setDescription("Unpack the CDC trigger data recorded in B2L");
549
550 // Parameter definitions
551 addParam("unpackMerger", m_unpackMerger,
552 "whether to unpack merger data (recorded by Merger Reader / TSF)", false);
553 addParam("unpackTracker2D", m_unpackTracker2D,
554 "whether to unpack 2D tracker data", false);
555 addParam("unpackNeuro", m_unpackNeuro,
556 "whether to unpacker neurotrigger data", false);
557 addParam("decode2DFinderTrack", m_decode2DFinderTrack,
558 "flag to decode 2D finder track", false);
559 addParam("decode2DFinderInput", m_decode2DFinderInputTS,
560 "flag to decode input TS to 2D", false);
561 addParam("decodeNeuro", m_decodeNeuro,
562 "flag to decode neurotrigger data", false);
563 // https://xwiki.desy.de/xwiki/rest/p/776d2 for CPR/HSLB
564 NodeList defaultMergerNodeID = { // These should be very temporary ones since no merger to B2L yet.
565 {0x11000001, 0},
566 {0x11000003, 0},
567 {0x11000001, 1},
568 {0x11000002, 0},
569 {0x11000002, 1}
570 };
571 addParam("MergerNodeId", m_mergerNodeID,
572 "list of COPPER and HSLB ID of Merger reader (TSF)", defaultMergerNodeID);
573 NodeList defaultTracker2DNodeID = {
574 {0x11000001, 0},
575 {0x11000001, 1},
576 {0x11000002, 0},
577 {0x11000002, 1}
578 };
579 addParam("2DNodeId", m_tracker2DNodeID,
580 "list of COPPER and HSLB ID of 2D tracker", defaultTracker2DNodeID);
581 NodeList defaultTracker2DNodeID_pcie40 = {
582 {0x10000001, 0},
583 {0x10000001, 1},
584 {0x10000001, 2},
585 {0x10000001, 3}
586 };
587 addParam("2DNodeId_pcie40", m_tracker2DNodeID_pcie40,
588 "list of PCIe40 ch ID of 2D tracker", defaultTracker2DNodeID_pcie40);
589
590 NodeList defaultNeuroNodeID = {
591 {0x11000005, 0},
592 {0x11000005, 1},
593 {0x11000006, 0},
594 {0x11000006, 1}
595 };
596 addParam("NeuroNodeId", m_neuroNodeID,
597 "list of COPPER and HSLB ID of neurotrigger", defaultNeuroNodeID);
598 NodeList defaultNeuroNodeID_pcie40 = {
599 {0x10000001, 8},
600 {0x10000001, 9},
601 {0x10000001, 10},
602 {0x10000001, 11}
603 };
604 addParam("NeuroNodeId_pcie40", m_neuroNodeID_pcie40,
605 "list of PCIe40 ch ID of neurotrigger", defaultNeuroNodeID_pcie40);
606
607 addParam("headerSize", m_headerSize,
608 "number of words (number of bits / 32) of the B2L header", 3);
609 addParam("alignFoundTime", m_alignFoundTime,
610 "Whether to align out-of-sync Belle2Link data between different sub-modules", true);
611 addParam("useDB", m_useDB,
612 "Use values stored in the payload of the ConditionsDB."
613 "This affects the output scaling of the Neurotrigger as well as the"
614 "bit configuration of its unpacker. If false, an old unpacker version with fixed scalings and old bit addresses is used.",
615 true);
616 addParam("NNTrackName", m_neuro_track_name,
617 "Name for unpacked Neurotrack",
618 (std::string)"CDCTriggerNeuroTracks");
619 addParam("NNInStereoTS", m_neuro_in_sTS_name,
620 "Name for unpacked Neurotrigger input all stereo TSs",
621 (std::string)"CDCTriggerNNInputAllStereoSegmentHits");
622 addParam("NNInSelectTS", m_neuro_select_TS_name,
623 "Name for unpacked Neurotrigger selected TSs",
624 (std::string)"CDCTriggerNNInputSegmentHits");
625 addParam("NNIn2DTrack", m_neuro_in_2dtrack_name,
626 "Name for unpacked Neurotrigger input 2d tracks",
627 (std::string)"CDCTriggerNNInput2DFinderTracks");
628 addParam("NNInETFT0", m_neuro_in_etf_name,
629 "Name for unpacked Neurotrigger input ETF T0",
630 (std::string)"CDCTriggerNeuroETFT0");
631 addParam("NNScaledInput", m_neuro_scaled_input_name,
632 "Name for unpacked Neurotrigger scaled input",
633 (std::string)"CDCTriggerNeuroTracksInput");
634 addParam("sim13dt", m_sim13dt,
635 "Simulate 13 bit drift time by using 2d clock counter value.",
636 false);
637 addParam("isDNN", m_isDNN,
638 "flag to unpack DNN trigger data", false);
640 "name of stored config, keep empty for neurotrigger config", (std::string)"");
641}
642
644{
646 //m_rawTriggers.isRequired();
647 if (m_unpackMerger) {
648 m_mergerBits.registerInDataStore("CDCTriggerMergerBits");
649 }
650 if (m_unpackTracker2D) {
651 m_bitsTo2D.registerInDataStore("CDCTriggerTSFTo2DBits");
652 m_bits2DTo3D.registerInDataStore("CDCTrigger2DTo3DBits");
653 }
654 if (m_unpackNeuro) {
655 m_bitsDNN.registerInDataStore("CDCTriggerDNNBits");
656 m_bitsNN.registerInDataStore("CDCTriggerNNBits");
657 }
660 m_TSHits.registerInDataStore("CDCTriggerSegmentHits");
661 }
663 m_2DFinderTracks.registerInDataStore("CDCTrigger2DFinderTracks");
664 m_2DFinderTracks.registerRelationTo(m_TSHits);
665 m_2DFinderClones.registerInDataStore("CDCTrigger2DFinderClones");
666 m_2DFinderClones.registerRelationTo(m_2DFinderTracks);
667 }
668 if (m_decodeNeuro) {
669 m_NNInputTSHitsAll.registerInDataStore(m_neuro_in_sTS_name.c_str());
670 m_NNInputTSHits.registerInDataStore(m_neuro_select_TS_name.c_str());
671 m_NNInput2DFinderTracks.registerInDataStore(m_neuro_in_2dtrack_name.c_str());
672 m_NeuroTracks.registerInDataStore(m_neuro_track_name.c_str());
673 m_NeuroInputs.registerInDataStore(m_neuro_scaled_input_name.c_str());
674 m_ETFTime.registerInDataStore(m_neuro_in_etf_name.c_str());
675 m_NeuroTracks.registerRelationTo(m_NNInputTSHits);
676 m_NNInput2DFinderTracks.registerRelationTo(m_NNInputTSHits);
678 m_NNInput2DFinderTracks.registerRelationTo(m_NeuroTracks);
679 m_NeuroTracks.registerRelationTo(m_NNInput2DFinderTracks);
680 m_NeuroTracks.registerRelationTo(m_NeuroInputs);
681 }
682 //make datastore object for neurotrigger config
683 m_cdctriggerneuroconfig = std::make_unique<DBObjPtr<CDCTriggerNeuroConfig>>(m_neurotrigger_config_name);
684
685 for (int iSL = 0; iSL < 9; iSL += 2) {
686 if (m_unpackMerger) {
687 const int nInnerMergers = std::accumulate(nMergers.begin(),
688 nMergers.begin() + iSL, 0);
689 B2DEBUG(20, "in: " << nInnerMergers);
690 Merger* m_merger =
691 new Merger(&m_mergerBits,
692 "Merger" + std::to_string(iSL), mergerWidth * nMergers[8] / wordWidth,
694 m_mergerNodeID[iSL / 2], m_mergerNodeID[iSL / 2], nInnerMergers,
697 m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_merger));
698 }
699 }
700 // TODO In the default scenario, data in all trackers will be recorded.
701 // This is not the case for now (around first collision), where some coppers are lacking.
702 // Therefore it might help to make the following code more flexible
703 // so that we won't have a hard fail when some boards are missing
704
705 m_n2DTS = m_dbn2DTS->getnTS();
706 int datasize_2D = 64;
707 if (m_n2DTS == 10) {
708 datasize_2D = 64;
709 } else if (m_n2DTS == 15) {
710 datasize_2D = 82;
711 }
712
713 for (int iTracker = 0; iTracker < 4; ++iTracker) {
714 if (m_unpackTracker2D) {
715 Tracker2D* m_tracker2d =
717 "Tracker2D" + std::to_string(iTracker), datasize_2D, 82, m_headerSize,
721 m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_tracker2d));
722 }
723 if (m_unpackNeuro) {
724 if (m_isDNN) {
727 "Neuro" + std::to_string(iTracker), (int)DNN_WIDTH / 32, 0, m_headerSize,
729 m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_neuro));
730 } else {
733 "Neuro" + std::to_string(iTracker), (int)NN_WIDTH / 32, 0, m_headerSize,
735 m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_neuro));
736 }
737 }
738 }
739}
740
742{
743 for (auto bits : m_subTrigger) {
744 delete bits;
745 }
746}
747
749{
750
752 m_exp = bevt->getExperiment();
753 m_run = bevt->getRun();
754
755 if (not m_cdctriggerneuroconfig->isValid())
756 B2FATAL("CDCTriggerNeuroConfig is not valid.");
757 if (m_useDB == true) {
758 B2DEBUG(2, "Load Neurotrigger configuration for network " << (*m_cdctriggerneuroconfig)->getNNName() << " from database ");
759 B2DEBUG(10, padright("Name", 50) << padright("start", 10) << padright("end", 10) << padright("offset", 10));
760 for (auto x : (*m_cdctriggerneuroconfig)->getB2Format()) {
761 B2DEBUG(10, padright(x.name, 48) << ": " << padright(std::to_string(x.start), 10) << padright(std::to_string(x.end),
762 10) << padright(std::to_string(x.offset), 10));
763 }
764 }
765}
766
767
769{
770 if (m_decodeNeuro == true) {
771 // needed to unpack neuroinput etf time without problems
772 if (!m_ETFTime.isValid()) m_ETFTime.create();
773 }
774 B2DEBUG(10, padright(" ", 100));
775 B2DEBUG(10, "----------------------------------------------------------------------------------------------------");
776 B2DEBUG(10, padright(" ", 100));
777 StoreObjPtr<EventMetaData> eventMetaData;
778 std::string experimentstring = "Experiment " + std::to_string(eventMetaData->getExperiment()) + " Run " +
779 std::to_string(eventMetaData->getRun()) + " Event " + std::to_string(eventMetaData->getEvent());
780 B2DEBUG(10, padright(experimentstring, 100));
781
783
784 if (m_exp < 7) {
785 B2DEBUG(20, "exp<7: skip cdctrg unpacker for DQM");
786 return;
787 }
788
789 // Read RawTRG data block.
790 B2DEBUG(99, m_rawTriggers.getEntries() << " COPPERs in RawTRGs");
791
792 // loop over all COPPERs
793 for (auto& rawTRG : m_rawTriggers) {
794
795 // Check PCIe40 data or Copper data
796 if (rawTRG.GetMaxNumOfCh(0) == 48) { m_pciedata = true; }
797 else if (rawTRG.GetMaxNumOfCh(0) == 4) { m_pciedata = false; }
798 else { B2FATAL("CDCTriggerUnpackerModule: Invalid value of GetMaxNumOfCh from raw data: " << LogVar("Number of ch: ", rawTRG.GetMaxNumOfCh(0))); }
799
800 const int subDetectorId = rawTRG.GetNodeID(0);
801 // const int iNode = (subDetectorId & 0xFFFFFF);
802 // number of entries in the rawTRG object.
803 const int nEntriesRawTRG = rawTRG.GetNumEntries();
804
805 // number of entries in rawTRG object ()
806 B2DEBUG(99, "nEntries of rawTRG: " << nEntriesRawTRG);
807 for (int j = 0; j < nEntriesRawTRG; ++j) {
808 //
809 // Search Data from Finesse A to D (0->3).
810 //
811 std::array<int, nFinesse> nWords;
812 std::array<int*, nFinesse> data32tab;
813 nWords.fill(0);
814
815 for (int iFinesse = 0; iFinesse < rawTRG.GetMaxNumOfCh(0); ++iFinesse) {
816 nWords[iFinesse] = rawTRG.GetDetectorNwords(j, iFinesse);
817 if (nWords[iFinesse] == 0) {
818 continue;
819 }
820 data32tab[iFinesse] = (int*)rawTRG.GetDetectorBuffer(j, iFinesse);
821 }
822 for (auto trg : m_subTrigger) {
823 //std::cout<<"This is m_subTrigger reserve and unpacker"<<std::endl;
824 // only unpack when there are enough words in the event
825 if (trg->getHeaders(subDetectorId, data32tab, nWords, m_pciedata)) {
826 //std::cout<<"This is m_subTrigger reserve"<<std::endl;
827 trg->reserve(subDetectorId, nWords, m_pciedata);
828 B2DEBUG(99, "starting to unpack a subTrigger, subDetectorId" << std::hex << subDetectorId);
829 //std::cout<<"This is m_subTrigger unpacker"<<std::endl;
830 trg->unpack(subDetectorId, data32tab, nWords, m_pciedata);
832 }
833 }
834 }
835 B2DEBUG(99, "looped over entries and filled words " << nEntriesRawTRG);
836 }
837 B2DEBUG(99, "looped over rawTriggers, unpacking 2D ");
838
839 // decode bitstream and make TSIM objects
841 for (short iclock = 0; iclock < m_bits2DTo3D.getEntries(); ++iclock) {
842 decode2DOutput(iclock - m_2DFinderDelay,
843 m_bits2DTo3D[iclock],
846 &m_TSHits);
847 }
848 }
849 B2DEBUG(99, "unpack 2D Input TS ");
851 std::array<int, 4> clockCounter2D = {0, 0, 0, 0};
852 std::array<int, 4> timeOffset2D = {0, 0, 0, 0};
853 // Align the data in other boards to 2D0 by looking at the CC in the midpoint of the time window
854 for (int iTracker = 0; iTracker < nTrackers; ++iTracker) {
855 if (! m_alignFoundTime || m_bitsTo2D.getEntries() == 0) {
856 break;
857 }
858 auto& trackerData = m_bitsTo2D[m_bitsTo2D.getEntries() / 2]->signal()[0][iTracker];
859 std::string strInput = slv_to_bin_string(trackerData);
860 clockCounter2D[iTracker] = std::stoi(strInput.substr(0, clockCounterWidth), 0, 2);
861 int clockCounterDiff = clockCounter2D[iTracker] - clockCounter2D[0];
862 /*
863 // clock counter rolls back to 0 from 319
864 if (clockCounterDiff > 300) {
865 clockCounterDiff -= 320;
866 } else if (clockCounterDiff < -300) {
867 clockCounterDiff += 320;
868 }
869 */
870 // clock counter rolls back to 0 from 1279, since certain B2L version, it has been changed to like this
871 if (clockCounterDiff > 1250) {
872 clockCounterDiff -= 1280;
873 } else if (clockCounterDiff < -1250) {
874 clockCounterDiff += 1280;
875 }
876 timeOffset2D[iTracker] = clockCounterDiff;
877 if (clockCounterDiff != 0) {
878 B2DEBUG(100, "Adding " << clockCounterDiff << " clock(s) to 2D" << iTracker << " found time");
879 }
880 if (std::abs(clockCounterDiff) > 2) {
881 B2DEBUG(20, "Clock counters between 2D [0," << iTracker << "] differ by " << clockCounterDiff << " clocks! (" \
882 << clockCounter2D[0] << ", " << clockCounter2D[iTracker] << ")");
883 }
884 }
885 for (short iclock = 0; iclock < m_bitsTo2D.getEntries(); ++iclock) {
886 B2DEBUG(30, "clock " << iclock);
887 decode2DInput(iclock - m_2DFinderDelay, timeOffset2D, m_bitsTo2D[iclock], &m_TSHits);
888 }
889 }
890 B2DEBUG(99, "now unpack neuro ");
891 if (m_decodeNeuro) {
892 if (m_useDB == true) {
893 if (m_isDNN) {
894 //std::cout<<"This is decode IO"<<std::endl;
897 } else {
900 }
901 } else {
903 }
904 }
905 B2DEBUG(99, " all is unpacked ##### ");
906}
907
SignalBus m_signal
SignalBus of the Bitstream.
Definition Bitstream.h:79
static constexpr std::array< int, 9 > nMergers
data width of a single merger unit
std::string m_neuro_track_name
name for neurotrigger array
int m_debugLevel
debug level specified in the steering file
StoreArray< RawTRG > m_rawTriggers
array containing the raw trigger data object
bool m_pciedata
PCIe40 data or copper data.
NodeList m_tracker2DNodeID_pcie40
list of (PCIe40 ID, ch ID) of 2D tracker
std::string m_neurotrigger_config_name
name for config saved in datastore
int m_headerSize
number of words (number of bits / 32) of the B2L header
int m_mergerDelay
Belle2Link delay of the merger reader.
bool m_sim13dt
bool value whether to simulate 13 bit drift time by using 2dcc
StoreArray< MergerBits > m_mergerBits
merger output bitstream
StoreArray< CDCTriggerMLPInput > m_NeuroInputs
decoded input vector for neural network
void initialize() override
Register input and output data.
int m_NeuroDelay
Belle2Link delay of the neurotrigger.
void event() override
convert raw data (in B2L buffer to bitstream)
bool m_isDNN
flag for unpacking DNN or not
std::string m_neuro_in_sTS_name
name for unpacked Neurotrigger input all stereo TSs array
NodeList m_neuroNodeID
list of (COPPER ID, HSLB ID) of neurotrigger
StoreArray< CDCTriggerUnpacker::T2DOutputBitStream > m_bits2DTo3D
bitstream of 2D output to 3D/Neuro
std::string m_neuro_in_etf_name
name for unpacked Neurotrigger input ETF T0 array
bool m_decodeNeuro
flag to decode neurotrigger data
void terminate() override
Delete dynamically allocated variables.
int m_2DFinderDelay
Belle2Link delay of the 2D finder.
StoreArray< CDCTriggerSegmentHit > m_TSHits
decoded track segment hit
bool m_alignFoundTime
flag to align found time in different sub-modules
bool m_unpackTracker2D
flag to unpack 2D tracker data
CDCTriggerUnpackerModule()
Constructor: Sets the description, the properties and the parameters of the module.
NodeList m_tracker2DNodeID
list of (COPPER ID, HSLB ID) of 2D tracker
StoreArray< CDCTriggerSegmentHit > m_NNInputTSHitsAll
all decoded stereo track segment hits from the neural network input
std::string m_neuro_in_2dtrack_name
name for unpacked Neurotrigger input 2d tracks array
StoreArray< CDCTriggerTrack > m_2DFinderTracks
decoded 2D finder track
bool m_decodeTSHit
flag to decode track segment
StoreArray< CDCTriggerUnpacker::DNNBitStream > m_bitsDNN
bitstream of DNN input and output (including intermediate results)
StoreArray< CDCTriggerTrack > m_NeuroTracks
decoded Neuro tracks
StoreArray< CDCTriggerTrack > m_NNInput2DFinderTracks
decoded 2D finder tracks from the neural network input
DBObjPtr< CDCTrigger2DConfig > m_dbn2DTS
condition database for number of TS in 2D
StoreObjPtr< BinnedEventT0 > m_ETFTime
store object for unpacked etf event time from neuro b2link
std::string m_neuro_scaled_input_name
name for unpacked Neurotrigger scaled input array
bool m_decode2DFinderInputTS
flag to decode 2D finder input TS
NodeList m_neuroNodeID_pcie40
list of (PCIe40 ID, ch ID) of neurotrigger
StoreArray< CDCTriggerUnpacker::NNBitStream > m_bitsNN
bitstream of Neuro input and output (including intermediate results)
std::string m_neuro_select_TS_name
name for unpacked Neurotrigger selected TSs array
NodeList m_mergerNodeID
list of (COPPER ID, HSLB ID) of Merger reader (TSF)
std::unique_ptr< DBObjPtr< CDCTriggerNeuroConfig > > m_cdctriggerneuroconfig
current neurotrigger config from database; used for unscaling network target
StoreArray< CDCTriggerFinderClone > m_2DFinderClones
additional information of the 2D finder track
StoreArray< CDCTriggerUnpacker::TSFOutputBitStream > m_bitsTo2D
bitstream of TSF output to 2D tracker
int m_n2DTS
flag to unpack 2D tracker data with 15TS
StoreArray< CDCTriggerSegmentHit > m_NNInputTSHits
decoded track segment hits from the neural network input
bool m_unpackNeuro
flag to unpack neurotrigger data
std::vector< SubTrigger * > m_subTrigger
vector holding the pointers to all the dynamically allocated SubTriggers
bool m_decode2DFinderTrack
flag to decode 2D finder track
bool m_useDB
bool value for whether to use the conditions database
bool m_unpackMerger
flag to unpack merger data (recorded by Merger Reader / TSF)
int getDebugLevel() const
Returns the configured debug messaging level.
Definition LogConfig.h:105
LogConfig & getLogConfig()
Returns the log system configuration.
Definition Module.h:224
void setDescription(const std::string &description)
Sets the description of the module.
Definition Module.cc:214
void setPropertyFlags(unsigned int propertyFlags)
Sets the flags for the module properties.
Definition Module.cc:208
Module()
Constructor.
Definition Module.cc:30
void setReturnValue(int value)
Sets the return value for this module as integer.
Definition Module.cc:220
@ c_ParallelProcessingCertified
This module can be run in parallel processing mode safely (All I/O must be done through the data stor...
Definition Module.h:80
Accessor to arrays stored in the data store.
Definition StoreArray.h:113
Type-safe access to single objects in the data store.
Definition StoreObjPtr.h:96
Class to store variables with their name which were sent to the logging service.
void addParam(const std::string &name, T &paramVariable, const std::string &description, const T &defaultValue)
Adds a new parameter to the module.
Definition Module.h:559
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition Module.h:649
static constexpr int wordWidth
width of a single word in the raw int buffer
static constexpr int mergerWidth
Merger data width.
std::vector< std::vector< int > > NodeList
Node list.
Abstract base class for different kinds of events.
STL namespace.
unpacker for the merger reader (TSF which reads the merger output)
StoreArray< MergerBits > * arrayPtr
pointer to the merger output Bitstream
void unpack(int subDetectorId, std::array< int *, 48 > data32tab, std::array< int, 48 > nWords, bool pciedata) override
Unpack function.
unsigned nInnerMergers
number of merger units in the inner super layer than this one
Merger(StoreArray< MergerBits > *inArrayPtr, const std::string &inName, unsigned inEventWidth, unsigned inOffset, int inHeaderSize, const std::vector< int > &inNodeID, const std::vector< int > &inNodeID_pcie40, unsigned inNInnerMergers, int &inDelay, int &inCnttrg, int inDebugLevel)
Constructor.
void reserve(int subDetectorId, std::array< int, nFinesse > nWords, bool pciedata) override
reserve enough number of clocks (entries) in the Bitstream StoreArray
unpacker for the Neuro
Neuro(StoreArray< T_bitstream > *arrPtr, const std::string &inName, unsigned inEventWidth, unsigned inOffset, unsigned inHeaderSize, const std::vector< int > &inNodeID, const std::vector< int > &inNodeID_pcie40, int &inDelay, int &inCnttrg, int inDebugLevel)
Constructor.
void unpack(int subDetectorId, std::array< int *, nFinesse > data32tab, std::array< int, nFinesse > nWords, bool pciedata) override
Unpack the Belle2Link data and fill the Bitstream.
StoreArray< T_bitstream > * ArrayPtr
Array pointer for NN.
unsigned offsetBitWidth
Offset bit width.
unsigned iTracker
Tracker board ID.
void reserve(int subDetectorId, std::array< int, nFinesse > nWords, bool pciedata) override
Calculate the number of clocks in the data, reserve that much of clocks in the Bitstream(s)
enum class SubTriggerType : unsigned char {Merger, TSF, T2D, T3D, Neuro, ETF};
int iNode_pcie40
PCIe40 id of the board.
int headerSize
Size of the B2L header in words.
unsigned offset
The starting point of the data in an event.
int debugLevel
debug level in the steering file
SubTrigger(const std::string &inName, unsigned inEventWidth, unsigned inOffset, int inHeaderSize, const std::vector< int > &inNodeID, const std::vector< int > &inNodeID_pcie40, int &inDelay, int &inCnttrg, int inDebugLevel=0)
constructor
std::string firmwareVersion
version of the FPGA firmware
int iFinesse
FINESSE (HSLB) id) of the board.
int iFinesse_pcie40
PCIe40 ch id of the board.
std::string name
Name of the UT3.
unsigned eventWidth
Size of an event in the Belle2Link data in 32-bit words.
int iNode
COPPER id of the board.
unpacker for the 2D tracker
Tracker2D(StoreArray< TSFOutputBitStream > *inArrayPtr, StoreArray< T2DOutputBitStream > *outArrayPtr, const std::string &inName, unsigned inEventWidth, unsigned inOffset, unsigned inHeaderSize, const std::vector< int > &inNodeID, const std::vector< int > &inNodeID_pcie40, unsigned inNumTS, int &inDelay, int &inCnttrg, int inDebugLevel)
constructor
StoreArray< T2DOutputBitStream > * outputArrayPtr
pointer to the Bitstream of 2D output to 3D/Neuro
void unpack(int subDetectorId, std::array< int *, 48 > data32tab, std::array< int, 48 > nWords, bool pciedata) override
Unpack the Belle2Link data and fill the Bitstream.
unsigned offsetBitWidth
starting point of the input data in an Belle2Link event
unsigned iTracker
ID of the 2D tracker (0 to 3)
unsigned numTS
Number of TS sent to 2D (0 to 20)
StoreArray< TSFOutputBitStream > * inputArrayPtr
pointer to the Bitstream of 2D input
void reserve(int subDetectorId, std::array< int, nFinesse > nWords, bool pciedata) override
Calculate the number of clocks in the data, reserve that much of clocks in the Bitstream(s)