Belle II Software  release-06-00-14
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,
59  unsigned inNInnerMergers, int& inDelay,
60  int& inCnttrg,
61  int inDebugLevel) :
62  SubTrigger(inName, inEventWidth, inOffset,
63  inHeaderSize, inNodeID, inDelay, inCnttrg, inDebugLevel),
64  arrayPtr(inArrayPtr),
65  nInnerMergers(inNInnerMergers) {};
66 
70  unsigned nInnerMergers;
72  void reserve(int subDetectorId, std::array<int, nFinesse> nWords) override
73  {
74  if (subDetectorId != iNode) {
75  return;
76  }
77  if (nWords[iFinesse] < headerSize) {
78  return;
79  }
80  size_t nClocks = (nWords[iFinesse] - headerSize) / eventWidth;
81  size_t entries = arrayPtr->getEntries();
82  if (entries == 0) {
83  for (unsigned i = 0; i < nClocks; ++i) {
84  arrayPtr->appendNew();
85  }
86  B2DEBUG(20, name << ": " << nClocks << " clocks");
87  } else if (entries != nClocks) {
88  B2DEBUG(20, "Number of clocks in " << name << " conflicts with others!");
89  }
90  };
91 
93  void unpack(int subDetectorId,
94  std::array<int*, 4> data32tab,
95  std::array<int, 4> nWords) override
96  {
97  if (subDetectorId != iNode) {
98  return;
99  }
100  if (nWords[iFinesse] < headerSize) {
101  B2DEBUG(20, "The module " << name << " does not have enough data (" <<
102  nWords[iFinesse] << "). Nothing will be unpacked.");
103  // TODO: need to clear the output bitstream because we return early here
104  return;
105  }
106  // make bitstream
107  // loop over all clocks
108  for (int i = headerSize; i < nWords[iFinesse]; i += eventWidth) {
109  int iclock = (i - headerSize) / eventWidth;
110  auto mergerClock = (*arrayPtr)[iclock];
111  B2DEBUG(100, "clock " << iclock);
112  // loop over all mergers
113  for (unsigned j = offset; j < eventWidth; ++j) {
114  int iMerger = (eventWidth - j - 1) / 8 + nInnerMergers;
115  int pos = (eventWidth - j - 1) % 8;
116  dataWord word(data32tab[iFinesse][i + j]);
117  for (int k = 0; k < wordWidth; ++k) {
118  mergerClock->m_signal[iMerger].set(pos * wordWidth + k, word[k]);
119  }
120  }
121  }
122  if (debugLevel >= 300) {
123  printBuffer(data32tab[iFinesse] + headerSize, eventWidth);
124  B2DEBUG(20, "");
125  printBuffer(data32tab[iFinesse] + headerSize + eventWidth, eventWidth);
126  }
127  for (int i = 0; i < std::accumulate(nMergers.begin(), nMergers.end(), 0); ++i) {
128  B2DEBUG(99, (*arrayPtr)[0]->m_signal[i].to_string());
129  }
130  }
131  };
132 
137  StoreArray<T2DOutputBitStream>* outArrayPtr,
138  const std::string& inName, unsigned inEventWidth, unsigned inOffset,
139  unsigned inHeaderSize, const std::vector<int>& inNodeID,
140  unsigned inNumTS, int& inDelay,
141  int& inCnttrg,
142  int inDebugLevel) :
143  SubTrigger(inName, inEventWidth, inOffset / wordWidth, inHeaderSize, inNodeID,
144  inDelay, inCnttrg, inDebugLevel),
145  inputArrayPtr(inArrayPtr), outputArrayPtr(outArrayPtr),
146  iTracker(std::stoul(inName.substr(inName.length() - 1))),
147  numTS(inNumTS), offsetBitWidth(inOffset) {};
148 
154  unsigned iTracker;
156  unsigned numTS;
158  unsigned offsetBitWidth;
159 
168  void reserve(int subDetectorId, std::array<int, nFinesse> nWords) override
169  {
170  size_t nClocks = (nWords[iFinesse] - headerSize) / eventWidth;
171  size_t entries = inputArrayPtr->getEntries();
172  if (subDetectorId == iNode) {
173  if (entries == 0) {
174  for (unsigned i = 0; i < nClocks; ++i) {
175  TSFOutputBitStream* inputClock = inputArrayPtr->appendNew();
176  T2DOutputBitStream* outputClock = outputArrayPtr->appendNew();
177  // fill bitstreams for all trackers with zeros
178  for (unsigned j = 0; j < nTrackers; ++j) {
179  for (unsigned iAxialTSF = 0; iAxialTSF < nAxialTSF; ++iAxialTSF) {
180  inputClock->m_signal[iAxialTSF][j].fill(zero_val);
181  }
182  outputClock->m_signal[j].fill(zero_val);
183  }
184  }
185  B2DEBUG(20, name << ": " << nClocks << " clocks");
186  } else if (entries != nClocks) {
187  B2DEBUG(20, "Number of clocks in " << name << " conflicts with others!");
188  }
189  }
190  };
191 
201  void unpack(int subDetectorId,
202  std::array<int*, 4> data32tab,
203  std::array<int, 4> nWords) override
204  {
205  if (subDetectorId != iNode) {
206  return;
207  }
208  // Recently, the content of the last clock appears at the beginning.
209  // Now we decide whether we will change the order of the clocks
210  // based on the 127MHz counter on the 2nd half of the first word [15:0]
211  int ccShift = 0;
212  using halfDataWord = std::bitset<16>;
213  std::vector<halfDataWord> counters;
214  counters.reserve(inputArrayPtr->getEntries());
215  for (int iclock = 0; iclock < inputArrayPtr->getEntries(); ++iclock) {
216  counters.emplace_back(data32tab[iFinesse]
217  [headerSize + eventWidth * iclock] & 0xffff);
218  B2DEBUG(100, "iclock " << iclock << " --> " << counters.at(iclock).to_ulong() << " : " << std::hex << counters.at(iclock));
219  }
220  bool counter_correct_error = false;
221  while (counters.at(1).to_ulong() - counters.at(0).to_ulong() != 4) {
222  std::rotate(counters.begin(), counters.begin() + 1, counters.end());
223  ccShift++;
224  // 2019,0410 This situation, looks like clockcounter shifted 6 bits left, was first seen in exp5 data.
225  // 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.
226  // The data header is 0xbbbb instead of 0xdddd.
227  // getHeader in the CDCTriggerUnpackerModule.h is modified to skip this kind event.
228  // 2019,0419 unfortunately, clockcounter found disorder since expt 7, run 2553, after update of B2L firmware to replace the b2dly with trigger counter.
229  // for that run, it seems the problem happens only at 2D1, 2D2, and 2D3.
230  if (ccShift >= inputArrayPtr->getEntries()) {
231  B2DEBUG(90, "PHYSJG: clock counter rotation over one cycle: " << ccShift);
232  for (const auto& c : counters) {
233  B2DEBUG(90, "" << c.to_ulong() << " : " << std::hex << c);
234  }
235  counter_correct_error = true;
236  break;
237  }
238  }
239  if (counter_correct_error) {
240  B2DEBUG(20, "PHYSJG: " << name << " too many clock counter rotation corrections: " << ccShift << " data object skipped.");
241  // maybe implement an option for user to decide if this data block should be kept or not?!
242  return;
243  }
244  if (! std::is_sorted(counters.begin(), counters.end(),
245  [](halfDataWord i, halfDataWord j) {
246  return (j.to_ulong() - i.to_ulong() == 4);
247  })) {
248  B2DEBUG(20, "clock counters are still out of order");
249  for (const auto& c : counters) {
250  B2DEBUG(90, "" << c.to_ulong());
251  }
252  }
253  // 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.
254  if (ccShift) {
255  B2DEBUG(15, "shifting the first " << ccShift <<
256  " clock(s) to the end for " << name);
257  }
258 
259  // get event body information
260  // make bitstream
261  // loop over all clocks
262  for (int i = headerSize; i < nWords[iFinesse]; i += eventWidth) {
263  int iclock = (i - headerSize) / eventWidth - ccShift;
264  if (iclock < 0) {
265  iclock += inputArrayPtr->getEntries();
266  }
267  auto inputClock = (*inputArrayPtr)[iclock];
268  auto outputClock = (*outputArrayPtr)[iclock];
269  // clear output bitstream
270  outputClock->m_signal[iTracker].fill(zero_val);
271  B2DEBUG(90, "unpacker clock " << iclock);
272  if (debugLevel >= 300) {
273  printBuffer(data32tab[iFinesse] + headerSize + eventWidth * iclock,
274  eventWidth);
275  }
276  // get the clock counters
277  std::array<dataWord, 2> ccword({
278  data32tab[iFinesse][i + 2], data32tab[iFinesse][i + 3]
279  });
280  // fill input
281  // Careful! this iTSF is (8 - iSL) / 2
282  for (unsigned iTSF = 0; iTSF < nAxialTSF; ++iTSF) {
283  // clear input bitstream
284  inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker].fill(zero_val);
285 
286  if (firmwareVersion < "18012600") {
287  /*
288  data_b2l_r <=
289  x"dddd" & cntr125M(15 downto 0) &
290  cc(4) & cc(3) & cc(2) & cc(1) & cc(0) &
291  ccError &
292  -- 82
293  tsfs(4)(209 downto 0) &
294  tsfs(3)(209 downto 0) &
295  tsfs(2)(209 downto 0) &
296  tsfs(1)(209 downto 0) &
297  tsfs(0)(209 downto 0) &
298  */
299  // fill the clock counters
300  for (unsigned pos = 0; pos < clockCounterWidth; ++pos) {
301  const int j = (pos + iTSF * clockCounterWidth) / wordWidth;
302  const int k = (pos + iTSF * clockCounterWidth) % wordWidth;
303  /* The index behaves differently in each containers
304  Here is an example of a 64-bit wide MSB data
305  |-------- smaller index in the firmware ----->
306 
307  data in the firmware/VHDL std_logic_vector(63 downto 0)
308  63 62 61 60 ... 01 00
309 
310  data in B2L/RawTRG (when using std::bitset<32> for a word)
311  (31 30 29 28 ... 01 00) (31 30 29 28 ... 01 00)
312  |------ word 0 -------| |------ word 1 -------|
313 
314  XSim / Bitstream of std::array<char, N> / std::string
315  00 01 02 03 ... 62 63
316  */
317  // Here we are filling std::array<char, N>, which has reversed order
318  // to std::bitset, so there is a - sign in [wordWidth - k]
319  inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker][pos] =
320  std_logic(ccword[j][wordWidth - k]);
321  }
322  // fill the TS hit
323  offsetBitWidth = 82;
324  for (unsigned pos = 0; pos < numTS * lenTS; ++pos) {
325  const int j = (offsetBitWidth + pos + iTSF * numTS * lenTS) / wordWidth;
326  const int k = (offsetBitWidth + pos + iTSF * numTS * lenTS) % wordWidth;
327  dataWord word(data32tab[iFinesse][i + j]);
328  // MSB (leftmost) in firmware -> smallest index in Bitstream's
329  // std::array (due to XSIM) -> largest index in std::bitset
330  // so the index is reversed in this assignment
331  inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker]
332  [clockCounterWidth + pos] = std_logic(word[wordWidth - 1 - k]);
333  }
334  } else {
335  /*
336  x"dddd" & (15 downto 11 => '0') & revoclk &
337  cntr125M(15 downto 0) &
338  (15 downto 5 => '0') & ccError &
339  -- 64
340  cc(4) & tsfs(4)(209 downto 0) &
341  cc(3) & tsfs(3)(209 downto 0) &
342  cc(2) & tsfs(2)(209 downto 0) &
343  cc(1) & tsfs(1)(209 downto 0) &
344  cc(0) & tsfs(0)(209 downto 0) &
345  */
346  // fill the cc and TS hit
347  offsetBitWidth = 64;
348  unsigned TSFWidth = clockCounterWidth + numTS * lenTS;
349  for (unsigned pos = 0; pos < TSFWidth; ++pos) {
350  const int j = (offsetBitWidth + pos + iTSF * TSFWidth) / wordWidth;
351  const int k = (offsetBitWidth + pos + iTSF * TSFWidth) % wordWidth;
352  dataWord word(data32tab[iFinesse][i + j]);
353  inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker][pos] =
354  std_logic(word[wordWidth - 1 - k]);
355  }
356  }
357  if (debugLevel >= 100) {
358  display_hex(inputClock->m_signal[nAxialTSF - 1 - iTSF][iTracker]);
359  }
360  }
361  // fill output
362  if (firmwareVersion < "18012600") {
363  /*
364  -- 1132
365  Main_out(731 downto 0) &
366  */
367  const int outputOffset = nAxialTSF * numTS * lenTS;
368  const int oldtrackWidth = 6;
369  for (unsigned pos = 0; pos < 732; ++pos) {
370  const int j = (offsetBitWidth + pos + outputOffset) / wordWidth;
371  const int k = (offsetBitWidth + pos + outputOffset) % wordWidth;
372  dataWord word(data32tab[iFinesse][i + j]);
373  outputClock->m_signal[iTracker][clockCounterWidth + oldtrackWidth + pos]
374  = std_logic(word[wordWidth - 1 - k]);
375  }
376  } else {
377  /*
378  -- 1159
379  old_track(5 downto 0) &
380  Main_out(731 downto 0) &
381  */
382  //const int outputOffset = 1159;
383  const int outputOffset = offsetBitWidth + nAxialTSF * numTS * lenTS + 45; //1159 with numTS=10 , 1684 with numTS=15
384  for (unsigned pos = 0; pos < T2DOutputWidth; ++pos) {
385  const int j = (pos + outputOffset) / wordWidth;
386  const int k = (pos + outputOffset) % wordWidth;
387  dataWord word(data32tab[iFinesse][i + j]);
388  outputClock->m_signal[iTracker][clockCounterWidth + pos]
389  = std_logic(word[wordWidth - 1 - k]);
390  }
391  }
392  if (debugLevel >= 100) {
393  display_hex(outputClock->m_signal[iTracker]);
394  }
395  }
396  }
397  };
398 
400  struct Neuro : SubTrigger {
403  const std::string& inName, unsigned inEventWidth, unsigned inOffset,
404  unsigned inHeaderSize, const std::vector<int>& inNodeID, int& inDelay,
405  int& inCnttrg,
406  int inDebugLevel) :
407  SubTrigger(inName, inEventWidth, inOffset / wordWidth, inHeaderSize, inNodeID,
408  inDelay, inCnttrg, inDebugLevel),
409  ArrayPtr(arrPtr),
410  iTracker(std::stoul(inName.substr(inName.length() - 1))),
411  offsetBitWidth(inOffset) {};
412 
416  unsigned iTracker;
418  unsigned offsetBitWidth;
419 
420  void reserve(int subDetectorId, std::array<int, nFinesse> nWords) override
421  {
422  size_t nClocks = (nWords[iFinesse] - headerSize) / eventWidth;
423  size_t entries = ArrayPtr->getEntries();
424  if (subDetectorId == iNode) {
425  if (entries == 0) {
426  for (unsigned i = 0; i < nClocks; ++i) {
427  NNBitStream* nnclock = ArrayPtr->appendNew();
428  // fill bitstreams for all trackers with zeros
429  for (unsigned j = 0; j < nTrackers; ++j) {
430  nnclock->m_signal[j].fill(zero_val);
431  }
432  }
433  B2DEBUG(20, name << ": " << nClocks << " clocks");
434  } else if (entries != nClocks) {
435  B2DEBUG(20, "Number of clocks in " << name << " conflicts with others!");
436  }
437  }
438  };
439 
440  void unpack(int subDetectorId,
441  std::array<int*, nFinesse> data32tab,
442  std::array<int, nFinesse> nWords) override
443  {
444  if (subDetectorId != iNode) {
445  return;
446  }
447  // make bitstream
448  // loop over all clocks
449  for (int i = headerSize; i < nWords[iFinesse]; i += eventWidth) {
450  int iclock = (i - headerSize) / eventWidth;
451  auto nnclock = (*ArrayPtr)[iclock];
452  B2DEBUG(20, "clock " << iclock);
453  if (debugLevel >= 300) {
454  printBuffer(data32tab[iFinesse] + headerSize + eventWidth * iclock,
455  eventWidth);
456  }
457  // fill output
458  for (unsigned pos = 0; pos < NN_WIDTH; ++pos) {
459  const int j = (offsetBitWidth + pos) / wordWidth;
460  const int k = (offsetBitWidth + pos) % wordWidth;
461  std::bitset<wordWidth> word(data32tab[iFinesse][i + j]);
462  nnclock->m_signal[iTracker][pos] = std_logic(word[wordWidth - 1 - k]);
463  }
464  if (debugLevel >= 100) {
465  display_hex(nnclock->m_signal[iTracker]);
466  }
467  }
468  }
469  };
471 };
472 
474 {
475  // Set module properties
476  setDescription("Unpack the CDC trigger data recorded in B2L");
478 
479  // Parameter definitions
480  addParam("unpackMerger", m_unpackMerger,
481  "whether to unpack merger data (recorded by Merger Reader / TSF)", false);
482  addParam("unpackTracker2D", m_unpackTracker2D,
483  "whether to unpack 2D tracker data", false);
484  addParam("unpackNeuro", m_unpackNeuro,
485  "whether to unpacker neurotrigger data", false);
486  addParam("decode2DFinderTrack", m_decode2DFinderTrack,
487  "flag to decode 2D finder track", false);
488  addParam("decode2DFinderInput", m_decode2DFinderInputTS,
489  "flag to decode input TS to 2D", false);
490  addParam("decodeNeuro", m_decodeNeuro,
491  "flag to decode neurotrigger data", false);
492  // https://confluence.desy.de/display/BI/DAQ+and+Operation for CPR/HSLB
493  NodeList defaultMergerNodeID = { // These should be very temporary ones since no merger to B2L yet.
494  {0x11000001, 0},
495  {0x11000003, 0},
496  {0x11000001, 1},
497  {0x11000002, 0},
498  {0x11000002, 1}
499  };
500  addParam("MergerNodeId", m_mergerNodeID,
501  "list of COPPER and HSLB ID of Merger reader (TSF)", defaultMergerNodeID);
502  NodeList defaultTracker2DNodeID = {
503  {0x11000001, 0},
504  {0x11000001, 1},
505  {0x11000002, 0},
506  {0x11000002, 1}
507  };
508  addParam("2DNodeId", m_tracker2DNodeID,
509  "list of COPPER and HSLB ID of 2D tracker", defaultTracker2DNodeID);
510  NodeList defaultNeuroNodeID = {
511  {0x11000005, 0},
512  {0x11000005, 1},
513  {0x11000006, 0},
514  {0x11000006, 1}
515  };
516  addParam("NeuroNodeId", m_neuroNodeID,
517  "list of COPPER and HSLB ID of neurotrigger", defaultNeuroNodeID);
518  addParam("headerSize", m_headerSize,
519  "number of words (number of bits / 32) of the B2L header", 3);
520  addParam("alignFoundTime", m_alignFoundTime,
521  "Whether to align out-of-sync Belle2Link data between different sub-modules", true);
522  addParam("useDB", m_useDB,
523  "Use values stored in the payload of the ConditionsDB."
524  "This affects the output scaling of the Neurotrigger as well as the"
525  "bit configuration of its unpacker. If false, an old unpacker version with fixed scalings and old bit adresses is used.",
526  true);
527  addParam("sim13dt", m_sim13dt,
528  "Simulate 13 bit drift time by using 2d clock counter value.",
529  false);
530 }
531 
533 {
535 
536  //m_rawTriggers.isRequired();
537  if (m_unpackMerger) {
538  m_mergerBits.registerInDataStore("CDCTriggerMergerBits");
539  }
540  if (m_unpackTracker2D) {
541  m_bitsTo2D.registerInDataStore("CDCTriggerTSFTo2DBits");
542  m_bits2DTo3D.registerInDataStore("CDCTrigger2DTo3DBits");
543  }
544  if (m_unpackNeuro) {
545  m_bitsNN.registerInDataStore("CDCTriggerNNBits");
546  }
549  m_TSHits.registerInDataStore("CDCTriggerSegmentHits");
550  }
551  if (m_decode2DFinderTrack) {
552  m_2DFinderTracks.registerInDataStore("CDCTrigger2DFinderTracks");
553  m_2DFinderTracks.registerRelationTo(m_TSHits);
554  m_2DFinderClones.registerInDataStore("CDCTrigger2DFinderClones");
555  m_2DFinderClones.registerRelationTo(m_2DFinderTracks);
556  }
557  if (m_decodeNeuro) {
558  m_NNInputTSHitsAll.registerInDataStore("CDCTriggerNNInputAllStereoSegmentHits");
559  m_NNInputTSHits.registerInDataStore("CDCTriggerNNInputSegmentHits");
560  m_NNInput2DFinderTracks.registerInDataStore("CDCTriggerNNInput2DFinderTracks");
561  m_NeuroTracks.registerInDataStore("CDCTriggerNeuroTracks");
562  m_NeuroInputs.registerInDataStore("CDCTriggerNeuroTracksInput");
563  m_NeuroTracks.registerRelationTo(m_NNInputTSHits);
564  m_NNInput2DFinderTracks.registerRelationTo(m_NNInputTSHits);
565  m_NNInput2DFinderTracks.registerRelationTo(m_NNInputTSHitsAll);
566  m_NNInput2DFinderTracks.registerRelationTo(m_NeuroTracks);
567  m_NeuroTracks.registerRelationTo(m_NNInput2DFinderTracks);
568  m_NeuroTracks.registerRelationTo(m_NeuroInputs);
569  }
570  for (int iSL = 0; iSL < 9; iSL += 2) {
571  if (m_unpackMerger) {
572  const int nInnerMergers = std::accumulate(nMergers.begin(),
573  nMergers.begin() + iSL, 0);
574  B2DEBUG(20, "in: " << nInnerMergers);
575  Merger* m_merger =
576  new Merger(&m_mergerBits,
577  "Merger" + std::to_string(iSL), mergerWidth * nMergers[8] / wordWidth,
579  m_mergerNodeID[iSL / 2], nInnerMergers,
581  m_debugLevel);
582  m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_merger));
583  }
584  }
585  // TODO In the default scenario, data in all trackers will be recorded.
586  // This is not the case for now (around first collision), where some coppers are lacking.
587  // Therefore it might help to make the following code more flexible
588  // so that we won't have a hard fail when some boards are missing
589 
590  m_n2DTS = m_dbn2DTS->getnTS();
591  int datasize_2D = 64;
592  if (m_n2DTS == 10) {
593  datasize_2D = 64;
594  } else if (m_n2DTS == 15) {
595  datasize_2D = 82;
596  }
597 
598  for (int iTracker = 0; iTracker < 4; ++iTracker) {
599  if (m_unpackTracker2D) {
600  Tracker2D* m_tracker2d =
602  "Tracker2D" + std::to_string(iTracker), datasize_2D, 82, m_headerSize,
603  m_tracker2DNodeID[iTracker], m_n2DTS,
605  m_debugLevel);
606  m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_tracker2d));
607  }
608  if (m_unpackNeuro) {
609  Neuro* m_neuro =
610  new Neuro(&m_bitsNN,
611  "Neuro" + std::to_string(iTracker), 64, 0, m_headerSize,
613  m_subTrigger.push_back(dynamic_cast<SubTrigger*>(m_neuro));
614  }
615  }
616 }
617 
619 {
620  for (auto bits : m_subTrigger) {
621  delete bits;
622  }
623 }
624 
626 {
627 
629  m_exp = bevt->getExperiment();
630  m_run = bevt->getRun();
631 
632  if (not m_cdctriggerneuroconfig.isValid())
633  B2FATAL("CDCTriggerNeuroConfig is not valid.");
634  if (m_useDB == true) {
635  B2DEBUG(2, "Load Neurotrigger configuration for network " << m_cdctriggerneuroconfig->getNNName() << " from database ");
636  B2DEBUG(10, padright("Name", 50) << padright("start", 10) << padright("end", 10) << padright("offset", 10));
637  for (auto x : m_cdctriggerneuroconfig->getB2Format()) {
638  B2DEBUG(10, padright(x.name, 48) << ": " << padright(std::to_string(x.start), 10) << padright(std::to_string(x.end),
639  10) << padright(std::to_string(x.offset), 10));
640  }
641  }
642 }
643 
644 
646 {
647 
648  B2DEBUG(10, padright(" ", 100));
649  B2DEBUG(10, "----------------------------------------------------------------------------------------------------");
650  B2DEBUG(10, padright(" ", 100));
651  StoreObjPtr<EventMetaData> eventMetaData;
652  std::string experimentstring = "Experiment " + std::to_string(eventMetaData->getExperiment()) + " Run " +
653  std::to_string(eventMetaData->getRun()) + " Event " + std::to_string(eventMetaData->getEvent());
654  B2DEBUG(10, padright(experimentstring, 100));
655 
656  setReturnValue(0);
657 
658  if (m_exp < 7) {
659  B2DEBUG(20, "exp<7: skip cdctrg unpacker for DQM");
660  return;
661  }
662 
663  // Read RawTRG data block.
664  B2DEBUG(99, m_rawTriggers.getEntries() << " COPPERs in RawTRGs");
665 
666  // loop over all COPPERs
667  for (auto& rawTRG : m_rawTriggers) {
668  const int subDetectorId = rawTRG.GetNodeID(0);
669  // const int iNode = (subDetectorId & 0xFFFFFF);
670  // number of entries in the rawTRG object.
671  const int nEntriesRawTRG = rawTRG.GetNumEntries();
672 
673  // number of entries in rawTRG object ()
674  B2DEBUG(99, "nEntries of rawTRG: " << nEntriesRawTRG);
675  for (int j = 0; j < nEntriesRawTRG; ++j) {
676  //
677  // Search Data from Finesse A to D (0->3).
678  //
679  std::array<int, nFinesse> nWords;
680  std::array<int*, nFinesse> data32tab;
681  nWords.fill(0);
682 
683  for (int iFinesse = 0; iFinesse < nFinesse; ++iFinesse) {
684  nWords[iFinesse] = rawTRG.GetDetectorNwords(j, iFinesse);
685  if (nWords[iFinesse] == 0) {
686  continue;
687  }
688  data32tab[iFinesse] = (int*)rawTRG.GetDetectorBuffer(j, iFinesse);
689  }
690 
691  for (auto trg : m_subTrigger) {
692  // only unpack when there are enough words in the event
693  if (trg->getHeaders(subDetectorId, data32tab, nWords)) {
694  trg->reserve(subDetectorId, nWords);
695  B2DEBUG(99, "starting to unpack a subTrigger, subDetectorId" << std::hex << subDetectorId);
696  trg->unpack(subDetectorId, data32tab, nWords);
697  setReturnValue(1);
698  }
699  }
700  }
701  B2DEBUG(99, "looped over entries and filled words " << nEntriesRawTRG);
702  }
703  B2DEBUG(99, "looped over rawTriggers, unpacking 2D ");
704 
705  // decode bitstream and make TSIM objects
706  if (m_decode2DFinderTrack) {
707  for (short iclock = 0; iclock < m_bits2DTo3D.getEntries(); ++iclock) {
708  decode2DOutput(iclock - m_2DFinderDelay,
709  m_bits2DTo3D[iclock],
712  &m_TSHits);
713  }
714  }
715  B2DEBUG(99, "unpack 2D Input TS ");
717  std::array<int, 4> clockCounter2D = {0, 0, 0, 0};
718  std::array<int, 4> timeOffset2D = {0, 0, 0, 0};
719  // Align the data in other boards to 2D0 by looking at the CC in the midpoint of the time window
720  for (int iTracker = 0; iTracker < nTrackers; ++iTracker) {
721  if (! m_alignFoundTime || m_bitsTo2D.getEntries() == 0) {
722  break;
723  }
724  auto& trackerData = m_bitsTo2D[m_bitsTo2D.getEntries() / 2]->signal()[0][iTracker];
725  std::string strInput = slv_to_bin_string(trackerData);
726  clockCounter2D[iTracker] = std::stoi(strInput.substr(0, clockCounterWidth), 0, 2);
727  int clockCounterDiff = clockCounter2D[iTracker] - clockCounter2D[0];
728  /*
729  // clock counter rolls back to 0 from 319
730  if (clockCounterDiff > 300) {
731  clockCounterDiff -= 320;
732  } else if (clockCounterDiff < -300) {
733  clockCounterDiff += 320;
734  }
735  */
736  // clock counter rolls back to 0 from 1279, since certain B2L version, it has been changed to like this
737  if (clockCounterDiff > 1250) {
738  clockCounterDiff -= 1280;
739  } else if (clockCounterDiff < -1250) {
740  clockCounterDiff += 1280;
741  }
742  timeOffset2D[iTracker] = clockCounterDiff;
743  if (clockCounterDiff != 0) {
744  B2DEBUG(100, "Adding " << clockCounterDiff << " clock(s) to 2D" << iTracker << " found time");
745  }
746  if (std::abs(clockCounterDiff) > 2) {
747  B2DEBUG(20, "Clock counters between 2D [0," << iTracker << "] differ by " << clockCounterDiff << " clocks! (" \
748  << clockCounter2D[0] << ", " << clockCounter2D[iTracker] << ")");
749  }
750  }
751  for (short iclock = 0; iclock < m_bitsTo2D.getEntries(); ++iclock) {
752  B2DEBUG(30, "clock " << iclock);
753  decode2DInput(iclock - m_2DFinderDelay, timeOffset2D, m_bitsTo2D[iclock], &m_TSHits);
754  }
755  }
756  B2DEBUG(99, "now unpack neuro ");
757  if (m_decodeNeuro) {
758  if (m_useDB == true) {
761  } else {
763  }
764  }
765  B2DEBUG(99, " all is unpacked ##### ");
766 }
767 
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
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
bool m_decode2DFinderInputTS
flag to decode 2D finder input TS
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
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
Type-safe access to single objects in the data store.
Definition: StoreObjPtr.h:95
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 nFinesse
Number of FINESSE in the copper.
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 reserve(int subDetectorId, std::array< int, nFinesse > nWords) override
reserve enough number of clocks (entries) in the Bitstream StoreArray
unsigned nInnerMergers
number of merger units in the inner super layer than this one
void unpack(int subDetectorId, std::array< int *, 4 > data32tab, std::array< int, 4 > nWords) override
Unpack function.
Merger(StoreArray< MergerBits > *inArrayPtr, const std::string &inName, unsigned inEventWidth, unsigned inOffset, int inHeaderSize, const std::vector< int > &inNodeID, unsigned inNInnerMergers, int &inDelay, int &inCnttrg, int inDebugLevel)
Constructor.
unpacker for the Neuro
void reserve(int subDetectorId, std::array< int, nFinesse > nWords) override
Calculate the number of clocks in the data, reserve that much of clocks in the Bitstream(s)
StoreArray< NNBitStream > * ArrayPtr
Array pointer for NN.
unsigned offsetBitWidth
Offset bit width.
Neuro(StoreArray< NNBitStream > *arrPtr, const std::string &inName, unsigned inEventWidth, unsigned inOffset, unsigned inHeaderSize, const std::vector< int > &inNodeID, int &inDelay, int &inCnttrg, int inDebugLevel)
Constructor.
unsigned iTracker
Tracker board ID.
void unpack(int subDetectorId, std::array< int *, nFinesse > data32tab, std::array< int, nFinesse > nWords) override
Unpack the Belle2Link data and fill the Bitstream.
enum class SubTriggerType : unsigned char {Merger, TSF, T2D, T3D, Neuro, ETF};
unpacker for the 2D tracker
StoreArray< T2DOutputBitStream > * outputArrayPtr
pointer to the Bitstream of 2D output to 3D/Neuro
void reserve(int subDetectorId, std::array< int, nFinesse > nWords) override
Calculate the number of clocks in the data, reserve that much of clocks in the Bitstream(s)
Tracker2D(StoreArray< TSFOutputBitStream > *inArrayPtr, StoreArray< T2DOutputBitStream > *outArrayPtr, const std::string &inName, unsigned inEventWidth, unsigned inOffset, unsigned inHeaderSize, const std::vector< int > &inNodeID, unsigned inNumTS, int &inDelay, int &inCnttrg, int inDebugLevel)
constructor
void unpack(int subDetectorId, std::array< int *, 4 > data32tab, std::array< int, 4 > nWords) 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