All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DecoderICARUSCRT_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: DecoderICARUSCRT
3 // Plugin Type: producer (art v3_06_03)
4 // File: DecoderICARUSCRT_module.cc
5 //
6 // Generated at Sat May 1 20:19:33 2021 by Biswaranjan Behera using cetskelgen
7 // from cetlib version v3_11_01.
8 //
9 // Thanks to Gianluca Petrillo for helping me on improving the decoder
10 ////////////////////////////////////////////////////////////////////////
11 
12 #include "art/Framework/Core/EDProducer.h"
13 #include "art/Framework/Core/ModuleMacros.h"
14 #include "art/Framework/Principal/Event.h"
15 #include "art/Framework/Principal/Handle.h"
16 #include "art/Framework/Principal/Run.h"
17 #include "art/Framework/Principal/SubRun.h"
18 #include "canvas/Utilities/InputTag.h"
19 #include "fhiclcpp/ParameterSet.h"
20 #include "messagefacility/MessageLogger/MessageLogger.h"
21 #include "canvas/Utilities/Exception.h"
22 #include "canvas/Persistency/Common/Ptr.h"
23 #include "canvas/Persistency/Common/PtrVector.h"
24 #include "canvas/Persistency/Common/FindManyP.h"
25 #include "art/Persistency/Common/PtrMaker.h"
26 
27 #include "sbndaq-artdaq-core/Overlays/Common/BernCRTFragment.hh"
28 #include "artdaq-core/Data/Fragment.hh"
29 #include "artdaq-core/Data/ContainerFragment.hh"
30 #include "sbndaq-artdaq-core/Overlays/FragmentType.hh"
31 #include "sbndaq-artdaq-core/Overlays/Common/BernCRTTranslator.hh"
32 
37 
39 
40 #include "art_root_io/TFileService.h"
41 #include "art_root_io/TFileDirectory.h"
42 
43 #include "TH1F.h"
44 #include "TNtuple.h"
45 
46 #include <memory>
47 #include <algorithm>
48 #include <cassert>
49 #include <cmath>
50 #include <fstream>
51 #include <iomanip>
52 #include <vector>
53 #include <iostream>
54 #include<stdlib.h>
55 #include <map>
56 
57 
58 namespace crt {
59  class DecoderICARUSCRT;
60 }
61 
62 
63 class crt::DecoderICARUSCRT : public art::EDProducer {
64 public:
65  explicit DecoderICARUSCRT(fhicl::ParameterSet const& p);
66  // The compiler-generated destructor is fine for non-base
67  // classes without bare pointers or other resource use.
68 
69  // Plugins should not be copied or assigned.
70  DecoderICARUSCRT(DecoderICARUSCRT const&) = delete;
74 
75  // Required functions.
76  void produce(art::Event& evt) override;
77 
78 private:
79  uint64_t CalculateTimestamp(icarus::crt::BernCRTTranslator& hit);
80  void CorrectForCableDelay(icarus::crt::BernCRTTranslator & hit);
81  bool IsSideCRT(icarus::crt::BernCRTTranslator & hit);
82 
83  // Declare member data here.
85 
86  /// Selector object detecting all the suitable data products.
88  bool fDropRawDataAfterUse; ///< Clear fragment data product cache after use.
89 
90  std::map<uint8_t, int32_t> FEB_delay_side; //<mac5, delay in ns>
91  std::map<uint8_t, int32_t> FEB_delay_top; //<mac5, delay in ns>
92 };
93 
94 
95 crt::DecoderICARUSCRT::DecoderICARUSCRT(fhicl::ParameterSet const& p)
96  : EDProducer{p}
97  , fInputTagPatterns{
99  "FragmentTagPatterns",
100  std::vector<std::string>{ "daq:(Container)?BERNCRT.*" }
101  ))
102  }
103  , fDropRawDataAfterUse{ p.get<bool>("DropRawDataAfterUse", true) }
104 {
105  fChannelMap = art::ServiceHandle<icarusDB::IICARUSChannelMap const>{}.get();
106  produces< std::vector<icarus::crt::CRTData> >();
107 
108  mayConsumeMany<artdaq::Fragments>();
109 
110  {
111  std::vector<std::vector<int32_t> > delays = p.get<std::vector<std::vector<int32_t> > >("FEB_delay_side");
112  for(auto & feb : delays) {
113  int32_t & mac = feb[0];
114  int32_t & d = feb[1];
115  FEB_delay_side[mac] = d;
116  }
117  }
118 
119  {
120  std::vector<std::vector<int32_t> > delays = p.get<std::vector<std::vector<int32_t> > >("FEB_delay_top");
121  for(auto & feb : delays) {
122  int32_t & mac = feb[0];
123  int32_t & d = feb[1];
124  FEB_delay_top[mac] = d;
125  }
126  }
127 }
128 
129 bool crt::DecoderICARUSCRT::IsSideCRT(icarus::crt::BernCRTTranslator & hit) {
130  /**
131  * Fragment ID described in SBN doc 16111
132  */
133  return (hit.fragment_ID & 0x3100) == 0x3100;
134 }
135 void crt::DecoderICARUSCRT::CorrectForCableDelay(icarus::crt::BernCRTTranslator & hit) {
136  if(!hit.IsReference_TS0() && !hit.IsReference_TS1()) { //don't correct reference T0 and T1 hits for cable length
137  try {
138  int32_t delay;
139  if(IsSideCRT(hit)) {
140  delay = FEB_delay_side.at(hit.mac5);
141  }
142  else {
143  delay = FEB_delay_top.at(hit.mac5);
144  }
145  hit.ts0 += delay;
146  hit.ts0 %= 1'000'000'000;
147  if(hit.ts0 < 0) hit.ts0 += 1000'000'000; //just in case the cable offset is negative (should be positive normally)
148  hit.ts1 += delay;
149  } catch(const std::out_of_range & e) {
150  TLOG(TLVL_ERROR)<<"CRT MAC "<<(int)(hit.mac5)<<" not found in the FEB_delay array!!! Please update FEB_delay FHiCL file";
151  throw cet::exception("DecoderICARUSCRT")
152  << "CRT MAC "<<(int)(hit.mac5)<<" not found in the FEB_delay array!!! Please update FEB_delay FHiCL file\n";
153  }
154  }
155 }
156 
157 uint64_t crt::DecoderICARUSCRT::CalculateTimestamp(icarus::crt::BernCRTTranslator& hit) {
158  /**
159  * Calculate timestamp based on nanosecond from FEB and poll times measured by server
160  * see: https://sbn-docdb.fnal.gov/cgi-bin/private/DisplayMeeting?sessionid=7783
161  */
162  int32_t ts0 = hit.ts0; //must be signed int
163 
164  uint64_t mean_poll_time = hit.last_poll_start/2 + hit.this_poll_end/2;
165  int mean_poll_time_ns = mean_poll_time % (1000'000'000);
166 
167  return mean_poll_time - mean_poll_time_ns + ts0
168  + (ts0 - mean_poll_time_ns < -500'000'000) * 1000'000'000
169  - (ts0 - mean_poll_time_ns > 500'000'000) * 1000'000'000;
170 }
171 
172 void crt::DecoderICARUSCRT::produce(art::Event& evt)
173 {
174 
175  util::LocalArtHandleTrackerManager dataCacheRemover
176  (evt, fDropRawDataAfterUse);
177 
178  std::vector<art::Handle<artdaq::Fragments>> fragmentHandles
179  = evt.getMany<artdaq::Fragments>(fInputTagPatterns);
180 
181  {
182  mf::LogDebug log { "DecoderICARUSCRT" };
183  log << "Found " << fragmentHandles.size()
184  << " CRT fragment data product candidates:";
185  for (auto const& handle: fragmentHandles)
186  log << "\n - '" << handle.provenance()->inputTag().encode() << '"';
187  }
188 
189  std::vector<icarus::crt::BernCRTTranslator> hit_vector;
190 
191  for (auto const& handle : fragmentHandles) {
192  if (!handle.isValid()) continue;
193 
194  dataCacheRemover.registerHandle(handle);
195 
196  if (handle->empty()) continue;
197 
198  auto this_hit_vector = icarus::crt::BernCRTTranslator::getCRTData(*handle);
199 
200  hit_vector.insert(hit_vector.end(),this_hit_vector.begin(),this_hit_vector.end());
201 
202  }
203 
204  struct Recipe_t {
205 
206  unsigned int destMac5;
207  unsigned int firstSourceChannel;
208  unsigned int lastSourceChannel;
209  unsigned int firstDestChannel;
210  unsigned int lastDestChannel;
211 
212  int direction; // +1 or -1
213 
214  };
215 
216  // vector: Mac5 -> its CRT data
217  std::vector<icarus::crt::CRTData> allCRTdata;
218 
219  for (auto & hit : hit_vector){
220  CorrectForCableDelay(hit); //add PPS cable length
221 
222  if(IsSideCRT(hit)) {
223  std::array<Recipe_t, 3U> allRecipes;
224 
225  //
226  // fill the recipe
227  //
228  if (!((hit.mac5 >= 88 && hit.mac5 <= 91)
229  || hit.mac5 == 96 || hit.mac5 == 97
230  || hit.mac5 == 1 || hit.mac5 == 3
231  || hit.mac5 == 6 || hit.mac5 == 7)) { // look for FEB those are not between 88 to 91
232 
233  int const destMac5 = fChannelMap->getSimMacAddress(hit.mac5);
234 
235  Recipe_t recipe;
236 
237  //
238  // first block of 10 channels from source
239  //
240  recipe.destMac5 = destMac5;
241 
242  recipe.firstSourceChannel = 2;
243  recipe.lastSourceChannel = 11;
244 
245  recipe.firstDestChannel = 0;
246  recipe.lastDestChannel = 9;
247  recipe.direction = +1;
248  allRecipes[0] = recipe;
249 
250  //
251  // second block of 10 channels from source
252  //
253  recipe.destMac5 = destMac5;
254  recipe.firstSourceChannel = 12;
255  recipe.lastSourceChannel = 21;
256 
257  recipe.firstDestChannel = 10;
258  recipe.lastDestChannel = 19;
259  recipe.direction = +1;
260  allRecipes[1] = recipe;
261 
262  //
263  // third block of 10 channels from source
264  //
265  recipe.destMac5 = destMac5;
266  recipe.firstSourceChannel = 22;
267  recipe.lastSourceChannel = 31;
268 
269  recipe.firstDestChannel = 20;
270  recipe.lastDestChannel = 29;
271  recipe.direction = +1;
272  allRecipes[2] = recipe;
273 
274 
275  } // "normal assignment"
276  else if (hit.mac5 == 97) { // south wall - east side top horizontal module channels are reversed
277 
278  int const destMac5 = fChannelMap->getSimMacAddress(hit.mac5);
279 
280  Recipe_t recipe;
281 
282  //
283  // first block of 10 channels from source
284  //
285  recipe.destMac5 = destMac5;
286 
287  recipe.firstSourceChannel = 2;
288  recipe.lastSourceChannel = 11;
289 
290  recipe.firstDestChannel = 0;
291  recipe.lastDestChannel = 9;
292  recipe.direction = +1;
293  allRecipes[0] = recipe;
294 
295  //
296  // second block of 10 channels from source
297  //
298  recipe.destMac5 = destMac5;
299  recipe.firstSourceChannel = 12;
300  recipe.lastSourceChannel = 21;
301 
302  recipe.firstDestChannel = 10;
303  recipe.lastDestChannel = 19;
304  recipe.direction = +1;
305  allRecipes[1] = recipe;
306 
307  //
308  // third block of 10 channels from source
309  //
310  recipe.destMac5 = destMac5;
311  recipe.firstSourceChannel = 22;
312  recipe.lastSourceChannel = 31;
313 
314  recipe.firstDestChannel = 29;
315  recipe.lastDestChannel = 20;
316  recipe.direction = -1;
317  allRecipes[2] = recipe;
318 
319 
320  }
321  else if (hit.mac5 == 1 || hit.mac5 == 3 ||
322  hit.mac5 == 6 || hit.mac5 == 7 ||
323  hit.mac5 == 96) { // north wall inner layer and south wall west side top three horizontal layer orientation is reversed
324 
325  int const destMac5 = fChannelMap->getSimMacAddress(hit.mac5);
326 
327  Recipe_t recipe;
328 
329  //
330  // first block of 10 channels from source
331  //
332  recipe.destMac5 = destMac5;
333 
334  recipe.firstSourceChannel = 2;
335  recipe.lastSourceChannel = 11;
336 
337  recipe.firstDestChannel = 9;
338  recipe.lastDestChannel = 0;
339  recipe.direction = -1;
340  allRecipes[0] = recipe;
341 
342  //
343  // second block of 10 channels from source
344  //
345  recipe.destMac5 = destMac5;
346  recipe.firstSourceChannel = 12;
347  recipe.lastSourceChannel = 21;
348 
349  recipe.firstDestChannel = 19;
350  recipe.lastDestChannel = 10;
351  recipe.direction = -1;
352  allRecipes[1] = recipe;
353 
354  //
355  // third block of 10 channels from source: special mapping
356  //
357  recipe.destMac5 = destMac5;
358  recipe.firstSourceChannel = 22;
359  recipe.lastSourceChannel = 31;
360 
361  recipe.firstDestChannel = 29;
362  recipe.lastDestChannel = 20;
363  recipe.direction = -1;
364  allRecipes[2] = recipe;
365 
366  }
367  else if (hit.mac5 == 88) {
368 
369  int const destMac5 = fChannelMap->getSimMacAddress(hit.mac5);
370 
371  Recipe_t recipe;
372 
373  //
374  // first block of 10 channels from source
375  //
376  recipe.destMac5 = 79;
377 
378  recipe.firstSourceChannel = 2;
379  recipe.lastSourceChannel = 11;
380 
381  recipe.firstDestChannel = 29;
382  recipe.lastDestChannel = 20;
383  recipe.direction = -1;
384  allRecipes[0] = recipe;
385 
386  //
387  // second block of 10 channels from source
388  //
389  recipe.destMac5 = destMac5;
390  recipe.firstSourceChannel = 12;
391  recipe.lastSourceChannel = 21;
392 
393  recipe.firstDestChannel = 10;
394  recipe.lastDestChannel = 19;
395  recipe.direction = +1;
396  allRecipes[1] = recipe;
397 
398  //
399  // third block of 10 channels from source: special mapping
400  //
401  recipe.destMac5 = destMac5;
402  recipe.firstSourceChannel = 22;
403  recipe.lastSourceChannel = 31;
404 
405  recipe.firstDestChannel = 0;
406  recipe.lastDestChannel = 9;
407  recipe.direction = +1;
408  allRecipes[2] = recipe;
409 
410  }
411  else if ((hit.mac5 >= 89) && (hit.mac5 <= 91)) {
412 
413  int const destMac5 = fChannelMap->getSimMacAddress(hit.mac5);
414 
415  Recipe_t recipe;
416 
417  //
418  // first block of 10 channels from source
419  //
420  recipe.destMac5 = destMac5;
421 
422  recipe.firstSourceChannel = 2;
423  recipe.lastSourceChannel = 11;
424 
425  recipe.firstDestChannel = 19;
426  recipe.lastDestChannel = 10;
427  recipe.direction = -1;
428  allRecipes[0] = recipe;
429 
430  //
431  // second block of 10 channels from source
432  //
433 
434  recipe.destMac5 = destMac5;
435  recipe.firstSourceChannel = 12;
436  recipe.lastSourceChannel = 21;
437 
438  recipe.firstDestChannel = 9;
439  recipe.lastDestChannel = 0;
440  recipe.direction = -1;
441  allRecipes[1] = recipe;
442 
443  //
444  // third block of 10 channels from source: special mapping
445  //
446  recipe.destMac5 = destMac5 - 1;
447  recipe.firstSourceChannel = 22;
448  recipe.lastSourceChannel = 31;
449 
450  recipe.firstDestChannel = 29;
451  recipe.lastDestChannel = 20;
452  recipe.direction = -1;
453 
454  allRecipes[2] = recipe;
455 
456  } // if not 88
457 
458  //
459  // cook the crtdata
460  //
461  for (Recipe_t const& recipe: allRecipes) {
462  if (recipe.firstSourceChannel == recipe.lastSourceChannel) continue;
463 
464  icarus::crt::CRTData data;
465  data.fMac5 = recipe.destMac5;
466  data.fTs0 = CalculateTimestamp(hit);
467  data.fTs1 = hit.ts1;
468  data.fFlags = hit.flags;
469  data.fThisPollStart = hit.this_poll_start;
470  data.fLastPollStart = hit.last_poll_start;
471  data.fHitsInPoll = hit.hits_in_poll;
472  data.fCoinc = hit.coinc;
473  data.fLastAcceptedTimestamp = hit.last_accepted_timestamp;
474  data.fLostHits = hit.lost_hits;
475 
476  unsigned destCh = recipe.firstDestChannel;
477  for (unsigned srcCh = recipe.firstSourceChannel; srcCh <= recipe.lastSourceChannel; ++srcCh) {
478 
479  data.fAdc[destCh] = hit.adc[srcCh];
480  destCh += recipe.direction; // increase or decrease the source
481 
482  }
483  allCRTdata.push_back(data);
484  } // for all recipes
485  }
486  else { //not side CRT, therefore top CRT
487  //this code needs review by the TOP CRT group!!!
488  icarus::crt::CRTData data;
489  data.fMac5 = fChannelMap->gettopSimMacAddress(hit.mac5);
490  data.fTs0 = CalculateTimestamp(hit);
491  data.fTs1 = hit.ts1;
492  data.fFlags = hit.flags;
493  data.fThisPollStart = hit.this_poll_start;
494  data.fLastPollStart = hit.last_poll_start;
495  data.fHitsInPoll = hit.hits_in_poll;
496  data.fCoinc = hit.coinc;
497  data.fLastAcceptedTimestamp = hit.last_accepted_timestamp;
498  data.fLostHits = hit.lost_hits;
499 
500  memcpy(data.fAdc, hit.adc, 32*sizeof(hit.adc[0]));
501 
502  allCRTdata.push_back(data);
503  }
504 
505  } // loop over all hits in an event
506 
507  // move the data which is actually present in the final data product
508  auto crtdata = std::make_unique<std::vector<icarus::crt::CRTData>>();
509  for (icarus::crt::CRTData& crtDataElem: allCRTdata) {
510  if (crtDataElem.fMac5 == 0) continue; // not a valid Mac5, data is not present
511  crtdata->push_back(std::move(crtDataElem));
512  }
513 
514  evt.put(std::move(crtdata));
515 
516 }
517 
518 DEFINE_ART_MODULE(crt::DecoderICARUSCRT)
Matches products by regex on process, module label and instance name.
std::map< uint8_t, int32_t > FEB_delay_top
This provides an art tool interface definition for tools which &quot;decode&quot; artdaq fragments into LArSoft...
pdgs p
Definition: selectors.fcl:22
DecoderICARUSCRT & operator=(DecoderICARUSCRT const &)=delete
process_name hit
Definition: cheaterreco.fcl:51
static std::vector< ProductRegex > makePatterns(SpecColl const &specs)
Parses a sequence of input tags to create data product patterns.
bool fDropRawDataAfterUse
Clear fragment data product cache after use.
std::map< uint8_t, int32_t > FEB_delay_side
Helpers to pass to art::Event::getMany() and similar.
void produce(art::Event &evt) override
void CorrectForCableDelay(icarus::crt::BernCRTTranslator &hit)
bool IsSideCRT(icarus::crt::BernCRTTranslator &hit)
util::RegexDataProductSelector const fInputTagPatterns
Selector object detecting all the suitable data products.
DecoderICARUSCRT(fhicl::ParameterSet const &p)
uint64_t CalculateTimestamp(icarus::crt::BernCRTTranslator &hit)
BEGIN_PROLOG FEB_delay_top
TCEvent evt
Definition: DataStructs.cxx:8
const icarusDB::IICARUSChannelMap * fChannelMap
Tracks handles for cache deletion.
process_name crt