All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DaqDecoderICARUSTPCwROI_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Class: DaqDecoderICARUSTPCwROI
4 // Module Type: producer
5 // File: DaqDecoderICARUSTPCwROI_module.cc
6 //
7 // The intent of this module is to both "decode" artdaq fragments
8 // and convert to RawDigits and also to do the initial noise
9 // filtering, specifically the coherent noise.
10 //
11 // Configuration parameters:
12 //
13 // DigitModuleLabel - the source of the RawDigit collection
14 //
15 //
16 // Modeled after example from Mike Wang (mwang@fnal.gov)
17 // Copied/Modified by Tracy Usher (usher@slac.stanford.edu) on January 27, 2020
18 //
19 ////////////////////////////////////////////////////////////////////////
20 
21 #include <cmath>
22 #include <algorithm>
23 #include <vector>
24 #include <iterator>
25 
26 #include "art/Framework/Core/ReplicatedProducer.h"
27 #include "art/Framework/Principal/Event.h"
28 #include "art/Framework/Services/Registry/ServiceHandle.h"
29 #include "art_root_io/TFileService.h"
30 #include "art/Framework/Core/ModuleMacros.h"
31 #include "art/Utilities/Globals.h"
32 #include "art/Utilities/make_tool.h"
33 #include "canvas/Persistency/Common/Ptr.h"
34 #include "messagefacility/MessageLogger/MessageLogger.h"
35 #include "cetlib/cpu_timer.h"
36 
37 #include "tbb/parallel_for.h"
38 #include "tbb/blocked_range.h"
39 #include "tbb/task_arena.h"
40 #include "tbb/spin_mutex.h"
41 #include "tbb/concurrent_vector.h"
42 
48 
49 #include "sbndaq-artdaq-core/Overlays/ICARUS/PhysCrateFragment.hh"
50 
54 
55 #include "icarus_signal_processing/ICARUSSigProcDefs.h"
56 #include "icarus_signal_processing/WaveformTools.h"
57 #include "icarus_signal_processing/Filters/FFTFilterFunctions.h"
58 #include "icarus_signal_processing/Filters/ImageFilters.h"
59 #include "icarus_signal_processing/Denoising.h"
60 #include "icarus_signal_processing/Detection/EdgeDetection.h"
61 #include "icarus_signal_processing/Filters/BilateralFilters.h"
62 #include "icarus_signal_processing/ROIFinder2D.h"
63 
64 namespace daq
65 {
66 
67 class DaqDecoderICARUSTPCwROI : public art::ReplicatedProducer
68 {
69 public:
70 
71  // Copnstructors, destructor.
72  explicit DaqDecoderICARUSTPCwROI(fhicl::ParameterSet const & pset, art::ProcessingFrame const& frame);
73  virtual ~DaqDecoderICARUSTPCwROI();
74 
75  // Overrides.
76  virtual void configure(fhicl::ParameterSet const & pset);
77  virtual void produce(art::Event & e, art::ProcessingFrame const& frame);
78  virtual void beginJob(art::ProcessingFrame const& frame);
79  virtual void endJob(art::ProcessingFrame const& frame);
80 
81  // Define the RawDigit collection
82  using RawDigitCollection = std::vector<raw::RawDigit>;
83  using RawDigitCollectionPtr = std::unique_ptr<RawDigitCollection>;
84  using ChannelROICollection = std::vector<recob::ChannelROI>;
85  using ChannelROICollectionPtr = std::unique_ptr<ChannelROICollection>;
86  using ConcurrentRawDigitCol = tbb::concurrent_vector<raw::RawDigit>;
87  using ConcurrentChannelROICol = tbb::concurrent_vector<recob::ChannelROI>;
88 
89  // Define data structures for organizing the decoded fragments
90  // The idea is to form complete "images" organized by "logical" TPC. Here we are including
91  // both the active AND inactive channels so the noise processing will be correct
92  // We build two lists here, first is the mapping to the actual image,
93  // the second will be a mapping to channel IDs where we assume the
94  // order is the same between the two
95  using PlaneIdxToImagePair = std::pair<unsigned int,icarus_signal_processing::ArrayFloat>;
96  using PlaneIdxToImageMap = std::map<unsigned int,icarus_signal_processing::ArrayFloat>;
97  using ChannelVec = std::vector<raw::ChannelID_t>;
98  using PlaneIdxToChannelPair = std::pair<unsigned int,ChannelVec>;
99  using PlaneIdxToChannelMap = std::map<unsigned int,ChannelVec>;
100 
101  using ChannelArrayPair = std::pair<daq::INoiseFilter::ChannelPlaneVec,icarus_signal_processing::ArrayFloat>;
102  using ChannelArrayPairVec = std::vector<ChannelArrayPair>;
103 
104 
105  // Function to do the work
106  void processSingleFragment(size_t,
107  detinfo::DetectorClocksData const& clockData,
108  art::Handle<artdaq::Fragments>,
112  ConcurrentChannelROICol&) const;
113 
114 private:
116  {
117  public:
119  detinfo::DetectorClocksData const& clockData,
120  art::Handle<artdaq::Fragments> const& fragmentsHandle,
121  ConcurrentRawDigitCol& concurrentRawRawDigits,
122  ConcurrentRawDigitCol& concurrentRawDigits,
123  ConcurrentRawDigitCol& coherentRawDigits,
124  ConcurrentChannelROICol& concurrentROIs)
125  : fDaqDecoderICARUSTPCwROI(parent),
126  fClockData{clockData},
127  fFragmentsHandle(fragmentsHandle),
128  fConcurrentRawRawDigits(concurrentRawRawDigits),
129  fConcurrentRawDigits(concurrentRawDigits),
130  fCoherentRawDigits(coherentRawDigits),
131  fConcurrentROIs(concurrentROIs)
132  {}
133 
134  void operator()(const tbb::blocked_range<size_t>& range) const
135  {
136  for (size_t idx = range.begin(); idx < range.end(); idx++)
138  }
139  private:
142  art::Handle<artdaq::Fragments> const& fFragmentsHandle;
147  };
148 
149  // Function to save our RawDigits
150  void saveRawDigits(const icarus_signal_processing::ArrayFloat&,
151  const icarus_signal_processing::VectorFloat&,
152  const icarus_signal_processing::VectorFloat&,
153  const icarus_signal_processing::VectorInt&,
154  ConcurrentRawDigitCol&) const;
155 
156  // Fcl parameters.
157  std::vector<art::InputTag> fFragmentsLabelVec; ///< The input artdaq fragment label vector (for more than one)
158  bool fOutputRawWaveform; ///< Should we output pedestal corrected (not noise filtered)?
159  bool fOutputCorrection; ///< Should we output the coherent noise correction vectors?
160  std::string fOutputRawWavePath; ///< Path to assign to the output if asked for
161  std::string fOutputCoherentPath; ///< Path to assign to the output if asked for
162  bool fDiagnosticOutput; ///< Set this to get lots of messages
163  float fSigmaForTruncation; ///< Cut for truncated rms calc
164  size_t fCoherentNoiseGrouping; ///< Grouping for removing coherent noise
165 
166  bool fDropRawDataAfterUse; ///< Clear fragment data product cache after use.
167 
168  const std::string fLogCategory; ///< Output category when logging messages
169 
170  // We need to give to the denoiser the "threshold vector" we will fill during our data loop
171  icarus_signal_processing::VectorFloat fThresholdVec; ///< "threshold vector" filled during decoding loop
172 
173  // Statistics.
174  int fNumEvent; ///< Number of events seen.
175 
176  // Plane to ROP plane mapping
177  using PlaneToROPPlaneMap = std::map<geo::PlaneID,unsigned int>;
178  using PlaneToWireOffsetMap = std::map<geo::PlaneID,raw::ChannelID_t>;
179  using ROPToNumWiresMap = std::map<unsigned int,unsigned int>;
180 
184  unsigned int fNumROPs;
185 
186  // Tools for decoding fragments depending on type
187  std::vector<std::unique_ptr<INoiseFilter>> fDecoderToolVec; ///< Decoder tools
188 
189  // Useful services, keep copies for now (we can update during begin run periods)
190  geo::GeometryCore const* fGeometry; ///< pointer to Geometry service
192 };
193 
194 DEFINE_ART_MODULE(DaqDecoderICARUSTPCwROI)
195 
196 //----------------------------------------------------------------------------
197 /// Constructor.
198 ///
199 /// Arguments:
200 ///
201 /// pset - Fcl parameters.
202 ///
203 DaqDecoderICARUSTPCwROI::DaqDecoderICARUSTPCwROI(fhicl::ParameterSet const & pset, art::ProcessingFrame const& frame) :
204  art::ReplicatedProducer(pset, frame),
205  fLogCategory("DaqDecoderICARUSTPCwROI"),fNumEvent(0), fNumROPs(0)
206 {
207  fGeometry = art::ServiceHandle<geo::Geometry const>{}.get();
208  fChannelMap = art::ServiceHandle<icarusDB::IICARUSChannelMap const>{}.get();
209 
210  configure(pset);
211 
212  // Check the concurrency
213  int max_concurrency = art::Globals::instance()->nthreads();
214 
215  mf::LogDebug("DaqDecoderICARUSTPCwROI") << " ==> concurrency: " << max_concurrency << std::endl;
216 
217  // Recover the vector of fhicl parameters for the ROI tools
218  const fhicl::ParameterSet& decoderToolParams = pset.get<fhicl::ParameterSet>("DecoderTool");
219 
220  fDecoderToolVec.resize(max_concurrency);
221 
222  for(auto& decoderTool : fDecoderToolVec)
223  {
224  // Get instance of tool
225  decoderTool = art::make_tool<INoiseFilter>(decoderToolParams);
226  }
227 
228  // Set up our "producers"
229  // Note that we can have multiple instances input to the module
230  // Our convention will be to create a similar number of outputs with the same instance names
231  for(const auto& fragmentLabel : fFragmentsLabelVec)
232  {
233  produces<std::vector<raw::RawDigit>>(fragmentLabel.instance());
234  produces<std::vector<recob::ChannelROI>>(fragmentLabel.instance());
235 
236  if (fOutputRawWaveform)
237  produces<std::vector<raw::RawDigit>>(fragmentLabel.instance() + fOutputRawWavePath);
238 
239  if (fOutputCorrection)
240  produces<std::vector<raw::RawDigit>>(fragmentLabel.instance() + fOutputCoherentPath);
241  }
242 
243  // Set up a WireID to ROP plane number table
244  PlaneToWireOffsetMap planeToLastWireOffsetMap;
245 
246  for(size_t cryoIdx = 0; cryoIdx < 2; cryoIdx++)
247  {
248  for(size_t logicalTPCIdx = 0; logicalTPCIdx < 4; logicalTPCIdx++)
249  {
250  for(size_t planeIdx = 0; planeIdx < 3; planeIdx++)
251  {
252  geo::PlaneID planeID(cryoIdx,logicalTPCIdx,planeIdx);
253 
254  raw::ChannelID_t channel = fGeometry->PlaneWireToChannel(planeID.Plane, 0, planeID.TPC, planeID.Cryostat);
255 
256  readout::ROPID ropID = fGeometry->ChannelToROP(channel);
257 
258  fPlaneToROPPlaneMap[planeID] = ropID.ROP;
259  fPlaneToWireOffsetMap[planeID] = channel;
260  planeToLastWireOffsetMap[planeID] = fGeometry->PlaneWireToChannel(planeID.Plane, fGeometry->Nwires(planeID), planeID.TPC, planeID.Cryostat);
261  fROPToNumWiresMap[ropID.ROP] = fGeometry->Nwires(planeID);
262 
263  if (ropID.ROP > fNumROPs) fNumROPs = ropID.ROP;
264 
265  // Watch for the middle induction and collection plane logical TPC split
266  if (ropID.ROP > 1 && (logicalTPCIdx == 1 || logicalTPCIdx == 3))
267  {
268  geo::PlaneID tempID(cryoIdx,logicalTPCIdx-1,planeIdx);
269 
270  fPlaneToWireOffsetMap[planeID] = fPlaneToWireOffsetMap[tempID];
271  fROPToNumWiresMap[ropID.ROP] = planeToLastWireOffsetMap[planeID] - fPlaneToWireOffsetMap[planeID];
272  }
273 
274  // Diagnostic output if requested
275  mf::LogDebug(fLogCategory) << "Initializing C/T/P: " << planeID.Cryostat << "/" << planeID.TPC << "/" << planeID.Plane << ", base channel: " << fPlaneToWireOffsetMap[planeID] << ", ROP: " << ropID << ", index: " << ropID.ROP;
276 
277  }
278  }
279  }
280 
281  fNumROPs++;
282 
283  // Report.
284  mf::LogInfo("DaqDecoderICARUSTPCwROI") << "DaqDecoderICARUSTPCwROI configured\n";
285 }
286 
287 //----------------------------------------------------------------------------
288 /// Destructor.
290 {}
291 
292 //----------------------------------------------------------------------------
293 /// Reconfigure method.
294 ///
295 /// Arguments:
296 ///
297 /// pset - Fcl parameter set.
298 ///
299 void DaqDecoderICARUSTPCwROI::configure(fhicl::ParameterSet const & pset)
300 {
301  fFragmentsLabelVec = pset.get<std::vector<art::InputTag>>("FragmentsLabelVec", std::vector<art::InputTag>()={"daq:PHYSCRATEDATA"});
302  fOutputRawWaveform = pset.get<bool >("OutputRawWaveform", false);
303  fOutputCorrection = pset.get<bool >("OutputCorrection", false);
304  fOutputRawWavePath = pset.get<std::string >("OutputRawWavePath", "raw");
305  fOutputCoherentPath = pset.get<std::string >("OutputCoherentPath", "Cor");
306  fDiagnosticOutput = pset.get<bool >("DiagnosticOutput", false);
307  fSigmaForTruncation = pset.get<float >("NSigmaForTrucation", 3.5);
308  fCoherentNoiseGrouping = pset.get<size_t >("CoherentGrouping", 64);
309  fDropRawDataAfterUse = pset.get<bool >("DropRawDataAfterUse", true);
310 }
311 
312 //----------------------------------------------------------------------------
313 /// Begin job method.
314 void DaqDecoderICARUSTPCwROI::beginJob(art::ProcessingFrame const&)
315 {
316  return;
317 }
318 
319 //----------------------------------------------------------------------------
320 /// Produce method.
321 ///
322 /// Arguments:
323 ///
324 /// evt - Art event.
325 ///
326 /// This is the primary method.
327 ///
328 void DaqDecoderICARUSTPCwROI::produce(art::Event & event, art::ProcessingFrame const&)
329 {
330  ++fNumEvent;
331 
332  mf::LogDebug("DaqDecoderICARUSTPCwROI") << "**** Processing raw data fragments ****" << std::endl;
333 
334  util::LocalArtHandleTrackerManager dataCacheRemover
335  (event, fDropRawDataAfterUse);
336 
337  // Check the concurrency
338  int max_concurrency = tbb::this_task_arena::max_concurrency();
339 
340  mf::LogDebug("DaqDecoderICARUSTPCwROI") << " ==> concurrency: " << max_concurrency << std::endl;
341 
342  cet::cpu_timer theClockTotal;
343 
344  theClockTotal.start();
345 
346  // Loop through the list of input daq fragment collections one by one
347  // We are not trying to multi thread at this stage because we are trying to control
348  // overall memory usage at this level. We'll multi thread internally...
349  for(const auto& fragmentLabel : fFragmentsLabelVec)
350  {
351  art::Handle<artdaq::Fragments> const& daq_handle
352  = dataCacheRemover.getHandle<artdaq::Fragments>(fragmentLabel);
353 
354  ConcurrentRawDigitCol concurrentRawDigits;
355  ConcurrentRawDigitCol concurrentRawRawDigits;
356  ConcurrentRawDigitCol coherentRawDigits;
357  ConcurrentChannelROICol concurrentROIs;
358 
359  PlaneIdxToImageMap planeIdxToImageMap;
360  PlaneIdxToChannelMap planeIdxToChannelMap;
361 
362  ChannelArrayPairVec channelArrayPairVec(fNumROPs);
363 
364  // Because the arrays can be variable size we need to loop to initialize
365  for(size_t ropIdx = 0; ropIdx < fNumROPs; ropIdx++)
366  {
367  ChannelArrayPair& channelArrayPair = channelArrayPairVec[ropIdx];
368 
369  channelArrayPair.first.resize(fROPToNumWiresMap[ropIdx]);
370  channelArrayPair.second.resize(fROPToNumWiresMap[ropIdx],icarus_signal_processing::VectorFloat(4096));
371 
372  mf::LogDebug("DaqDecoderICARUSTPCwROI") << "**> Initializing ropIdx: " << ropIdx << " channelPairVec to " << channelArrayPair.first.size() << " channels with " << channelArrayPair.second[0].size() << " ticks" << std::endl;
373  }
374 
375  mf::LogDebug("DaqDecoderICARUSTPCwROI") << "****> Let's get ready to rumble!" << std::endl;
376 
377  // ... Launch multiple threads with TBB to do the deconvolution and find ROIs in parallel
378  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService>()->DataFor(event);
379 
380  multiThreadFragmentProcessing fragmentProcessing(*this, clockData, daq_handle, concurrentRawRawDigits, concurrentRawDigits, coherentRawDigits, concurrentROIs);
381 
382  tbb::parallel_for(tbb::blocked_range<size_t>(0, daq_handle->size()), fragmentProcessing);
383 
384  // Now let's process the resulting images
385  // multiThreadImageProcessing imageProcessing(*this, clockData, channelArrayPairVec, concurrentRawDigits, coherentRawDigits, concurrentROIs);
386 
387  // tbb::parallel_for(tbb::blocked_range<size_t>(0, fNumROPs), imageProcessing);
388 
389  // Copy the raw digits from the concurrent vector to our output vector
390  RawDigitCollectionPtr rawDigitCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(concurrentRawDigits.begin()),
391  std::move_iterator(concurrentRawDigits.end()));
392 
393  // Want the RawDigits to be sorted in channel order... has to be done somewhere so why not now?
394  std::sort(rawDigitCollection->begin(),rawDigitCollection->end(),[](const auto& left,const auto&right){return left.Channel() < right.Channel();});
395 
396  // What did we get back?
397  mf::LogDebug("DaqDecoderICARUSTPCwROI") << "****> Total size of map: " << planeIdxToImageMap.size() << std::endl;
398  for(const auto& planeImagePair : planeIdxToImageMap)
399  {
400  mf::LogDebug("DaqDecoderICARUSTPCwROI") << " - plane: " << planeImagePair.first << " has " << planeImagePair.second.size() << " wires" << std::endl;
401  }
402 
403  // Now transfer ownership to the event store
404  event.put(std::move(rawDigitCollection), fragmentLabel.instance());
405 
406  // Do the same to output the candidate ROIs
407  ChannelROICollectionPtr channelROICollection = std::make_unique<std::vector<recob::ChannelROI>>(std::move_iterator(concurrentROIs.begin()),
408  std::move_iterator(concurrentROIs.end()));
409 
410  std::sort(channelROICollection->begin(),channelROICollection->end(),[](const auto& left, const auto& right){return left.Channel() < right.Channel();});
411 
412  event.put(std::move(channelROICollection), fragmentLabel.instance());
413 
414 
415  if (fOutputRawWaveform)
416  {
417  // Copy the raw digits from the concurrent vector to our output vector
418  RawDigitCollectionPtr rawRawDigitCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(concurrentRawRawDigits.begin()),
419  std::move_iterator(concurrentRawRawDigits.end()));
420 
421  // Want the RawDigits to be sorted in channel order... has to be done somewhere so why not now?
422  std::sort(rawRawDigitCollection->begin(),rawRawDigitCollection->end(),[](const auto& left,const auto&right){return left.Channel() < right.Channel();});
423 
424  // Now transfer ownership to the event store
425  event.put(std::move(rawRawDigitCollection),fragmentLabel.instance() + fOutputRawWavePath);
426  }
427 
428  if (fOutputCorrection)
429  {
430  // Copy the raw digits from the concurrent vector to our output vector
431  RawDigitCollectionPtr coherentCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(coherentRawDigits.begin()),
432  std::move_iterator(coherentRawDigits.end()));
433 
434  // Want the RawDigits to be sorted in channel order... has to be done somewhere so why not now?
435  std::sort(coherentCollection->begin(),coherentCollection->end(),[](const auto& left,const auto&right){return left.Channel() < right.Channel();});
436 
437  // Now transfer ownership to the event store
438  event.put(std::move(coherentCollection),fragmentLabel.instance() + fOutputCoherentPath);
439  }
440  }
441 
442  theClockTotal.stop();
443 
444  double totalTime = theClockTotal.accumulated_real_time();
445 
446  mf::LogInfo(fLogCategory) << "==> DaqDecoderICARUSTPCwROI total time: " << totalTime << std::endl;
447 
448  return;
449 }
450 
452  detinfo::DetectorClocksData const& clockData,
453  art::Handle<artdaq::Fragments> fragmentHandle,
454  ConcurrentRawDigitCol& concurrentRawRawDigitCol,
455  ConcurrentRawDigitCol& concurrentRawDigitCol,
456  ConcurrentRawDigitCol& coherentRawDigitCol,
457  ConcurrentChannelROICol& concurrentROIs) const
458 {
459  cet::cpu_timer theClockProcess;
460 
461  theClockProcess.start();
462 
463  art::Ptr<artdaq::Fragment> fragmentPtr(fragmentHandle, idx);
464 
465  mf::LogDebug("DaqDecoderICARUSTPCwROI") << "--> Processing fragment ID: " << fragmentPtr->fragmentID() << std::endl;
466  mf::LogDebug("DaqDecoderICARUSTPCwROI") << " ==> Current thread index: " << tbb::this_task_arena::current_thread_index() << std::endl;
467 
468  cet::cpu_timer theClockTotal;
469 
470  theClockTotal.start();
471 
472  // convert fragment to Nevis fragment
473  icarus::PhysCrateFragment physCrateFragment(*fragmentPtr);
474 
475  size_t nBoardsPerFragment = physCrateFragment.nBoards();
476  size_t nChannelsPerBoard = physCrateFragment.nChannelsPerBoard();
477  size_t nSamplesPerChannel = physCrateFragment.nSamplesPerChannel();
478 // size_t nChannelsPerFragment = nBoardsPerFragment * nChannelsPerBoard;
479 
480  // Recover the Fragment id:
481  artdaq::detail::RawFragmentHeader::fragment_id_t fragmentID = fragmentPtr->fragmentID();
482 
483  mf::LogDebug(fLogCategory) << "==> Recovered fragmentID: " << std::hex << fragmentID << std::dec << std::endl;
484 
485  // Look for special case of diagnostic running
486  if (!fChannelMap->hasFragmentID(fragmentID))
487  {
488  return;
489  }
490 
491  // Recover the crate name for this fragment
492  const std::string& crateName = fChannelMap->getCrateName(fragmentID);
493 
494  // Get the board ids for this fragment
495  const icarusDB::ReadoutIDVec& readoutIDVec = fChannelMap->getReadoutBoardVec(fragmentID);
496 
497  icarusDB::ReadoutIDVec boardIDVec(readoutIDVec.size());
498 
499  // Note we want these to be in "slot" order...
500  for(const auto& boardID : readoutIDVec)
501  {
502  // Look up the channels associated to this board
503  if (!fChannelMap->hasBoardID(boardID))
504  {
505  mf::LogDebug(fLogCategory) << "*** COULD NOT FIND BOARD ***\n" <<
506  " - boardID: " << std::hex << boardID << ", board map size: " << readoutIDVec.size() << ", nBoardsPerFragment: " << nBoardsPerFragment;
507 
508  return;
509  }
510 
511  unsigned int boardSlot = fChannelMap->getBoardSlot(boardID);
512 
513  boardIDVec[boardSlot] = boardID;
514  }
515 
516  std::string boardIDs = "";
517 
518  for(const auto& id : boardIDVec) boardIDs += std::to_string(id) + " ";
519 
520  mf::LogDebug(fLogCategory) << " - # boards: " << boardIDVec.size() << ", boards: " << boardIDs;
521 
522  cet::cpu_timer theClockPedestal;
523 
524  theClockPedestal.start();
525 
526  // Recover pointer to the decoder needed here
527  INoiseFilter* decoderTool = fDecoderToolVec[tbb::this_task_arena::current_thread_index()].get();
528 
529  // Create a local channel pair to hold at most a boards worth of info (64 channels x 4096 ticks)
530  ChannelArrayPair channelArrayPair;
531 
532  channelArrayPair.first.resize(nChannelsPerBoard);
533  channelArrayPair.second.resize(nChannelsPerBoard,icarus_signal_processing::VectorFloat(nSamplesPerChannel));
534 
535  // Now set up for output, we need to convert back from float to short int so use this
536  raw::RawDigit::ADCvector_t wvfm(nSamplesPerChannel);
537 
538  // The first task is to recover the data from the board data block, determine and subtract the pedestals
539  // and store into vectors useful for the next steps
540  for(size_t board = 0; board < boardIDVec.size(); board++)
541  {
542  // Some diagnostics test are removing boards so put in check here to watch for this
543  if (board >= nBoardsPerFragment)
544  {
545  mf::LogInfo("TPCDecoderFilter1D") << " Asking for board beyond number in fragment, want board " << board << ", maximum is " << nBoardsPerFragment << std::endl;
546  continue;
547  }
548 
549  uint32_t boardSlot = physCrateFragment.DataTileHeader(board)->StatusReg_SlotID();
550 
551  const icarusDB::ChannelPlanePairVec& channelPlanePairVec = fChannelMap->getChannelPlanePair(boardIDVec[boardSlot]);
552 
553  mf::LogDebug(fLogCategory) << "********************************************************************************\n"
554  << "FragmentID: " << std::hex << fragmentID << std::dec << ", Crate: " << crateName << ", boardID: " << boardSlot << "/" << nBoardsPerFragment << ", size " << channelPlanePairVec.size() << "/" << nChannelsPerBoard;
555 
556  if (board != boardSlot)
557  {
558  mf::LogInfo(fLogCategory) << "==> Found board/boardSlot mismatch, crate: " << crateName << ", board: " << board << ", boardSlot: " << boardSlot << " channelPlanePair: " << fChannelMap->getChannelPlanePair(boardIDVec[board]).front().first << "/" << fChannelMap->getChannelPlanePair(boardIDVec[board]).front().second << ", slot: " << channelPlanePairVec[0].first << "/" << channelPlanePairVec[0].second;
559  }
560 
561  // Get the pointer to the start of this board's block of data
562  const icarus::A2795DataBlock::data_t* dataBlock = physCrateFragment.BoardData(board);
563 
564  // Copy to input data array
565  for(size_t chanIdx = 0; chanIdx < nChannelsPerBoard; chanIdx++)
566  {
567  icarus_signal_processing::VectorFloat& rawDataVec = channelArrayPair.second[chanIdx];
568 
569  for(size_t tick = 0; tick < nSamplesPerChannel; tick++)
570  rawDataVec[tick] = -dataBlock[chanIdx + tick * nChannelsPerBoard];
571 
572  // Keep track of the channel
573  channelArrayPair.first[chanIdx] = channelPlanePairVec[chanIdx];
574  }
575 
576  //process_fragment(event, rawfrag, product_collection, header_collection);
577  decoderTool->process_fragment(clockData, channelArrayPair.first, channelArrayPair.second, fCoherentNoiseGrouping);
578 
579  // We need to recalculate pedestals for the noise corrected waveforms
580  icarus_signal_processing::WaveformTools<float> waveformTools;
581 
582  // Local storage for recomputing the the pedestals for the noise corrected data
583  float localPedestal(0.);
584  float localFullRMS(0.);
585  float localTruncRMS(0.);
586  int localNumTruncBins(0);
587  int localRangeBins(0);
588 
589  float sigmaCut(fSigmaForTruncation);
590 
591  // Recover the denoised waveform
592  const icarus_signal_processing::ArrayFloat& denoised = decoderTool->getWaveLessCoherent();
593 
594  icarus_signal_processing::VectorFloat pedCorWaveforms(denoised[0].size());
595 
596  for(size_t chanIdx = 0; chanIdx < nChannelsPerBoard; chanIdx++)
597  {
598  // Get the channel number on the Fragment
599  raw::ChannelID_t channel = channelPlanePairVec[chanIdx].first;
600 
601  // Are we storing the raw waveforms?
602  if (fOutputRawWaveform)
603  {
604  const icarus_signal_processing::VectorFloat& waveform = decoderTool->getPedCorWaveforms()[chanIdx];
605 
606  // Need to convert from float to short int
607  std::transform(waveform.begin(),waveform.end(),wvfm.begin(),[](const auto& val){return short(std::round(val));});
608 
609  ConcurrentRawDigitCol::iterator newRawObjItr = concurrentRawRawDigitCol.emplace_back(channel,wvfm.size(),wvfm);
610 
611  newRawObjItr->SetPedestal(decoderTool->getPedestalVals()[chanIdx],decoderTool->getFullRMSVals()[chanIdx]);
612  }
613 
614  if (fOutputCorrection)
615  {
616  const icarus_signal_processing::VectorFloat& corrections = decoderTool->getCorrectedMedians()[chanIdx];
617 
618  // Need to convert from float to short int
619  std::transform(corrections.begin(),corrections.end(),wvfm.begin(),[](const auto& val){return short(std::round(val));});
620 
621  //ConcurrentRawDigitCol::iterator newRawObjItr = coherentRawDigitCol.emplace_back(channel,wvfm.size(),wvfm);
622  ConcurrentRawDigitCol::iterator newRawObjItr = coherentRawDigitCol.push_back(raw::RawDigit(channel,wvfm.size(),wvfm));
623 
624  newRawObjItr->SetPedestal(0.,0.);
625  }
626 
627  // Now determine the pedestal and correct for it
628  waveformTools.getPedestalCorrectedWaveform(denoised[chanIdx],
629  pedCorWaveforms,
630  sigmaCut,
631  localPedestal,
632  localFullRMS,
633  localTruncRMS,
634  localNumTruncBins,
635  localRangeBins);
636 
637  // Need to convert from float to short int
638 // std::transform(denoised[chanIdx].begin(),denoised[chanIdx].end(),wvfm.begin(),[](const auto& val){return short(std::round(val));});
639  std::transform(pedCorWaveforms.begin(),pedCorWaveforms.end(),wvfm.begin(),[](const auto& val){return short(std::round(val));});
640 
641  ConcurrentRawDigitCol::iterator newObjItr = concurrentRawDigitCol.emplace_back(channel,wvfm.size(),wvfm);
642 
643  newObjItr->SetPedestal(localPedestal,localFullRMS);
644 
645  // And, finally, the ROIs
646  const icarus_signal_processing::VectorBool& chanROIs = decoderTool->getROIVals()[chanIdx];
648 
649  // Go through candidate ROIs and create Wire ROIs
650  size_t roiIdx = 0;
651 
652  while(roiIdx < chanROIs.size())
653  {
654  size_t roiStartIdx = roiIdx;
655 
656  while(roiIdx < chanROIs.size() && chanROIs[roiIdx]) roiIdx++;
657 
658  if (roiIdx > roiStartIdx)
659  {
660  std::vector<short> holder(roiIdx - roiStartIdx);
661 
662  for(size_t idx = 0; idx < holder.size(); idx++) holder[idx] = wvfm[roiStartIdx+idx];
663 
664  ROIVec.add_range(roiStartIdx, std::move(holder));
665  }
666 
667  roiIdx++;
668  }
669 
670  concurrentROIs.push_back(recob::ChannelROICreator(std::move(ROIVec),channel).move());
671  }
672  }
673 
674  // We need to make sure the channelID information is not preserved when less than 9 boards in the fragment
675 // if (nBoardsPerFragment < 9)
676 // {
677 // std::fill(fChannelIDVec.begin() + nBoardsPerFragment * nChannelsPerBoard, fChannelIDVec.end(), -1);
678 // }
679 
680 
681  theClockProcess.stop();
682 
683  double totalTime = theClockProcess.accumulated_real_time();
684 
685  mf::LogDebug(fLogCategory) << "--> Exiting fragment processing for thread: " << tbb::this_task_arena::current_thread_index() << ", time: " << totalTime << std::endl;
686  return;
687 }
688 
689 //----------------------------------------------------------------------------
690 /// End job method.
691 void DaqDecoderICARUSTPCwROI::endJob(art::ProcessingFrame const&)
692 {
693  mf::LogInfo(fLogCategory) << "Looked at " << fNumEvent << " events" << std::endl;
694 }
695 
696 } // end of namespace
virtual const icarus_signal_processing::ArrayFloat & getWaveLessCoherent() const =0
Recover the waveforms less coherent noise.
std::unique_ptr< RawDigitCollection > RawDigitCollectionPtr
std::pair< daq::INoiseFilter::ChannelPlaneVec, icarus_signal_processing::ArrayFloat > ChannelArrayPair
multiThreadFragmentProcessing(DaqDecoderICARUSTPCwROI const &parent, detinfo::DetectorClocksData const &clockData, art::Handle< artdaq::Fragments > const &fragmentsHandle, ConcurrentRawDigitCol &concurrentRawRawDigits, ConcurrentRawDigitCol &concurrentRawDigits, ConcurrentRawDigitCol &coherentRawDigits, ConcurrentChannelROICol &concurrentROIs)
std::vector< ChannelPlanePair > ChannelPlanePairVec
std::vector< raw::RawDigit > RawDigitCollection
Collection of charge vs time digitized from a single readout channel.
Definition: RawDigit.h:69
static constexpr Sample_t transform(Sample_t sample)
void saveRawDigits(const icarus_signal_processing::ArrayFloat &, const icarus_signal_processing::VectorFloat &, const icarus_signal_processing::VectorFloat &, const icarus_signal_processing::VectorInt &, ConcurrentRawDigitCol &) const
std::map< unsigned int, icarus_signal_processing::ArrayFloat > PlaneIdxToImageMap
tbb::concurrent_vector< raw::RawDigit > ConcurrentRawDigitCol
std::vector< unsigned int > ReadoutIDVec
virtual const ReadoutIDVec & getReadoutBoardVec(const unsigned int) const =0
std::vector< std::unique_ptr< INoiseFilter > > fDecoderToolVec
Decoder tools.
walls no right
Definition: selectors.fcl:105
This provides an art tool interface definition for tools which &quot;decode&quot; artdaq fragments into LArSoft...
std::vector< ChannelArrayPair > ChannelArrayPairVec
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
virtual const icarus_signal_processing::ArrayFloat & getPedCorWaveforms() const =0
Recover the pedestal corrected waveforms.
std::vector< short > ADCvector_t
Type representing a (compressed) vector of ADC counts.
Definition: RawDigit.h:73
const std::string instance
const datarange_t & add_range(size_type offset, ITER first, ITER last)
Adds a sequence of elements as a range with specified offset.
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
Definition of basic raw digits.
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
bool fOutputCorrection
Should we output the coherent noise correction vectors?
std::unique_ptr< ChannelROICollection > ChannelROICollectionPtr
virtual const icarus_signal_processing::ArrayBool & getROIVals() const =0
Recover the ROI values.
virtual void process_fragment(detinfo::DetectorClocksData const &, const daq::INoiseFilter::ChannelPlaneVec &, const icarus_signal_processing::ArrayFloat &, const size_t &)=0
std::vector< raw::ChannelID_t > ChannelVec
bool fDiagnosticOutput
Set this to get lots of messages.
virtual void configure(fhicl::ParameterSet const &pset)
geo::GeometryCore const * fGeometry
pointer to Geometry service
virtual void endJob(art::ProcessingFrame const &frame)
End job method.
fDetProps &fDetProps fDetProps &fDetProps fLogCategory
virtual const std::string & getCrateName(const unsigned int) const =0
virtual bool hasBoardID(const unsigned int) const =0
ROPID_t ROP
Index of the readout plane within its TPC set.
bool fDropRawDataAfterUse
Clear fragment data product cache after use.
icarus_signal_processing::VectorFloat fThresholdVec
&quot;threshold vector&quot; filled during decoding loop
std::map< geo::PlaneID, unsigned int > PlaneToROPPlaneMap
float fSigmaForTruncation
Cut for truncated rms calc.
virtual const ChannelPlanePairVec & getChannelPlanePair(const unsigned int) const =0
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
std::vector< art::InputTag > fFragmentsLabelVec
The input artdaq fragment label vector (for more than one)
virtual bool hasFragmentID(const unsigned int) const =0
virtual const icarus_signal_processing::ArrayFloat & getCorrectedMedians() const =0
Recover the correction median values.
walls no left
Definition: selectors.fcl:105
const icarusDB::IICARUSChannelMap * fChannelMap
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
std::map< geo::PlaneID, raw::ChannelID_t > PlaneToWireOffsetMap
std::map< unsigned int, unsigned int > ROPToNumWiresMap
Description of geometry of one entire detector.
IDecoderFilter interface class definiton.
Definition: INoiseFilter.h:32
Class identifying a set of planes sharing readout channels.
std::pair< unsigned int, icarus_signal_processing::ArrayFloat > PlaneIdxToImagePair
virtual const icarus_signal_processing::VectorFloat & getPedestalVals() const =0
Recover the pedestals for each channel.
Helper functions to create a wire.
void operator()(const tbb::blocked_range< size_t > &range) const
std::vector< recob::ChannelROI > ChannelROICollection
std::pair< unsigned int, ChannelVec > PlaneIdxToChannelPair
Contains all timing reference information for the detector.
std::string to_string(WindowPattern const &pattern)
Class managing the creation of a new recob::Wire object.
tbb::concurrent_vector< recob::ChannelROI > ConcurrentChannelROICol
Declaration of basic channel signal object for ICARUS.
void processSingleFragment(size_t, detinfo::DetectorClocksData const &clockData, art::Handle< artdaq::Fragments >, ConcurrentRawDigitCol &, ConcurrentRawDigitCol &, ConcurrentRawDigitCol &, ConcurrentChannelROICol &) const
std::map< unsigned int, ChannelVec > PlaneIdxToChannelMap
std::string fOutputCoherentPath
Path to assign to the output if asked for.
do i e
virtual void produce(art::Event &e, art::ProcessingFrame const &frame)
virtual unsigned int getBoardSlot(const unsigned int) const =0
virtual void beginJob(art::ProcessingFrame const &frame)
Begin job method.
virtual const icarus_signal_processing::VectorFloat & getFullRMSVals() const =0
Recover the full RMS before coherent noise.
DaqDecoderICARUSTPCwROI(fhicl::ParameterSet const &pset, art::ProcessingFrame const &frame)
bool fOutputRawWaveform
Should we output pedestal corrected (not noise filtered)?
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
art::Handle< T > getHandle(Args &&...args)
Retrieves an handle from the event, and registers it.
size_t fCoherentNoiseGrouping
Grouping for removing coherent noise.
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
Tracks handles for cache deletion.
const std::string fLogCategory
Output category when logging messages.
std::string fOutputRawWavePath
Path to assign to the output if asked for.
Variant of util::ArtHandleTrackerManager in local scope.
art framework interface to geometry description