Belle II Software  release-08-01-10
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 
19 using namespace Belle2;
20 using namespace CDCTriggerUnpacker;
21 
22 
23 //-----------------------------------------------------------------
24 // Register the Module
25 //-----------------------------------------------------------------
26 REG_MODULE(CDCTriggerUnpacker);
27 
28 //-----------------------------------------------------------------
29 // Implementation
30 //-----------------------------------------------------------------
31 
32 constexpr std::array<int, 9> CDCTriggerUnpackerModule::nMergers;
33 using dataWord = std::bitset<wordWidth>;
34 
35 namespace 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 
158  StoreArray<T2DOutputBitStream>* outArrayPtr,
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;
179  unsigned offsetBitWidth;
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[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 
232  void unpack(int subDetectorId,
233  std::array<int*, 48> data32tab,
234  std::array<int, 48> nWords,
235  bool pciedata) override
236  {
237  int iNode_i = 0;
238  int iFinesse_i = 0;
239  if (pciedata) {
240  iNode_i = iNode_pcie40;
241  iFinesse_i = iFinesse_pcie40;
242  } else {
243  iNode_i = iNode;
244  iFinesse_i = iFinesse;
245  }
246 
247  if (subDetectorId != iNode_i) {
248  return;
249  }
250  // Recently, the content of the last clock appears at the beginning.
251  // Now we decide whether we will change the order of the clocks
252  // based on the 127MHz counter on the 2nd half of the first word [15:0]
253  int ccShift = 0;
254  using halfDataWord = std::bitset<16>;
255  std::vector<halfDataWord> counters;
256  counters.reserve(inputArrayPtr->getEntries());
257  for (int iclock = 0; iclock < inputArrayPtr->getEntries(); ++iclock) {
258  counters.emplace_back(data32tab[iFinesse_i]
259  [headerSize + eventWidth * iclock] & 0xffff);
260  B2DEBUG(100, "iclock " << iclock << " --> " << counters.at(iclock).to_ulong() << " : " << std::hex << counters.at(iclock));
261  }
262  bool counter_correct_error = false;
263  while (counters.at(1).to_ulong() - counters.at(0).to_ulong() != 4) {
264  std::rotate(counters.begin(), counters.begin() + 1, counters.end());
265  ccShift++;
266  // 2019,0410 This situation, looks like clockcounter shifted 6 bits left, was first seen in exp5 data.
267  // 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.
268  // The data header is 0xbbbb instead of 0xdddd.
269  // getHeader in the CDCTriggerUnpackerModule.h is modified to skip this kind event.
270  // 2019,0419 unfortunately, clockcounter found disorder since expt 7, run 2553, after update of B2L firmware to replace the b2dly with trigger counter.
271  // for that run, it seems the problem happens only at 2D1, 2D2, and 2D3.
272  if (ccShift >= inputArrayPtr->getEntries()) {
273  B2DEBUG(90, "PHYSJG: clock counter rotation over one cycle: " << ccShift);
274  for (const auto& c : counters) {
275  B2DEBUG(90, "" << c.to_ulong() << " : " << std::hex << c);
276  }
277  counter_correct_error = true;
278  break;
279  }
280  }
281  if (counter_correct_error) {
282  B2DEBUG(20, "PHYSJG: " << name << " too many clock counter rotation corrections: " << ccShift << " data object skipped.");
283  // maybe implement an option for user to decide if this data block should be kept or not?!
284  return;
285  }
286  if (! std::is_sorted(counters.begin(), counters.end(),
287  [](halfDataWord i, halfDataWord j) {
288  return (j.to_ulong() - i.to_ulong() == 4);
289  })) {
290  B2DEBUG(20, "clock counters are still out of order");
291  for (const auto& c : counters) {
292  B2DEBUG(90, "" << c.to_ulong());
293  }
294  }
295  // 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.
296  if (ccShift) {
297  B2DEBUG(15, "shifting the first " << ccShift <<
298  " clock(s) to the end for " << name);
299  }
300 
301  // get event body information
302  // make bitstream
303  // loop over all clocks
304  for (int i = headerSize; i < nWords[iFinesse_i]; i += eventWidth) {
305  int iclock = (i - headerSize) / eventWidth - ccShift;
306  if (iclock < 0) {
307  iclock += inputArrayPtr->getEntries();
308  }
309  auto inputClock = (*inputArrayPtr)[iclock];
310  auto outputClock = (*outputArrayPtr)[iclock];
311  // clear output bitstream
312  outputClock->m_signal[iTracker].fill(zero_val);
313  B2DEBUG(90, "unpacker clock " << iclock);
314  if (debugLevel >= 300) {
315  printBuffer(data32tab[iFinesse_i] + headerSize + eventWidth * iclock,
316  eventWidth);
317  }
318  // get the clock counters
319  std::array<dataWord, 2> ccword({
320  data32tab[iFinesse_i][i + 2], data32tab[iFinesse_i][i + 3]
321  });
322  // fill input
323  // Careful! this iTSF is (8 - iSL) / 2
324  for (unsigned iTSF = 0; iTSF < nAxialTSF; ++iTSF) {
325  // clear input bitstream
326  inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker].fill(zero_val);
327 
328  if (firmwareVersion < "18012600") {
329  /*
330  data_b2l_r <=
331  x"dddd" & cntr125M(15 downto 0) &
332  cc(4) & cc(3) & cc(2) & cc(1) & cc(0) &
333  ccError &
334  -- 82
335  tsfs(4)(209 downto 0) &
336  tsfs(3)(209 downto 0) &
337  tsfs(2)(209 downto 0) &
338  tsfs(1)(209 downto 0) &
339  tsfs(0)(209 downto 0) &
340  */
341  // fill the clock counters
342  for (unsigned pos = 0; pos < clockCounterWidth; ++pos) {
343  const int j = (pos + iTSF * clockCounterWidth) / wordWidth;
344  const int k = (pos + iTSF * clockCounterWidth) % wordWidth;
345  /* The index behaves differently in each containers
346  Here is an example of a 64-bit wide MSB data
347  |-------- smaller index in the firmware ----->
348 
349  data in the firmware/VHDL std_logic_vector(63 downto 0)
350  63 62 61 60 ... 01 00
351 
352  data in B2L/RawTRG (when using std::bitset<32> for a word)
353  (31 30 29 28 ... 01 00) (31 30 29 28 ... 01 00)
354  |------ word 0 -------| |------ word 1 -------|
355 
356  XSim / Bitstream of std::array<char, N> / std::string
357  00 01 02 03 ... 62 63
358  */
359  // Here we are filling std::array<char, N>, which has reversed order
360  // to std::bitset, so there is a - sign in [wordWidth - k]
361  inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker][pos] =
362  std_logic(ccword[j][wordWidth - k]);
363  }
364  // fill the TS hit
365  offsetBitWidth = 82;
366  for (unsigned pos = 0; pos < numTS * lenTS; ++pos) {
367  const int j = (offsetBitWidth + pos + iTSF * numTS * lenTS) / wordWidth;
368  const int k = (offsetBitWidth + pos + iTSF * numTS * lenTS) % wordWidth;
369  dataWord word(data32tab[iFinesse_i][i + j]);
370  // MSB (leftmost) in firmware -> smallest index in Bitstream's
371  // std::array (due to XSIM) -> largest index in std::bitset
372  // so the index is reversed in this assignment
373  inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker]
374  [clockCounterWidth + pos] = std_logic(word[wordWidth - 1 - k]);
375  }
376  } else {
377  /*
378  x"dddd" & (15 downto 11 => '0') & revoclk &
379  cntr125M(15 downto 0) &
380  (15 downto 5 => '0') & ccError &
381  -- 64
382  cc(4) & tsfs(4)(209 downto 0) &
383  cc(3) & tsfs(3)(209 downto 0) &
384  cc(2) & tsfs(2)(209 downto 0) &
385  cc(1) & tsfs(1)(209 downto 0) &
386  cc(0) & tsfs(0)(209 downto 0) &
387  */
388  // fill the cc and TS hit
389  offsetBitWidth = 64;
390  unsigned TSFWidth = clockCounterWidth + numTS * lenTS;
391  for (unsigned pos = 0; pos < TSFWidth; ++pos) {
392  const int j = (offsetBitWidth + pos + iTSF * TSFWidth) / wordWidth;
393  const int k = (offsetBitWidth + pos + iTSF * TSFWidth) % wordWidth;
394  dataWord word(data32tab[iFinesse_i][i + j]);
395  inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker][pos] =
396  std_logic(word[wordWidth - 1 - k]);
397  }
398  }
399  if (debugLevel >= 100) {
400  display_hex(inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker]);
401  }
402  }
403  // fill output
404  if (firmwareVersion < "18012600") {
405  /*
406  -- 1132
407  Main_out(731 downto 0) &
408  */
409  const int outputOffset = nAxialTSF * numTS * lenTS;
410  const int oldtrackWidth = 6;
411  for (unsigned pos = 0; pos < 732; ++pos) {
412  const int j = (offsetBitWidth + pos + outputOffset) / wordWidth;
413  const int k = (offsetBitWidth + pos + outputOffset) % wordWidth;
414  dataWord word(data32tab[iFinesse_i][i + j]);
415  outputClock->m_signal[iTracker][clockCounterWidth + oldtrackWidth + pos]
416  = std_logic(word[wordWidth - 1 - k]);
417  }
418  } else {
419  /*
420  -- 1159
421  old_track(5 downto 0) &
422  Main_out(731 downto 0) &
423  */
424  //const int outputOffset = 1159;
425  const int outputOffset = offsetBitWidth + nAxialTSF * numTS * lenTS + 45; //1159 with numTS=10 , 1684 with numTS=15
426  for (unsigned pos = 0; pos < T2DOutputWidth; ++pos) {
427  const int j = (pos + outputOffset) / wordWidth;
428  const int k = (pos + outputOffset) % wordWidth;
429  dataWord word(data32tab[iFinesse_i][i + j]);
430  outputClock->m_signal[iTracker][clockCounterWidth + pos]
431  = std_logic(word[wordWidth - 1 - k]);
432  }
433  }
434  if (debugLevel >= 100) {
435  display_hex(outputClock->m_signal[iTracker]);
436  }
437  }
438  }
439  };
440 
442  struct Neuro : SubTrigger {
445  const std::string& inName, unsigned inEventWidth, unsigned inOffset,
446  unsigned inHeaderSize, const std::vector<int>& inNodeID, const std::vector<int>& inNodeID_pcie40, int& inDelay,
447  int& inCnttrg,
448  int inDebugLevel) :
449  SubTrigger(inName, inEventWidth, inOffset / wordWidth, inHeaderSize, inNodeID, inNodeID_pcie40,
450  inDelay, inCnttrg, inDebugLevel),
451  ArrayPtr(arrPtr),
452  iTracker(std::stoul(inName.substr(inName.length() - 1))),
453  offsetBitWidth(inOffset) {};
454 
458  unsigned iTracker;
460  unsigned offsetBitWidth;
461 
462  void reserve(int subDetectorId, std::array<int, nFinesse> nWords, bool pciedata) override
463  {
464  int iNode_i = 0;
465  int iFinesse_i = 0;
466  if (pciedata) {
467  iNode_i = iNode_pcie40;
468  iFinesse_i = iFinesse_pcie40;
469  } else {
470  iNode_i = iNode;
471  iFinesse_i = iFinesse;
472  }
473 
474  size_t nClocks = (nWords[iFinesse_i] - headerSize) / eventWidth;
475  size_t entries = ArrayPtr->getEntries();
476  if (subDetectorId == iNode_i) {
477  if (entries == 0) {
478  for (unsigned i = 0; i < nClocks; ++i) {
479  NNBitStream* nnclock = ArrayPtr->appendNew();
480  // fill bitstreams for all trackers with zeros
481  for (unsigned j = 0; j < nTrackers; ++j) {
482  nnclock->m_signal[j].fill(zero_val);
483  }
484  }
485  B2DEBUG(20, name << ": " << nClocks << " clocks");
486  } else if (entries != nClocks) {
487  B2DEBUG(20, "Number of clocks in " << name << " conflicts with others!");
488  }
489  }
490  };
491 
492  void unpack(int subDetectorId,
493  std::array<int*, nFinesse> data32tab,
494  std::array<int, nFinesse> nWords,
495  bool pciedata) override
496  {
497  int iNode_i = 0;
498  int iFinesse_i = 0;
499  if (pciedata) {
500  iNode_i = iNode_pcie40;
501  iFinesse_i = iFinesse_pcie40;
502  } else {
503  iNode_i = iNode;
504  iFinesse_i = iFinesse;
505  }
506 
507  if (subDetectorId != iNode_i) {
508  return;
509  }
510  // make bitstream
511  // loop over all clocks
512  for (int i = headerSize; i < nWords[iFinesse_i]; i += eventWidth) {
513  int iclock = (i - headerSize) / eventWidth;
514  auto nnclock = (*ArrayPtr)[iclock];
515  B2DEBUG(20, "clock " << iclock);
516  if (debugLevel >= 300) {
517  printBuffer(data32tab[iFinesse_i] + headerSize + eventWidth * iclock,
518  eventWidth);
519  }
520  // fill output
521  for (unsigned pos = 0; pos < NN_WIDTH; ++pos) {
522  const int j = (offsetBitWidth + pos) / wordWidth;
523  const int k = (offsetBitWidth + pos) % wordWidth;
524  std::bitset<wordWidth> word(data32tab[iFinesse_i][i + j]);
525  nnclock->m_signal[iTracker][pos] = std_logic(word[wordWidth - 1 - k]);
526  }
527  if (debugLevel >= 100) {
528  display_hex(nnclock->m_signal[iTracker]);
529  }
530  }
531  }
532  };
534 };
535 
537 {
538  // Set module properties
539  setDescription("Unpack the CDC trigger data recorded in B2L");
541 
542  // Parameter definitions
543  addParam("unpackMerger", m_unpackMerger,
544  "whether to unpack merger data (recorded by Merger Reader / TSF)", false);
545  addParam("unpackTracker2D", m_unpackTracker2D,
546  "whether to unpack 2D tracker data", false);
547  addParam("unpackNeuro", m_unpackNeuro,
548  "whether to unpacker neurotrigger data", false);
549  addParam("decode2DFinderTrack", m_decode2DFinderTrack,
550  "flag to decode 2D finder track", false);
551  addParam("decode2DFinderInput", m_decode2DFinderInputTS,
552  "flag to decode input TS to 2D", false);
553  addParam("decodeNeuro", m_decodeNeuro,
554  "flag to decode neurotrigger data", false);
555  // https://confluence.desy.de/display/BI/DAQ+and+Operation for CPR/HSLB
556  NodeList defaultMergerNodeID = { // These should be very temporary ones since no merger to B2L yet.
557  {0x11000001, 0},
558  {0x11000003, 0},
559  {0x11000001, 1},
560  {0x11000002, 0},
561  {0x11000002, 1}
562  };
563  addParam("MergerNodeId", m_mergerNodeID,
564  "list of COPPER and HSLB ID of Merger reader (TSF)", defaultMergerNodeID);
565  NodeList defaultTracker2DNodeID = {
566  {0x11000001, 0},
567  {0x11000001, 1},
568  {0x11000002, 0},
569  {0x11000002, 1}
570  };
571  addParam("2DNodeId", m_tracker2DNodeID,
572  "list of COPPER and HSLB ID of 2D tracker", defaultTracker2DNodeID);
573  NodeList defaultTracker2DNodeID_pcie40 = {
574  {0x10000001, 0},
575  {0x10000001, 1},
576  {0x10000001, 2},
577  {0x10000001, 3}
578  };
579  addParam("2DNodeId_pcie40", m_tracker2DNodeID_pcie40,
580  "list of PCIe40 ch ID of 2D tracker", defaultTracker2DNodeID_pcie40);
581 
582  NodeList defaultNeuroNodeID = {
583  {0x11000005, 0},
584  {0x11000005, 1},
585  {0x11000006, 0},
586  {0x11000006, 1}
587  };
588  addParam("NeuroNodeId", m_neuroNodeID,
589  "list of COPPER and HSLB ID of neurotrigger", defaultNeuroNodeID);
590  NodeList defaultNeuroNodeID_pcie40 = {
591  {0x10000001, 8},
592  {0x10000001, 9},
593  {0x10000001, 10},
594  {0x10000001, 11}
595  };
596  addParam("NeuroNodeId_pcie40", m_neuroNodeID_pcie40,
597  "list of PCIe40 ch ID of neurotrigger", defaultNeuroNodeID_pcie40);
598 
599  addParam("headerSize", m_headerSize,
600  "number of words (number of bits / 32) of the B2L header", 3);
601  addParam("alignFoundTime", m_alignFoundTime,
602  "Whether to align out-of-sync Belle2Link data between different sub-modules", true);
603  addParam("useDB", m_useDB,
604  "Use values stored in the payload of the ConditionsDB."
605  "This affects the output scaling of the Neurotrigger as well as the"
606  "bit configuration of its unpacker. If false, an old unpacker version with fixed scalings and old bit adresses is used.",
607  true);
608  addParam("sim13dt", m_sim13dt,
609  "Simulate 13 bit drift time by using 2d clock counter value.",
610  false);
611 }
612 
614 {
616 
617  //m_rawTriggers.isRequired();
618  if (m_unpackMerger) {
619  m_mergerBits.registerInDataStore("CDCTriggerMergerBits");
620  }
621  if (m_unpackTracker2D) {
622  m_bitsTo2D.registerInDataStore("CDCTriggerTSFTo2DBits");
623  m_bits2DTo3D.registerInDataStore("CDCTrigger2DTo3DBits");
624  }
625  if (m_unpackNeuro) {
626  m_bitsNN.registerInDataStore("CDCTriggerNNBits");
627  }
630  m_TSHits.registerInDataStore("CDCTriggerSegmentHits");
631  }
632  if (m_decode2DFinderTrack) {
633  m_2DFinderTracks.registerInDataStore("CDCTrigger2DFinderTracks");
635  m_2DFinderClones.registerInDataStore("CDCTrigger2DFinderClones");
636  m_2DFinderClones.registerRelationTo(m_2DFinderTracks);
637  }
638  if (m_decodeNeuro) {
639  m_NNInputTSHitsAll.registerInDataStore("CDCTriggerNNInputAllStereoSegmentHits");
640  m_NNInputTSHits.registerInDataStore("CDCTriggerNNInputSegmentHits");
641  m_NNInput2DFinderTracks.registerInDataStore("CDCTriggerNNInput2DFinderTracks");
642  m_NeuroTracks.registerInDataStore("CDCTriggerNeuroTracks");
643  m_NeuroInputs.registerInDataStore("CDCTriggerNeuroTracksInput");
644  m_ETFTime.registerInDataStore("CDCTriggerNeuroETFT0");
651  }
652  for (int iSL = 0; iSL < 9; iSL += 2) {
653  if (m_unpackMerger) {
654  const int nInnerMergers = std::accumulate(nMergers.begin(),
655  nMergers.begin() + iSL, 0);
656  B2DEBUG(20, "in: " << nInnerMergers);
657  Merger* m_merger =
658  new Merger(&m_mergerBits,
659  "Merger" + std::to_string(iSL), mergerWidth * nMergers[8] / wordWidth,
661  m_mergerNodeID[iSL / 2], m_mergerNodeID[iSL / 2], nInnerMergers,
663  m_debugLevel);
664  m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_merger));
665  }
666  }
667  // TODO In the default scenario, data in all trackers will be recorded.
668  // This is not the case for now (around first collision), where some coppers are lacking.
669  // Therefore it might help to make the following code more flexible
670  // so that we won't have a hard fail when some boards are missing
671 
672  m_n2DTS = m_dbn2DTS->getnTS();
673  int datasize_2D = 64;
674  if (m_n2DTS == 10) {
675  datasize_2D = 64;
676  } else if (m_n2DTS == 15) {
677  datasize_2D = 82;
678  }
679 
680  for (int iTracker = 0; iTracker < 4; ++iTracker) {
681  if (m_unpackTracker2D) {
682  Tracker2D* m_tracker2d =
684  "Tracker2D" + std::to_string(iTracker), datasize_2D, 82, m_headerSize,
685  m_tracker2DNodeID[iTracker], m_tracker2DNodeID_pcie40[iTracker], m_n2DTS,
687  m_debugLevel);
688  m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_tracker2d));
689  }
690  if (m_unpackNeuro) {
691  Neuro* m_neuro =
692  new Neuro(&m_bitsNN,
693  "Neuro" + std::to_string(iTracker), 64, 0, m_headerSize,
695  m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_neuro));
696  }
697  }
698 }
699 
701 {
702  for (auto bits : m_subTrigger) {
703  delete bits;
704  }
705 }
706 
708 {
709 
711  m_exp = bevt->getExperiment();
712  m_run = bevt->getRun();
713 
714  if (not m_cdctriggerneuroconfig.isValid())
715  B2FATAL("CDCTriggerNeuroConfig is not valid.");
716  if (m_useDB == true) {
717  B2DEBUG(2, "Load Neurotrigger configuration for network " << m_cdctriggerneuroconfig->getNNName() << " from database ");
718  B2DEBUG(10, padright("Name", 50) << padright("start", 10) << padright("end", 10) << padright("offset", 10));
719  for (auto x : m_cdctriggerneuroconfig->getB2Format()) {
720  B2DEBUG(10, padright(x.name, 48) << ": " << padright(std::to_string(x.start), 10) << padright(std::to_string(x.end),
721  10) << padright(std::to_string(x.offset), 10));
722  }
723  }
724 }
725 
726 
728 {
729  if (m_decodeNeuro == true) {
730  // needed to unpack neuroinput etf time without problems
731  if (!m_ETFTime.isValid()) m_ETFTime.create();
732  }
733  B2DEBUG(10, padright(" ", 100));
734  B2DEBUG(10, "----------------------------------------------------------------------------------------------------");
735  B2DEBUG(10, padright(" ", 100));
736  StoreObjPtr<EventMetaData> eventMetaData;
737  std::string experimentstring = "Experiment " + std::to_string(eventMetaData->getExperiment()) + " Run " +
738  std::to_string(eventMetaData->getRun()) + " Event " + std::to_string(eventMetaData->getEvent());
739  B2DEBUG(10, padright(experimentstring, 100));
740 
741  setReturnValue(0);
742 
743  if (m_exp < 7) {
744  B2DEBUG(20, "exp<7: skip cdctrg unpacker for DQM");
745  return;
746  }
747 
748  // Read RawTRG data block.
749  B2DEBUG(99, m_rawTriggers.getEntries() << " COPPERs in RawTRGs");
750 
751  // loop over all COPPERs
752  for (auto& rawTRG : m_rawTriggers) {
753 
754  // Check PCIe40 data or Copper data
755  if (rawTRG.GetMaxNumOfCh(0) == 48) { m_pciedata = true; }
756  else if (rawTRG.GetMaxNumOfCh(0) == 4) { m_pciedata = false; }
757  else { B2FATAL("CDCTriggerUnpackerModule: Invalid value of GetMaxNumOfCh from raw data: " << LogVar("Number of ch: ", rawTRG.GetMaxNumOfCh(0))); }
758 
759  const int subDetectorId = rawTRG.GetNodeID(0);
760  // const int iNode = (subDetectorId & 0xFFFFFF);
761  // number of entries in the rawTRG object.
762  const int nEntriesRawTRG = rawTRG.GetNumEntries();
763 
764  // number of entries in rawTRG object ()
765  B2DEBUG(99, "nEntries of rawTRG: " << nEntriesRawTRG);
766  for (int j = 0; j < nEntriesRawTRG; ++j) {
767  //
768  // Search Data from Finesse A to D (0->3).
769  //
770  std::array<int, nFinesse> nWords;
771  std::array<int*, nFinesse> data32tab;
772  nWords.fill(0);
773 
774  for (int iFinesse = 0; iFinesse < rawTRG.GetMaxNumOfCh(0); ++iFinesse) {
775  nWords[iFinesse] = rawTRG.GetDetectorNwords(j, iFinesse);
776  if (nWords[iFinesse] == 0) {
777  continue;
778  }
779  data32tab[iFinesse] = (int*)rawTRG.GetDetectorBuffer(j, iFinesse);
780  }
781 
782  for (auto trg : m_subTrigger) {
783  // only unpack when there are enough words in the event
784  if (trg->getHeaders(subDetectorId, data32tab, nWords, m_pciedata)) {
785  trg->reserve(subDetectorId, nWords, m_pciedata);
786  B2DEBUG(99, "starting to unpack a subTrigger, subDetectorId" << std::hex << subDetectorId);
787  trg->unpack(subDetectorId, data32tab, nWords, m_pciedata);
788  setReturnValue(1);
789  }
790  }
791  }
792  B2DEBUG(99, "looped over entries and filled words " << nEntriesRawTRG);
793  }
794  B2DEBUG(99, "looped over rawTriggers, unpacking 2D ");
795 
796  // decode bitstream and make TSIM objects
797  if (m_decode2DFinderTrack) {
798  for (short iclock = 0; iclock < m_bits2DTo3D.getEntries(); ++iclock) {
799  decode2DOutput(iclock - m_2DFinderDelay,
800  m_bits2DTo3D[iclock],
803  &m_TSHits);
804  }
805  }
806  B2DEBUG(99, "unpack 2D Input TS ");
808  std::array<int, 4> clockCounter2D = {0, 0, 0, 0};
809  std::array<int, 4> timeOffset2D = {0, 0, 0, 0};
810  // Align the data in other boards to 2D0 by looking at the CC in the midpoint of the time window
811  for (int iTracker = 0; iTracker < nTrackers; ++iTracker) {
812  if (! m_alignFoundTime || m_bitsTo2D.getEntries() == 0) {
813  break;
814  }
815  auto& trackerData = m_bitsTo2D[m_bitsTo2D.getEntries() / 2]->signal()[0][iTracker];
816  std::string strInput = slv_to_bin_string(trackerData);
817  clockCounter2D[iTracker] = std::stoi(strInput.substr(0, clockCounterWidth), 0, 2);
818  int clockCounterDiff = clockCounter2D[iTracker] - clockCounter2D[0];
819  /*
820  // clock counter rolls back to 0 from 319
821  if (clockCounterDiff > 300) {
822  clockCounterDiff -= 320;
823  } else if (clockCounterDiff < -300) {
824  clockCounterDiff += 320;
825  }
826  */
827  // clock counter rolls back to 0 from 1279, since certain B2L version, it has been changed to like this
828  if (clockCounterDiff > 1250) {
829  clockCounterDiff -= 1280;
830  } else if (clockCounterDiff < -1250) {
831  clockCounterDiff += 1280;
832  }
833  timeOffset2D[iTracker] = clockCounterDiff;
834  if (clockCounterDiff != 0) {
835  B2DEBUG(100, "Adding " << clockCounterDiff << " clock(s) to 2D" << iTracker << " found time");
836  }
837  if (std::abs(clockCounterDiff) > 2) {
838  B2DEBUG(20, "Clock counters between 2D [0," << iTracker << "] differ by " << clockCounterDiff << " clocks! (" \
839  << clockCounter2D[0] << ", " << clockCounter2D[iTracker] << ")");
840  }
841  }
842  for (short iclock = 0; iclock < m_bitsTo2D.getEntries(); ++iclock) {
843  B2DEBUG(30, "clock " << iclock);
844  decode2DInput(iclock - m_2DFinderDelay, timeOffset2D, m_bitsTo2D[iclock], &m_TSHits);
845  }
846  }
847  B2DEBUG(99, "now unpack neuro ");
848  if (m_decodeNeuro) {
849  if (m_useDB == true) {
852  } else {
854  }
855  }
856  B2DEBUG(99, " all is unpacked ##### ");
857 }
858 
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
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
LogConfig & getLogConfig()
Returns the log system configuration.
Definition: Module.h:225
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.
REG_MODULE(arichBtest)
Register the Module.
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
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.
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};
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)