IcebergFELIXBufferDecoderMarch2021_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: IcebergFELIXBufferDecoderMarch2021
3 // Plugin Type: producer (art v2_10_03)
4 // File: IcebergFELIXBufferDecoderMarch2021_module.cc
5 //
6 // Generated at Fri Mar 2 15:36:20 2018 by Thomas Junk using cetskelgen
7 // from cetlib version v3_02_00.
8 ////////////////////////////////////////////////////////////////////////
9 
18 #include "fhiclcpp/ParameterSet.h"
21 #include "art_root_io/TFileService.h"
22 
23 #include <memory>
24 #include <cmath>
25 
26 // ROOT includes
27 #include "TMath.h"
28 
29 // artdaq and dune-raw-data includes
31 
32 // larsoft includes
35 #include "lardataobj/RawData/raw.h"
36 
37 // DUNE includes
39 
40 #include <stdio.h>
41 
43 
44 public:
50  void produce(art::Event & e) override;
51 
52 private:
53  typedef std::vector<raw::RawDigit> RawDigits;
54  typedef std::vector<raw::RDTimeStamp> RDTimeStamps;
58  typedef std::vector<raw::RDStatus> RDStatuses;
59 
60  // open files
61 
62  std::vector<FILE*> fInputFilePointers;
63 
64  // configuration parameters
65 
66  std::vector<std::string> fInputFiles;
67  size_t fNSamples;
71  bool fFirstRead;
72 
73  void computeMedianSigma(raw::RawDigit::ADCvector_t &v_adc, float &median, float &sigma);
74  // Converts 14 bit packed channel data (56 uint32 words from the WIB) to byte-aligned 16 bit arrays (128 uint16 values)
75  void unpack14(const uint32_t *packed, uint16_t *unpacked);
76 };
77 
78 
80  : EDProducer(p)
81 {
82  fInputFiles = p.get<std::vector<std::string>>("InputFiles");
83  fNSamples = p.get<size_t>("NSamples",2000);
84  fOutputLabel = p.get<std::string>("OutputDataLabel","daq");
85  fCompressHuffman = p.get<bool>("CompressHuffman",false);
86  fDesiredStartTimestamp = p.get<ULong64_t>("StartTimestamp",0);
87 
88  produces<RawDigits>( fOutputLabel ); //the strings in <> are the typedefs defined above
89  produces<RDTimeStamps>( fOutputLabel );
90  produces<RDTsAssocs>( fOutputLabel );
91  produces<RDStatuses>( fOutputLabel );
92 
93  fInputFilePointers.clear();
94  for (size_t ifile=0; ifile<fInputFiles.size(); ++ifile)
95  {
96  fInputFilePointers.push_back(fopen(fInputFiles.at(ifile).data(),"r"));
97  }
98  fFirstRead = true;
99 }
100 
102 {
103 
105  RawDigits raw_digits;
106  RDTimeStamps rd_timestamps;
107  RDTsAssocs rd_ts_assocs;
108 
109  RDPmkr rdpm(e,fOutputLabel);
110  TSPmkr tspm(e,fOutputLabel);
111 
112  bool discard_data = false;
113 
114  uint32_t framebuf[117];
115  uint16_t databuf[128];
116  uint64_t timestampstart=0;
117  uint64_t timestamp=0;
118 
119  size_t nfiles = fInputFiles.size();
120 
121  // search for the first timestamp on the first read
122  // don't do on subsequent reads so we don't always read in a frame just to see what
123  // the timestamp is.
124 
125  if (fFirstRead)
126  {
127  for (size_t ifile=0; ifile < nfiles; ++ ifile)
128  {
129  do
130  {
131  fread(framebuf, sizeof(uint32_t), 117, fInputFilePointers.at(ifile));
132  if (feof(fInputFilePointers.at(ifile)))
133  {
134  // don't handle this too gracefully at the moment
135  throw cet::exception("IcebergFELXIBufferDecoderMarch2021") <<
136  "Attempt to read off the end of file " << fInputFiles.at(ifile);
137  }
138  timestamp= framebuf[3];
139  timestamp <<= 32;
140  timestamp += framebuf[2];
141  }
142  while (timestamp+47 < fDesiredStartTimestamp);
143  // criterion so the next timestamp (+32) will be the one we want
144  }
145  fFirstRead = false;
146  }
147 
148  // align the readin
149 
150  std::vector<std::vector<uint32_t>> fbcache(nfiles);
151  std::vector<uint64_t> tscache;
152  uint64_t latest_timestamp=0;
153 
154  // read one frame in from each file to see what the latest timestamp is
155 
156  for (size_t ifile=0; ifile<nfiles; ++ifile)
157  {
158  fbcache.at(ifile).resize(117);
159  fread(fbcache.at(ifile).data(), sizeof(uint32_t), 117, fInputFilePointers.at(ifile));
160  if (feof(fInputFilePointers.at(ifile)))
161  {
162  // don't handle this too gracefully at the moment
163  throw cet::exception("IcebergFELXIBufferDecoderMarch2021") <<
164  "Attempt to read off the end of file " << fInputFiles.at(ifile);
165  }
166  timestamp= fbcache.at(ifile)[3];
167  timestamp <<= 32;
168  timestamp += fbcache.at(ifile)[2];
169  tscache.push_back(timestamp);
170  if (timestamp > latest_timestamp)
171  {
172  latest_timestamp = timestamp;
173  }
174  }
175 
176  // read enough frames from the other files so that we align the frames to +- 16 ticks
177 
178  for (size_t ifile=0; ifile<nfiles; ++ifile)
179  {
180  while (tscache.at(ifile) + 16 < latest_timestamp)
181  {
182  fread(fbcache.at(ifile).data(), sizeof(uint32_t), 117, fInputFilePointers.at(ifile));
183  if (feof(fInputFilePointers.at(ifile)))
184  {
185  // don't handle this too gracefully at the moment
186  throw cet::exception("IcebergFELXIBufferDecoderMarch2021") <<
187  "Attempt to read off the end of file " << fInputFiles.at(ifile);
188  }
189  timestamp= fbcache.at(ifile)[3];
190  timestamp <<= 32;
191  timestamp += fbcache.at(ifile)[2];
192  tscache.at(ifile) = timestamp;
193  }
194  }
195 
196  for (size_t ifile=0; ifile < nfiles; ++ ifile)
197  {
198  int slot = 0;
199  int fiber = 0;
200 
201  std::vector<raw::RawDigit::ADCvector_t> adcvv(256);
202  for (size_t itick=0; itick<fNSamples; ++itick)
203  {
204  if (itick == 0) // already read in the first frame
205  {
206  for (size_t i=0; i<117; ++i)
207  {
208  framebuf[i] = fbcache.at(ifile).at(i);
209  }
210  }
211  else
212  {
213  fread(framebuf, sizeof(uint32_t), 117, fInputFilePointers.at(ifile));
214  if (feof(fInputFilePointers.at(ifile)))
215  {
216  // don't handle this too gracefully at the moment
217  throw cet::exception("IcebergFELXIBufferDecoderMarch2021") <<
218  "Attempt to read off the end of file " << fInputFiles.at(ifile);
219  }
220  }
221  int curslot = (framebuf[0] & 0x7000) >> 12; // assume these are all the same
222  int curfiber = (framebuf[0] & 0x8000) >> 15;
223  if (itick>0)
224  {
225  if (curslot != slot)
226  {
227  throw cet::exception("IcebergFELXIBufferDecoderMarch2021") <<
228  "Slot mismatch in file: " << curslot << " " << slot;
229  }
230  if (curfiber != fiber)
231  {
232  throw cet::exception("IcebergFELXIBufferDecoderMarch2021") <<
233  "Fiber mismatch in file: " << curfiber << " " << fiber;
234  }
235  }
236  else
237  {
238  slot = curslot;
239  fiber = curfiber;
240  }
241 
242  uint64_t timestamp= framebuf[3];
243  timestamp <<= 32;
244  timestamp += framebuf[2];
245  //std::cout << std::dec << " Slot: " << slot << " Fiber: " << fiber
246  // << " Timestamp: " << std::dec << timestamp <<std::endl;
247  if (itick == 0)
248  {
249  timestampstart = timestamp;
250  }
251 
252  // do the data-rearrangement transpose
253 
254  unpack14(&(framebuf[4]),databuf);
255  for (size_t ichan=0; ichan<128; ++ichan)
256  {
257  adcvv.at(ichan).push_back(databuf[ichan]);
258  }
259  unpack14(&(framebuf[4+56]),databuf);
260  for (size_t ichan=0; ichan<128; ++ichan)
261  {
262  adcvv.at(ichan+128).push_back(databuf[ichan]);
263  }
264  }
265 
266  for (size_t ichan=0; ichan<256; ++ichan)
267  {
268  float median=0;
269  float sigma=0;
270  computeMedianSigma(adcvv.at(ichan),median,sigma);
271 
272  // handle 256 channels on two fibers -- use the channel map that assumes 128 chans per fiber (=FEMB)
273 
274  unsigned int fiberloc = 0;
275  if (fiber == 0)
276  {
277  fiberloc = 1;
278  }
279  else if (fiber == 1)
280  {
281  fiberloc = 3;
282  }
283 
284  unsigned int chloc = ichan;
285  if (chloc > 127)
286  {
287  chloc -= 128;
288  fiberloc++;
289  }
290  //unsigned int crateloc = crate;
291 
292 
293  // inverted ordering on back side, Run 2c (=Run 3)
294  // note Shekhar's FEMB number is fiber-1, and WIB is slot+1
295 
296  auto slotloc2 = slot;
297  auto fiberloc2 = fiberloc;
298 
299  if (slot == 0 && fiberloc == 4)
300  {
301  slotloc2 = 1;
302  fiberloc2 = 3;
303  }
304  if (slot == 1 && fiberloc == 4)
305  {
306  slotloc2 = 0;
307  fiberloc2 = 3;
308  }
309  if (slot == 1 && fiberloc == 3)
310  {
311  slotloc2 = 0;
312  fiberloc2 = 4;
313  }
314  if (slot == 0 && fiberloc == 3)
315  {
316  slotloc2 = 1;
317  fiberloc2 = 4;
318  }
319 
320  // skip the fake TPC data
321 
322  if ( slotloc2 == 1 && fiberloc2 == 1 )
323  {
324  continue;
325  }
326 
327  if ( slotloc2 == 2 && fiberloc2 == 1 )
328  {
329  continue;
330  }
331 
332  // for iceberg, hardcode the crate number to suppress warnings
333  unsigned int offlineChannel = channelMap->GetOfflineNumberFromDetectorElements(1, slotloc2, fiberloc2, chloc, dune::IcebergChannelMapService::kFELIX);
334 
335  size_t uncompressed_nticks = fNSamples;
337  if (fCompressHuffman)
338  {
339  cflag = raw::kHuffman;
340  raw::Compress(adcvv.at(ichan),cflag);
341  }
342 
343  raw::RawDigit raw_digit(offlineChannel, uncompressed_nticks, adcvv.at(ichan), cflag);
344  raw_digit.SetPedestal(median,sigma);
345  raw_digits.push_back(raw_digit);
346 
347  raw::RDTimeStamp rdtimestamp(timestampstart,offlineChannel);
348  rd_timestamps.push_back(rdtimestamp);
349 
350  //associate the raw digit and the timestamp data products
351  auto const rawdigitptr = rdpm(raw_digits.size()-1);
352  auto const rdtimestampptr = tspm(rd_timestamps.size()-1);
353  rd_ts_assocs.addSingle(rawdigitptr,rdtimestampptr);
354 
355  }
356  }
357 
358  if (discard_data)
359  {
360  RawDigits empty_raw_digits;
361  RDTimeStamps empty_rd_timestamps;
362  RDTsAssocs empty_rd_ts_assocs;
363  RDStatuses statuses;
364  statuses.emplace_back(true,false,1);
365  e.put(std::make_unique<decltype(empty_raw_digits)>(std::move(empty_raw_digits)),fOutputLabel);
366  e.put(std::make_unique<decltype(empty_rd_timestamps)>(std::move(empty_rd_timestamps)),fOutputLabel);
367  e.put(std::make_unique<decltype(empty_rd_ts_assocs)>(std::move(empty_rd_ts_assocs)),fOutputLabel);
368  e.put(std::make_unique<decltype(statuses)>(std::move(statuses)),fOutputLabel);
369  }
370  else
371  {
372  RDStatuses statuses;
373  unsigned int statword=0;
374  statuses.emplace_back(false,false,statword);
375  e.put(std::make_unique<decltype(raw_digits)>(std::move(raw_digits)),fOutputLabel);
376  e.put(std::make_unique<decltype(rd_timestamps)>(std::move(rd_timestamps)),fOutputLabel);
377  e.put(std::make_unique<decltype(rd_ts_assocs)>(std::move(rd_ts_assocs)),fOutputLabel);
378  e.put(std::make_unique<decltype(statuses)>(std::move(statuses)),fOutputLabel);
379  }
380 }
381 
382 
383 // compute median and sigma. Sigma is half the distance between the upper and lower bounds of the
384 // 68% region where 34% is above the median and 34% is below ("centered" on the median).
385 
387 {
388  size_t asiz = v_adc.size();
389  if (asiz == 0)
390  {
391  median = 0;
392  sigma = 0;
393  }
394  else
395  {
396  // this is actually faster than the code below by about one second per event.
397  // the RMS includes tails from bad samples and signals and may not be the best RMS calc.
398 
399  median = TMath::Median(asiz,v_adc.data());
400  sigma = TMath::RMS(asiz,v_adc.data());
401  }
402 
403  // std::cout << "sigma: " << sigma << std::endl;
404 }
405 
406 void IcebergFELIXBufferDecoderMarch2021::unpack14(const uint32_t *packed, uint16_t *unpacked) {
407  for (size_t i = 0; i < 128; i++) { // i == n'th U,V,X value
408  const size_t low_bit = i*14;
409  const size_t low_word = low_bit / 32;
410  const size_t high_bit = (i+1)*14-1;
411  const size_t high_word = high_bit / 32;
412  //std::cout << "low_word, high_word: " << low_word << " " << high_word << std::endl;
413  //glog.log("word %li :: low %li (%li[%li]) high %li (%li[%li])\n",i,low_bit,low_word,low_bit%32,high_bit,high_word,high_bit%32);
414  if (low_word == high_word) { //all the bits are in the same word
415  unpacked[i] = (packed[low_word] >> (low_bit%32)) & 0x3FFF;
416  } else { //some of the bits are in the next word
417  size_t high_off = high_word*32-low_bit;
418  //glog.log("pre_mask 0x%X post_mask 0x%X\n", (0x3FFF >> (14-high_off)), ((0x3FFF << high_off) & 0x3FFF) );
419  unpacked[i] = (packed[low_word] >> (low_bit%32)) & (0x3FFF >> (14-high_off));
420  unpacked[i] |= (packed[high_word] << high_off) & ((0x3FFF << high_off) & 0x3FFF);
421  }
422  }
423 }
Huffman Encoding.
Definition: RawTypes.h:10
enum raw::_compress Compress_t
Collection of charge vs time digitized from a single readout channel.
Definition: RawDigit.h:69
std::string string
Definition: nybbler.cc:12
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.h:20
void unpack14(const uint32_t *packed, uint16_t *unpacked)
std::vector< short > ADCvector_t
Type representing a (compressed) vector of ADC counts.
Definition: RawDigit.h:73
no compression
Definition: RawTypes.h:9
unsigned int GetOfflineNumberFromDetectorElements(unsigned int crate, unsigned int slot, unsigned int fiber, unsigned int fembchannel, FelixOrRCE frswitch)
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
def move(depos, offset)
Definition: depos.py:107
T get(std::string const &key) const
Definition: ParameterSet.h:271
art::Assns< raw::RawDigit, raw::RDTimeStamp > RDTsAssocs
p
Definition: test.py:223
ProductID put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: DataViewImpl.h:686
void computeMedianSigma(raw::RawDigit::ADCvector_t &v_adc, float &median, float &sigma)
void SetPedestal(float ped, float sigma=1.)
Set pedestal and its RMS (the latter is 0 by default)
Definition: RawDigit.cxx:68
void addSingle(Ptr< left_t > const &left, Ptr< right_t > const &right, data_t const &data)
Definition: Assns.h:546
void Compress(std::vector< short > &adc, raw::Compress_t compress)
Compresses a raw data buffer.
Definition: raw.cxx:19
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
double median(sqlite3 *db, std::string const &table_name, std::string const &column_name)
Definition: statistics.cc:26
IcebergFELIXBufferDecoderMarch2021 & operator=(IcebergFELIXBufferDecoderMarch2021 const &)=delete