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) {
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 ot 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 struct Neuro : SubTrigger {
452 const std::string& inName, unsigned inEventWidth, unsigned inOffset,
453 unsigned inHeaderSize, const std::vector<int>& inNodeID, const std::vector<int>& inNodeID_pcie40, int& inDelay,
454 int& inCnttrg,
455 int inDebugLevel) :
456 SubTrigger(inName, inEventWidth, inOffset / wordWidth, inHeaderSize, inNodeID, inNodeID_pcie40,
457 inDelay, inCnttrg, inDebugLevel),
458 ArrayPtr(arrPtr),
459 iTracker(std::stoul(inName.substr(inName.length() - 1))),
460 offsetBitWidth(inOffset) {};
461
465 unsigned iTracker;
468
469 void reserve(int subDetectorId, std::array<int, nFinesse> nWords, bool pciedata) override
470 {
471 int iNode_i = 0;
472 int iFinesse_i = 0;
473 if (pciedata) {
474 iNode_i = iNode_pcie40;
475 iFinesse_i = iFinesse_pcie40;
476 } else {
477 iNode_i = iNode;
478 iFinesse_i = iFinesse;
479 }
480
481 size_t nClocks = (nWords[iFinesse_i] - headerSize) / eventWidth;
482 size_t entries = ArrayPtr->getEntries();
483 if (subDetectorId == iNode_i) {
484 if (entries == 0) {
485 for (unsigned i = 0; i < nClocks; ++i) {
486 NNBitStream* nnclock = ArrayPtr->appendNew();
487 // fill bitstreams for all trackers with zeros
488 for (unsigned j = 0; j < nTrackers; ++j) {
489 nnclock->m_signal[j].fill(zero_val);
490 }
491 }
492 B2DEBUG(20, name << ": " << nClocks << " clocks");
493 } else if (entries != nClocks) {
494 B2DEBUG(20, "Number of clocks in " << name << " conflicts with others!");
495 }
496 }
497 };
498
499 void unpack(int subDetectorId,
500 std::array<int*, nFinesse> data32tab,
501 std::array<int, nFinesse> nWords,
502 bool pciedata) override
503 {
504 int iNode_i = 0;
505 int iFinesse_i = 0;
506 if (pciedata) {
507 iNode_i = iNode_pcie40;
508 iFinesse_i = iFinesse_pcie40;
509 } else {
510 iNode_i = iNode;
511 iFinesse_i = iFinesse;
512 }
513
514 if (subDetectorId != iNode_i) {
515 return;
516 }
517 // make bitstream
518 // loop over all clocks
519 for (int i = headerSize; i < nWords[iFinesse_i]; i += eventWidth) {
520 int iclock = (i - headerSize) / eventWidth;
521 auto nnclock = (*ArrayPtr)[iclock];
522 B2DEBUG(20, "clock " << iclock);
523 if (debugLevel >= 300) {
524 printBuffer(data32tab[iFinesse_i] + headerSize + eventWidth * iclock,
525 eventWidth);
526 }
527 // fill output
528 for (unsigned pos = 0; pos < NN_WIDTH; ++pos) {
529 const int j = (offsetBitWidth + pos) / wordWidth;
530 const int k = (offsetBitWidth + pos) % wordWidth;
531 std::bitset<wordWidth> word(data32tab[iFinesse_i][i + j]);
532 nnclock->m_signal[iTracker][pos] = std_logic(word[wordWidth - 1 - k]);
533 }
534 if (debugLevel >= 100) {
535 display_hex(nnclock->m_signal[iTracker]);
536 }
537 }
538 }
539 };
541};
542
544{
545 // Set module properties
546 setDescription("Unpack the CDC trigger data recorded in B2L");
548
549 // Parameter definitions
550 addParam("unpackMerger", m_unpackMerger,
551 "whether to unpack merger data (recorded by Merger Reader / TSF)", false);
552 addParam("unpackTracker2D", m_unpackTracker2D,
553 "whether to unpack 2D tracker data", false);
554 addParam("unpackNeuro", m_unpackNeuro,
555 "whether to unpacker neurotrigger data", false);
556 addParam("decode2DFinderTrack", m_decode2DFinderTrack,
557 "flag to decode 2D finder track", false);
558 addParam("decode2DFinderInput", m_decode2DFinderInputTS,
559 "flag to decode input TS to 2D", false);
560 addParam("decodeNeuro", m_decodeNeuro,
561 "flag to decode neurotrigger data", false);
562 // https://xwiki.desy.de/xwiki/rest/p/776d2 for CPR/HSLB
563 NodeList defaultMergerNodeID = { // These should be very temporary ones since no merger to B2L yet.
564 {0x11000001, 0},
565 {0x11000003, 0},
566 {0x11000001, 1},
567 {0x11000002, 0},
568 {0x11000002, 1}
569 };
570 addParam("MergerNodeId", m_mergerNodeID,
571 "list of COPPER and HSLB ID of Merger reader (TSF)", defaultMergerNodeID);
572 NodeList defaultTracker2DNodeID = {
573 {0x11000001, 0},
574 {0x11000001, 1},
575 {0x11000002, 0},
576 {0x11000002, 1}
577 };
578 addParam("2DNodeId", m_tracker2DNodeID,
579 "list of COPPER and HSLB ID of 2D tracker", defaultTracker2DNodeID);
580 NodeList defaultTracker2DNodeID_pcie40 = {
581 {0x10000001, 0},
582 {0x10000001, 1},
583 {0x10000001, 2},
584 {0x10000001, 3}
585 };
586 addParam("2DNodeId_pcie40", m_tracker2DNodeID_pcie40,
587 "list of PCIe40 ch ID of 2D tracker", defaultTracker2DNodeID_pcie40);
588
589 NodeList defaultNeuroNodeID = {
590 {0x11000005, 0},
591 {0x11000005, 1},
592 {0x11000006, 0},
593 {0x11000006, 1}
594 };
595 addParam("NeuroNodeId", m_neuroNodeID,
596 "list of COPPER and HSLB ID of neurotrigger", defaultNeuroNodeID);
597 NodeList defaultNeuroNodeID_pcie40 = {
598 {0x10000001, 8},
599 {0x10000001, 9},
600 {0x10000001, 10},
601 {0x10000001, 11}
602 };
603 addParam("NeuroNodeId_pcie40", m_neuroNodeID_pcie40,
604 "list of PCIe40 ch ID of neurotrigger", defaultNeuroNodeID_pcie40);
605
606 addParam("headerSize", m_headerSize,
607 "number of words (number of bits / 32) of the B2L header", 3);
608 addParam("alignFoundTime", m_alignFoundTime,
609 "Whether to align out-of-sync Belle2Link data between different sub-modules", true);
610 addParam("useDB", m_useDB,
611 "Use values stored in the payload of the ConditionsDB."
612 "This affects the output scaling of the Neurotrigger as well as the"
613 "bit configuration of its unpacker. If false, an old unpacker version with fixed scalings and old bit adresses is used.",
614 true);
615 addParam("sim13dt", m_sim13dt,
616 "Simulate 13 bit drift time by using 2d clock counter value.",
617 false);
618}
619
621{
623
624 //m_rawTriggers.isRequired();
625 if (m_unpackMerger) {
626 m_mergerBits.registerInDataStore("CDCTriggerMergerBits");
627 }
628 if (m_unpackTracker2D) {
629 m_bitsTo2D.registerInDataStore("CDCTriggerTSFTo2DBits");
630 m_bits2DTo3D.registerInDataStore("CDCTrigger2DTo3DBits");
631 }
632 if (m_unpackNeuro) {
633 m_bitsNN.registerInDataStore("CDCTriggerNNBits");
634 }
637 m_TSHits.registerInDataStore("CDCTriggerSegmentHits");
638 }
640 m_2DFinderTracks.registerInDataStore("CDCTrigger2DFinderTracks");
642 m_2DFinderClones.registerInDataStore("CDCTrigger2DFinderClones");
643 m_2DFinderClones.registerRelationTo(m_2DFinderTracks);
644 }
645 if (m_decodeNeuro) {
646 m_NNInputTSHitsAll.registerInDataStore("CDCTriggerNNInputAllStereoSegmentHits");
647 m_NNInputTSHits.registerInDataStore("CDCTriggerNNInputSegmentHits");
648 m_NNInput2DFinderTracks.registerInDataStore("CDCTriggerNNInput2DFinderTracks");
649 m_NeuroTracks.registerInDataStore("CDCTriggerNeuroTracks");
650 m_NeuroInputs.registerInDataStore("CDCTriggerNeuroTracksInput");
651 m_ETFTime.registerInDataStore("CDCTriggerNeuroETFT0");
658 }
659 for (int iSL = 0; iSL < 9; iSL += 2) {
660 if (m_unpackMerger) {
661 const int nInnerMergers = std::accumulate(nMergers.begin(),
662 nMergers.begin() + iSL, 0);
663 B2DEBUG(20, "in: " << nInnerMergers);
664 Merger* m_merger =
665 new Merger(&m_mergerBits,
666 "Merger" + std::to_string(iSL), mergerWidth * nMergers[8] / wordWidth,
668 m_mergerNodeID[iSL / 2], m_mergerNodeID[iSL / 2], nInnerMergers,
671 m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_merger));
672 }
673 }
674 // TODO In the default scenario, data in all trackers will be recorded.
675 // This is not the case for now (around first collision), where some coppers are lacking.
676 // Therefore it might help to make the following code more flexible
677 // so that we won't have a hard fail when some boards are missing
678
679 m_n2DTS = m_dbn2DTS->getnTS();
680 int datasize_2D = 64;
681 if (m_n2DTS == 10) {
682 datasize_2D = 64;
683 } else if (m_n2DTS == 15) {
684 datasize_2D = 82;
685 }
686
687 for (int iTracker = 0; iTracker < 4; ++iTracker) {
688 if (m_unpackTracker2D) {
689 Tracker2D* m_tracker2d =
691 "Tracker2D" + std::to_string(iTracker), datasize_2D, 82, m_headerSize,
692 m_tracker2DNodeID[iTracker], m_tracker2DNodeID_pcie40[iTracker], m_n2DTS,
695 m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_tracker2d));
696 }
697 if (m_unpackNeuro) {
698 Neuro* m_neuro =
699 new Neuro(&m_bitsNN,
700 "Neuro" + std::to_string(iTracker), 64, 0, m_headerSize,
702 m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_neuro));
703 }
704 }
705}
706
708{
709 for (auto bits : m_subTrigger) {
710 delete bits;
711 }
712}
713
715{
716
718 m_exp = bevt->getExperiment();
719 m_run = bevt->getRun();
720
721 if (not m_cdctriggerneuroconfig.isValid())
722 B2FATAL("CDCTriggerNeuroConfig is not valid.");
723 if (m_useDB == true) {
724 B2DEBUG(2, "Load Neurotrigger configuration for network " << m_cdctriggerneuroconfig->getNNName() << " from database ");
725 B2DEBUG(10, padright("Name", 50) << padright("start", 10) << padright("end", 10) << padright("offset", 10));
726 for (auto x : m_cdctriggerneuroconfig->getB2Format()) {
727 B2DEBUG(10, padright(x.name, 48) << ": " << padright(std::to_string(x.start), 10) << padright(std::to_string(x.end),
728 10) << padright(std::to_string(x.offset), 10));
729 }
730 }
731}
732
733
735{
736 if (m_decodeNeuro == true) {
737 // needed to unpack neuroinput etf time without problems
739 }
740 B2DEBUG(10, padright(" ", 100));
741 B2DEBUG(10, "----------------------------------------------------------------------------------------------------");
742 B2DEBUG(10, padright(" ", 100));
743 StoreObjPtr<EventMetaData> eventMetaData;
744 std::string experimentstring = "Experiment " + std::to_string(eventMetaData->getExperiment()) + " Run " +
745 std::to_string(eventMetaData->getRun()) + " Event " + std::to_string(eventMetaData->getEvent());
746 B2DEBUG(10, padright(experimentstring, 100));
747
749
750 if (m_exp < 7) {
751 B2DEBUG(20, "exp<7: skip cdctrg unpacker for DQM");
752 return;
753 }
754
755 // Read RawTRG data block.
756 B2DEBUG(99, m_rawTriggers.getEntries() << " COPPERs in RawTRGs");
757
758 // loop over all COPPERs
759 for (auto& rawTRG : m_rawTriggers) {
760
761 // Check PCIe40 data or Copper data
762 if (rawTRG.GetMaxNumOfCh(0) == 48) { m_pciedata = true; }
763 else if (rawTRG.GetMaxNumOfCh(0) == 4) { m_pciedata = false; }
764 else { B2FATAL("CDCTriggerUnpackerModule: Invalid value of GetMaxNumOfCh from raw data: " << LogVar("Number of ch: ", rawTRG.GetMaxNumOfCh(0))); }
765
766 const int subDetectorId = rawTRG.GetNodeID(0);
767 // const int iNode = (subDetectorId & 0xFFFFFF);
768 // number of entries in the rawTRG object.
769 const int nEntriesRawTRG = rawTRG.GetNumEntries();
770
771 // number of entries in rawTRG object ()
772 B2DEBUG(99, "nEntries of rawTRG: " << nEntriesRawTRG);
773 for (int j = 0; j < nEntriesRawTRG; ++j) {
774 //
775 // Search Data from Finesse A to D (0->3).
776 //
777 std::array<int, nFinesse> nWords;
778 std::array<int*, nFinesse> data32tab;
779 nWords.fill(0);
780
781 for (int iFinesse = 0; iFinesse < rawTRG.GetMaxNumOfCh(0); ++iFinesse) {
782 nWords[iFinesse] = rawTRG.GetDetectorNwords(j, iFinesse);
783 if (nWords[iFinesse] == 0) {
784 continue;
785 }
786 data32tab[iFinesse] = (int*)rawTRG.GetDetectorBuffer(j, iFinesse);
787 }
788
789 for (auto trg : m_subTrigger) {
790 // only unpack when there are enough words in the event
791 if (trg->getHeaders(subDetectorId, data32tab, nWords, m_pciedata)) {
792 trg->reserve(subDetectorId, nWords, m_pciedata);
793 B2DEBUG(99, "starting to unpack a subTrigger, subDetectorId" << std::hex << subDetectorId);
794 trg->unpack(subDetectorId, data32tab, nWords, m_pciedata);
796 }
797 }
798 }
799 B2DEBUG(99, "looped over entries and filled words " << nEntriesRawTRG);
800 }
801 B2DEBUG(99, "looped over rawTriggers, unpacking 2D ");
802
803 // decode bitstream and make TSIM objects
805 for (short iclock = 0; iclock < m_bits2DTo3D.getEntries(); ++iclock) {
806 decode2DOutput(iclock - m_2DFinderDelay,
807 m_bits2DTo3D[iclock],
810 &m_TSHits);
811 }
812 }
813 B2DEBUG(99, "unpack 2D Input TS ");
815 std::array<int, 4> clockCounter2D = {0, 0, 0, 0};
816 std::array<int, 4> timeOffset2D = {0, 0, 0, 0};
817 // Align the data in other boards to 2D0 by looking at the CC in the midpoint of the time window
818 for (int iTracker = 0; iTracker < nTrackers; ++iTracker) {
819 if (! m_alignFoundTime || m_bitsTo2D.getEntries() == 0) {
820 break;
821 }
822 auto& trackerData = m_bitsTo2D[m_bitsTo2D.getEntries() / 2]->signal()[0][iTracker];
823 std::string strInput = slv_to_bin_string(trackerData);
824 clockCounter2D[iTracker] = std::stoi(strInput.substr(0, clockCounterWidth), 0, 2);
825 int clockCounterDiff = clockCounter2D[iTracker] - clockCounter2D[0];
826 /*
827 // clock counter rolls back to 0 from 319
828 if (clockCounterDiff > 300) {
829 clockCounterDiff -= 320;
830 } else if (clockCounterDiff < -300) {
831 clockCounterDiff += 320;
832 }
833 */
834 // clock counter rolls back to 0 from 1279, since certain B2L version, it has been changed to like this
835 if (clockCounterDiff > 1250) {
836 clockCounterDiff -= 1280;
837 } else if (clockCounterDiff < -1250) {
838 clockCounterDiff += 1280;
839 }
840 timeOffset2D[iTracker] = clockCounterDiff;
841 if (clockCounterDiff != 0) {
842 B2DEBUG(100, "Adding " << clockCounterDiff << " clock(s) to 2D" << iTracker << " found time");
843 }
844 if (std::abs(clockCounterDiff) > 2) {
845 B2DEBUG(20, "Clock counters between 2D [0," << iTracker << "] differ by " << clockCounterDiff << " clocks! (" \
846 << clockCounter2D[0] << ", " << clockCounter2D[iTracker] << ")");
847 }
848 }
849 for (short iclock = 0; iclock < m_bitsTo2D.getEntries(); ++iclock) {
850 B2DEBUG(30, "clock " << iclock);
851 decode2DInput(iclock - m_2DFinderDelay, timeOffset2D, m_bitsTo2D[iclock], &m_TSHits);
852 }
853 }
854 B2DEBUG(99, "now unpack neuro ");
855 if (m_decodeNeuro) {
856 if (m_useDB == true) {
859 } else {
861 }
862 }
863 B2DEBUG(99, " all is unpacked ##### ");
864}
865
Class to hold one clock cycle of raw bit content.
Definition: Bitstream.h:54
SignalBus m_signal
SignalBus of the Bitstream.
Definition: Bitstream.h:77
static constexpr std::array< int, 9 > nMergers
data width of a single merger unit
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
DBObjPtr< CDCTriggerNeuroConfig > m_cdctriggerneuroconfig
current neurotrigger config from database; used for unscaling network target
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 wether 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)
NodeList m_neuroNodeID
list of (COPPER ID, HSLB ID) of neurotrigger
StoreArray< CDCTriggerUnpacker::T2DOutputBitStream > m_bits2DTo3D
bitstream of 2D output to 3D/Neuro
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
StoreArray< CDCTriggerTrack > m_2DFinderTracks
decoded 2D finder track
bool m_decodeTSHit
flag to decode track segment
StoreArray< CDCTriggerTrack > m_NeuroTracks
decoded Neuro tracks
StoreArray< CDCTriggerTrack > m_NNInput2DFinderTracks
decoded 2D finder tracks from the neural network input
StoreObjPtr< BinnedEventT0 > m_ETFTime
store object for unpacked etf event time from neuro b2link
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)
NodeList m_mergerNodeID
list of (COPPER ID, HSLB ID) of Merger reader (TSF)
StoreArray< CDCTriggerFinderClone > m_2DFinderClones
additional information of the 2D finder track
StoreArray< CDCTriggerUnpacker::TSFOutputBitStream > m_bitsTo2D
bitstream of TSF output to 2D tracker
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 wether 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
Base class for Modules.
Definition: Module.h:72
LogConfig & getLogConfig()
Returns the log system configuration.
Definition: Module.h:225
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
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
bool registerInDataStore(DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut)
Register the object/array in the DataStore.
bool create(bool replace=false)
Create a default object in the data store.
Accessor to arrays stored in the data store.
Definition: StoreArray.h:113
T * appendNew()
Construct a new T object at the end of the array.
Definition: StoreArray.h:246
int getEntries() const
Get the number of objects in the array.
Definition: StoreArray.h:216
bool registerRelationTo(const StoreArray< TO > &toArray, DataStore::EDurability durability=DataStore::c_Event, DataStore::EStoreFlags storeFlags=DataStore::c_WriteOut, const std::string &namedRelation="") const
Register a relation to the given StoreArray.
Definition: StoreArray.h:140
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:96
bool isValid() const
Check whether the object was created.
Definition: StoreObjPtr.h:111
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:560
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
Definition: Module.h:650
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< NNBitStream > *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< NNBitStream > * 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
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)