All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MCDecoderICARUSTPCwROI_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Class: MCDecoderICARUSTPCwROI
4 // Module Type: producer
5 // File: MCDecoderICARUSTPCwROI_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 
46 #include "lardataobj/RawData/raw.h"
47 #include "lardataobj/RecoBase/Wire.h" // This for outputting the ROIs
49 
52 
53 namespace daq
54 {
55 
56 class MCDecoderICARUSTPCwROI : public art::ReplicatedProducer
57 {
58 public:
59 
60  // Copnstructors, destructor.
61  explicit MCDecoderICARUSTPCwROI(fhicl::ParameterSet const & pset, art::ProcessingFrame const& frame);
62  virtual ~MCDecoderICARUSTPCwROI();
63 
64  // Overrides.
65  virtual void configure(fhicl::ParameterSet const & pset);
66  virtual void produce(art::Event & e, art::ProcessingFrame const& frame);
67  virtual void beginJob(art::ProcessingFrame const& frame);
68  virtual void endJob(art::ProcessingFrame const& frame);
69 
70  // Define the RawDigit collection
71  using RawDigitCollection = std::vector<raw::RawDigit>;
72  using RawDigitCollectionPtr = std::unique_ptr<RawDigitCollection>;
73  using WireCollection = std::vector<recob::Wire>;
74  using WireCollectionPtr = std::unique_ptr<WireCollection>;
75  using ConcurrentRawDigitCol = tbb::concurrent_vector<raw::RawDigit>;
76  using ConcurrentWireCol = tbb::concurrent_vector<recob::Wire>;
77 
78  // Define data structures for organizing the decoded fragments
79  // The idea is to form complete "images" organized by "logical" TPC. Here we are including
80  // both the active AND inactive channels so the noise processing will be correct
81  // We build two lists here, first is the mapping to the actual image,
82  // the second will be a mapping to channel IDs where we assume the
83  // order is the same between the two
84  using PlaneIdxToImagePair = std::pair<unsigned int,icarus_signal_processing::ArrayFloat>;
85  using PlaneIdxToImageMap = std::map<unsigned int,icarus_signal_processing::ArrayFloat>;
86  using ChannelVec = std::vector<raw::ChannelID_t>;
87  using PlaneIdxToChannelPair = std::pair<unsigned int,ChannelVec>;
88  using PlaneIdxToChannelMap = std::map<unsigned int,ChannelVec>;
89 
90  using ChannelArrayPair = std::pair<daq::INoiseFilter::ChannelPlaneVec,icarus_signal_processing::ArrayFloat>;
91  using ChannelArrayPairVec = std::vector<ChannelArrayPair>;
92 
93  // Function to do the work
95  const ChannelArrayPair&,
96  size_t,
100  ConcurrentWireCol&) const;
101 
102 private:
103 
104  // Function to grab the input data and package
105  void processSingleLabel(art::Event&,
106  const art::InputTag&,
108  ChannelArrayPairVec const&,
109  size_t const&,
113  ConcurrentWireCol&) const;
114 
116  {
117  public:
119  detinfo::DetectorClocksData const& clockData,
120  ChannelArrayPairVec const& channelArrayPairVec,
121  size_t const& coherentNoiseGrouping,
122  ConcurrentRawDigitCol& concurrentRawDigits,
123  ConcurrentRawDigitCol& concurrentRawRawDigits,
124  ConcurrentRawDigitCol& coherentRawDigits,
125  ConcurrentWireCol& concurrentROIs)
126  : fMCDecoderICARUSTPCwROI(parent),
127  fClockData{clockData},
128  fChannelArrayPairVec(channelArrayPairVec),
129  fCoherentNoiseGrouping(coherentNoiseGrouping),
130  fConcurrentRawDigits(concurrentRawDigits),
131  fConcurrentRawRawDigits(concurrentRawRawDigits),
132  fCoherentRawDigits(coherentRawDigits),
133  fConcurrentROIs(concurrentROIs)
134  {}
135 
136  void operator()(const tbb::blocked_range<size_t>& range) const
137  {
138  for (size_t idx = range.begin(); idx < range.end(); idx++)
139  {
140  const ChannelArrayPair& channelArrayPair = fChannelArrayPairVec[idx];
141 
143  }
144  }
145  private:
154  };
155 
156  // Function to save our RawDigits
157  void saveRawDigits(const icarus_signal_processing::ArrayFloat&,
158  const icarus_signal_processing::VectorFloat&,
159  const icarus_signal_processing::VectorFloat&,
160  const icarus_signal_processing::VectorInt&,
161  ConcurrentRawDigitCol&) const;
162 
163  // Fcl parameters.
164  std::vector<art::InputTag> fRawDigitLabelVec; ///< The input artdaq fragment label vector (for more than one)
165  std::vector<std::string> fOutInstanceLabelVec; ///< The output instance labels to apply
166  bool fOutputRawWaveform; ///< Should we output pedestal corrected (not noise filtered)?
167  bool fOutputCorrection; ///< Should we output the coherent noise correction vectors?
168  std::string fOutputRawWavePath; ///< Path to assign to the output if asked for
169  std::string fOutputCoherentPath; ///< Path to assign to the output if asked for
170  bool fDiagnosticOutput; ///< Set this to get lots of messages
171  size_t fCoherentNoiseGrouping; ///< # channels in common for coherent noise
172 
173  const std::string fLogCategory; ///< Output category when logging messages
174 
175  // Statistics.
176  int fNumEvent; ///< Number of events seen.
177 
178  // Plane to ROP plane mapping
179  using PlaneToROPPlaneMap = std::map<geo::PlaneID,unsigned int>;
180  using PlaneToWireOffsetMap = std::map<geo::PlaneID,raw::ChannelID_t>;
181  using ROPToNumWiresMap = std::map<unsigned int,unsigned int>;
182 
186  unsigned int fNumROPs;
187 
188  using WirePlanePair = std::pair<unsigned int, unsigned int>;
189  using BoardWirePlanePair = std::pair<unsigned int, WirePlanePair>;
190  using ChannelToBoardWirePlaneMap = std::map<unsigned int, BoardWirePlanePair>;
191 
193 
194  // Tools for decoding fragments depending on type
195  std::vector<std::unique_ptr<INoiseFilter>> fDecoderToolVec; ///< Decoder tools
196 
197  // Useful services, keep copies for now (we can update during begin run periods)
198  geo::GeometryCore const* fGeometry; ///< pointer to Geometry service
200 };
201 
202 DEFINE_ART_MODULE(MCDecoderICARUSTPCwROI)
203 
204 //----------------------------------------------------------------------------
205 /// Constructor.
206 ///
207 /// Arguments:
208 ///
209 /// pset - Fcl parameters.
210 ///
211 MCDecoderICARUSTPCwROI::MCDecoderICARUSTPCwROI(fhicl::ParameterSet const & pset, art::ProcessingFrame const& frame) :
212  art::ReplicatedProducer(pset, frame),
213  fLogCategory("MCDecoderICARUSTPCwROI"),fNumEvent(0), fNumROPs(0)
214 {
215  fGeometry = art::ServiceHandle<geo::Geometry const>{}.get();
216  fChannelMap = art::ServiceHandle<icarusDB::IICARUSChannelMap const>{}.get();
217 
218  configure(pset);
219 
220  // Check the concurrency
221  int max_concurrency = art::Globals::instance()->nthreads();
222 
223  mf::LogDebug("MCDecoderICARUSTPCwROI") << " ==> concurrency: " << max_concurrency << std::endl;
224 
225  // Recover the vector of fhicl parameters for the ROI tools
226  const fhicl::ParameterSet& decoderToolParams = pset.get<fhicl::ParameterSet>("DecoderTool");
227 
228  fDecoderToolVec.resize(max_concurrency);
229 
230  for(auto& decoderTool : fDecoderToolVec)
231  {
232  // Get instance of tool
233  decoderTool = art::make_tool<INoiseFilter>(decoderToolParams);
234  }
235 
236  // Set up our "produces"
237  // Note that we can have multiple instances input to the module
238  // Our convention will be to create a similar number of outputs with the same instance names
239  for(const auto& instanceLabel : fOutInstanceLabelVec)
240  {
241  produces<std::vector<raw::RawDigit>>(instanceLabel);
242  produces<std::vector<recob::Wire>>(instanceLabel);
243 
244  if (fOutputRawWaveform)
245  produces<std::vector<raw::RawDigit>>(instanceLabel + fOutputRawWavePath);
246 
247  if (fOutputCorrection)
248  produces<std::vector<raw::RawDigit>>(instanceLabel + fOutputCoherentPath);
249  }
250 
251  // Set up a WireID to ROP plane number table
252  PlaneToWireOffsetMap planeToLastWireOffsetMap;
253 
254  for(size_t cryoIdx = 0; cryoIdx < 2; cryoIdx++)
255  {
256  for(size_t logicalTPCIdx = 0; logicalTPCIdx < 4; logicalTPCIdx++)
257  {
258  for(size_t planeIdx = 0; planeIdx < 3; planeIdx++)
259  {
260  geo::PlaneID planeID(cryoIdx,logicalTPCIdx,planeIdx);
261 
262  raw::ChannelID_t channel = fGeometry->PlaneWireToChannel(planeID.Plane, 0, planeID.TPC, planeID.Cryostat);
263 
264  readout::ROPID ropID = fGeometry->ChannelToROP(channel);
265 
266  fPlaneToROPPlaneMap[planeID] = ropID.ROP;
267  fPlaneToWireOffsetMap[planeID] = channel;
268  planeToLastWireOffsetMap[planeID] = fGeometry->PlaneWireToChannel(planeID.Plane, fGeometry->Nwires(planeID), planeID.TPC, planeID.Cryostat);
269  fROPToNumWiresMap[ropID.ROP] = fGeometry->Nwires(planeID);
270 
271  // Special case handling
272 // if (ropID.ROP > 1) fROPToNumWiresMap[ropID.ROP] *= 2;
273 
274  if (ropID.ROP > fNumROPs) fNumROPs = ropID.ROP;
275 
276  // Watch for the middle induction and collection plane logical TPC split
277  if (ropID.ROP > 1 && (logicalTPCIdx == 1 || logicalTPCIdx == 3))
278  {
279  geo::PlaneID tempID(cryoIdx,logicalTPCIdx-1,planeIdx);
280 
281  fPlaneToWireOffsetMap[planeID] = fPlaneToWireOffsetMap[tempID];
282  fROPToNumWiresMap[ropID.ROP] = planeToLastWireOffsetMap[planeID] - fPlaneToWireOffsetMap[planeID];
283  }
284 
285  // Diagnostic output if requested
286  mf::LogDebug(fLogCategory) << "Initializing C/T/P: " << planeID.Cryostat << "/" << planeID.TPC << "/" << planeID.Plane << ", base channel: " << fPlaneToWireOffsetMap[planeID] << ", ROP: " << ropID << ", index: " << ropID.ROP;
287 
288  }
289  }
290  }
291 
292  fNumROPs++;
293 
294  // We need to build a mapping fronm channel to a readout board/wire pair
295  // Get the board ids for this fragment
296  const icarusDB::TPCReadoutBoardToChannelMap& readoutBoardToChannelMap = fChannelMap->getReadoutBoardToChannelMap();
297 
298  for(const auto& boardPair : readoutBoardToChannelMap)
299  {
300  // The board pair will give us the readout board and a vector of "wires"
301  unsigned int readoutBoardID = boardPair.first;
302 
303  // Loop through the vector of wires on this board
304  for(unsigned int wireIdx = 0; wireIdx < boardPair.second.second.size(); wireIdx++)
305  {
306  unsigned int channelID = boardPair.second.second[wireIdx].first;
307  unsigned int planeID = boardPair.second.second[wireIdx].second;
308 
309  fChannelToBoardWirePlaneMap[channelID] = BoardWirePlanePair(readoutBoardID,WirePlanePair(wireIdx,planeID));
310  }
311  }
312 
313 
314  // Report.
315  mf::LogInfo("MCDecoderICARUSTPCwROI") << "MCDecoderICARUSTPCwROI configured\n";
316 }
317 
318 //----------------------------------------------------------------------------
319 /// Destructor.
321 {}
322 
323 //----------------------------------------------------------------------------
324 /// Reconfigure method.
325 ///
326 /// Arguments:
327 ///
328 /// pset - Fcl parameter set.
329 ///
330 void MCDecoderICARUSTPCwROI::configure(fhicl::ParameterSet const & pset)
331 {
332  fRawDigitLabelVec = pset.get<std::vector<art::InputTag>>("FragmentsLabelVec", {"daq:PHYSCRATEDATA"});
333  fOutInstanceLabelVec = pset.get<std::vector<std::string>> ("OutInstanceLabelVec", {"PHYSCRATEDATA"});
334  fOutputRawWaveform = pset.get<bool >("OutputRawWaveform", false);
335  fOutputCorrection = pset.get<bool >("OutputCorrection", false);
336  fOutputRawWavePath = pset.get<std::string >("OutputRawWavePath", "raw");
337  fOutputCoherentPath = pset.get<std::string >("OutputCoherentPath", "Cor");
338  fDiagnosticOutput = pset.get<bool >("DiagnosticOutput", false);
339  fCoherentNoiseGrouping = pset.get<size_t >("CoherentGrouping", 64);
340 
341 }
342 
343 //----------------------------------------------------------------------------
344 /// Begin job method.
345 void MCDecoderICARUSTPCwROI::beginJob(art::ProcessingFrame const&)
346 {
347  return;
348 }
349 
350 //----------------------------------------------------------------------------
351 /// Produce method.
352 ///
353 /// Arguments:
354 ///
355 /// evt - Art event.
356 ///
357 /// This is the primary method.
358 ///
359 void MCDecoderICARUSTPCwROI::produce(art::Event & event, art::ProcessingFrame const&)
360 {
361  ++fNumEvent;
362 
363  mf::LogDebug("MCDecoderICARUSTPCwROI") << "**** Processing raw data fragments ****" << std::endl;
364 
365  // Check the concurrency
366  int max_concurrency = tbb::this_task_arena::max_concurrency();
367 
368  mf::LogDebug("MCDecoderICARUSTPCwROI") << " ==> concurrency: " << max_concurrency << std::endl;
369 
370  cet::cpu_timer theClockTotal;
371 
372  theClockTotal.start();
373 
374  // Loop through the list of input daq fragment collections one by one
375  // We are not trying to multi thread at this stage because we are trying to control
376  // overall memory usage at this level. We'll multi thread internally...
377  size_t instanceIdx(0);
378 
379  for(const auto& rawDigitLabel : fRawDigitLabelVec)
380  {
381  art::Handle<artdaq::Fragments> daq_handle;
382  event.getByLabel(rawDigitLabel, daq_handle);
383 
384  ConcurrentRawDigitCol concurrentRawDigits;
385  ConcurrentRawDigitCol concurrentRawRawDigits;
386  ConcurrentRawDigitCol coherentRawDigits;
387  ConcurrentWireCol concurrentROIs;
388 
389  PlaneIdxToImageMap planeIdxToImageMap;
390  PlaneIdxToChannelMap planeIdxToChannelMap;
391 
392  ChannelArrayPairVec channelArrayPairVec(fNumROPs);
393 
394  // Because the arrays can be variable size we need to loop to initialize
395  for(size_t ropIdx = 0; ropIdx < fNumROPs; ropIdx++)
396  {
397  ChannelArrayPair& channelArrayPair = channelArrayPairVec[ropIdx];
398 
399  channelArrayPair.first.resize(fROPToNumWiresMap[ropIdx]);
400  channelArrayPair.second.resize(fROPToNumWiresMap[ropIdx],icarus_signal_processing::VectorFloat(4096));
401 
402  mf::LogDebug("MCDecoderICARUSTPCwROI") << "**> Initializing ropIdx: " << ropIdx << " channelPairVec to " << channelArrayPair.first.size() << " channels with " << channelArrayPair.second[0].size() << " ticks" << std::endl;
403  }
404 
405  mf::LogDebug("MCDecoderICARUSTPCwROI") << "****> Let's get ready to rumble!" << std::endl;
406 
407  // Now let's process the resulting images
408  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService>()->DataFor(event);
409 
410  // ... repackage the input MC data to format suitable for noise processing
411  processSingleLabel(event, rawDigitLabel, clockData, channelArrayPairVec, fCoherentNoiseGrouping, concurrentRawDigits, concurrentRawRawDigits, coherentRawDigits, concurrentROIs);
412 
413 // multiThreadImageProcessing imageProcessing(*this, clockData, channelArrayPairVec, fCoherentNoiseGrouping, concurrentRawDigits, concurrentRawRawDigits, coherentRawDigits, concurrentROIs);
414 //
415 // tbb::parallel_for(tbb::blocked_range<size_t>(0, fNumROPs), imageProcessing);
416 
417  // Copy the raw digits from the concurrent vector to our output vector
418  RawDigitCollectionPtr rawDigitCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(concurrentRawDigits.begin()),
419  std::move_iterator(concurrentRawDigits.end()));
420 
421  // Want the RawDigits to be sorted in channel order... has to be done somewhere so why not now?
422  std::sort(rawDigitCollection->begin(),rawDigitCollection->end(),[](const auto& left,const auto&right){return left.Channel() < right.Channel();});
423 
424  // What did we get back?
425  mf::LogDebug("MCDecoderICARUSTPCwROI") << "****> Total size of map: " << planeIdxToImageMap.size() << std::endl;
426  for(const auto& planeImagePair : planeIdxToImageMap)
427  {
428  mf::LogDebug("MCDecoderICARUSTPCwROI") << " - plane: " << planeImagePair.first << " has " << planeImagePair.second.size() << " wires" << std::endl;
429  }
430 
431  // Now transfer ownership to the event store
432  event.put(std::move(rawDigitCollection), fOutInstanceLabelVec[instanceIdx]);
433 
434  // Do the same to output the candidate ROIs
435  WireCollectionPtr wireCollection = std::make_unique<std::vector<recob::Wire>>(std::move_iterator(concurrentROIs.begin()),
436  std::move_iterator(concurrentROIs.end()));
437 
438  std::sort(wireCollection->begin(),wireCollection->end(),[](const auto& left, const auto& right){return left.Channel() < right.Channel();});
439 
440  event.put(std::move(wireCollection), fOutInstanceLabelVec[instanceIdx]);
441 
442  if (fOutputRawWaveform)
443  {
444  // Copy the raw digits from the concurrent vector to our output vector
445  RawDigitCollectionPtr rawRawDigitCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(concurrentRawRawDigits.begin()),
446  std::move_iterator(concurrentRawRawDigits.end()));
447 
448  // Want the RawDigits to be sorted in channel order... has to be done somewhere so why not now?
449  std::sort(rawRawDigitCollection->begin(),rawRawDigitCollection->end(),[](const auto& left,const auto&right){return left.Channel() < right.Channel();});
450 
451  // Now transfer ownership to the event store
452  event.put(std::move(rawRawDigitCollection),fOutInstanceLabelVec[instanceIdx] + fOutputRawWavePath);
453  }
454 
455  if (fOutputCorrection)
456  {
457  // Copy the raw digits from the concurrent vector to our output vector
458  RawDigitCollectionPtr coherentCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(coherentRawDigits.begin()),
459  std::move_iterator(coherentRawDigits.end()));
460 
461  // Want the RawDigits to be sorted in channel order... has to be done somewhere so why not now?
462  std::sort(coherentCollection->begin(),coherentCollection->end(),[](const auto& left,const auto&right){return left.Channel() < right.Channel();});
463 
464  // Now transfer ownership to the event store
465  event.put(std::move(coherentCollection),fOutInstanceLabelVec[instanceIdx] + fOutputCoherentPath);
466  }
467 
468  instanceIdx++;
469  }
470 
471  theClockTotal.stop();
472 
473  double totalTime = theClockTotal.accumulated_real_time();
474 
475  mf::LogInfo(fLogCategory) << "==> MCDecoderICARUSTPCwROI total time: " << totalTime << std::endl;
476 
477  return;
478 }
479 
481  const art::InputTag& inputLabel,
482  detinfo::DetectorClocksData const& clockData,
483  ChannelArrayPairVec const& channelArrayPairVec,
484  size_t const& coherentNoiseGrouping,
485  ConcurrentRawDigitCol& concurrentRawDigits,
486  ConcurrentRawDigitCol& concurrentRawRawDigits,
487  ConcurrentRawDigitCol& coherentRawDigits,
488  ConcurrentWireCol& concurrentROIs) const
489 {
490  cet::cpu_timer theClockProcess;
491 
492  theClockProcess.start();
493 
494  // Read in the digit List object(s).
495  art::Handle< std::vector<raw::RawDigit> > digitVecHandle;
496  event.getByLabel(inputLabel, digitVecHandle);
497 
498  // Require a valid handle
499  if (digitVecHandle.isValid() && digitVecHandle->size()>0 )
500  {
501  // Sadly, the RawDigits come to us in an unsorted condition which is not optimal for
502  // what we want to do here. So we make a vector of pointers to the input raw digits and sort them
503  std::vector<const raw::RawDigit*> rawDigitVec;
504 
505  // Ugliness to fill the pointer vector...
506  for(size_t idx = 0; idx < digitVecHandle->size(); idx++) rawDigitVec.emplace_back(&digitVecHandle->at(idx)); //art::Ptr<raw::RawDigit>(digitVecHandle, idx).get());
507 
508  // Sort (use a lambda to sort by channel id)
509  std::sort(rawDigitVec.begin(),rawDigitVec.end(),[](const raw::RawDigit* left, const raw::RawDigit* right) {return left->Channel() < right->Channel();});
510 
511  // Declare a temporary digit holder and resize it if downsizing the waveform
512  unsigned int dataSize = art::Ptr<raw::RawDigit>(digitVecHandle,0)->Samples(); //size of raw data vectors
513  raw::RawDigit::ADCvector_t rawDataVec(dataSize);
514 
515  using BoardToChannelArrayPairMap = std::map<unsigned int, ChannelArrayPair>;
516 
517  BoardToChannelArrayPairMap boardToChannelArrayPairMap;
518  std::map<unsigned int, int> boardWireCountMap;
519  const unsigned int MAXCHANNELS(64);
520 
521  // Commence looping over raw digits
522  for(const auto& rawDigit : rawDigitVec)
523  {
524  raw::ChannelID_t channel = rawDigit->Channel();
525 
526  ChannelToBoardWirePlaneMap::const_iterator channelToBoardItr = fChannelToBoardWirePlaneMap.find(channel);
527 
528  if (channelToBoardItr == fChannelToBoardWirePlaneMap.end())
529  {
530  std::cout << "********************************************************************************" << std::endl;
531  std::cout << "********* We did not find channel " << channel << "*****************************" << std::endl;
532  std::cout << "********************************************************************************" << std::endl;
533  continue;
534  }
535 
536  unsigned int readoutBoardID = channelToBoardItr->second.first;
537  unsigned int wireIdx = channelToBoardItr->second.second.first;
538  unsigned int planeIdx = channelToBoardItr->second.second.second;
539 
540  BoardToChannelArrayPairMap::iterator boardMapItr = boardToChannelArrayPairMap.find(readoutBoardID);
541 
542  if (boardMapItr == boardToChannelArrayPairMap.end())
543  {
544  const auto [mapItr, success] =
545  boardToChannelArrayPairMap.insert({readoutBoardID,{daq::INoiseFilter::ChannelPlaneVec(MAXCHANNELS,{0,3}),icarus_signal_processing::ArrayFloat(MAXCHANNELS,icarus_signal_processing::VectorFloat(dataSize))}});
546 
547  if (!success)
548  {
549  std::cout << "+++> failed to insert data structure! " << std::endl;
550  continue;
551  }
552 
553  boardMapItr = mapItr;
554  boardWireCountMap[readoutBoardID] = 0;
555  }
556 
557  // Decompress data into local holder
558  raw::Uncompress(rawDigit->ADCs(), rawDataVec, rawDigit->Compression());
559 
560  // Fill into the data structure
561  icarus_signal_processing::VectorFloat& boardDataVec = boardMapItr->second.second[wireIdx];
562 
563  for(size_t tick = 0; tick < dataSize; tick++) boardDataVec[tick] = rawDataVec[tick];
564 
565  boardMapItr->second.first[wireIdx] = daq::INoiseFilter::ChannelPlanePair(channel,planeIdx);
566 
567  if (++boardWireCountMap[readoutBoardID] == MAXCHANNELS)
568  {
569  processSingleImage(clockData, boardMapItr->second, coherentNoiseGrouping, concurrentRawDigits, concurrentRawRawDigits, coherentRawDigits, concurrentROIs);
570 
571  boardToChannelArrayPairMap.erase(boardMapItr);
572 
573  // Get the wireIDs for this channel
574 // std::vector<geo::WireID> wids = fGeometry->ChannelToWire(channel);
575 //
576 // // Since we work with channels we can ignore the case in the middle of the TPC where there are
577 // // wires crossing the midplane and just work with the first wire ID
578 // const geo::WireID& wireID = wids[0];
579 // const geo::PlaneID& planeID = wireID.planeID();
580 //
581 // // Ok, now store things...
582 // unsigned int planeIndex = fPlaneToROPPlaneMap.find(planeID)->second;
583 // unsigned int wire = channel - fPlaneToWireOffsetMap.find(planeID)->second;
584 //
585 // if (wire >= channelArrayPairVec[planeIndex].second.size()) continue;
586 //
587 // icarus_signal_processing::VectorFloat& dataVec = channelArrayPairVec[planeIndex].second[wire];
588 //
589 // for(size_t tick = 0; tick < dataSize; tick++) dataVec[tick] = rawDataVec[tick];
590 //
591 // // Keep track of the channel
592 // channelArrayPairVec[planeIndex].first[wire] = daq::INoiseFilter::ChannelPlanePair(channel,planeID.Plane);
593  }
594  }
595 
596  // Some detector simulations don't output channels that don't have any possibility of signal (ghost channels)
597  // Do a cleanup phase here to find these
598  for(auto& boardInfo : boardToChannelArrayPairMap)
599  {
600  if (boardWireCountMap[boardInfo.first] < 64)
601  {
602  processSingleImage(clockData, boardInfo.second, boardWireCountMap[boardInfo.first], concurrentRawDigits, concurrentRawRawDigits, coherentRawDigits, concurrentROIs);
603  }
604  }
605 
606  }
607 
608  theClockProcess.stop();
609 
610  double totalTime = theClockProcess.accumulated_real_time();
611 
612  mf::LogDebug(fLogCategory) << "--> Exiting fragment processing for thread: " << tbb::this_task_arena::current_thread_index() << ", time: " << totalTime << std::endl;
613 
614  return;
615 }
616 
618  const ChannelArrayPair& channelArrayPair,
619  size_t coherentNoiseGrouping,
620  ConcurrentRawDigitCol& concurrentRawDigitCol,
621  ConcurrentRawDigitCol& concurrentRawRawDigitCol,
622  ConcurrentRawDigitCol& coherentRawDigitCol,
623  ConcurrentWireCol& concurrentROIs) const
624 {
625  // Let's go through and fill the output vector
626  const daq::INoiseFilter::ChannelPlaneVec& channelVec = channelArrayPair.first;
627  const icarus_signal_processing::ArrayFloat& dataArray = channelArrayPair.second;
628 
629  unsigned int numChannels = dataArray.size();
630  unsigned int numTicks = dataArray[0].size();
631 
632  // Recover pointer to the decoder needed here
633  INoiseFilter* decoderTool = fDecoderToolVec[tbb::this_task_arena::current_thread_index()].get();
634 
635  //process_fragment(event, rawfrag, product_collection, header_collection);
636  decoderTool->process_fragment(clockData, channelVec, dataArray, coherentNoiseGrouping);
637 
638  // Now set up for output, we need to convert back from float to short int so use this
639  raw::RawDigit::ADCvector_t wvfm(numTicks);
640 
641  // Loop over the channels to recover the RawDigits after filtering
642  for(size_t chanIdx = 0; chanIdx < numChannels; chanIdx++)
643  {
644  // Skip if no channel data (plane is wrong)
645  if (channelVec[chanIdx].second > 2) continue;
646 
647  raw::ChannelID_t channel = channelVec[chanIdx].first;
648 
649  if (fOutputRawWaveform)
650  {
651  const icarus_signal_processing::VectorFloat& waveform = decoderTool->getPedCorWaveforms()[chanIdx];
652 
653  // Need to convert from float to short int
654  std::transform(waveform.begin(),waveform.end(),wvfm.begin(),[](const auto& val){return short(std::round(val));});
655 
656  ConcurrentRawDigitCol::iterator newRawObjItr = concurrentRawRawDigitCol.emplace_back(channel,wvfm.size(),wvfm);
657 
658  newRawObjItr->SetPedestal(decoderTool->getPedestalVals()[chanIdx],decoderTool->getFullRMSVals()[chanIdx]);
659  }
660 
661  if (fOutputCorrection)
662  {
663  const icarus_signal_processing::VectorFloat& corrections = decoderTool->getCorrectedMedians()[chanIdx];
664 
665  // Need to convert from float to short int
666  std::transform(corrections.begin(),corrections.end(),wvfm.begin(),[](const auto& val){return short(std::round(val));});
667 
668  //ConcurrentRawDigitCol::iterator newRawObjItr = coherentRawDigitCol.emplace_back(channel,wvfm.size(),wvfm);
669  ConcurrentRawDigitCol::iterator newRawObjItr = coherentRawDigitCol.push_back(raw::RawDigit(channel,wvfm.size(),wvfm));
670 
671  newRawObjItr->SetPedestal(0.,0.);
672  }
673 
674  // Recover the denoised waveform
675  const icarus_signal_processing::VectorFloat& denoised = decoderTool->getWaveLessCoherent()[chanIdx];
676 
677  // Need to convert from float to short int
678  std::transform(denoised.begin(),denoised.end(),wvfm.begin(),[](const auto& val){return short(std::round(val));});
679 
680  ConcurrentRawDigitCol::iterator newObjItr = concurrentRawDigitCol.emplace_back(channel,wvfm.size(),wvfm);
681 
682  newObjItr->SetPedestal(0.,decoderTool->getTruncRMSVals()[chanIdx]);
683 
684  // And, finally, the ROIs
685  const icarus_signal_processing::VectorBool& chanROIs = decoderTool->getROIVals()[chanIdx];
687 
688  // Go through candidate ROIs and create Wire ROIs
689  size_t roiIdx = 0;
690 
691  while(roiIdx < chanROIs.size())
692  {
693  size_t roiStartIdx = roiIdx;
694 
695  while(roiIdx < chanROIs.size() && chanROIs[roiIdx]) roiIdx++;
696 
697  if (roiIdx > roiStartIdx)
698  {
699  std::vector<float> holder(roiIdx - roiStartIdx, 10.);
700 
701  ROIVec.add_range(roiStartIdx, std::move(holder));
702  }
703 
704  roiIdx++;
705  }
706 
707  concurrentROIs.push_back(recob::WireCreator(std::move(ROIVec),channel,fGeometry->View(channel)).move());
708  }//loop over channel indices
709 
710  return;
711 }
712 
713 void MCDecoderICARUSTPCwROI::saveRawDigits(const icarus_signal_processing::ArrayFloat& dataArray,
714  const icarus_signal_processing::VectorFloat& pedestalVec,
715  const icarus_signal_processing::VectorFloat& rmsVec,
716  const icarus_signal_processing::VectorInt& channelVec,
717  ConcurrentRawDigitCol& rawDigitCol) const
718 {
719  if (!dataArray.empty())
720  {
721  cet::cpu_timer theClockSave;
722 
723  theClockSave.start();
724 
725  raw::RawDigit::ADCvector_t wvfm(dataArray[0].size());
726 
727  mf::LogDebug(fLogCategory) << " --> saving rawdigits for " << dataArray.size() << " channels" << std::endl;
728 
729  // Loop over the channels to recover the RawDigits after filtering
730  for(size_t chanIdx = 0; chanIdx != dataArray.size(); chanIdx++)
731  {
732  // Protect against case where there was no readout
733  if (channelVec[chanIdx] < 0) continue;
734 
735  const icarus_signal_processing::VectorFloat& dataVec = dataArray[chanIdx];
736 
737  // Need to convert from float to short int
738  std::transform(dataVec.begin(),dataVec.end(),wvfm.begin(),[](const auto& val){return short(std::round(val));});
739 
740  ConcurrentRawDigitCol::iterator newObjItr = rawDigitCol.emplace_back(channelVec[chanIdx],wvfm.size(),wvfm);
741  newObjItr->SetPedestal(pedestalVec[chanIdx],rmsVec[chanIdx]);
742  }//loop over channel indices
743 
744  theClockSave.stop();
745 
746  double totalTime = theClockSave.accumulated_real_time();
747 
748  mf::LogDebug(fLogCategory) << " --> done with save, time: " << totalTime << std::endl;
749  }
750 
751  return;
752 }
753 
754 //----------------------------------------------------------------------------
755 /// End job method.
756 void MCDecoderICARUSTPCwROI::endJob(art::ProcessingFrame const&)
757 {
758  mf::LogInfo(fLogCategory) << "Looked at " << fNumEvent << " events" << std::endl;
759 }
760 
761 } // end of namespace
virtual const icarus_signal_processing::ArrayFloat & getWaveLessCoherent() const =0
Recover the waveforms less coherent noise.
std::pair< unsigned int, icarus_signal_processing::ArrayFloat > PlaneIdxToImagePair
std::pair< unsigned int, ChannelVec > PlaneIdxToChannelPair
Collection of charge vs time digitized from a single readout channel.
Definition: RawDigit.h:69
std::vector< raw::RawDigit > RawDigitCollection
ChannelToBoardWirePlaneMap fChannelToBoardWirePlaneMap
const icarusDB::IICARUSChannelMap * fChannelMap
static constexpr Sample_t transform(Sample_t sample)
bool fOutputRawWaveform
Should we output pedestal corrected (not noise filtered)?
std::vector< raw::ChannelID_t > ChannelVec
std::map< unsigned int, unsigned int > ROPToNumWiresMap
virtual void produce(art::Event &e, art::ProcessingFrame const &frame)
size_t fCoherentNoiseGrouping
channels in common for coherent noise
std::vector< ChannelArrayPair > ChannelArrayPairVec
Helper functions to create a wire.
walls no right
Definition: selectors.fcl:105
This provides an art tool interface definition for tools which &quot;decode&quot; artdaq fragments into LArSoft...
virtual void endJob(art::ProcessingFrame const &frame)
End job method.
bool fOutputCorrection
Should we output the coherent noise correction vectors?
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.
ChannelID_t Channel() const
DAQ channel this raw data was read from.
Definition: RawDigit.h:212
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
std::map< geo::PlaneID, unsigned int > PlaneToROPPlaneMap
void processSingleImage(const detinfo::DetectorClocksData &, const ChannelArrayPair &, size_t, ConcurrentRawDigitCol &, ConcurrentRawDigitCol &, ConcurrentRawDigitCol &, ConcurrentWireCol &) const
virtual const icarus_signal_processing::ArrayBool & getROIVals() const =0
Recover the ROI values.
Class managing the creation of a new recob::Wire object.
Definition: WireCreator.h:53
void operator()(const tbb::blocked_range< size_t > &range) const
virtual void process_fragment(detinfo::DetectorClocksData const &, const daq::INoiseFilter::ChannelPlaneVec &, const icarus_signal_processing::ArrayFloat &, const size_t &)=0
std::pair< unsigned int, unsigned int > ChannelPlanePair
Given a set of recob hits, run DBscan to form 3D clusters.
Definition: INoiseFilter.h:53
std::map< unsigned int, icarus_signal_processing::ArrayFloat > PlaneIdxToImageMap
tbb::concurrent_vector< recob::Wire > ConcurrentWireCol
fDetProps &fDetProps fDetProps &fDetProps fLogCategory
virtual const icarus_signal_processing::VectorFloat & getTruncRMSVals() const =0
Recover the truncated RMS noise.
std::unique_ptr< RawDigitCollection > RawDigitCollectionPtr
ROPID_t ROP
Index of the readout plane within its TPC set.
std::pair< daq::INoiseFilter::ChannelPlaneVec, icarus_signal_processing::ArrayFloat > ChannelArrayPair
Collect all the RawData header files together.
std::string fOutputCoherentPath
Path to assign to the output if asked for.
std::unique_ptr< WireCollection > WireCollectionPtr
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
virtual const icarus_signal_processing::ArrayFloat & getCorrectedMedians() const =0
Recover the correction median values.
std::vector< art::InputTag > fRawDigitLabelVec
The input artdaq fragment label vector (for more than one)
walls no left
Definition: selectors.fcl:105
virtual void configure(fhicl::ParameterSet const &pset)
geo::GeometryCore const * fGeometry
pointer to Geometry service
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
Description of geometry of one entire detector.
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
IDecoderFilter interface class definiton.
Definition: INoiseFilter.h:32
Class identifying a set of planes sharing readout channels.
virtual const icarus_signal_processing::VectorFloat & getPedestalVals() const =0
Recover the pedestals for each channel.
bool fDiagnosticOutput
Set this to get lots of messages.
std::string fOutputRawWavePath
Path to assign to the output if asked for.
virtual void beginJob(art::ProcessingFrame const &frame)
Begin job method.
multiThreadImageProcessing(MCDecoderICARUSTPCwROI const &parent, detinfo::DetectorClocksData const &clockData, ChannelArrayPairVec const &channelArrayPairVec, size_t const &coherentNoiseGrouping, ConcurrentRawDigitCol &concurrentRawDigits, ConcurrentRawDigitCol &concurrentRawRawDigits, ConcurrentRawDigitCol &coherentRawDigits, ConcurrentWireCol &concurrentROIs)
std::pair< unsigned int, unsigned int > WirePlanePair
Contains all timing reference information for the detector.
std::map< unsigned int, ChannelVec > PlaneIdxToChannelMap
std::map< unsigned int, SlotChannelVecPair > TPCReadoutBoardToChannelMap
std::map< geo::PlaneID, raw::ChannelID_t > PlaneToWireOffsetMap
do i e
void processSingleLabel(art::Event &, const art::InputTag &, detinfo::DetectorClocksData const &, ChannelArrayPairVec const &, size_t const &, ConcurrentRawDigitCol &, ConcurrentRawDigitCol &, ConcurrentRawDigitCol &, ConcurrentWireCol &) const
Declaration of basic channel signal object.
virtual const icarus_signal_processing::VectorFloat & getFullRMSVals() const =0
Recover the full RMS before coherent noise.
std::vector< std::unique_ptr< INoiseFilter > > fDecoderToolVec
Decoder tools.
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
void Uncompress(const std::vector< short > &adc, std::vector< short > &uncompressed, raw::Compress_t compress)
Uncompresses a raw data buffer.
Definition: raw.cxx:776
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, BoardWirePlanePair > ChannelToBoardWirePlaneMap
std::vector< recob::Wire > WireCollection
MCDecoderICARUSTPCwROI(fhicl::ParameterSet const &pset, art::ProcessingFrame const &frame)
std::pair< unsigned int, WirePlanePair > BoardWirePlanePair
const std::string fLogCategory
Output category when logging messages.
art framework interface to geometry description
BEGIN_PROLOG could also be cout
tbb::concurrent_vector< raw::RawDigit > ConcurrentRawDigitCol
std::vector< ChannelPlanePair > ChannelPlaneVec
Definition: INoiseFilter.h:54
std::vector< std::string > fOutInstanceLabelVec
The output instance labels to apply.