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