FelixDecode.hh
Go to the documentation of this file.
1 // FelixDecode.hh serves to decode root files containing artdaq Fragments with
2 // FELIX data.
3 
4 #ifndef artdaq_dune_Overlays_FelixDecode_hh
5 #define artdaq_dune_Overlays_FelixDecode_hh
6 
7 #include <math.h>
8 #include <stdint.h>
9 #include <complex>
10 #include <fstream>
11 #include <iomanip>
12 #include <iostream>
13 #include <string>
14 #include <valarray>
15 #include <vector>
17 #include "artdaq-core/Data/ContainerFragment.hh"
18 #include "artdaq-core/Data/Fragment.hh"
22 #include "gallery/Event.h"
23 
24 namespace dune {
25 
26 class FelixDecoder {
27  private:
28  art::InputTag tag = "daq:ContainerFELIX:DAQ";
29  std::vector<std::string> filenames;
30  std::vector<artdaq::Fragment> frags_;
31 
32  std::vector<unsigned> Uch = {3, 4, 5, 6, 7, 24, 25, 26, 27, 28};
33  std::vector<unsigned> Vch = {0, 1, 2, 8, 9, 22, 23, 29, 30, 31};
34  std::vector<unsigned> Wch = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21};
35 
36  // Vectors to contain channel averages, RMSes and test results.
37  std::vector<double> ch_avgsU;
38  std::vector<double> ch_avgsV;
39  std::vector<double> ch_avgsW;
40  std::vector<double> ch_rmsU;
41  std::vector<double> ch_rmsV;
42  std::vector<double> ch_rmsW;
43  std::vector<unsigned> ch_freqU;
44  std::vector<unsigned> ch_freqV;
45  std::vector<unsigned> ch_freqW;
46  // Vector to contain fragment test results.
47  std::vector<bool> frag_good;
48  // Vector to contain FFT results per FEMB.
49  std::vector<std::vector<double>> FEMB_FFT;
50  // Number of fragments to be analysed.
51  unsigned num_frags_ana;
52  // Bad channels.
53  const unsigned bad_channel_threshold_ = 400000;
54  const unsigned bad_channel_threshold_lower_ = 1;
55  std::vector<bool> bad_channel_;
56 
57  public:
58  // General information accessors.
59  size_t total_fragments() const { return frags_.size(); }
60 
61  size_t total_frames(const size_t i = 0) const {
62  dune::FelixFragment flxfrag(frags_[i]);
63  return flxfrag.total_frames();
64  }
65 
66  size_t total_events() const {
67  gallery::Event evt(filenames);
68  return evt.numberOfEventsInFile();
69  }
70 
71  // Check functions.
72  bool check_timestamps(unsigned frag_num) const {
73  bool failed = false;
74 
75  dune::FelixFragment flxfrag(frags_[frag_num]);
76  // Loop over frames in the fragment and check the timestamps.
77  uint64_t prevtimestamp = flxfrag.timestamp(0);
78  for (unsigned fr = 1; fr < flxfrag.total_frames(); ++fr) {
79  // Check timestamp.
80  if (flxfrag.timestamp(fr) - prevtimestamp != 25) {
81  std::cout << "Timestamp does not increase by 25 at frame " << fr
82  << " in fragment " << frag_num << "!\n";
83  std::cout << "It instead increases by "
84  << flxfrag.timestamp(fr) - prevtimestamp << "\n";
85  std::cout << "Fiber " << (unsigned)flxfrag.fiber_no(fr) << ", slot "
86  << (unsigned)flxfrag.slot_no(fr) << ", crate "
87  << (unsigned)flxfrag.crate_no(fr) << '\n';
88  failed = true;
89  break;
90  }
91  // std::cout << flxfrag.timestamp(fr) - prevtimestamp << "\t";
92  prevtimestamp = flxfrag.timestamp(fr);
93  } // Loop over frames.
94 
95  return !failed;
96  }
97 
98  bool check_all_timestamps() const {
99  bool failed = false;
100  // Loop over fragments within an event.
101  std::cout << "Going through " << frags_.size() << " fragments.\n";
102  for (unsigned i = 0; i < frags_.size(); ++i) {
103  std::cout << i << '\r';
104  failed |= !(check_timestamps(i));
105  }
106 
107  if (failed) {
108  std::cout << "Timestamp check failed.\n";
109  } else {
110  std::cout << "Timestamp check succeeded.\n";
111  }
112 
113  return !failed;
114  }
115 
116  bool check_CCCs(unsigned frag_num) const {
117  bool failed = false;
118 
119  dune::FelixFragment flxfrag(frags_[frag_num]);
120  // Loop over frames in the fragment and check the COLDATA convert
121  // counts.
122  uint16_t prevCCC1 = flxfrag.coldata_convert_count(0, 0);
123  uint16_t prevCCC2 = flxfrag.coldata_convert_count(0, 2);
124  for (unsigned fr = 1; fr < flxfrag.total_frames(); ++fr) {
125  // Check CCC1.
126  if (flxfrag.coldata_convert_count(fr, 0) - prevCCC1 != 1 &&
127  flxfrag.coldata_convert_count(fr, 0) - prevCCC1 != -33919 &&
128  flxfrag.coldata_convert_count(fr, 0) - prevCCC1 != -65535) {
129  std::cout << "CCC1 does not increase by 1 at frame " << fr
130  << " in fragment " << frag_num << "!\n";
131  std::cout << "It instead increases by "
132  << flxfrag.coldata_convert_count(fr, 0) - prevCCC1 << '\n';
133  failed = true;
134  break;
135 
136  // Check CCC2.
137  if (flxfrag.coldata_convert_count(fr, 2) - prevCCC2 != 1 &&
138  flxfrag.coldata_convert_count(fr, 2) - prevCCC2 != -33919 &&
139  flxfrag.coldata_convert_count(fr, 0) - prevCCC2 != -65535) {
140  std::cout << "CCC2 does not increase by 1 at frame " << fr
141  << " in fragment " << frag_num << "!\n";
142  std::cout << "It instead increases by "
143  << flxfrag.coldata_convert_count(fr, 2) - prevCCC2 << '\n';
144  failed = true;
145  break;
146  }
147  prevCCC2 = flxfrag.coldata_convert_count(fr, 2);
148  }
149  prevCCC1 = flxfrag.coldata_convert_count(fr, 0);
150 
151  // Check whether other CCCs correspond.
152  if (flxfrag.coldata_convert_count(fr, 0) !=
153  flxfrag.coldata_convert_count(fr, 1) ||
154  flxfrag.coldata_convert_count(fr, 2) !=
155  flxfrag.coldata_convert_count(fr, 3)) {
156  std::cout << "CCC in frame " << fr << " do not correspond!\n";
157  failed = true;
158  break;
159  }
160  } // Loop over frames.
161 
162  return !failed;
163  }
164 
165  bool check_all_CCCs() const {
166  bool failed = false;
167  for (unsigned i = 0; i < frags_.size(); ++i) {
168  failed |= !(check_CCCs(i));
169  }
170 
171  if (failed) {
172  std::cout << "CCC check failed.\n";
173  } else {
174  std::cout << "CCC check succeeded.\n";
175  }
176 
177  return !failed;
178  }
179 
180  bool check_IDs(unsigned frag_num) const {
181  bool failed = false;
182 
183  dune::FelixFragment flxfrag(frags_[frag_num]);
184  // Output a fragment's fiber, crate and slot number.
185  unsigned fiber_no = flxfrag.fiber_no();
186  unsigned crate_no = flxfrag.crate_no();
187  unsigned slot_no = flxfrag.slot_no();
188  // std::cout << "Fragment " << i << " has:\nfiber_no: " << fiber_no <<
189  // '\n'; std::cout << "crate_no: " << crate_no << '\n'; std::cout <<
190  // "slot_no: " << slot_no << '\n';
191 
192  // Check whether fragments have logical
193  // fiber, crate and slot numbers between frames.
194  for (unsigned fi = 1; fi < flxfrag.total_frames(); ++fi) {
195  // The fiber_no has to stay constant
196  if (flxfrag.fiber_no(fi) != fiber_no) {
197  std::cout << "Non-constant fiber_no in fragment " << frag_num
198  << " frame " << fi << ": " << (unsigned)(flxfrag.fiber_no(fi))
199  << " instead of " << fiber_no << '\n';
200  fiber_no = flxfrag.fiber_no(fi);
201  failed = true;
202  break;
203  }
204  // The crate_no has to stay constant.
205  if (flxfrag.crate_no(fi) != crate_no) {
206  std::cout << "Non-constant crate_no in fragment " << frag_num
207  << " frame " << fi << ": " << (unsigned)(flxfrag.crate_no(fi))
208  << " instead of " << crate_no << '\n';
209  crate_no = flxfrag.crate_no(fi);
210  failed = true;
211  break;
212  }
213  // The slot_no has to stay constant.
214  if (flxfrag.slot_no(fi) != slot_no) {
215  std::cout << "Non-constant slot_no in fragment " << frag_num
216  << " frame " << fi << ": " << (unsigned)(flxfrag.slot_no(fi))
217  << " instead of " << slot_no << '\n';
218  slot_no = flxfrag.slot_no(fi);
219  failed = true;
220  break;
221  }
222  } // Loop over frames.
223 
224  return !failed;
225  }
226 
227  bool check_all_IDs() const {
228  bool failed = false;
229  for (unsigned i = 0; i < frags_.size(); ++i) {
230  failed |= !(check_IDs(i));
231  }
232 
233  if (failed) {
234  std::cout << "ID check failed.\n";
235  } else {
236  std::cout << "ID check succeeded.\n";
237  }
238 
239  return !failed;
240  }
241 
242  // Accessor for artdaq::Fragments.
243  artdaq::Fragment Fragment(const size_t& frag_num) const {
244  if (frag_num >= total_fragments()) {
245  std::cout << "Fragment index out of range.\n";
246  artdaq::Fragment emptyfrag;
247  return emptyfrag;
248  }
249  return frags_[frag_num];
250  }
251 
252  // Cooley-Tukey FFT (in-place, breadth-first, decimation-in-frequency)
253  // Copied from rosettacode.org and modified here. Perform FFT over the first
254  // fragment and print to file for plotting.
255  void FFT(std::vector<std::complex<double>>& x) {
256  typedef std::complex<double> Complex;
257 
258  // Determine the length of the vector to be processed.
259  unsigned N = 1;
260  for (unsigned i = 0; i < 16; ++i) {
261  if (N << 1 < x.size()) {
262  N <<= 1;
263  }
264  }
265  // Resize original vector.
266  x.resize(N);
267 
268  // DFT
269  unsigned int k = N, n;
270  double thetaT = 3.14159265358979323846264338328L / N;
271  Complex phiT = Complex(cos(thetaT), -sin(thetaT)), T;
272  while (k > 1) {
273  n = k;
274  k /= 2;
275  phiT = phiT * phiT;
276  T = 1.0L;
277  for (unsigned int l = 0; l < k; l++) {
278  for (unsigned int a = l; a < N; a += n) {
279  unsigned int b = a + k;
280  Complex t = x[a] - x[b];
281  x[a] += x[b];
282  x[b] = t * T;
283  }
284  T *= phiT;
285  }
286  }
287  // Decimate
288  unsigned int m = (unsigned int)log2(N);
289  for (unsigned int a = 0; a < N; a++) {
290  unsigned int b = a;
291  // Reverse bits
292  b = (((b & 0xaaaaaaaa) >> 1) | ((b & 0x55555555) << 1));
293  b = (((b & 0xcccccccc) >> 2) | ((b & 0x33333333) << 2));
294  b = (((b & 0xf0f0f0f0) >> 4) | ((b & 0x0f0f0f0f) << 4));
295  b = (((b & 0xff00ff00) >> 8) | ((b & 0x00ff00ff) << 8));
296  b = ((b >> 16) | (b << 16)) >> (32 - m);
297  if (b > a) {
298  Complex t = x[a];
299  x[a] = x[b];
300  x[b] = t;
301  }
302  }
303  // // Normalize
304  // Complex f = 1.0 / sqrt(N);
305  // for (unsigned int i = 0; i < N; i++) {
306  // x[i] *= f;
307  // }
308  }
309 
310  // Check the integrity of all stored fragments and store the information.
311  void checkFragments() {
312  // Test fragments for data integrity.
313  std::cout << "Testing fragments for integrity.\n";
314  for (unsigned frag_num = 0; frag_num < num_frags_ana; ++frag_num) {
315  bool data_good = true;
316  data_good |= check_timestamps(frag_num); // Checks increments by 25.
317  data_good |= check_CCCs(
318  frag_num); // Checks increments by 1 and correspondence between CCCs.
319  data_good |= check_IDs(frag_num); // Check the identifier fields of
320  // all the frames in fragments.
321  frag_good[frag_num] = data_good;
322  }
323  }
324 
325  // Fill the channel averages and frequencies for good fragments.
327  // Record the average of all channels of good fragments.
328  std::cout << "Calculating channel averages.\n";
329  for (unsigned frag_num = 0; frag_num < num_frags_ana; ++frag_num) {
330  if (!frag_good[frag_num]) {
331  continue;
332  }
333 
334  // Load the fragment and put it in the overlay.
335  artdaq::Fragment frag = Fragment(frag_num);
336  dune::FelixFragment flxfrag(frag);
337  unsigned ch_num_base =
338  flxfrag.slot_no() * 512 + (flxfrag.fiber_no() - 1) * 256;
339  // Loop through frames and channels.
340  for (unsigned fr_num = 0; fr_num < flxfrag.total_frames(); ++fr_num) {
341  for (unsigned u = 0; u < Uch.size(); ++u) {
342  ch_avgsU[ch_num_base + Uch[u]] += flxfrag.get_ADC(fr_num, Uch[u]);
343  ch_freqU[ch_num_base + Uch[u]]++;
344  }
345  for (unsigned v = 0; v < Vch.size(); ++v) {
346  ch_avgsV[ch_num_base + Vch[v]] += flxfrag.get_ADC(fr_num, Vch[v]);
347  ch_freqV[ch_num_base + Vch[v]]++;
348  }
349  for (unsigned w = 0; w < Wch.size(); ++w) {
350  ch_avgsW[ch_num_base + Wch[w]] += flxfrag.get_ADC(fr_num, Wch[w]);
351  ch_freqW[ch_num_base + Wch[w]]++;
352  }
353  }
354  }
355  for (unsigned ch_num = 0; ch_num < ch_avgsU.size(); ++ch_num) {
356  if (ch_freqU[ch_num] != 0) {
357  ch_avgsU[ch_num] /= ch_freqU[ch_num];
358  }
359  }
360  for (unsigned ch_num = 0; ch_num < ch_avgsV.size(); ++ch_num) {
361  if (ch_freqV[ch_num] != 0) {
362  ch_avgsV[ch_num] /= ch_freqV[ch_num];
363  }
364  }
365  for (unsigned ch_num = 0; ch_num < ch_avgsW.size(); ++ch_num) {
366  if (ch_freqW[ch_num] != 0) {
367  ch_avgsW[ch_num] /= ch_freqW[ch_num];
368  }
369  }
370  }
371 
373  // Record the RMS of each channel.
374  std::cout << "Calculating noise RMS values per channel.\n";
375  for (unsigned frag_num = 0; frag_num < num_frags_ana; ++frag_num) {
376  if (!frag_good[frag_num]) {
377  continue;
378  }
379 
380  // Load the fragment and put it in the overlay.
381  artdaq::Fragment frag = Fragment(frag_num);
382  dune::FelixFragment flxfrag(frag);
383  // std::cout << "Fragment " << frag_num << " has crate " <<
384  // (unsigned)flxfrag.crate_no()
385  // << " slot " << (unsigned)flxfrag.slot_no() << " and fiber "
386  // << (unsigned)flxfrag.fiber_no() << '\n';
387  unsigned ch_num_base =
388  flxfrag.slot_no() * 512 + (flxfrag.fiber_no() - 1) * 256;
389  // Loop through channels and frames.
390  // Add to noise RMS vectors.
391  for (unsigned u = 0; u < Uch.size(); ++u) {
392  for (unsigned fr_num = 0; fr_num < flxfrag.total_frames(); ++fr_num) {
393  ch_rmsU[ch_num_base + Uch[u]] += pow(
394  ch_avgsU[ch_num_base + Uch[u]] - flxfrag.get_ADC(fr_num, Uch[u]),
395  2);
396  }
397  }
398  for (unsigned v = 0; v < Vch.size(); ++v) {
399  for (unsigned fr_num = 0; fr_num < flxfrag.total_frames(); ++fr_num) {
400  ch_rmsV[ch_num_base + Vch[v]] += pow(
401  ch_avgsV[ch_num_base + Vch[v]] - flxfrag.get_ADC(fr_num, Vch[v]),
402  2);
403  }
404  }
405  for (unsigned w = 0; w < Wch.size(); ++w) {
406  for (unsigned fr_num = 0; fr_num < flxfrag.total_frames(); ++fr_num) {
407  ch_rmsW[ch_num_base + Wch[w]] += pow(
408  ch_avgsW[ch_num_base + Wch[w]] - flxfrag.get_ADC(fr_num, Wch[w]),
409  2);
410  }
411  }
412  }
413 
414  // Final value manipulation.
415  unsigned num_bad_channels = 0;
416  for (unsigned ch = 0; ch < 2560; ++ch) {
417  ch_rmsU[ch] = sqrt(ch_rmsU[ch] / ch_freqU[ch]);
418  ch_rmsV[ch] = sqrt(ch_rmsV[ch] / ch_freqV[ch]);
419  ch_rmsW[ch] = sqrt(ch_rmsW[ch] / ch_freqW[ch]);
420 
421  // Fill bad channel vector.
422  if (ch_rmsU[ch] > bad_channel_threshold_ ||
423  ch_rmsV[ch] > bad_channel_threshold_ ||
424  ch_rmsW[ch] > bad_channel_threshold_ || (ch_rmsU[ch]<bad_channel_threshold_lower_ && ch_rmsV[ch]<bad_channel_threshold_lower_ && ch_rmsW[ch]<bad_channel_threshold_lower_)) {
425  bad_channel_[ch] = true;
426  ++num_bad_channels;
427  }
428  }
429  std::cout << "Number of bad channels: " << num_bad_channels << ".\n";
430  }
431 
432  void calculateFFT() {
433  // Track how many occurrences of every FEMB there are.
434  std::vector<unsigned> FEMB_freq(20, 0);
435  for (unsigned frag_num = 0; frag_num < num_frags_ana; ++frag_num) {
436  if (!frag_good[frag_num]) {
437  continue;
438  }
439 
440  // Load the fragment and put it in the overlay.
441  artdaq::Fragment frag = Fragment(frag_num);
442  dune::FelixFragment flxfrag(frag);
443 
444  // Increment the frequency of the two FEMBs contained within a fragment.
445  ++FEMB_freq[flxfrag.slot_no() * 4 + (flxfrag.fiber_no() - 1) * 2];
446  ++FEMB_freq[flxfrag.slot_no() * 4 + (flxfrag.fiber_no() - 1) * 2 + 1];
447  }
448  // for(unsigned i = 0; i < FEMB_freq.size(); ++i) {
449  // std::cout << "FEMB " << i << " occurred " << FEMB_freq[i] << "
450  // times.\n";
451  // }
452 
453  for (unsigned frag_num = 0; frag_num < num_frags_ana; ++frag_num) {
454  if (!frag_good[frag_num]) {
455  continue;
456  }
457 
458  // Load the fragment and put it in the overlay.
459  artdaq::Fragment frag = Fragment(frag_num);
460  dune::FelixFragment flxfrag(frag);
461  // FFT calculations.
462  for (unsigned ch_num = 0; ch_num < 256; ++ch_num) {
463  // FFT vector.
464  std::vector<std::complex<double>> ch_fft_waveform(
465  flxfrag.total_frames(), 0);
466  for (unsigned fr_num = 0; fr_num < flxfrag.total_frames(); ++fr_num) {
467  // Add to FFT vector.
468  ch_fft_waveform[fr_num] = flxfrag.get_ADC(fr_num, ch_num);
469  }
470  FFT(ch_fft_waveform);
471  // Add to master FFT waveform.
472  unsigned FEMB_num = (flxfrag.slot_no() - 0) * 4 +
473  (flxfrag.fiber_no() - 1) * 2 + ch_num / 128;
474  if(bad_channel_[FEMB_num*128 + ch_num]) { continue; }
475  // if (std::abs(ch_fft_waveform[5000]) / (FEMB_freq[FEMB_num] * 128) >
476  // 4.3) {
477  // std::cout << "BAD CHANNEL: " << ch_num << " IN FEMB " << FEMB_num << '\n';
478  // }
479  for (unsigned i = 0; i < ch_fft_waveform.size(); ++i) {
480  FEMB_FFT[FEMB_num][i] +=
481  std::abs(ch_fft_waveform[i])/(FEMB_freq[FEMB_num]*128);
482  }
483  }
484  }
485  }
486 
487  // Function to determine channel RMS and print to file.
488  void analyse(std::string destination) {
489  // Number of fragments to run this code over.
490  std::cout << "calculateNoiseRMS: found " << frags_.size()
491  << " fragments.\n";
492  num_frags_ana = std::min<unsigned>(frags_.size(), 100);
493 
494  // Resize noise calculation vectors.
495  ch_avgsU.resize(2 * 5 * 256, 0);
496  ch_avgsV.resize(2 * 5 * 256, 0);
497  ch_avgsW.resize(2 * 5 * 256, 0);
498  ch_rmsU.resize(2 * 5 * 256, 0);
499  ch_rmsV.resize(2 * 5 * 256, 0);
500  ch_rmsW.resize(2 * 5 * 256, 0);
501  ch_freqU.resize(2 * 5 * 256, 0);
502  ch_freqV.resize(2 * 5 * 256, 0);
503  ch_freqW.resize(2 * 5 * 256, 0);
504  frag_good.resize(num_frags_ana, false);
505  FEMB_FFT.resize(20, std::vector<double>(total_frames(), 0));
506  bad_channel_.resize(2 * 5 * 256, 0);
507 
508  // Set integrity flags.
509  checkFragments();
510  // Fill averages and frequencies for each channel.
512  // Populate noise RMS vectors.
514  // Populate FFT vectors.
515  calculateFFT();
516 
517  // Write noise RMS to file.
518  std::cout << "Writing to file " << destination + "/RMSU.dat"
519  << ".\n";
520  std::ofstream rmsfileU(destination + "/RMSU.dat");
521  rmsfileU << "#WIB Fibre Channel Global Noise RMS U\n";
522  for (unsigned ch_num = 0; ch_num < ch_rmsU.size(); ++ch_num) {
523  if (ch_freqU[ch_num] == 0) {
524  continue;
525  }
526  rmsfileU << ch_num / 512 + 1 << " " << (ch_num % 512) / 256 + 1
527  << " " << ch_num % 256 << " " << ch_num << " "
528  << ch_rmsU[ch_num] << '\n';
529  }
530  rmsfileU.close();
531 
532  std::cout << "Writing to file " << destination + "/RMSV.dat"
533  << ".\n";
534  std::ofstream rmsfileV(destination + "/RMSV.dat");
535  rmsfileV << "#WIB Fibre Channel Global Noise RMS V\n";
536  for (unsigned ch_num = 0; ch_num < ch_rmsV.size(); ++ch_num) {
537  if (ch_freqV[ch_num] == 0) {
538  continue;
539  }
540  rmsfileV << ch_num / 512 + 1 << " " << (ch_num % 512) / 256 + 1
541  << " " << ch_num % 256 << " " << ch_num << " "
542  << ch_rmsV[ch_num] << '\n';
543  }
544  rmsfileV.close();
545 
546  std::cout << "Writing to file " << destination + "/RMSW.dat"
547  << ".\n";
548  std::ofstream rmsfileW(destination + "/RMSW.dat");
549  rmsfileW << "#WIB Fibre Channel Global Noise RMS W\n";
550  for (unsigned ch_num = 0; ch_num < ch_rmsW.size(); ++ch_num) {
551  if (ch_freqW[ch_num] == 0) {
552  continue;
553  }
554  rmsfileW << ch_num / 512 + 1 << " " << (ch_num % 512) / 256 + 1
555  << " " << ch_num % 256 << " " << ch_num << " "
556  << ch_rmsW[ch_num] << '\n';
557  }
558  rmsfileW.close();
559 
560  // Normalise and write FFTs to file.
561  std::string fftfilename = destination + "/FFT.dat";
562  std::cout << "Writing to file " << fftfilename << ".\n";
563  std::ofstream fftfile(fftfilename);
564  // Write headers.
565  fftfile << "#Slot -> ";
566  for (unsigned f = 0; f < 20; ++f) {
567  fftfile << std::setw(15) << f / 4 + 1;
568  }
569  fftfile << '\n' << "#Fiber -> ";
570  for (unsigned f = 0; f < 20; ++f) {
571  fftfile << std::setw(15) << (f % 4) / 2 + 1;
572  }
573  fftfile << '\n' << "#FEMB -> ";
574  for (unsigned f = 0; f < 20; ++f) {
575  fftfile << std::setw(15) << f % 2 + 1;
576  }
577  fftfile << '\n' << "#Global ->";
578  for (unsigned f = 0; f < 20; ++f) {
579  fftfile << std::setw(15) << f + 1;
580  }
581  fftfile << '\n';
582 
583  // Write the first row a little wider.
584  fftfile << std::left << std::setw(5) << 0 << std::right;
585  for (unsigned femb = 0; femb < 20; ++femb) {
586  fftfile << std::setw(15) << log10(pow(FEMB_FFT[femb][0], 2));
587  }
588  fftfile << '\n';
589 
590  for (unsigned tick = 1; tick < total_frames(); ++tick) {
591  // std::cout << "Tick" << tick << " written.\n";
592  fftfile << std::left << std::setw(10) << tick << std::right;
593  // Write FFT for each FEMB.
594  for (unsigned femb = 0; femb < 20; ++femb) {
595  fftfile << std::setw(15) << log10(pow(FEMB_FFT[femb][tick], 2));
596  }
597  fftfile << '\n';
598  }
599 
600  fftfile.close();
601  }
602 
603  // Print function.
604  void printFrames(const size_t& begin_frame = 0, const size_t& end_frame = 1,
605  const size_t& frag_num = 0) const {
606  artdaq::Fragment frag(Fragment(frag_num));
607  dune::FelixFragment flxfrag(frag);
608  for (unsigned i = begin_frame; i < end_frame; ++i) {
609  std::cout << "Frame " << i << '\n';
610  flxfrag.print(i);
611  }
612  }
613 
614  // Overloaded loadFiles to deal with one or multiple files.
615  void loadFiles(const std::string& filename) { filenames.push_back(filename); }
616  void loadFiles(const std::vector<std::string>& input_files) {
617  filenames = input_files;
618  }
619 
620  // Constructors that load a file.
621  FelixDecoder() = delete;
622 
623  template <class T>
624  FelixDecoder(const T& input_files) {
625  loadFiles(input_files);
626  unsigned num_evts = 0;
627  for (gallery::Event evt(filenames); !evt.atEnd(); evt.next()) {
628  ++num_evts;
630  evt.getValidHandle<std::vector<artdaq::Fragment>>(tag);
631  for (const auto& frag : *frags) {
632  artdaq::ContainerFragment cont_frag(frag);
633  for (unsigned b = 0; b < cont_frag.block_count(); ++b) {
634  if(cont_frag[b]->dataSizeBytes() != 0) {
635  frags_.push_back(*cont_frag[b]);
636  }
637  }
638  }
639  std::cout << "Event " << num_evts << " loaded.\n";
640  if (frags_.size() >= 50) {
641  break;
642  }
643  }
644  std::cout << "Loaded " << total_fragments() << " fragments in " << num_evts
645  << " events.\n";
646 
647  // Ugly way to get the rest of the channel map from a repeating pattern.
648  unsigned Usize = Uch.size();
649  unsigned Vsize = Vch.size();
650  unsigned Wsize = Wch.size();
651  for (unsigned j = 0; j < 8; ++j) {
652  for (unsigned i = 0; i < Usize; ++i) {
653  Uch.push_back(Uch[i] + 32 * j);
654  }
655  for (unsigned i = 0; i < Vsize; ++i) {
656  Vch.push_back(Vch[i] + 32 * j);
657  }
658  for (unsigned i = 0; i < Wsize; ++i) {
659  Wch.push_back(Wch[i] + 32 * j);
660  }
661  }
662  }
663 }; // class FelixDecoder
664 
665 } // namespace dune
666 
667 #endif /* artdaq_dune_Overlays_FelixDecode_hh */
std::vector< double > ch_avgsU
Definition: FelixDecode.hh:37
bool check_all_IDs() const
Definition: FelixDecode.hh:227
size_t total_frames() const
std::vector< bool > frag_good
Definition: FelixDecode.hh:47
std::vector< double > ch_avgsW
Definition: FelixDecode.hh:39
uint8_t slot_no(const unsigned &frame_ID=0) const
Fw2dFFT::Complex Complex
std::string string
Definition: nybbler.cc:12
unsigned num_frags_ana
Definition: FelixDecode.hh:51
uint8_t crate_no(const unsigned &frame_ID=0) const
std::vector< unsigned > ch_freqU
Definition: FelixDecode.hh:43
size_t total_frames(const size_t i=0) const
Definition: FelixDecode.hh:61
constexpr T pow(T x)
Definition: pow.h:72
struct vector vector
artdaq::Fragment Fragment(const size_t &frag_num) const
Definition: FelixDecode.hh:243
void FFT(std::vector< std::complex< double >> &x)
Definition: FelixDecode.hh:255
string filename
Definition: train.py:213
std::vector< unsigned > Uch
Definition: FelixDecode.hh:32
static QStrList * l
Definition: config.cpp:1044
std::vector< double > ch_avgsV
Definition: FelixDecode.hh:38
adc_t get_ADC(const unsigned &frame_ID, const uint8_t channel_ID) const
void calculateAveragesAndFreqs()
Definition: FelixDecode.hh:326
size_t total_fragments() const
Definition: FelixDecode.hh:59
T abs(T value)
std::vector< double > ch_rmsW
Definition: FelixDecode.hh:42
void loadFiles(const std::string &filename)
Definition: FelixDecode.hh:615
size_t total_events() const
Definition: FelixDecode.hh:66
std::vector< bool > bad_channel_
Definition: FelixDecode.hh:55
bool check_CCCs(unsigned frag_num) const
Definition: FelixDecode.hh:116
std::void_t< T > n
const double a
bool check_IDs(unsigned frag_num) const
Definition: FelixDecode.hh:180
std::vector< unsigned > Wch
Definition: FelixDecode.hh:34
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
uint16_t coldata_convert_count(const unsigned &frame_ID, const uint8_t &block_num) const
void analyse(std::string destination)
Definition: FelixDecode.hh:488
std::vector< std::string > filenames
Definition: FelixDecode.hh:29
long long numberOfEventsInFile() const
Definition: Event.cc:65
Q_EXPORT QTSManip setw(int w)
Definition: qtextstream.h:331
uint8_t fiber_no(const unsigned &frame_ID=0) const
std::vector< double > ch_rmsU
Definition: FelixDecode.hh:40
std::vector< unsigned > ch_freqV
Definition: FelixDecode.hh:44
bool check_all_timestamps() const
Definition: FelixDecode.hh:98
void loadFiles(const std::vector< std::string > &input_files)
Definition: FelixDecode.hh:616
bool check_timestamps(unsigned frag_num) const
Definition: FelixDecode.hh:72
std::vector< unsigned > ch_freqW
Definition: FelixDecode.hh:45
std::vector< double > ch_rmsV
Definition: FelixDecode.hh:41
std::vector< artdaq::Fragment > frags_
Definition: FelixDecode.hh:30
static bool * b
Definition: config.cpp:1043
art::InputTag tag
Definition: FelixDecode.hh:28
list x
Definition: train.py:276
bool check_all_CCCs() const
Definition: FelixDecode.hh:165
void printFrames(const size_t &begin_frame=0, const size_t &end_frame=1, const size_t &frag_num=0) const
Definition: FelixDecode.hh:604
TCEvent evt
Definition: DataStructs.cxx:7
void print(const unsigned i) const
const unsigned bad_channel_threshold_lower_
Definition: FelixDecode.hh:54
FelixDecoder(const T &input_files)
Definition: FelixDecode.hh:624
std::vector< std::vector< double > > FEMB_FFT
Definition: FelixDecode.hh:49
const unsigned bad_channel_threshold_
Definition: FelixDecode.hh:53
std::vector< unsigned > Vch
Definition: FelixDecode.hh:33
uint64_t timestamp(const unsigned &frame_ID=0) const