raw.cxx
Go to the documentation of this file.
1 /// \file raw.cxx
2 /// \brief raw data utilities
3 /// \author trj@fnal.gov
4 /// with thanks to Brian Rebel and Jonathan Insler
5 
6 #include "RawDataProducts/raw.h"
8 
9 #include <iostream>
10 #include <string>
11 #include <bitset>
12 #include <numeric> // std::adjacent_difference()
13 #include <iterator> // std::back_inserter()
14 
15 #include "cetlib_except/exception.h"
17 
18 namespace gar {
19  namespace raw {
20 
21  //----------------------------------------------------------
22  // no arguments -- can only run Huffman for now (or other future parameterless compression methods)
24  gar::raw::Compress_t compress)
25  {
26  if(compress == gar::raw::kHuffman) CompressHuffman(adc);
27  else if(compress == raw::kZeroHuffman){
28  throw cet::exception("gar::raw")
29  << "Compress method called for kZeroHuffman but no threshold or pedestal value";
30  }
31  else {
32  throw cet::exception("gar::raw")
33  << "Compress method called with compression type: " << compress << " but no threshold or pedestal value";
34  }
35  return;
36  }
37 
38  //----------------------------------------------------------
40  gar::raw::Compress_t compress,
41  gar::raw::ADC_t zerothreshold,
42  size_t ticksbefore,
43  size_t ticksafter)
44  {
45  int retval = 1;
46  if(compress == raw::kHuffman)
47  {
48  CompressHuffman(adc);
49  }
50  else if(compress == raw::kZeroSuppression)
51  {
52  retval = ZeroSuppression(adc,zerothreshold,ticksbefore,ticksafter);
53  }
54  else if(compress == raw::kZeroHuffman)
55  {
56  retval = ZeroSuppression(adc,zerothreshold,ticksbefore,ticksafter);
57  CompressHuffman(adc);
58  }
59 
60  return retval;
61  }
62 
63 
64  //----------------------------------------------------------
65  // Zero suppression function
67  gar::raw::ADC_t zerothreshold,
68  size_t ticksbefore_in,
69  size_t ticksafter_in)
70  {
71  const size_t adcsize = adc.size();
72  if (adcsize == 0) return 0;
73 
74  size_t ticksbefore = ticksbefore_in;
75  if (adcsize < ticksbefore_in) ticksbefore = adcsize;
76  size_t ticksafter = ticksafter_in;
77  if (adcsize < ticksafter_in) ticksafter = adcsize;
78 
79  gar::raw::ADCvector_t zerosuppressed(adcsize);
80  std::vector<int> inablock(adcsize,0); // flags to include this tick in a block or not
81  std::vector<int> blockbegin;
82  std::vector<int> blocksize;
83 
84  // set the flags if a tick is to be included in a block. Flags may get set multiple times
85 
86  for (size_t i=0; i<adcsize; ++i)
87  {
88  if (adc[i] >= zerothreshold)
89  {
90  size_t jmin = 0;
91  if (i >= ticksbefore) jmin = i-ticksbefore;
92  size_t jmax = adcsize - 1;
93  if (i+ticksafter < jmax) jmax = i+ticksafter;
94  for (size_t j=jmin; j<=jmax; ++j)
95  {
96  inablock[j] = 1;
97  }
98  }
99  }
100 
101  // count the blocks and label their sizes
102 
103  bool curblock = false;
104  for (size_t i=0; i<adcsize; ++i)
105  {
106  if (!curblock && inablock[i] != 0)
107  {
108  curblock = true;
109  blockbegin.push_back(i);
110  }
111  if (curblock && (inablock[i] == 0 || i+1 == adcsize))
112  {
113  curblock = false;
114  blocksize.push_back(i - blockbegin.back() + 1);
115  }
116  }
117 
118  size_t nblocks = blockbegin.size();
119 
120  adc[0] = adcsize; //fill first entry in adc with length of uncompressed vector
121  adc[1] = nblocks;
122 
123  for(size_t i = 0; i < nblocks; ++i)
124  adc[i+2] = blockbegin[i];
125 
126  for(size_t i = 0; i < nblocks; ++i)
127  adc[i+nblocks+2] = blocksize[i];
128 
129  size_t zsi = 0;
130  for(size_t i = 0; i < nblocks; ++i)
131  {
132  for (int j=0; j < blocksize[i]; ++j)
133  {
134  zerosuppressed[zsi] = adc[blockbegin[i]+j];
135  ++zsi;
136  }
137  }
138 
139  adc.resize(2+nblocks+nblocks+zsi);
140  for (size_t i=0; i<zsi; ++i)
141  {
142  adc[i+nblocks+nblocks+2] = zerosuppressed[i];
143  }
144 
145  return nblocks; // for use in discarding rawdigit in case it's all zero
146  }
147 
148 
149  //----------------------------------------------------------
150  // Reverse zero suppression function, filling in suppressed ADC values with pedestal
151 
153  gar::raw::ADCvector_t &uncompressed,
154  gar::raw::ADC_t pedestal)
155  {
156  const int lengthofadc = adc[0];
157  const int nblocks = adc[1];
158 
159  uncompressed.resize(lengthofadc);
160  for (int i = 0;i < lengthofadc; ++i){
161  uncompressed[i] = pedestal;
162  }
163 
164  int zerosuppressedindex = nblocks*2 + 2;
165 
166  for(int i = 0; i < nblocks; ++i){ //loop over each nonzero block of the compressed vector
167 
168  for(int j = 0; j < adc[2+nblocks+i]; ++j){//loop over each block size
169 
170  //set uncompressed value
171  uncompressed[adc[2+i]+j] = adc[zerosuppressedindex];
172  zerosuppressedindex++;
173 
174  }
175  }
176 
177  return;
178  }
179 
180 
181  //----------------------------------------------------------
182  // if the compression type is kNone, copy the adc vector into the uncompressed vector
184  gar::raw::ADCvector_t &uncompressed,
185  gar::raw::Compress_t compress)
186  {
187  if(compress == raw::kHuffman) UncompressHuffman(adc, uncompressed);
188  else if(compress == raw::kNone){
189  for(unsigned int i = 0; i < adc.size(); ++i) uncompressed[i] = adc[i];
190  }
191  else {
192  throw cet::exception("raw")
193  << "raw::Uncompress() does not support compression #"
194  << ((int) compress) << " without a pedestal specified";
195  }
196  return;
197 
198  }
199 
200  //----------------------------------------------------------
201  // if the compression type is kNone, copy the adc vector into the uncompressed vector
203  gar::raw::ADCvector_t &uncompressed,
204  ADC_t pedestal,
205  gar::raw::Compress_t compress)
206  {
207  if(compress == raw::kHuffman) UncompressHuffman(adc, uncompressed);
208  else if(compress == raw::kZeroSuppression){
209  ZeroUnsuppression(adc, uncompressed, pedestal);
210  }
211  else if(compress == raw::kZeroHuffman){
212  gar::raw::ADCvector_t tmp(2*adc[0]);
213  UncompressHuffman(adc, tmp);
214  ZeroUnsuppression(tmp, uncompressed, pedestal);
215  }
216  else if(compress == raw::kNone){
217  for(unsigned int i = 0; i < adc.size(); ++i) uncompressed[i] = adc[i];
218  }
219  else {
220  throw cet::exception("raw")
221  << "raw::Uncompress() does not support compression #"
222  << ((int) compress);
223  }
224  return;
225  }
226 
227 
228  // the current Huffman Coding scheme used by uBooNE is
229  // based on differences between adc values in adjacent time bins
230  // the code is
231  // no change for 4 ticks --> 1
232  // no change for 1 tick --> 01
233  // +1 change --> 001
234  // -1 change --> 0001
235  // +2 change --> 00001
236  // -2 change --> 000001
237  // +3 change --> 0000001
238  // -3 change --> 00000001
239  // abs(change) > 3 --> write actual value to short
240  // use 15th bit to set whether a block is encoded or raw value
241  // 1 --> Huffman coded, 0 --> raw
242  // pad out the lowest bits in a word with 0's
244  {
245  gar::raw::ADCvector_t const orig_adc(std::move(adc));
246 
247  // diffs contains the difference between an element of adc and the previous
248  // one; the first entry is never used.
249  std::vector<short> diffs;
250  diffs.reserve(orig_adc.size());
251  std::adjacent_difference
252  (orig_adc.begin(), orig_adc.end(), std::back_inserter(diffs));
253 
254  // prepare adc for the new data; we kind-of-expect the size,
255  // so we pre-allocate it; we might want to shrink-to-fit at the end
256  adc.clear();
257  adc.reserve(orig_adc.size());
258  // now loop over the diffs and do the Huffman encoding
259  adc.push_back(orig_adc.front());
260  unsigned int curb = 15U;
261 
262  std::bitset<16> bset;
263  bset.set(15);
264 
265  for(size_t i = 1U; i < diffs.size(); ++i){
266 
267  switch (diffs[i]) {
268  // if the difference is 0, check to see what the next 3 differences are
269  case 0 : {
270  if(i < diffs.size() - 3){
271  // if next 3 are also 0, set the next bit to be 1
272  if(diffs[i+1] == 0 && diffs[i+2] == 0 && diffs[i+3] == 0){
273  if(curb > 0){
274  --curb;
275  bset.set(curb);
276  i += 3;
277  continue;
278  }
279  else{
280  adc.push_back(bset.to_ulong());
281 
282  // reset the bitset to be ready for the next word
283  bset.reset();
284  bset.set(15);
285  bset.set(14); // account for the fact that this is a zero diff
286  curb = 14;
287  i += 3;
288  continue;
289  } // end if curb is not big enough to put current difference in bset
290  } // end if next 3 are also zero
291  else{
292  // 0 diff is encoded as 01, so move the current bit one to the right
293  if(curb > 1){
294  curb -= 2;
295  bset.set(curb);
296  continue;
297  } // end if the current bit is large enough to set this one
298  else{
299  adc.push_back(bset.to_ulong());
300  // reset the bitset to be ready for the next word
301  bset.reset();
302  bset.set(15);
303  bset.set(13); // account for the fact that this is a zero diff
304  curb = 13;
305  continue;
306  } // end if curb is not big enough to put current difference in bset
307  } // end if next 3 are not also 0
308  }// end if able to check next 3
309  else{
310  // 0 diff is encoded as 01, so move the current bit one to the right
311  if(curb > 1){
312  curb -= 2;
313  bset.set(curb);
314  continue;
315  } // end if the current bit is large enough to set this one
316  else{
317  adc.push_back(bset.to_ulong());
318  // reset the bitset to be ready for the next word
319  bset.reset();
320  bset.set(15);
321  bset.set(13); // account for the fact that this is a zero diff
322  curb = 13;
323  continue;
324  } // end if curb is not big enough to put current difference in bset
325  }// end if not able to check the next 3
326  break;
327  }// end if current difference is zero
328  case 1: {
329  if(curb > 2){
330  curb -= 3;
331  bset.set(curb);
332  }
333  else{
334  adc.push_back(bset.to_ulong());
335  // reset the bitset to be ready for the next word
336  bset.reset();
337  bset.set(15);
338  bset.set(12); // account for the fact that this is a +1 diff
339  curb = 12;
340  } // end if curb is not big enough to put current difference in bset
341  break;
342  } // end if difference = 1
343  case -1: {
344  if(curb > 3){
345  curb -= 4;
346  bset.set(curb);
347  }
348  else{
349  adc.push_back(bset.to_ulong());
350  // reset the bitset to be ready for the next word
351  bset.reset();
352  bset.set(15);
353  bset.set(11); // account for the fact that this is a -1 diff
354  curb = 11;
355  } // end if curb is not big enough to put current difference in bset
356  break;
357  }// end if difference = -1
358  case 2: {
359  if(curb > 4){
360  curb -= 5;
361  bset.set(curb);
362  }
363  else{
364  adc.push_back(bset.to_ulong());
365  // reset the bitset to be ready for the next word
366  bset.reset();
367  bset.set(15);
368  bset.set(10); // account for the fact that this is a +2 diff
369  curb = 10;
370  } // end if curb is not big enough to put current difference in bset
371  break;
372  }// end if difference = 2
373  case -2: {
374  if(curb > 5){
375  curb -= 6;
376  bset.set(curb);
377  }
378  else{
379  adc.push_back(bset.to_ulong());
380  // reset the bitset to be ready for the next word
381  bset.reset();
382  bset.set(15);
383  bset.set(9); // account for the fact that this is a -2 diff
384  curb = 9;
385  } // end if curb is not big enough to put current difference in bset
386  break;
387  }// end if difference = -2
388  case 3: {
389  if(curb > 6){
390  curb -= 7;
391  bset.set(curb);
392  }
393  else{
394  adc.push_back(bset.to_ulong());
395  // reset the bitset to be ready for the next word
396  bset.reset();
397  bset.set(15);
398  bset.set(8); // account for the fact that this is a +3 diff
399  curb = 8;
400  } // end if curb is not big enough to put current difference in bset
401  break;
402  }// end if difference = 3
403  case -3: {
404  if(curb > 7){
405  curb -= 8;
406  bset.set(curb);
407  }
408  else{
409  adc.push_back(bset.to_ulong());
410  // reset the bitset to be ready for the next word
411  bset.reset();
412  bset.set(15);
413  bset.set(7); // account for the fact that this is a -3 diff
414  curb = 7;
415  } // end if curb is not big enough to put current difference in bset
416  break;
417  }// end if difference = -3
418  default: {
419  // if the difference is too large that we have to put the entire adc value in:
420  // put the current value into the adc vec unless the current bit is 15, then there
421  // were multiple large difference values in a row
422  if(curb != 15){
423  adc.push_back(bset.to_ulong());
424  }
425 
426  bset.reset();
427  bset.set(15);
428  curb = 15;
429 
430  // put the current adcvalue in adc, with its bit 15 set to 0
431  if(orig_adc[i] > 0) adc.push_back(orig_adc[i]);
432  else{
433  std::bitset<16> tbit(-orig_adc[i]);
434  tbit.set(14);
435  adc.push_back(tbit.to_ulong());
436  }
437  break;
438  } // if |difference| > 3
439  }// switch diff[i]
440  }// end loop over differences
441 
442  //write out the last bitset
443  adc.push_back(bset.to_ulong());
444 
445  // this would reduce global memory usage,
446  // at the cost of a new allocation and copy
447  // adc.shrink_to_fit();
448 
449  } // CompressHuffman()
450  //--------------------------------------------------------
451  // need to decrement the bit you are looking at to determine the deltas as that is how
452  // the bits are set
454  gar::raw::ADCvector_t &uncompressed)
455  {
456 
457  //the first entry in adc is a data value by construction
458  uncompressed[0] = adc[0];
459 
460  unsigned int curu = 1;
461  short curADC = uncompressed[0];
462 
463  // loop over the entries in adc and uncompress them according to the
464  // encoding scheme above the CompressHuffman method
465  for(unsigned int i = 1; i < adc.size() && curu < uncompressed.size(); ++i){
466 
467  std::bitset<16> bset(adc[i]);
468 
469  int numu = 0;
470 
471  //check the 15 bit to see if this entry is a full data value or not
472  if( !bset.test(15) ){
473  curADC = adc[i];
474  if(bset.test(14)){
475  bset.set(14, false);
476  curADC = -1*bset.to_ulong();
477  }
478  uncompressed[curu] = curADC;
479 
480  ++curu;
481  }
482  else{
483 
484  int b = 14;
485  int lowestb = 0;
486 
487  // ignore any padding with zeros in the lower order bits
488  while( !bset.test(lowestb) && lowestb < 15) ++lowestb;
489 
490  if(lowestb > 14){
491  mf::LogWarning("raw.cxx") << "encoded entry has no set bits!!! "
492  << i << " "
493  << bset.to_string< char,std::char_traits<char>,std::allocator<char> >();
494  continue;
495  }
496 
497  while( b >= lowestb){
498 
499  // count the zeros between the current bit and the next on bit
500  int zerocnt = 0;
501  while( !bset.test(b-zerocnt) && b-zerocnt > lowestb) ++zerocnt;
502 
503  b -= zerocnt;
504 
505  if(zerocnt == 0){
506  for(int s = 0; s < 4; ++s){
507  uncompressed[curu] = curADC;
508  ++curu;
509  ++numu;
510  if(curu > uncompressed.size()-1) break;
511  }
512  --b;
513  }
514  else if(zerocnt == 1){
515  uncompressed[curu] = curADC;
516  ++curu;
517  ++numu;
518  --b;
519  }
520  else if(zerocnt == 2){
521  curADC += 1;
522  uncompressed[curu] = curADC;
523  ++curu;
524  ++numu;
525  --b;
526  }
527  else if(zerocnt == 3){
528  curADC -= 1;
529  uncompressed[curu] = curADC;
530  ++curu;
531  ++numu;
532  --b;
533  }
534  else if(zerocnt == 4){
535  curADC += 2;
536  uncompressed[curu] = curADC;
537  ++curu;
538  ++numu;
539  --b;
540  }
541  else if(zerocnt == 5){
542  curADC -= 2;
543  uncompressed[curu] = curADC;
544  ++curu;
545  ++numu;
546  --b;
547  }
548  else if(zerocnt == 6){
549  curADC += 3;
550  uncompressed[curu] = curADC;
551  ++curu;
552  ++numu;
553  --b;
554  }
555  else if(zerocnt == 7){
556  curADC -= 3;
557  uncompressed[curu] = curADC;
558  ++curu;
559  ++numu;
560  --b;
561  }
562 
563  if(curu > uncompressed.size() - 1) break;
564 
565  }// end loop over bits
566 
567  if(curu > uncompressed.size() - 1) break;
568 
569  }// end if this entry in the vector is encoded
570 
571  }// end loop over entries in adc
572 
573  return;
574  }
575 
576  } // namespace raw
577 } // namespace gar
std::vector< ADC_t > ADCvector_t
Definition: RawTypes.h:13
void CompressHuffman(gar::raw::ADCvector_t &adc)
Definition: raw.cxx:243
void ZeroUnsuppression(const gar::raw::ADCvector_t &adc, gar::raw::ADCvector_t &uncompressed, gar::raw::ADC_t pedestal)
Definition: raw.cxx:152
int ZeroSuppression(gar::raw::ADCvector_t &adc, gar::raw::ADC_t zerothreshold, size_t ticksbefore_in, size_t ticksafter_in)
Definition: raw.cxx:66
Zero Suppression followed by Huffman Encoding.
Definition: RawTypes.h:19
void UncompressHuffman(const gar::raw::ADCvector_t &adc, gar::raw::ADCvector_t &uncompressed)
Definition: raw.cxx:453
enum gar::raw::_compress Compress_t
int16_t adc
Definition: CRTFragment.hh:202
Raw data description.
def move(depos, offset)
Definition: depos.py:107
Zero Suppression algorithm.
Definition: RawTypes.h:18
string tmp
Definition: languages.py:63
short ADC_t
Definition: RawTypes.h:12
no compression
Definition: RawTypes.h:16
General GArSoft Utilities.
Huffman Encoding.
Definition: RawTypes.h:17
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
static bool * b
Definition: config.cpp:1043
void Uncompress(const gar::raw::ADCvector_t &adc, gar::raw::ADCvector_t &uncompressed, gar::raw::Compress_t compress)
Uncompresses a raw data buffer.
Definition: raw.cxx:183
void Compress(gar::raw::ADCvector_t &adc, gar::raw::Compress_t compress)
In-place compression of raw data buffer.
Definition: raw.cxx:23
static QCString * s
Definition: config.cpp:1042
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33