FelixIntegrityTest_module.cc
Go to the documentation of this file.
1 // art includes
11 #include "art_root_io/TFileService.h"
12 
13 // artdaq and dune-raw-data includes
15 #include "artdaq-core/Data/Fragment.hh"
16 #include "artdaq-core/Data/ContainerFragment.hh"
19 
20 // larsoft includes
22 
23 // ROOT includes
24 #include "TH1.h"
25 
26 // C++ Includes
27 #include <memory>
28 #include <iostream>
29 #include <iomanip>
30 
31 namespace dune {
32  class FelixIntegrityTest;
33 }
34 
36 public:
37  explicit FelixIntegrityTest(fhicl::ParameterSet const & p);
38  // The destructor generated by the compiler is fine for classes
39  // without bare pointers or other resoufelix use.
40 
41  // Plugins should not be copied or assigned.
42  FelixIntegrityTest(FelixIntegrityTest const &) = delete;
46 
47  // Required functions.
48  void analyze(const art::Event & evt) override;
49  void beginJob() override;
50  void endJob() override;
51 
52  // Error metrics
53  struct ErrorMetrics {
54  uint64_t sequenceID;
55  uint64_t fragmentID;
56  uint64_t type;
57  uint64_t timestamp;
58 
60  uint64_t crate_no;
61  uint64_t slot_no;
62  uint64_t fiber_no;
63 
64  bool meta_err;
68 
69  bool bad;
70 
71  void print() const {
72  std::cout
73  << "SequenceID: " << sequenceID
74  << " fragmentID: " << fragmentID
75  << " fragmentType: " << type
76  << " Timestamp: " << timestamp
77  << " Crate number: " << crate_no
78  << " Slot number: " << slot_no
79  << " Fiber number: " << fiber_no << "\n\n";
80  std::cout << "Metadata error: ";
81  meta_err? std::cout << "YES\n" : std::cout << "NO\n";
82  std::cout << "Timestamp error: ";
83  timestamp_err? std::cout << "YES\n" : std::cout << "NO\n";
84  std::cout << "Convert count error: ";
85  convert_count_err? std::cout << "YES\n" : std::cout << "NO\n";
86  // << "Error fields set: " << error_fields_set? "YES" : "NO\n";
87  }
88  };
89 
90 private:
91  ErrorMetrics _process(const artdaq::Fragment& frag);
92 
93  // Variables read from the fcl file
96 
97  // Keeping track of fragment metadata
99 
100  // WIB constants
101  const uint64_t timestamp_increase = 25;
102 
103  // COLDATA constants
104  const uint16_t convert_count_increase = 1;
105  std::vector<ErrorMetrics> test_results;
106  unsigned n_good_frags = 0;
107  unsigned n_bad_frags = 0;
108 };
109 
110 
112  : EDAnalyzer(pset),
113  _input_label(pset.get<std::string>("RawDataLabel")),
114  _expect_container_fragments(pset.get<bool>("ExpectContainerFragments", true)) {}
115 
117 }
118 
120  std::cout << "-------------------- FELIX Integrity Test -------------------";
121 
123  art::InputTag itag1(_input_label, "ContainerFELIX");
124  auto cont_frags = evt.getHandle<artdaq::Fragments>(itag1);
125  art::EventNumber_t eventNumber = evt.event();
126  // Check if there is Timing data in this event
127  // Don't crash code if not present, just don't save anything
128  try { cont_frags->size(); }
129  catch(std::exception const&) {
130  std::cout << "WARNING: Container FELIX data not found in event " << eventNumber << std::endl;
131  return;
132  }
133  //Check that the data is valid
134  if (!cont_frags){
135  MF_LOG_ERROR("FelixIntegrityTest")
136  << "Run: " << evt.run()
137  << ", SubRun: " << evt.subRun()
138  << ", Event: " << evt.event()
139  << " Container Fragment data invalid";
140  }
141 
142  for (auto const& cont : *cont_frags)
143  {
144  artdaq::ContainerFragment cont_frag(cont);
145  for (size_t ii = 0; ii < cont_frag.block_count(); ++ii)
146  {
147  const ErrorMetrics this_err = _process(*cont_frag[ii]);
148  test_results.push_back(this_err);
149  this_err.bad? ++n_bad_frags : ++n_good_frags;
150  }
151  }
152  }
153  else
154  {
155  art::InputTag itag2(_input_label, "FELIX");
156  auto frags = evt.getHandle<artdaq::Fragments>(itag2);
157  // Check if there is Timing data in this event
158  // Don't crash code if not present, just don't save anything
159  art::EventNumber_t eventNumber = evt.event();
160  try { frags->size(); }
161  catch(std::exception const&) {
162  std::cout << "WARNING: Raw FELIX data not found in event " << eventNumber << std::endl;
163  return;
164  }
165 
166  //Check that the data is valid
167  if (!frags){
168  MF_LOG_ERROR("FelixIntegrityTest")
169  << "Run: " << evt.run()
170  << ", SubRun: " << evt.subRun()
171  << ", Event: " << evt.event()
172  << " Fragment data invalid";
173  }
174 
175  for(auto const& frag: *frags)
176  {
177  const ErrorMetrics this_err = _process(frag);
178  test_results.push_back(this_err);
179  this_err.bad? ++n_bad_frags : ++n_good_frags;
180  }
181  }
182 }
183 
185  const unsigned long n_frags = n_bad_frags + n_good_frags;
186  std::cout
187  << "\nProcessed " << n_bad_frags+n_good_frags
188  << " FELIX Fragments.\nFound " << n_good_frags
189  << " good fragments. Success rate: "
190  << (double)n_good_frags/n_frags << "/1.\n\n";
191 
192  // Create structs for easier looping.
193  struct Location {
194  uint64_t crate_no, slot_no, fiber_no;
195  bool operator<(const Location& b) const {
196  if(crate_no == b.crate_no && slot_no == b.slot_no) {
197  return fiber_no < b.fiber_no;
198  } else if(crate_no == b.crate_no) {
199  return slot_no < b.slot_no;
200  }
201  return crate_no < b.crate_no;
202  }
203  };
204  struct Errors {
205  unsigned long meta_err, timestamp_err, convert_count_err, error_fields_set;
206  void operator+=(const Errors& other) {
207  meta_err += other.meta_err;
208  timestamp_err += other.timestamp_err;
209  convert_count_err += other.convert_count_err;
210  error_fields_set += other.error_fields_set;
211  }
212  };
213  // Loop over collected error metrics to find their origin
214  std::map<Location, Errors> errMap;
215  for(const ErrorMetrics& errm : test_results) {
216  Location loc = {errm.crate_no, errm.slot_no, errm.fiber_no};
217  Errors err = {(unsigned long)errm.meta_err, (unsigned long)errm.timestamp_err,
218  (unsigned long)errm.convert_count_err, (unsigned long)errm.error_fields_set};
219  errMap[loc] += err;
220  }
221  // Print the error rate in a nice table
222  std::cout << "Error rates\n";
223  std::cout << "Crate:Slot:Fiber | Metadata error | Timestamp error | Convert count error | Error fields set\n"
224  << "--------------------------------------------------------------------------------------------\n";
225  for(const std::pair<Location, Errors>& p : errMap) {
226  std::cout << std::left << std::setw(16) << std::to_string(p.first.crate_no) + ":" + std::to_string(p.first.slot_no) + ":" + std::to_string(p.first.fiber_no) << " | ";
227  if(p.second.meta_err) std::cout << std::setw(14) << (double)p.second.meta_err/n_frags << " | ";
228  else std::cout << std::setw(14) << " " << " | ";
229  if(p.second.timestamp_err) std::cout << std::setw(15) << (double)p.second.timestamp_err/n_frags << " | ";
230  else std::cout << std::setw(15) << " " << " | ";
231  if(p.second.convert_count_err) std::cout << std::setw(19) << (double)p.second.convert_count_err/n_frags << " | ";
232  else std::cout << std::setw(19) << " " << " | ";
233  if(p.second.error_fields_set) std::cout << std::setw(16) << (double)p.second.error_fields_set/n_frags;
234  else std::cout << std::setw(16) << " ";
235 
236  std::cout << '\n';
237  }
238 }
239 
241 {
242  // Load overlay class
243  dune::FelixFragment flxfrag(frag);
244 
245  std::cout
246  << "-------------------- Testing fragment -------------------" << '\n'
247  << "SequenceID: " << frag.sequenceID()
248  << " fragmentID: " << frag.fragmentID()
249  << " fragmentType: " << (unsigned)frag.type()
250  << " Timestamp: " << frag.timestamp()
251  << " Crate number: " << (int)flxfrag.crate_no()
252  << " Slot number: " << (int)flxfrag.slot_no()
253  << " Fiber number: " << (int)flxfrag.fiber_no() << "\n\n";
254 
255  // Metadata tests
257  bool meta_failed = false;
258  // Record the first metadata, compare otherwise
259  if(run_meta.control_word == 0xcba) {
260  run_meta = *meta;
261  } else {
262  meta_failed |= meta->control_word != run_meta.control_word
263  || meta->version != run_meta.version
264  || meta->reordered != run_meta.reordered
265  || meta->compressed != run_meta.compressed
266  || meta->num_frames != run_meta.num_frames
269  if(meta_failed) {
270  std::cout
271  << "Metadata error." << '\n'
272  << " This fragment's metadata: " << '\n'
273  << " Control word: " << meta->control_word
274  << " Version: " << meta->version
275  << " Reordered: " << meta->reordered
276  << " Compressed: " << meta->compressed
277  << " Number of frames: " << meta->num_frames
278  << " Offset frames: " << meta->offset_frames
279  << " Window frames: " << meta->window_frames << '\n'
280  << " Expected metadata: " << '\n'
281  << " Control word: " << run_meta.control_word
282  << " Version: " << run_meta.version
283  << " Reordered: " << run_meta.reordered
284  << " Compressed: " << run_meta.compressed
285  << " Number of frames: " << run_meta.num_frames
286  << " Offset frames: " << run_meta.offset_frames
287  << " Window frames: " << run_meta.window_frames << "\n\n";
288  } else {
289  std::cout
290  << "Metadata test successful." << "\n\n";
291  }
292  }
293 
294  // Timestamp tests
295  bool timestamp_failed = false;
296  // Compare to metadata: first frame must be within 25 counts of the fragment timestamp
297  if(frag.timestamp() - meta->offset_frames*timestamp_increase - flxfrag.timestamp(0) >= timestamp_increase) {
298  timestamp_failed = true;
299  std::cout
300  << "First timestamp matching error." << '\n'
301  << " This fragment's timestamp: " << frag.timestamp()
302  << " First frame's timestamp: " << flxfrag.timestamp(0)
303  << " Expected offset (-24 or less): " << meta->offset_frames*timestamp_increase
304  << " Offset: " << frag.timestamp() - flxfrag.timestamp(0) << "\n\n";
305  }
306  // Make sure the correct number of frames is contained when compared to the metadata
307  if(flxfrag.total_frames() != meta->window_frames) {
308  timestamp_failed = true;
309  std::cout
310  << "Trigger window error." << '\n'
311  << " This fragment's expected number of frames: " << meta->window_frames
312  << " Number of frames available: " << flxfrag.timestamp(0) << "\n\n";
313  }
314  // Go through all timestamps and check their increase
315  for(unsigned fi = 1; fi < flxfrag.total_frames(); ++fi) {
316  if(flxfrag.timestamp(fi) - flxfrag.timestamp(fi-1) != timestamp_increase) {
317  timestamp_failed = true;
318  std::cout
319  << "Timestamp increase error." << '\n'
320  << " Timestamp of frame " << fi - 1 << ": " << flxfrag.timestamp(fi-1)
321  << " Timestamp of frame " << fi << ": " << flxfrag.timestamp(fi)
322  << " Difference: " << flxfrag.timestamp(fi) - flxfrag.timestamp(fi-1) << "\n\n";
323  break;
324  }
325  }
326  if(!timestamp_failed) {
327  std::cout
328  << "Timestamp test successful." << "\n\n";
329  }
330 
331  // Convert count test
332  bool convert_count_failed = false;
333  // Check the increase of all convert counts between frames
334  for(unsigned fi = 1; fi < flxfrag.total_frames(); ++fi) {
335  // The first two counts and last two counts need to be identical
336  for(int bi = 0; bi < 2; ++bi) {
337  if(flxfrag.coldata_convert_count(fi, 2*bi) != flxfrag.coldata_convert_count(fi, 2*bi + 1)
338  || (flxfrag.coldata_convert_count(fi, bi) - flxfrag.coldata_convert_count(fi - 1, bi)
340  && flxfrag.coldata_convert_count(fi, bi) - flxfrag.coldata_convert_count(fi - 1, bi)
341  != convert_count_increase - (1<<16))) {
342  convert_count_failed = true;
343  std::cout
344  << "COLDATA convert count increase error in frame " << fi << ".\n"
345  << " Count 1 of frame " << fi - 1 << ": " << flxfrag.coldata_convert_count(fi-1, 0)
346  << " Count 2 of frame " << fi - 1 << ": " << flxfrag.coldata_convert_count(fi-1, 1)
347  << " Count 3 of frame " << fi - 1 << ": " << flxfrag.coldata_convert_count(fi-1, 2)
348  << " Count 4 of frame " << fi - 1 << ": " << flxfrag.coldata_convert_count(fi-1, 3) << '\n'
349  << " Count 1 of frame " << fi << ": " << flxfrag.coldata_convert_count(fi, 0)
350  << " Count 2 of frame " << fi << ": " << flxfrag.coldata_convert_count(fi, 1)
351  << " Count 3 of frame " << fi << ": " << flxfrag.coldata_convert_count(fi, 2)
352  << " Count 4 of frame " << fi << ": " << flxfrag.coldata_convert_count(fi, 3) << '\n'
353  << " Difference: "
354  << flxfrag.coldata_convert_count(fi, 0) - flxfrag.coldata_convert_count(fi-1, 0) << "\n\n";
355  break;
356  }
357  }
358  if(convert_count_failed) break;
359  }
360  if(!convert_count_failed) {
361  std::cout
362  << "COLDATA convert count test successful." << "\n\n";
363  }
364 
365  // Frame error fields test
366  bool error_field_failed = false;
367  // Check all error fields in all frames without distinction for now
368  // // TODO: Look into what errors are relevant!
369  // for(unsigned fi = 0; fi < 0/*flxfrag.total_frames()*/; ++fi) {
370  // error_field_failed |= flxfrag.mm(fi) || flxfrag.oos(fi) || flxfrag.wib_errors(fi);
371  // for(unsigned bi = 0; bi < 4; ++bi) {
372  // error_field_failed |= flxfrag.s1_error(fi, bi) || flxfrag.s2_error(fi, bi)
373  // || flxfrag.error_register(fi, bi);
374  // }
375  //
376  // if(error_field_failed) {
377  // std::cout
378  // << "One or more error fields set in frame " << fi << ".\n"
379  // << " Mismatch: " << (int)flxfrag.mm(fi)
380  // << " Out of sync: " << (int)flxfrag.oos(fi)
381  // << " WIB errors: " << (int)flxfrag.wib_errors(fi) << '\n';
382  // for(unsigned bi = 0; bi < 4; ++bi) {
383  // std::cout
384  // << " Block " << bi+1 << ":\n"
385  // << " Stream 1 error: " << (int)flxfrag.s1_error(fi, bi)
386  // << " Stream 2 error: " << (int)flxfrag.s2_error(fi, bi)
387  // << " Error register: " << (int)flxfrag.error_register(fi, bi) << '\n';
388  // }
389  // std::cout << '\n';
390  // break;
391  // }
392  // }
393 
394  //Output error metrics
395  ErrorMetrics outem;
396  outem.sequenceID = frag.sequenceID();
397  outem.fragmentID = frag.fragmentID();
398  outem.type = frag.type();
399  outem.timestamp = frag.timestamp();
400  outem.crate_no = flxfrag.crate_no();
401  outem.slot_no = flxfrag.slot_no();
402  outem.fiber_no = flxfrag.fiber_no();
403  outem.meta = *meta;
404  outem.meta_err = meta_failed;
405  outem.timestamp_err = timestamp_failed;
406  outem.convert_count_err = convert_count_failed;
407  outem.error_fields_set = error_field_failed;
408 
409  outem.bad = timestamp_failed || convert_count_failed || error_field_failed;
410 
411  return outem;
412 }
413 
size_t total_frames() const
EventNumber_t event() const
Definition: DataViewImpl.cc:85
uint8_t slot_no(const unsigned &frame_ID=0) const
DoubleProduct & operator+=(DoubleProduct &left, DoubleProduct const &right)
Definition: ToyProducts.h:103
Handle< PROD > getHandle(SelectorBase const &) const
Definition: DataViewImpl.h:382
std::string string
Definition: nybbler.cc:12
std::vector< ErrorMetrics > test_results
uint8_t crate_no(const unsigned &frame_ID=0) const
FelixIntegrityTest & operator=(FelixIntegrityTest const &)=delete
#define MF_LOG_ERROR(category)
STL namespace.
EDAnalyzer(fhicl::ParameterSet const &pset)
Definition: EDAnalyzer.h:25
bool operator<(ProductInfo const &a, ProductInfo const &b)
Definition: ProductInfo.cc:51
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
dune::FelixFragmentBase::Metadata run_meta
p
Definition: test.py:223
dune::FelixFragmentBase::Metadata meta
SubRunNumber_t subRun() const
Definition: DataViewImpl.cc:78
RunNumber_t run() const
Definition: DataViewImpl.cc:71
uint16_t coldata_convert_count(const unsigned &frame_ID, const uint8_t &block_num) const
void err(const char *fmt,...)
Definition: message.cpp:226
Q_EXPORT QTSManip setw(int w)
Definition: qtextstream.h:331
uint8_t fiber_no(const unsigned &frame_ID=0) const
FelixIntegrityTest(fhicl::ParameterSet const &p)
void analyze(const art::Event &evt) override
IDNumber_t< Level::Event > EventNumber_t
Definition: IDNumber.h:118
static bool * b
Definition: config.cpp:1043
TCEvent evt
Definition: DataStructs.cxx:7
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
int bool
Definition: qglobal.h:345
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
std::vector< Fragment > Fragments
Definition: HDF5Utils.h:57
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)
ErrorMetrics _process(const artdaq::Fragment &frag)
uint64_t timestamp(const unsigned &frame_ID=0) const