Belle II Software  release-05-01-25
Unpacker.h
1 #include <string>
2 #include <sstream>
3 #include <iostream>
4 #include <iomanip>
5 #include <bitset>
6 #include <numeric>
7 #include <cmath>
8 #include <algorithm>
9 
10 #include <trg/cdc/dataobjects/Bitstream.h>
11 #include <trg/cdc/dataobjects/CDCTriggerTrack.h>
12 #include <trg/cdc/dataobjects/CDCTriggerSegmentHit.h>
13 #include <trg/cdc/dataobjects/CDCTriggerFinderClone.h>
14 #include <trg/cdc/dataobjects/CDCTriggerMLPInput.h>
15 #include <framework/gearbox/Const.h>
16 #include <trg/cdc/dbobjects/CDCTriggerNeuroConfig.h>
17 
18 namespace Belle2 {
24  namespace CDCTriggerUnpacker {
25 
26  constexpr double pi() { return std::atan(1) * 4; }
27 
28  // constants
29  static constexpr std::array<int, 9> nMergers = {10, 10, 12, 14, 16, 18, 20, 22, 24};
30 
31  // The data width are the specs under full speed.
32  // When using one of the half-speed version,
33  // TS/track are filled from MSB, leaving LSB blank.
34  static constexpr int TSFOutputWidth = TSF_TO_2D_WIDTH; // 429 (#defined in Bitstream.h)
35  static constexpr int nTrackers = NUM_2D; // 4
36  static constexpr int nAxialTSF = NUM_TSF; // 5
37  static constexpr int nStereoTSF = 4;
38  static constexpr int T2DOutputWidth = T2D_TO_3D_WIDTH; // 747
39  static constexpr unsigned lenTS = 21; // ID (8 bit) + t (9 bit) + LR (2 bit) + priority (2 bit)
40 
41  static constexpr int nMax2DTracksPerClock = 4;
42 
43  // bit width of the clock counter
44  static constexpr int clockCounterWidth = 9;
45 
46  /* number of mergers in axial super layers */
47  static constexpr std::array<int, nAxialTSF> nAxialMergers = {10, 12, 16, 20, 24};
48  /* number of wires in a super layer*/
49  static constexpr std::array<int, 9> nWiresInSuperLayer = {
50  160, 160, 192, 224, 256, 288, 320, 352, 384
51  };
52  /* Number of wire/cells in a single layer per merger unit */
53  static constexpr int nCellsInLayer = 16;
54 
55  // dataobjects
56  using TSFOutputVector = std::array<char, TSFOutputWidth>;
57  using TSFOutputArray = std::array<TSFOutputVector, nTrackers>;
58  using TSFOutputBus = std::array<TSFOutputArray, nAxialTSF>;
59  using TSFOutputBitStream = Bitstream<TSFOutputBus>;
60 
61  using T2DOutputVector = std::array<char, T2DOutputWidth>;
62  using T2DOutputBus = std::array<T2DOutputVector, nTrackers>;
63  using T2DOutputBitStream = Bitstream<T2DOutputBus>;
64 
65  using NNVector = std::array<char, NN_WIDTH>;
66  using NNBus = std::array<NNVector, nTrackers>;
67  using NNBitStream = Bitstream<NNBus>;
68  // using NNInputVector = std::array<char, NNInputWidth>;
69  // using NNInputBus = std::array<NNInputVector, nTrackers>;
70  // using NNInputBitStream = Bitstream<NNInputBus>;
71 
72  // using NNOutputVector = std::array<char, NNOutputWidth>;
73  // using NNOutputBus = std::array<NNOutputVector, nTrackers>;
74  // using NNOutputBitStream = Bitstream<NNOutputBus>;
75 
76  // functions
77  std::string padto(std::string s, unsigned l)
78  {
79  if (s.size() < l) {
80  s.insert(s.begin(), l - s.size(), ' ');
81  }
82  return s;
83  }
84  std::string padright(std::string s, unsigned l)
85  {
86  if (s.size() < l) {
87  s.insert(s.end(), l - s.size(), ' ');
88  }
89  return s;
90  }
91 
92  void printBuffer(int* buf, int nwords)
93  {
94  for (int j = 0; j < nwords; ++j) {
95  printf(" %.8x", buf[j]);
96  if ((j + 1) % 8 == 0) {
97  printf("\n");
98  }
99  }
100  printf("\n");
101  return;
102  };
103 
104  std::string rawIntToAscii(int buf)
105  {
106  std::ostringstream firmwareTypeStream;
107  firmwareTypeStream << std::hex << buf;
108  std::string firmwareTypeHex(firmwareTypeStream.str());
109  std::string firmwareType(4, '0');
110  for (int i = 0; i < 4; i++) {
111  std::istringstream firmwareTypeIStream(firmwareTypeHex.substr(i * 2, 2));
112  int character;
113  firmwareTypeIStream >> std::hex >> character;
114  firmwareType[i] = character;
115  }
116  return firmwareType;
117  };
118 
119  std::string rawIntToString(int buf)
120  {
121  std::ostringstream firmwareVersionStream;
122  firmwareVersionStream << std::hex << buf;
123  return firmwareVersionStream.str();
124  };
125 
126  /* Note: VHDL std_logic value is stored in a byte (char). The
127  * 9 values are mapped as 'U':0, 'X':1, '0':2, '1':3
128  * 'Z':4, 'W':5, 'L':6, 'H':7, '-':8 . The std_logic_vector
129  * is stored as a contiguous array of bytes. For example
130  * "0101Z" is stored in five bytes as char s[5] = {2,3,2,3,4}
131  * An HDL integer type is stored as C int, a HDL real type is
132  * stored as a C double and a VHDL string type is stored as char*.
133  * An array of HDL integer or double is stored as an array of C
134  * integer or double respectively
135  */
136 
137  /* In case you are not familiar with VHDL simulation, there are 9 possible
138  * values defined for the standard logic type, instead of just 0 and 1. The
139  * simulator needs to compute all these possible outcomes. Therefore, XSI uses
140  * a byte, instead of a bit, to represent a std_logic. This is represented
141  * with a char with possible values ranging from 0 to 8.
142  */
143  const char* std_logic_literal[] = {"U", "X", "0", "1", "Z", "W", "L", "H", "-"};
145  const char one_val = 3;
147  const char zero_val = 2;
148 
149  char std_logic(bool inBit)
150  {
151  char outBit = zero_val;
152  if (inBit) {
153  outBit = one_val;
154  }
155  return outBit;
156  }
157 
158  std::string display_value(const char* count, int size)
159  {
160  std::string res;
161  for (int i = 0; i < size; i++) {
162  if (count[i] >= 0 && count[i] < 9) {
163  res += std_logic_literal[(int) count[i]];
164  } else {
165  B2DEBUG(20, "invalid signal detected: " << static_cast<int>(count[i]));
166  res += "?";
167  }
168  }
169  return res;
170  }
171 
172  template<size_t N>
173  std::string slv_to_bin_string(std::array<char, N> signal, bool padding = false)
174  {
175  int ini = padding ? 4 - signal.size() % 4 : 0;
176  std::string res(ini, '0');
177  for (auto const& bit : signal) {
178  if (bit >= 0 && bit < 9) {
179  res += std_logic_literal[(int) bit];
180  } else {
181  B2DEBUG(20, "invalid signal detected: " << static_cast<int>(bit));
182  res += "0";
183  }
184  }
185  return res;
186  }
187 
188  template<size_t N>
189  void display_hex(const std::array<char, N>& signal)
190  {
191  std::ios oldState(nullptr);
192  oldState.copyfmt(std::cout);
193  if (std::any_of(signal.begin(), signal.end(), [](char i)
194  {return i != zero_val && i != one_val;})) {
195  B2DEBUG(20, "Some bit in the signal vector is neither 0 nor 1. \n" <<
196  "Displaying binary values instead.");
197  std::cout << slv_to_bin_string(signal) << std::endl;
198  } else {
199  std::string binString = slv_to_bin_string(signal, true);
200  std::cout << std::setfill('0');
201  for (unsigned i = 0; i < signal.size(); i += 4) {
202  std::bitset<4> set(binString.substr(i, 4));
203  std::cout << std::setw(1) << std::hex << set.to_ulong();
204  }
205  }
206  std::cout << "\n";
207  std::cout.copyfmt(oldState);
208  }
209 
210  /* extract a subset of bitstring, like substring.
211  *
212  * In principle this can be done using only integer manipulations, but for the
213  * sake of simplicity, let's just cast them to string. Beware the endianness.
214  * 0 refer to the rightmost bit in std::bitset, but the leftmost bit in
215  * std::string
216  */
217  template<size_t nbits, size_t min, size_t max>
218  std::bitset < max - min + 1 > subset(std::bitset<nbits> set)
219  {
220  const size_t outWidth = max - min + 1;
221  std::string str = set.to_string();
222  return std::bitset<outWidth>(str.substr(nbits - max - 1, outWidth));
223  }
224 
225 
233  unsigned short globalSegmentID(unsigned short localID, unsigned short iSL)
234  {
235  auto itr = nWiresInSuperLayer.begin();
236  unsigned short globalID = std::accumulate(itr, itr + iSL, 0);
237  globalID += localID;
238  return globalID;
239  }
240 
241  using tsOut = std::array<unsigned, 4>;
242  using tsOutArray = std::array<tsOut, 5>;
245  TRG2DFinderTrack() {}
247  double omega;
249  double phi0;
251  tsOutArray ts;
252  };
254  struct TRGNeuroTrack {
256  double z;
258  double theta;
260  unsigned sector;
262  std::array<float, 9> inputID;
264  std::array<float, 9> inputT;
266  std::array<float, 9> inputAlpha;
268  std::array<tsOut, 9> ts;
269  };
270  struct B2LDataField {
271  B2LDataField(
273  unsigned foundtime,
274  unsigned iTracker,
276  {
277  if ((b2line.offset + foundtime >= 0) &&
278  (b2line.offset + foundtime <= bitsNN->getEntries())) {
279 
280  NNBitStream* bitsn = (*bitsNN)[foundtime + b2line.offset];
281 
282  if (slv_to_bin_string(bitsn->signal()[iTracker]).size() >= (NN_WIDTH - b2line.start)) {
283  data = slv_to_bin_string(bitsn->signal()[iTracker]).substr(NN_WIDTH - 1 - b2line.end, b2line.end - b2line.start + 1);
284  } else {
285  data = "";
286  }
287  } else {
288  data = "";
289  }
290 
291  // std::cout << "new datafield: " << b2line.name << ": " << b2line.start << ", " << b2line.end << ", " << data << std::endl;
292 
293  name = b2line.name;
294  }
295  std::string data;
296  std::string name;
297  };
298 
299  std::vector<bool> decodedriftthreshold(std::string p_driftthreshold)
300  {
301  std::vector<bool> res;
302  for (unsigned i = 0; i < p_driftthreshold.size(); ++i) {
303  if (p_driftthreshold.substr(i, 1) == "1") {
304  res.push_back(true);
305  } else if (p_driftthreshold.substr(i, 1) == "0") {
306  res.push_back(false);
307  } else {
308  B2WARNING("Invalid input in NNBitstream appending 'false'!");
309  res.push_back(false);
310  }
311  }
312  return res;
313  }
314  std::vector<bool> decodefoundoldtrack(std::string p_foundoldtrack)
315  {
316  std::vector<bool> res;
317  for (unsigned i = 0; i < p_foundoldtrack.size(); ++i) {
318  if (p_foundoldtrack.substr(i, 1) == "1") {
319  res.push_back(true);
320  } else if (p_foundoldtrack.substr(i, 1) == "0") {
321  res.push_back(false);
322  } else {
323  B2WARNING("Invalid input in NNBitstream appending 'false'!");
324  res.push_back(false);
325  }
326  }
327  return res;
328  }
329  bool decodevalstereobit(std::string p_valstereobit)
330  {
331  bool res;
332  if (p_valstereobit == "1") {
333  res = true;
334  } else if (p_valstereobit == "0") {
335  res = false;
336  } else {
337  B2WARNING("Invalid input in NNBitstream appending 'false'!");
338  res = false;
339  }
340  return res;
341  }
353  unsigned TSIDInSL(unsigned tsIDInTracker, unsigned iSL, unsigned iTracker)
354  {
355  const unsigned nCellsInSL = nMergers[iSL] * nCellsInLayer;
356  // get global TS ID
357  unsigned iTS = tsIDInTracker + nCellsInSL * iTracker / nTrackers;
358  // periodic ID overflow when phi0 > 0 for the 4th tracker
359  if (iTS >= nCellsInSL) {
360  iTS -= nCellsInSL;
361  }
362  // ID in SL8 is shifted by 16
363  if (iSL == 8) {
364  if (iTS < 16) {
365  iTS += nCellsInSL;
366  }
367  iTS -= 16;
368  }
369  return iTS;
370  }
371 
374  int mlp_bin_to_signed_int(std::string signal)
375  {
376  constexpr unsigned len = 13;
377  std::bitset<len> signal_bit(signal);
378  const unsigned shift = 16 - len;
379  // shift to 16 bits, cast it to signed 16-bit int, and shift it back
380  // thus the signed bit is preserved (when right-shifting)
381  int signal_out = (int16_t (signal_bit.to_ulong() << shift)) >> shift;
382  return signal_out;
383  }
384 
392  tsOut decodeTSHit(std::string tsIn)
393  {
394  constexpr unsigned lenID = 8;
395  constexpr unsigned lenPriorityTime = 9; //(twodcc.size() > 0) ? 13 : 9;
396  constexpr unsigned lenLR = 2;
397  constexpr unsigned lenPriorityPosition = 2;
398  constexpr std::array<unsigned, 4> tsLens = {
399  lenID, lenPriorityTime, lenLR, lenPriorityPosition
400  };
401  std::array<unsigned, 5> tsPos = { 0 };
402  std::partial_sum(tsLens.begin(), tsLens.end(), tsPos.begin() + 1);
403  tsOut tsOutput;
404  tsOutput[0] = std::bitset<tsLens[0]>(tsIn.substr(tsPos[0], tsLens[0])).to_ulong();
405  tsOutput[1] = std::bitset<tsLens[1]>(tsIn.substr(tsPos[1], tsLens[1])).to_ulong();
406  tsOutput[2] = std::bitset<tsLens[2]>(tsIn.substr(tsPos[2], tsLens[2])).to_ulong();
407  tsOutput[3] = std::bitset<tsLens[3]>(tsIn.substr(tsPos[3], tsLens[3])).to_ulong();
408  return tsOutput;
409  }
410  tsOut decodeTSHit_sim(std::string tsIn, std::string twodcc)
411  {
412  constexpr unsigned lenID = 8;
413  constexpr unsigned lenPriorityTime = 9; //(twodcc.size() > 0) ? 13 : 9;
414  constexpr unsigned lenLR = 2;
415  constexpr unsigned lenPriorityPosition = 2;
416  constexpr std::array<unsigned, 4> tsLens = {
417  lenID, lenPriorityTime, lenLR, lenPriorityPosition
418  };
419  std::string C = tsIn.substr(lenID + 5, 4);
420  std::string B = tsIn.substr(lenID, 5);
421  std::string Bp = twodcc.substr(4, 5);
422  std::string Ap = twodcc.substr(0, 4);
423  int pt;
424  std::string pts;
425  if (std::stoul(B, 0, 2) <= std::stoul(Bp, 0, 2)) {
426  pts = Ap + B + C;
427  } else {
428  B2DEBUG(14, "2DCC overflow detected!");
429  pts = std::bitset<4>(std::stoul(Ap, 0, 2) - 1).to_string() + B + C;
430  }
431  pt = std::stoul(pts, 0, 2);
432  std::array<unsigned, 5> tsPos = { 0 };
433  std::partial_sum(tsLens.begin(), tsLens.end(), tsPos.begin() + 1);
434  tsOut tsOutput;
435  tsOutput[0] = std::bitset<tsLens[0]>(tsIn.substr(tsPos[0], tsLens[0])).to_ulong();
436  tsOutput[1] = pt; // std::bitset<tsLens[1]>(tsIn.substr(tsPos[1], tsLens[1])).to_ulong();
437  tsOutput[2] = std::bitset<tsLens[2]>(tsIn.substr(tsPos[2], tsLens[2])).to_ulong();
438  tsOutput[3] = std::bitset<tsLens[3]>(tsIn.substr(tsPos[3], tsLens[3])).to_ulong();
439  return tsOutput;
440  }
441  tsOut decodeTSHit_ext(std::string tsIn, std::string expt)
442  {
443  constexpr unsigned lenID = 8;
444  constexpr unsigned lenPriorityTime = 9; //(twodcc.size() > 0) ? 13 : 9;
445  constexpr unsigned lenLR = 2;
446  constexpr unsigned lenPriorityPosition = 2;
447  constexpr std::array<unsigned, 4> tsLens = {
448  lenID, lenPriorityTime, lenLR, lenPriorityPosition
449  };
450  unsigned pt = std::stoul(expt, 0, 2);
451  std::array<unsigned, 5> tsPos = { 0 };
452  std::partial_sum(tsLens.begin(), tsLens.end(), tsPos.begin() + 1);
453  tsOut tsOutput;
454  tsOutput[0] = std::bitset<tsLens[0]>(tsIn.substr(tsPos[0], tsLens[0])).to_ulong();
455  tsOutput[1] = pt; //std::bitset<13>(expt).to_ulong();
456  tsOutput[2] = std::bitset<tsLens[2]>(tsIn.substr(tsPos[2], tsLens[2])).to_ulong();
457  tsOutput[3] = std::bitset<tsLens[3]>(tsIn.substr(tsPos[3], tsLens[3])).to_ulong();
458  return tsOutput;
459  }
460 
470  TRG2DFinderTrack decode2DTrack(std::string p_charge,
471  std::string p_omega,
472  std::string p_phi,
473  std::string p_ts0,
474  std::string p_ts2,
475  std::string p_ts4,
476  std::string p_ts6,
477  std::string p_ts8,
478  unsigned iTracker,
479  std::string p_2dcc,
480  bool sim13dt)
481  {
482 //constexpr unsigned lenomega = p_omega.size();
483  unsigned shift = 16 - p_omega.size();
484  TRG2DFinderTrack trackout;
485  int omega = std::stoi(p_omega, 0, 2);
486  // shift omega to 16 bits, cast it to signed 16-bit int, and shift it back to 7 bits
487  // thus the signed bit is preserved (when right-shifting)
488  int omegafirm = (int16_t (omega << shift)) >> shift;
489  //int omegafirm = (int16_t (omega.to_ulong() << shift)) >> shift;
490  // B field is 1.5T
491  const double BField = 1.5e-4; // why is it so small?
492  // omega in 1/cm
493  // omega = 1/R = c * B / pt
494  trackout.omega = Const::speedOfLight * BField / 0.3 / 34 * omegafirm;
495 
496 
497 
498 
499  int phi = std::stoi(p_phi, 0, 2);
500  // c.f. https://confluence.desy.de/download/attachments/34033650/output-def.pdf
501  double globalPhi0 = pi() / 4 + pi() / 2 / 80 * (phi + 1) + pi() / 2 * iTracker; // see document above
502 
503 
504  trackout.ts[0] = (sim13dt) ? decodeTSHit_sim(p_ts0, p_2dcc) : decodeTSHit(p_ts0);
505  trackout.ts[1] = (sim13dt) ? decodeTSHit_sim(p_ts2, p_2dcc) : decodeTSHit(p_ts2);
506  trackout.ts[2] = (sim13dt) ? decodeTSHit_sim(p_ts4, p_2dcc) : decodeTSHit(p_ts4);
507  trackout.ts[3] = (sim13dt) ? decodeTSHit_sim(p_ts6, p_2dcc) : decodeTSHit(p_ts6);
508  trackout.ts[4] = (sim13dt) ? decodeTSHit_sim(p_ts8, p_2dcc) : decodeTSHit(p_ts8);
509  // rotate the tracks to the correct quadrant (iTracker)
510  if (globalPhi0 > pi() * 2) {
511  globalPhi0 -= pi() * 2;
512  }
513  trackout.phi0 = globalPhi0;
514  B2DEBUG(20, "Unpacking 2DTrack in Tracker: " << iTracker);
515  B2DEBUG(20, " Omega: " << std::to_string(omega) << ", Omegafirm: " << std::to_string(omegafirm) << ", converted to: " <<
516  std::to_string(trackout.omega));
517  B2DEBUG(20, " Phi: " << std::to_string(phi) << ", converted to: " << std::to_string(trackout.phi0));
518  return trackout;
519 
520  }
521  TRG2DFinderTrack decode2DTrack(std::string trackIn, unsigned iTracker)
522  {
523  constexpr unsigned lenCharge = 2;
524  constexpr unsigned lenOmega = 7;
525  constexpr unsigned lenPhi0 = 7;
526  constexpr std::array<unsigned, 3> trackLens = {lenCharge, lenOmega, lenPhi0};
527  std::array<unsigned, 4> trackPos{ 0 };
528  std::partial_sum(trackLens.begin(), trackLens.end(), trackPos.begin() + 1);
529  const unsigned shift = 16 - lenOmega;
530  TRG2DFinderTrack trackOut;
531  std::bitset<trackLens[1]> omega(trackIn.substr(trackPos[1], trackLens[1]));
532  // shift omega to 16 bits, cast it to signed 16-bit int, and shift it back to 7 bits
533  // thus the signed bit is preserved (when right-shifting)
534  int omegaFirm = (int16_t (omega.to_ulong() << shift)) >> shift;
535  // B field is 1.5T
536  const double BField = 1.5e-4;
537  // omega in 1/cm
538  // omega = 1/R = c * B / pt
539  // c.f. https://confluence.desy.de/download/attachments/34033650/output-def.pdf
540  trackOut.omega = Const::speedOfLight * BField / 0.3 / 34 * omegaFirm;
541  int phi0 = std::bitset<trackLens[2]>(trackIn.substr(trackPos[2], trackLens[2])).to_ulong();
542  trackOut.phi0 = pi() / 4 + pi() / 2 / 80 * (phi0 + 1);
543  for (unsigned i = 0; i < 5; ++i) {
544  trackOut.ts[i] = decodeTSHit(trackIn.substr(trackPos.back() + i * lenTS, lenTS));
545  }
546 
547  // rotate the tracks to the correct quadrant (iTracker)
548  double globalPhi0 = trackOut.phi0 + pi() / 2 * iTracker;
549  if (globalPhi0 > pi() * 2) {
550  globalPhi0 -= pi() * 2;
551  }
552  trackOut.phi0 = globalPhi0;
553  return trackOut;
554  }
555 
564  TRGNeuroTrack decodeNNTrack(std::string p_mlpout_z,
565  std::string p_mlpout_theta,
566  std::string p_tsfsel,
567  std::string p_mlpin_alpha,
568  std::string p_mlpin_drifttime,
569  std::string p_mlpin_id,
570  std::string p_netsel,
571  const DBObjPtr<CDCTriggerNeuroConfig> neurodb,
572  std::string p_2dcc,
573  bool sim13dt,
574  B2LDataField p_extendedpts)
575  {
576  // constexpr unsigned lenMLP = 13;
577  float scale_z = 1. / (1 << (p_mlpout_z.size() - 1));
578  float scale_theta = 1. / (1 << (p_mlpout_theta.size() - 1));
579  float scale_alpha = 1. / (1 << (p_mlpin_alpha.size() - 1) / 9);
580  float scale_drifttime = 1. / (1 << (p_mlpin_drifttime.size() - 1) / 9);
581  float scale_id = 1. / (1 << (p_mlpin_id.size() - 1) / 9);
582  TRGNeuroTrack foundTrack;
583  int theta_raw = mlp_bin_to_signed_int(p_mlpout_theta);
584  int z_raw = mlp_bin_to_signed_int(p_mlpout_z);
585  std::vector<float> unscaledT = neurodb->getMLPs()[0].unscaleTarget({(z_raw * scale_z), (theta_raw * scale_theta)});
586  foundTrack.z = unscaledT[0];
587  foundTrack.theta = unscaledT[1];
588  foundTrack.sector = std::stoi(p_netsel, 0, 2);
589  for (unsigned iSL = 0; iSL < 9; ++iSL) {
590  foundTrack.inputAlpha[iSL] =
591  mlp_bin_to_signed_int(p_mlpin_alpha.substr((8 - iSL) * p_mlpin_alpha.size() / 9, p_mlpin_alpha.size() / 9)) * scale_alpha;
592  foundTrack.inputT[iSL] =
593  mlp_bin_to_signed_int(p_mlpin_drifttime.substr((8 - iSL) * p_mlpin_drifttime.size() / 9,
594  p_mlpin_drifttime.size() / 9)) * scale_drifttime;
595  foundTrack.inputID[iSL] =
596  mlp_bin_to_signed_int(p_mlpin_id.substr((8 - iSL) * p_mlpin_drifttime.size() / 9, p_mlpin_drifttime.size() / 9)) * scale_id;
597  if (sim13dt) {
598  foundTrack.ts[iSL] = decodeTSHit_sim(p_tsfsel.substr((8 - iSL) * lenTS, lenTS), p_2dcc);
599  } else {
600  if (p_extendedpts.name != "None") {
601  foundTrack.ts[iSL] = decodeTSHit_ext(p_tsfsel.substr((8 - iSL) * lenTS, lenTS), p_extendedpts.data.substr((8 - iSL) * 13, 13));
602  } else {
603  foundTrack.ts[iSL] = decodeTSHit(p_tsfsel.substr((8 - iSL) * lenTS, lenTS));
604  }
605  }
606  }
607  return foundTrack;
608  }
609  TRGNeuroTrack decodeNNTrack_old(std::string trackIn, std::string selectIn)
610  {
611  constexpr unsigned lenMLP = 13;
612  float scale = 1. / (1 << (lenMLP - 1));
613  TRGNeuroTrack foundTrack;
614  int theta_raw = mlp_bin_to_signed_int(trackIn.substr(1, lenMLP));
615  foundTrack.theta = theta_raw * scale * M_PI_2 + M_PI_2;
616  int z_raw = mlp_bin_to_signed_int(trackIn.substr(lenMLP + 1, lenMLP));
617  foundTrack.z = z_raw * scale * 50.;
618  foundTrack.sector = std::bitset<3>(trackIn.substr(2 * lenMLP + 1, 3)).to_ulong();
619  for (unsigned iSL = 0; iSL < 9; ++iSL) {
620  foundTrack.inputAlpha[iSL] =
621  mlp_bin_to_signed_int(selectIn.substr((2 + (8 - iSL)) * lenMLP + 4, lenMLP)) * scale;
622  foundTrack.inputT[iSL] =
623  mlp_bin_to_signed_int(selectIn.substr((11 + (8 - iSL)) * lenMLP + 4, lenMLP)) * scale;
624  foundTrack.inputID[iSL] =
625  mlp_bin_to_signed_int(selectIn.substr((20 + (8 - iSL)) * lenMLP + 4, lenMLP)) * scale;
626  foundTrack.ts[iSL] = // order: SL8, ..., SL0
627  decodeTSHit(selectIn.substr(29 * lenMLP + 4 + (8 - iSL) * lenTS, lenTS));
628  }
629  return foundTrack;
630  }
631 
636  CDCTriggerSegmentHit* addTSHit(tsOut ts, unsigned iSL, unsigned iTracker,
637  StoreArray<CDCTriggerSegmentHit>* tsHits,
638  int foundTime = 0)
639  {
640  unsigned iTS = TSIDInSL(ts[0], iSL, iTracker);
641  // check if hit is already existing in datastore
642  CDCTriggerSegmentHit* hit = nullptr;
643  //for (int ihit = 0; ihit < tsHits->getEntries(); ++ihit) {
644  // CDCTriggerSegmentHit* compare = (*tsHits)[ihit];
645  // if (compare->getISuperLayer() == iSL &&
646  // compare->getIWireCenter() == iTS &&
647  // compare->getPriorityPosition() == ts[3] &&
648  // compare->getLeftRight() == ts[2] &&
649  // compare->priorityTime() == int(ts[1])) {
650  // hit = compare;
651  // break;
652  // }
653  //}
654 // !hit is always true.
655 // if (!hit) {
656  hit = tsHits->appendNew(iSL, iTS, ts[3], ts[2], ts[1], 0, foundTime, iTracker);
657  B2DEBUG(15, "make hit at SL " << iSL << " ID " << iTS << " clock " << foundTime << " iTracker " << iTracker);
658 // }
659  return hit;
660  }
661 
676  void decode2DOutput(short foundTime,
677  T2DOutputBitStream* bits,
678  StoreArray<CDCTriggerTrack>* storeTracks,
679  StoreArray<CDCTriggerFinderClone>* storeClones,
680  StoreArray<CDCTriggerSegmentHit>* tsHits)
681  {
682  const unsigned lenTrack = 121;
683  const unsigned oldTrackWidth = 6;
684  const unsigned foundWidth = 6;
685  std::array<int, 4> posTrack;
686  for (unsigned i = 0; i < posTrack.size(); ++i) {
687  posTrack[i] = oldTrackWidth + foundWidth + lenTrack * i;
688  }
689  for (unsigned iTracker = 0; iTracker < nTrackers; ++iTracker) {
690  const auto slv = bits->signal()[iTracker];
691  std::string strOutput = slv_to_bin_string(slv).
692  substr(clockCounterWidth, T2DOutputWidth - clockCounterWidth);
693  for (unsigned i = 0; i < nMax2DTracksPerClock; ++i) {
694  // The first 6 bits indicate whether a track is found or not
695  if (slv[clockCounterWidth + oldTrackWidth + i] == one_val) {
696  TRG2DFinderTrack trk = decode2DTrack(strOutput.substr(posTrack[i], lenTrack), iTracker);
697  B2DEBUG(15, "2DOut phi0:" << trk.phi0 << ", omega:" << trk.omega
698  << ", at clock " << foundTime << ", tracker " << iTracker);
699  CDCTriggerTrack* track =
700  storeTracks->appendNew(trk.phi0, trk.omega, 0., foundTime, iTracker);
701  CDCTriggerFinderClone* clone =
702  storeClones->appendNew(slv[clockCounterWidth + i] == one_val, iTracker);
703  clone->addRelationTo(track);
704  // TODO: dig out the TS hits in DataStore, and
705  // add relations to them.
706  // Otherwise, create a new TS hit object and add the relation.
707  // However, the fastest time would be lost in this case.
708  // Problem: there might be multiple TS hits with the same ID,
709  // so the foundTime needs to be aligned first in order to compare.
710  for (unsigned iAx = 0; iAx < nAxialTSF; ++iAx) {
711  const auto& ts = trk.ts[iAx];
712  if (ts[3] > 0) {
713  unsigned iTS = TSIDInSL(ts[0], 2 * iAx, iTracker);
714  CDCTriggerSegmentHit* hit =
715  tsHits->appendNew(2 * iAx, // super layer
716  iTS, // TS number in super layer
717  ts[3], // priority position
718  ts[2], // L/R
719  ts[1], // priority time
720  0, // fastest time (unknown)
721  // set to a clock definitely outside the time window to receive the TS from TSF,
722  // so it won't cause any confusion of the TS origin.
723  // what I want to is to set it to (200 + 2DmoduleID[0,1,2,3]),
724  // so one can distinguish in which 2D this track is found.
725  // foundTime); // found time (using the unpacked clock cycle)
726  2000 + iTracker * 100 + foundTime,
727  iTracker); // quadrant
728  track->addRelationTo(hit);
729  }
730  }
731  }
732  }
733  }
734  }
735 
748  void decode2DInput(short foundTime,
749  std::array<int, 4> timeOffset,
750  TSFOutputBitStream* bits,
751  StoreArray<CDCTriggerSegmentHit>* tsHits)
752  {
753  // Get the input TS to 2D from the Bitstream
754  for (unsigned iAx = 0; iAx < nAxialTSF; ++iAx) {
755  for (unsigned iTracker = 0; iTracker < nTrackers; ++iTracker) {
756  const auto& tracker = bits->signal()[iAx][iTracker];
757  std::string strInput = slv_to_bin_string(tracker);
758  bool noMoreHit = false;
759  for (unsigned pos = clockCounterWidth; pos < TSFOutputWidth; pos += lenTS) {
760  std::string tsHitStr = strInput.substr(pos, lenTS);
761  B2DEBUG(50, tsHitStr);
762  tsOut ts = decodeTSHit(tsHitStr);
763  // check if all the hits are on the MSB side
764  if (ts[2] == 0) {
765  noMoreHit = true;
766  continue;
767  } else if (noMoreHit) {
768  B2DEBUG(20, "Discontinuous TS hit detected!");
769  }
770  unsigned iTS = TSIDInSL(ts[0], 2 * iAx, iTracker);
771  // Make TS hit object
772  CDCTriggerSegmentHit hit(2 * iAx, // super layer
773  iTS, // TS number in super layer
774  ts[3], // priority position
775  ts[2], // L/R
776  ts[1], // priority time
777  0, // fastest time (unknown)
778  foundTime + timeOffset[iTracker], // found time
779  iTracker); // quadrant
780 
781  // add if the TS hit of identical ID and foundTime is not already in the StoreArray
782  // (from the 2D input of another quarter or the 2D track output)
783 
784  /* TODO: Currently, it is very likely that a TS hit will appear
785  * multiple times in the StoreArray. To avoid adding the input from
786  * another quarter again, we need to look at the clock counter,
787  * because the data from different 2D's are not always synchronized
788  * due to Belle2Link instability. To avoid adding again from the 2D
789  * output, we need to consider the 2D latency.
790  */
791  if (std::none_of(tsHits->begin(), tsHits->end(),
792  [hit](CDCTriggerSegmentHit storeHit) {
793  return (storeHit.getSegmentID() == hit.getSegmentID() &&
794  storeHit.foundTime() == hit.foundTime());
795  })) {
796  B2DEBUG(40, "found TS hit ID " << hit.getSegmentID() <<
797  ", SL" << 2 * iAx << ", local ID " << iTS <<
798  ", 2D" << iTracker);
799  tsHits->appendNew(hit);
800  } else {
801  B2DEBUG(45, "skipping redundant hit ID " << hit.getSegmentID() << " in 2D" << iTracker);
802  }
803  }
804  }
805  }
806  }
807 
824  CDCTriggerTrack* decodeNNInput(short iclock,
825  unsigned iTracker,
826  NNBitStream* bitsIn,
827  StoreArray<CDCTriggerTrack>* store2DTracks,
828  StoreArray<CDCTriggerSegmentHit>* tsHits)
829  {
830  CDCTriggerTrack* track2D = nullptr;
831  constexpr unsigned lenTrack = 135; //119;
832  // omega (7 bit) + phi (7 bit) + 5 * TS (21 bit) + old track found(6bit) + valid stereo bit (1bit) + drift threshold (9bit)
833  const auto slvIn = bitsIn->signal()[iTracker];
834  std::string strIn = slv_to_bin_string(slvIn);
835  strIn = strIn.substr(NN_WIDTH - 570 - 496, 982);
836  // decode stereo hits
837  for (unsigned iSt = 0; iSt < nStereoTSF; ++iSt) {
838  for (unsigned iHit = 0; iHit < 10; ++iHit) {
839  // order: 10 * SL7, 10 * SL5, 10 * SL3, 10 * SL1
840  unsigned pos = ((nStereoTSF - iSt - 1) * 10 + iHit) * lenTS;
841  tsOut ts = decodeTSHit(strIn.substr(pos, lenTS));
842  if (ts[3] > 0) {
843  addTSHit(ts, iSt * 2 + 1, iTracker, tsHits, iclock);
844  }
845  }
846  }
847  std::string strTrack = strIn.substr(nStereoTSF * 10 * lenTS, lenTrack);
848  if (!std::all_of(strTrack.begin(), strTrack.end(), [](char i) {return i == '0';})) {
849  std::string infobits = strTrack.substr(5 * lenTS + 14, 16);
850  strTrack = "00" + strTrack.substr(5 * lenTS, 14) + strTrack.substr(0,
851  5 * lenTS); // add 2 dummy bits for the charge (not stored in NN)
852  TRG2DFinderTrack trk2D = decode2DTrack(strTrack, iTracker);
853  B2DEBUG(15, "NNIn phi0:" << trk2D.phi0 << ", omega:" << trk2D.omega
854  << ", at clock " << iclock << ", tracker " << iTracker);
855  B2DEBUG(300, "Content of new infobits: " << infobits);
856  std::vector<bool> foundoldtrack;
857  std::vector<bool> driftthreshold;
858  bool valstereobit;
859  unsigned i = 0;
860  for (i = 0; i < 6; i++) {
861  if (infobits.substr(i, 1) == "1") {
862  foundoldtrack.push_back(true);
863  } else if (infobits.substr(i, 1) == "0") {
864  foundoldtrack.push_back(false);
865  } else {
866  B2WARNING("Invalid input in NNBitstream appending 'false'!");
867  foundoldtrack.push_back(false);
868  }
869  }
870  i = 6;
871  if (infobits.substr(i, 1) == "1") {
872  valstereobit = true;
873  } else if (infobits.substr(i, 1) == "0") {
874  valstereobit = false;
875  } else {
876  B2WARNING("Invalid input in NNBitstream appending 'false'!");
877  valstereobit = false;
878  }
879  for (i = 7; i < 16; i++) {
880  if (infobits.substr(i, 1) == "1") {
881  driftthreshold.push_back(true);
882  } else if (infobits.substr(i, 1) == "0") {
883  driftthreshold.push_back(false);
884  } else {
885  B2WARNING("Invalid input in NNBitstream appending 'false'!");
886  driftthreshold.push_back(false);
887  }
888  }
889  B2DEBUG(15, "bits for foundoldtrack: " << foundoldtrack[0]
890  << foundoldtrack[1]
891  << foundoldtrack[2]
892  << foundoldtrack[3]
893  << foundoldtrack[4]
894  << foundoldtrack[5]);
895  B2DEBUG(15, "bits for driftthreshold: " << driftthreshold[0]
896  << driftthreshold[1]
897  << driftthreshold[2]
898  << driftthreshold[3]
899  << driftthreshold[4]
900  << driftthreshold[5]
901  << driftthreshold[6]
902  << driftthreshold[7]
903  << driftthreshold[8]);
904  B2DEBUG(15, "bits for valstereobit: " << valstereobit);
905 
906  // check if 2D track is already in list, otherwise add it
907  //for (int itrack = 0; itrack < store2DTracks->getEntries(); ++itrack) {
908  // if ((*store2DTracks)[itrack]->getPhi0() == trk2D->phi0 &&
909  // (*store2DTracks)[itrack]->getOmega() == trk2D->omega) {
910  // track2D = (*store2DTracks)[itrack];
911  // B2DEBUG(15, "found 2D track in store with phi " << trk2D->phi0 << " omega " << trk2D->omega);
912  // break;
913  // }
914  //}
915  B2DEBUG(15, "make new 2D track with phi " << trk2D.phi0 << " omega " << trk2D.omega << " clock " << iclock);
916  track2D = store2DTracks->appendNew(trk2D.phi0, trk2D.omega, 0., foundoldtrack, driftthreshold, valstereobit, iclock, iTracker);
917  // add axial hits and create relations
918  for (unsigned iAx = 0; iAx < nAxialTSF; ++iAx) {
919  const auto& ts = trk2D.ts[iAx];
920  if (ts[3] > 0) {
921  CDCTriggerSegmentHit* hit =
922  addTSHit(ts, 2 * iAx, iTracker, tsHits, iclock);
923  track2D->addRelationTo(hit);
924  }
925  }
926  // TODO: decode event time
927  }
928  return track2D;
929  }
930 
951  void decodeNNOutput_old(short foundTime,
952  unsigned iTracker,
953  NNBitStream* bitsOut,
954  NNBitStream* bitsSelectTS,
955  StoreArray<CDCTriggerTrack>* storeNNTracks,
956  StoreArray<CDCTriggerSegmentHit>* tsHits,
957  StoreArray<CDCTriggerMLPInput>* storeNNInputs,
958  CDCTriggerTrack* track2D)
959  {
960  const auto slvOut = bitsOut->signal()[iTracker];
961  std::string strTrack = slv_to_bin_string(slvOut);
962  strTrack = strTrack.substr(496, 570);
963  const auto slvSelect = bitsSelectTS->signal()[iTracker];
964  std::string strSelect = slv_to_bin_string(slvSelect);
965  strSelect = strSelect.substr(496, 570);
966  TRGNeuroTrack trkNN = decodeNNTrack_old(strTrack, strSelect);
967  B2DEBUG(15, "make new NN track with , z:" << trkNN.z << ", theta:" << trkNN.theta <<
968  ", sector:" << trkNN.sector << ", clock " << foundTime);
969  double phi0 = 0;
970  double omega = 0;
971  if (track2D) {
972  phi0 = track2D->getPhi0();
973  omega = track2D->getOmega();
974  }
975  std::vector<bool> tsvector(9, false);
976  for (unsigned iSL = 0; iSL < 9; ++iSL) {
977  if (trkNN.ts[iSL][3] > 0) {
978  tsvector[iSL] = true;
979  }
980  }
981  CDCTriggerTrack* trackNN = storeNNTracks->appendNew(phi0, omega, 0.,
982  trkNN.z, cos(trkNN.theta) / sin(trkNN.theta), 0., track2D->getFoundOldTrack(), track2D->getDriftThreshold(),
983  track2D->getValidStereoBit(), trkNN.sector, tsvector, foundTime, iTracker);
984  std::vector<float> inputVector(27, 0.);
985  for (unsigned iSL = 0; iSL < 9; ++iSL) {
986  inputVector[3 * iSL] = trkNN.inputID[iSL];
987  inputVector[3 * iSL + 1] = trkNN.inputT[iSL];
988  inputVector[3 * iSL + 2] = trkNN.inputAlpha[iSL];
989  }
990  CDCTriggerMLPInput* storeInput =
991  storeNNInputs->appendNew(inputVector, trkNN.sector);
992  trackNN->addRelationTo(storeInput);
993  if (track2D) {
994  track2D->addRelationTo(trackNN);
995  }
996 
997  for (unsigned iSL = 0; iSL < 9; ++iSL) {
998  if (trkNN.ts[iSL][3] > 0) {
999  CDCTriggerSegmentHit* hit = addTSHit(trkNN.ts[iSL] , iSL, iTracker, tsHits, foundTime);
1000  trackNN->addRelationTo(hit);
1001  }
1002  }
1003  }
1004 
1022  void decodeNNIO(
1023  StoreArray<CDCTriggerUnpacker::NNBitStream>* bitsNN,
1024  StoreArray<CDCTriggerTrack>* store2DTracks,
1025  StoreArray<CDCTriggerTrack>* storeNNTracks,
1026  StoreArray<CDCTriggerSegmentHit>* tsHits,
1027  StoreArray<CDCTriggerSegmentHit>* tsHitsAll,
1028  StoreArray<CDCTriggerMLPInput>* storeNNInputs,
1029  const DBObjPtr<CDCTriggerNeuroConfig> neurodb,
1030  bool sim13dt)
1031  {
1032  for (unsigned iTracker = 0; iTracker < nTrackers; ++iTracker) {
1033  B2DEBUG(21, "----------------------------------------------------------------------------------------------------");
1034  B2DEBUG(21, padright(" Unpacking Tracker: " + std::to_string(iTracker), 100));
1035  // loop over boards belonging to geometrical sectors
1036 
1037  for (short iclock = 0; iclock < bitsNN->getEntries(); ++iclock) {
1038  // check for NNEnable bit:
1039  B2LDataField p_nnenable(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("NNEnable"));
1040  if (p_nnenable.name == "None") {
1041  B2DEBUG(5, "Neurotrigger: NNENable position unknown, skipping ... ");
1042  continue;
1043  } else if (p_nnenable.data == "1") {
1044  B2DEBUG(10, padright("Tracker: " + std::to_string(iTracker) + ", Clock: " + std::to_string(iclock) + " : NNEnable set!", 100));
1045  } else {
1046  B2DEBUG(21, padright(" UnpackerClock: " + std::to_string(iclock), 100));
1047  }
1048 
1049 
1050  CDCTriggerNeuroConfig::B2FormatLine nnall;
1051  nnall.start = 0;
1052  nnall.end = 2047;
1053  nnall.offset = 0;
1054  nnall.name = "nnall";
1055  B2LDataField p_nnall(bitsNN, iclock, iTracker, nnall);
1056  B2DEBUG(22, padright(" all bits: ", 100));
1057  B2DEBUG(22, padright(" " + p_nnall.data, 100));
1058  // define variables to fill from the bitstream, B2LDataField holds just the string, not the unpacked data yet
1059  B2LDataField p_driftthreshold(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("DriftThreshold"));
1060  if ((p_driftthreshold.name != "None") && (p_driftthreshold.data.size() == 0)) {
1061  B2DEBUG(10, "Could not load Datafield: " << p_driftthreshold.name << " from bitstream. Maybe offset was out of bounds? clock: " <<
1062  iclock);
1063  continue;
1064  }
1065 
1066  B2LDataField p_valstereobit(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("ValStereoBit"));
1067  if ((p_valstereobit.name != "None") && (p_valstereobit.data.size() == 0)) {
1068  B2DEBUG(10, "Could not load Datafield: " << p_valstereobit.name << " from bitstream. Maybe offset was out of bounds? clock: " <<
1069  iclock);
1070  continue;
1071  }
1072 
1073  B2LDataField p_foundoldtrack(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("FoundOldTrack"));
1074  if ((p_foundoldtrack.name != "None") && (p_foundoldtrack.data.size() == 0)) {
1075  B2DEBUG(10, "Could not load Datafield: " << p_foundoldtrack.name << " from bitstream. Maybe offset was out of bounds? clock: " <<
1076  iclock);
1077  continue;
1078  }
1079 
1080  B2LDataField p_phi(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("Phi"));
1081  if ((p_phi.name != "None") && (p_phi.data.size() == 0)) {
1082  B2DEBUG(10, "Could not load Datafield: " << p_phi.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1083  continue;
1084  }
1085 
1086  B2LDataField p_omega(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("Omega"));
1087  if ((p_omega.name != "None") && (p_omega.data.size() == 0)) {
1088  B2DEBUG(10, "Could not load Datafield: " << p_omega.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1089  continue;
1090  }
1091 
1092  B2LDataField p_ts8(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("TS8"));
1093  if ((p_ts8.name != "None") && (p_ts8.data.size() == 0)) {
1094  B2DEBUG(10, "Could not load Datafield: " << p_ts8.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1095  continue;
1096  }
1097 
1098  B2LDataField p_ts6(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("TS6"));
1099  if ((p_ts6.name != "None") && (p_ts6.data.size() == 0)) {
1100  B2DEBUG(10, "Could not load Datafield: " << p_ts6.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1101  continue;
1102  }
1103 
1104  B2LDataField p_ts4(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("TS4"));
1105  if ((p_ts4.name != "None") && (p_ts4.data.size() == 0)) {
1106  B2DEBUG(10, "Could not load Datafield: " << p_ts4.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1107  continue;
1108  }
1109 
1110  B2LDataField p_ts2(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("TS2"));
1111  if ((p_ts2.name != "None") && (p_ts2.data.size() == 0)) {
1112  B2DEBUG(10, "Could not load Datafield: " << p_ts2.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1113  continue;
1114  }
1115 
1116  B2LDataField p_ts0(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("TS0"));
1117  if ((p_ts0.name != "None") && (p_ts0.data.size() == 0)) {
1118  B2DEBUG(10, "Could not load Datafield: " << p_ts0.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1119  continue;
1120  }
1121 
1122  B2LDataField p_tsf1(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("TSF1"));
1123  if ((p_tsf1.name != "None") && (p_tsf1.data.size() == 0)) {
1124  B2DEBUG(10, "Could not load Datafield: " << p_tsf1.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1125  continue;
1126  }
1127 
1128  B2LDataField p_tsf3(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("TSF3"));
1129  if ((p_tsf3.name != "None") && (p_tsf3.data.size() == 0)) {
1130  B2DEBUG(10, "Could not load Datafield: " << p_tsf3.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1131  continue;
1132  }
1133 
1134  B2LDataField p_tsf5(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("TSF5"));
1135  if ((p_tsf5.name != "None") && (p_tsf5.data.size() == 0)) {
1136  B2DEBUG(10, "Could not load Datafield: " << p_tsf5.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1137  continue;
1138  }
1139 
1140  B2LDataField p_tsf7(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("TSF7"));
1141  if ((p_tsf7.name != "None") && (p_tsf7.data.size() == 0)) {
1142  B2DEBUG(10, "Could not load Datafield: " << p_tsf7.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1143  continue;
1144  }
1145 
1146  B2LDataField p_tsfsel(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("TSFsel"));
1147  if ((p_tsfsel.name != "None") && (p_tsfsel.data.size() == 0)) {
1148  B2DEBUG(10, "Could not load Datafield: " << p_tsfsel.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1149  continue;
1150  }
1151 
1152  B2LDataField p_mlpin_alpha(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("MLPIn_alpha"));
1153  if ((p_mlpin_alpha.name != "None") && (p_mlpin_alpha.data.size() == 0)) {
1154  B2DEBUG(10, "Could not load Datafield: " << p_mlpin_alpha.name << " from bitstream. Maybe offset was out of bounds? clock: " <<
1155  iclock);
1156  continue;
1157  }
1158 
1159  B2LDataField p_mlpin_drifttime(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("MLPIn_driftt"));
1160  if ((p_mlpin_drifttime.name != "None") && (p_mlpin_drifttime.data.size() == 0)) {
1161  B2DEBUG(10, "Could not load Datafield: " << p_mlpin_drifttime.name << " from bitstream. Maybe offset was out of bounds? clock: " <<
1162  iclock);
1163  continue;
1164  }
1165 
1166  B2LDataField p_mlpin_id(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("MLPIn_id"));
1167  if ((p_mlpin_id.name != "None") && (p_mlpin_id.data.size() == 0)) {
1168  B2DEBUG(10, "Could not load Datafield: " << p_mlpin_id.name << " from bitstream. Maybe offset was out of bounds? clock: " <<
1169  iclock);
1170  continue;
1171  }
1172 
1173  B2LDataField p_netsel(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("Netsel"));
1174  if ((p_netsel.name != "None") && (p_netsel.data.size() == 0)) {
1175  B2DEBUG(10, "Could not load Datafield: " << p_netsel.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1176  continue;
1177  }
1178 
1179  B2LDataField p_mlpout_z(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("MLPOut_z"));
1180  if ((p_mlpout_z.name != "None") && (p_mlpout_z.data.size() == 0)) {
1181  B2DEBUG(10, "Could not load Datafield: " << p_mlpout_z.name << " from bitstream. Maybe offset was out of bounds? clock: " <<
1182  iclock);
1183  continue;
1184  }
1185 
1186  B2LDataField p_mlpout_theta(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("MLPOut_theta"));
1187  if ((p_mlpout_theta.name != "None") && (p_mlpout_theta.data.size() == 0)) {
1188  B2DEBUG(10, "Could not load Datafield: " << p_mlpout_theta.name << " from bitstream. Maybe offset was out of bounds? clock: " <<
1189  iclock);
1190  continue;
1191  }
1192 
1193  B2LDataField p_2dcc(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("2dcc"));
1194  if ((p_2dcc.name != "None") && (p_2dcc.data.size() == 0)) {
1195  B2DEBUG(10, "Could not load Datafield: " << p_2dcc.name << " from bitstream. Maybe offset was out of bounds? clock: " << iclock);
1196  continue;
1197  }
1198 
1199  B2LDataField p_extendedpts(bitsNN, iclock, iTracker, neurodb->getB2FormatLine("extendedPriorityTimes"));
1200  if ((p_extendedpts.name != "None") && (p_extendedpts.data.size() == 0)) {
1201  B2DEBUG(10, "Could not load Datafield: " << p_extendedpts.name << " from bitstream. Maybe offset was out of bounds? clock: " <<
1202  iclock);
1203  continue;
1204  }
1205  // B2LDataField (bitsNN, iclock, iTracker, neurodb->getB2FormatLine(""));
1206 
1207  CDCTriggerTrack* track2D = nullptr;
1208  // decode stereo hits
1209  if (true) { // (p_nnenable.data == "1") {
1210  unsigned sln = 0;
1211  B2DEBUG(21, padright(" Stereos: ", 100));
1212  for (auto stereolayer : {p_tsf1, p_tsf3, p_tsf5, p_tsf7}) {
1213  if (stereolayer.name == "None") {
1214  B2ERROR("Error in CDCTriggerNeuroConfig Payload, position of stereo tsf could not be found!");
1215  continue;
1216  }
1217  std::string tsstr = " | ";
1218  for (unsigned iHit = 0; iHit < 10; ++iHit) {
1219  tsOut ts = (sim13dt) ? decodeTSHit_sim(stereolayer.data.substr(iHit * lenTS, lenTS),
1220  p_2dcc.data) : decodeTSHit(stereolayer.data.substr(iHit * lenTS, lenTS));
1221  if (ts[3] > 0) { // if it is 0, it means 'no hit'
1222  unsigned iTS = TSIDInSL(ts[0], sln * 2 + 1, iTracker);
1223  tsstr += std::to_string(iTS) + ", " + std::to_string(ts[1]) + ", " + std::to_string(ts[2]) + ", " + std::to_string(ts[3]) + " | ";
1224  addTSHit(ts, sln * 2 + 1, iTracker, tsHitsAll, iclock);
1225  }
1226  }
1227  B2DEBUG(21, padright(" SL" + std::to_string(sln * 2 + 1) + tsstr, 100));
1228  ++sln;
1229  }
1230  }
1231  B2DEBUG(21, padright(" 2DCC: " + std::to_string(std::stoi(p_2dcc.data, 0, 2)) + ", (" + p_2dcc.data + ")", 100));
1232  if (p_nnenable.data == "1") {
1233  std::vector<bool> foundoldtrack{false};
1234  std::vector<bool> driftthreshold{false};
1235  bool valstereobit;
1236  if (p_foundoldtrack.name != "None") {
1237  foundoldtrack = decodefoundoldtrack(p_foundoldtrack.data);
1238  }
1239  if (p_driftthreshold.name != "None") {
1240  driftthreshold = decodedriftthreshold(p_driftthreshold.data);
1241  }
1242  if (p_valstereobit.name != "None") {
1243  valstereobit = decodevalstereobit(p_valstereobit.data);
1244  }
1245 
1246  if (std::all_of(p_phi.data.begin(), p_phi.data.end(), [](char i) {return i == 0;})) {
1247  B2ERROR("Empty Phi Value found for 2DTrack, should not happen!");
1248  continue;
1249  }
1250  TRG2DFinderTrack trk2D = decode2DTrack(
1251  "00", //charge
1252  p_omega.data,
1253  p_phi.data,
1254  p_ts0.data,
1255  p_ts2.data,
1256  p_ts4.data,
1257  p_ts6.data,
1258  p_ts8.data,
1259  iTracker,
1260  p_2dcc.data,
1261  sim13dt);
1262  track2D = store2DTracks->appendNew(trk2D.phi0, trk2D.omega, 0., foundoldtrack, driftthreshold, valstereobit, iclock, iTracker);
1263  B2DEBUG(12, padright(" 2DTrack: (phi=" + std::to_string(trk2D.phi0) + ", omega=" + std::to_string(
1264  trk2D.omega) + ", update=" + std::to_string(foundoldtrack[1]) + ")", 100));
1265 
1266  // add axial hits and create relations
1267  std::string tsstr;
1268  for (unsigned iAx = 0; iAx < nAxialTSF; ++iAx) {
1269  const auto& ts = trk2D.ts[iAx];
1270  if (ts[3] > 0) {
1271  CDCTriggerSegmentHit* hit =
1272  addTSHit(ts, 2 * iAx, iTracker, tsHitsAll, iclock);
1273  unsigned iTS = TSIDInSL(ts[0], iAx * 2, iTracker);
1274  tsstr += "(SL" + std::to_string(iAx * 2) + ", " + std::to_string(iTS) + ", " + std::to_string(ts[1]) + ", " + std::to_string(
1275  ts[2]) + ", " + std::to_string(ts[3]) + "),";
1276  track2D->addRelationTo(hit);
1277  }
1278  }
1279  B2DEBUG(16, padright(" 2DTrack TS: " + tsstr, 100));
1280 
1281 
1282  if (track2D) {
1283  TRGNeuroTrack trkNN;
1284  trkNN = decodeNNTrack(p_mlpout_z.data,
1285  p_mlpout_theta.data,
1286  p_tsfsel.data,
1287  p_mlpin_alpha.data,
1288  p_mlpin_drifttime.data,
1289  p_mlpin_id.data,
1290  p_netsel.data,
1291  neurodb,
1292  p_2dcc.data,
1293  sim13dt,
1294  p_extendedpts);
1295 
1296 
1297  B2DEBUG(11, padright(" NNTrack: (z=" + std::to_string(trkNN.z) + ", theta=" + std::to_string(trkNN.theta) + ")", 100));
1298 
1299  double phi0 = track2D->getPhi0();
1300  double omega = track2D->getOmega();
1301 
1302  std::vector<bool> tsvector(9, false);
1303  tsstr = "";
1304  for (unsigned iSL = 0; iSL < 9; ++iSL) {
1305  if (trkNN.ts[iSL][3] > 0) {
1306  tsvector[iSL] = true;
1307  unsigned iTS = TSIDInSL(trkNN.ts[iSL][0], iSL, iTracker);
1308  tsstr += "(SL" + std::to_string(iSL) + ", " + std::to_string(iTS) + ", " + std::to_string(trkNN.ts[iSL][1]) + ", " + std::to_string(
1309  trkNN.ts[iSL][2]) + ", " + std::to_string(trkNN.ts[iSL][3]) + "),\n";
1310 
1311 
1312  } else {
1313  tsstr += "( - ),\n";
1314  }
1315  }
1316  B2DEBUG(15, padright(" NNTrack TS: " + tsstr, 100));
1317 
1318  CDCTriggerTrack* trackNN = storeNNTracks->appendNew(phi0, omega, 0.,
1319  trkNN.z, cos(trkNN.theta) / sin(trkNN.theta), 0., track2D->getFoundOldTrack(), track2D->getDriftThreshold(),
1320  track2D->getValidStereoBit(), trkNN.sector, tsvector, iclock, iTracker);
1321  std::vector<float> inputVector(27, 0.);
1322  for (unsigned iSL = 0; iSL < 9; ++iSL) {
1323  inputVector[3 * iSL] = trkNN.inputID[iSL];
1324  inputVector[3 * iSL + 1] = trkNN.inputT[iSL];
1325  inputVector[3 * iSL + 2] = trkNN.inputAlpha[iSL];
1326  }
1327  CDCTriggerMLPInput* storeInput =
1328  storeNNInputs->appendNew(inputVector, trkNN.sector);
1329  trackNN->addRelationTo(storeInput);
1330  track2D->addRelationTo(trackNN);
1331 
1332  for (unsigned iSL = 0; iSL < 9; ++iSL) {
1333  if (trkNN.ts[iSL][3] > 0) {
1334  CDCTriggerSegmentHit* hit = nullptr;
1335  // if (sim13dt) {
1336  // // get extended priority time for stereos from the allstereots storearray
1337  // for (int ihit = 0; ihit<tsHitsAll->getEntries(); ++ihit) {
1338  // CDCTriggerSegmentHit* compare = (*tsHitsAll)[ihit];
1339  // if (compare->getISuperLayer() == iSL &&
1340  // compare->getIWireCenter() == TSIDInSL(trkNN.ts[iSL][0], iSL, iTracker) &&
1341  // compare->getPriorityPosition() == trkNN.ts[iSL][3] &&
1342  // compare->getLeftRight() == trkNN.ts[iSL][2] ) {
1343  // hit = compare;
1344  // }
1345  // }
1346  // if (!(!hit)) {
1347  // tsHits->appendNew(hit->getISuperLayer(), hit->getIWireCenter(), hit->getPriorityPosition(), hit->getLeftRight(), hit->priorityTime(), 0, hit->foundTime(), iTracker);
1348  // }
1349  // // get the extended pt for axials from the already existing 2d TS
1350  // for (int ihit = 0; ihit<tsHits->getEntries(); ++ihit) {
1351  // CDCTriggerSegmentHit* compare = (*tsHits)[ihit];
1352  // if (compare->getISuperLayer() == iSL &&
1353  // compare->getIWireCenter() == TSIDInSL(trkNN.ts[iSL][0], iSL, iTracker) &&
1354  // compare->getPriorityPosition() == trkNN.ts[iSL][3] &&
1355  // compare->getLeftRight() == trkNN.ts[iSL][2] ) {
1356  // hit = compare;
1357  // }
1358  // }
1359 
1360  // }
1361  if (!hit) {
1362  hit = addTSHit(trkNN.ts[iSL] , iSL, iTracker, tsHits, iclock);
1363  // B2DEBUG(1, "Hit with short drift time added, should not happen!");
1364  // }
1365  }
1366  trackNN->addRelationTo(hit);
1367  if (iSL % 2 == 0) {
1368  track2D->addRelationTo(hit);
1369  }
1370  }
1371  }
1372  }
1373 
1374 
1375  //
1376  // B2DEBUG(15, "bits for foundoldtrack: ");
1377  // for (auto x : foundoldtrack) {
1378  // B2DEBUG(15, x);
1379  // }
1380  // B2DEBUG(15, "bits for driftthreshold: ");
1381  // for (auto x : driftthreshold) {
1382  // B2DEBUG(15, x);
1383  // }
1384  // B2DEBUG(15, "bits for valstereobit: " << valstereobit);
1385  // B2DEBUG(15, "make new 2D track with phi " << trk2D.phi0 << " omega " << trk2D.omega << " clock " << iclock);
1386 
1387  }
1388  }
1389  }
1390  }
1391 
1392  void decodeNNIO_old(
1393  StoreArray<CDCTriggerUnpacker::NNBitStream>* bitsNN,
1394  StoreArray<CDCTriggerTrack>* store2DTracks,
1395  StoreArray<CDCTriggerTrack>* storeNNTracks,
1396  StoreArray<CDCTriggerSegmentHit>* tsHits,
1397  StoreArray<CDCTriggerMLPInput>* storeNNInputs)
1398  {
1399  for (short iclock = 0; iclock < bitsNN->getEntries(); ++iclock) {
1400  NNBitStream* bitsIn = (*bitsNN)[iclock];
1401  NNBitStream* bitsOutEnable = (*bitsNN)[iclock];
1402  for (unsigned iTracker = 0; iTracker < nTrackers; ++iTracker) {
1403  const auto slvOutEnable = bitsOutEnable->signal()[iTracker];
1404  const auto slvIn = bitsIn->signal()[iTracker];
1405  std::string stringOutEnable = slv_to_bin_string(slvOutEnable); //.substr(NN_OUT_WIDTH - 570, NN_OUT_WIDTH);
1406  std::string stringIn = slv_to_bin_string(slvIn); //.substr(NN_OUT_WIDTH - 570, NN_OUT_WIDTH);
1407  if (stringOutEnable.c_str()[0] == '1') {
1408  CDCTriggerTrack* nntrack2D = decodeNNInput(iclock, iTracker, bitsIn, store2DTracks, tsHits);
1409  if (nntrack2D) {
1410  int foundTime = iclock;
1411  if (foundTime < bitsNN->getEntries()) {
1412  NNBitStream* bitsOut = (*bitsNN)[foundTime];
1413  NNBitStream* bitsSelectTS = (*bitsNN)[iclock];
1414  decodeNNOutput_old(iclock, iTracker, bitsOut, bitsSelectTS,
1415  storeNNTracks, tsHits, storeNNInputs,
1416  nntrack2D);
1417  }
1418  }
1419  }
1420  }
1421  }
1422  }
1423  }
1425 }
Belle2::tsOutArray
std::array< tsOut, 5 > tsOutArray
TS array.
Definition: CDCTrigger2DFinderFirmwareModule.h:27
Belle2::CDCTriggerUnpacker::B2LDataField
Definition: Unpacker.h:270
Cosim::slv_to_bin_string
std::string slv_to_bin_string(std::array< char, N > signal, bool padding=false)
Transform into string.
Definition: Cosim.h:57
Belle2::Bitstream
Class to hold one clock cycle of raw bit content.
Definition: Bitstream.h:47
Belle2::CDCTriggerUnpacker::TRG2DFinderTrack::ts
tsOutArray ts
all TS of a 2D track
Definition: Unpacker.h:251
Cosim::std_logic_literal
const char * std_logic_literal[]
In case you are not familiar with VHDL simulation, there are 9 possible values defined for the standa...
Definition: Cosim.h:33
Belle2::CDCTriggerUnpacker::TRG2DFinderTrack::phi0
double phi0
phi0 of a 2D track
Definition: Unpacker.h:249
Belle2::CDCTriggerNeuroConfig::B2FormatLine::end
int end
end bit number in B2Link
Definition: CDCTriggerNeuroConfig.h:49
Cosim::display_hex
void display_hex(const std::array< char, N > &signal)
Display signal in hex.
Definition: Cosim.h:74
Belle2::CDCTriggerUnpacker::TRGNeuroTrack
TRG Neuro track.
Definition: Unpacker.h:254
Cosim::zero_val
const char zero_val
'0' in XSI VHDL simulation
Definition: Cosim.h:38
Belle2::Bitstream::signal
const SignalBus & signal()
accessors
Definition: Bitstream.h:66
Belle2::CDCTriggerUnpacker::TRGNeuroTrack::theta
double theta
theta of a NN track
Definition: Unpacker.h:258
Belle2::Const::speedOfLight
static const double speedOfLight
[cm/ns]
Definition: Const.h:568
Belle2::CDCTriggerUnpacker::TRGNeuroTrack::inputID
std::array< float, 9 > inputID
input ID list of a NN track
Definition: Unpacker.h:262
Belle2::CDCTriggerUnpacker::TRG2DFinderTrack
TRG 2DFinder Track.
Definition: Unpacker.h:244
Belle2::CDCTriggerNeuroConfig::B2FormatLine::offset
int offset
offset of information in B2Link
Definition: CDCTriggerNeuroConfig.h:51
Cosim::subset
std::bitset< max - min+1 > subset(std::bitset< nbits > set)
extract a subset of bitstring, like substring.
Definition: Cosim.h:113
Belle2::CDCTriggerUnpacker::TRGNeuroTrack::inputAlpha
std::array< float, 9 > inputAlpha
input Alpha list of a NN track
Definition: Unpacker.h:266
Belle2::CDCTriggerNeuroConfig::B2FormatLine::start
int start
start bit number in B2Link
Definition: CDCTriggerNeuroConfig.h:47
Belle2
Abstract base class for different kinds of events.
Definition: MillepedeAlgorithm.h:19
Belle2::tsOut
std::array< unsigned, 4 > tsOut
TS.
Definition: CDCTrigger2DFinderFirmwareModule.h:25
Cosim::one_val
const char one_val
'1' in XSI VHDL simulation
Definition: Cosim.h:36
Belle2::CDCTriggerNeuroConfig::B2FormatLine
Definition: CDCTriggerNeuroConfig.h:44
Belle2::CDCTriggerUnpacker::TRGNeuroTrack::sector
unsigned sector
sector of a NN track
Definition: Unpacker.h:260
Belle2::CDCTriggerUnpacker::TRGNeuroTrack::ts
std::array< tsOut, 9 > ts
input TS list of a NN track
Definition: Unpacker.h:268
Belle2::CDCTriggerUnpacker::TRGNeuroTrack::inputT
std::array< float, 9 > inputT
input T list of a NN track
Definition: Unpacker.h:264
Belle2::StoreArray
Accessor to arrays stored in the data store.
Definition: ECLMatchingPerformanceExpertModule.h:33
Cosim::display_value
std::string display_value(const char *count, int size)
Display value of the signal.
Definition: Cosim.h:41
Belle2::CDCTriggerNeuroConfig::B2FormatLine::name
std::string name
name of information in B2link
Definition: CDCTriggerNeuroConfig.h:53
Belle2::CDCTriggerUnpacker::TRG2DFinderTrack::omega
double omega
omega of a 2D track
Definition: Unpacker.h:247
Belle2::CDCTriggerUnpacker::TRGNeuroTrack::z
double z
z0 of a NN track
Definition: Unpacker.h:256