All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FilterNoiseICARUS_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Class: FilterNoiseICARUS
4 // Module Type: producer
5 // File: FilterNoiseICARUS_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/make_tool.h"
32 #include "canvas/Persistency/Common/Ptr.h"
33 #include "messagefacility/MessageLogger/MessageLogger.h"
34 #include "cetlib/cpu_timer.h"
35 
36 #include "tbb/parallel_for.h"
37 #include "tbb/blocked_range.h"
38 #include "tbb/task_arena.h"
39 #include "tbb/spin_mutex.h"
40 #include "tbb/concurrent_vector.h"
41 
43 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom()
46 
47 #include "sbndaq-artdaq-core/Overlays/ICARUS/PhysCrateFragment.hh"
48 
50 
51 #include "icarus_signal_processing/ICARUSSigProcDefs.h"
52 
53 namespace daq
54 {
55 
56 class FilterNoiseICARUS : public art::ReplicatedProducer
57 {
58 public:
59 
60  // Copnstructors, destructor.
61  explicit FilterNoiseICARUS(fhicl::ParameterSet const & pset, art::ProcessingFrame const& frame);
62  virtual ~FilterNoiseICARUS();
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 ConcurrentRawDigitCol = tbb::concurrent_vector<raw::RawDigit>;
74 
75  // Function to do the work
76  void processSingleFragment(size_t,
77  detinfo::DetectorClocksData const& clockData,
78  art::Handle<artdaq::Fragments>, ConcurrentRawDigitCol&, ConcurrentRawDigitCol&, ConcurrentRawDigitCol&) const;
79 
80 private:
81 
83  {
84  public:
86  detinfo::DetectorClocksData const& clockData,
87  art::Handle<artdaq::Fragments>& fragmentsHandle,
88  ConcurrentRawDigitCol& rawDigitCollection,
89  ConcurrentRawDigitCol& rawRawDigitCollection,
90  ConcurrentRawDigitCol& coherentCollection)
91  : fFilterNoiseICARUS(parent),
92  fClockData{clockData},
93  fFragmentsHandle(fragmentsHandle),
94  fRawDigitCollection(rawDigitCollection),
95  fRawRawDigitCollection(rawRawDigitCollection),
96  fCoherentCollection(coherentCollection)
97  {}
98 
99  void operator()(const tbb::blocked_range<size_t>& range) const
100  {
101  for (size_t idx = range.begin(); idx < range.end(); idx++)
103  }
104  private:
107  art::Handle<artdaq::Fragments>& fFragmentsHandle;
111  };
112 
113  // Function to save our RawDigits
114  void saveRawDigits(const icarus_signal_processing::ArrayFloat&,
115  const icarus_signal_processing::VectorFloat&,
116  const icarus_signal_processing::VectorFloat&,
117  const icarus_signal_processing::VectorInt&,
118  ConcurrentRawDigitCol&) const;
119 
120  // Tools for decoding fragments depending on type
121  std::vector<std::unique_ptr<IDecoderFilter>> fDecoderToolVec; ///< Decoder tools
122 
123  // Fcl parameters.
124  art::InputTag fFragmentsLabel; ///< The input artdaq fragment label
125  bool fOutputPedestalCor; ///< Should we output pedestal corrected (not noise filtered)?
126  bool fOutputCorrection; ///< Should we output the coherent noise correction vectors?
127  std::string fOutputPedCorPath; ///< Path to assign to the output if asked for
128  std::string fOutputCoherentPath; ///< Path to assign to the output if asked for
129  unsigned int fPlaneToSimulate; ///< Use to get fragment offset
130 
131  // Statistics.
132  int fNumEvent; ///< Number of events seen.
133 
134  size_t fFragmentOffset; ///< The fragment offset to set channel numbering
135 
136  // Useful services, keep copies for now (we can update during begin run periods)
137  geo::GeometryCore const* fGeometry; ///< pointer to Geometry service
138 };
139 
140 DEFINE_ART_MODULE(FilterNoiseICARUS)
141 
142 //----------------------------------------------------------------------------
143 /// Constructor.
144 ///
145 /// Arguments:
146 ///
147 /// pset - Fcl parameters.
148 ///
149 FilterNoiseICARUS::FilterNoiseICARUS(fhicl::ParameterSet const & pset, art::ProcessingFrame const& frame) :
150  art::ReplicatedProducer(pset, frame),
151  fNumEvent(0)
152 {
153  fGeometry = lar::providerFrom<geo::Geometry>();
154 
155  configure(pset);
156 
157  // Check the concurrency
158  int max_concurrency = tbb::this_task_arena::max_concurrency();
159 
160  mf::LogDebug("FilterNoiseICARUS") << " ==> concurrency: " << max_concurrency << std::endl;
161 
162  // Recover the vector of fhicl parameters for the ROI tools
163  const fhicl::ParameterSet& decoderToolParams = pset.get<fhicl::ParameterSet>("DecoderTool");
164 
165  fDecoderToolVec.resize(max_concurrency);
166 
167  for(auto& decoderTool : fDecoderToolVec)
168  {
169  // Get instance of tool
170  decoderTool = art::make_tool<IDecoderFilter>(decoderToolParams);
171  }
172 
173  // Compute the fragment offset from the channel number for the desired plane
174  // Get a base channel number for the plane we want
175  mf::LogDebug("FilterNoiseICARUS") << "ICARUS has " << fGeometry->Nchannels() << " in total with " << fGeometry->Views().size() << " views" << std::endl;
176 
177  geo::WireID wireID(0, 0, fPlaneToSimulate, 0);
178 
179  mf::LogDebug("FilterNoiseICARUS") << "WireID: " << wireID << std::endl;
180 
181  geo::WireID firstWireID = fGeometry->GetBeginWireID(geo::PlaneID(0,0,fPlaneToSimulate));
182 
183  mf::LogDebug("FilterNoiseICARUS") << "From geo, first WireID: " << firstWireID << std::endl;
184 
185  raw::ChannelID_t channel = fGeometry->PlaneWireToChannel(wireID);
186 
187  mf::LogDebug("FilterNoiseICARUS") << "Channel: " << channel << std::endl;
188 
189  for(size_t thePlane = 0; thePlane < 3; thePlane++)
190  {
191  geo::WireID tempWireID(0, 0, thePlane, 0);
192  geo::PlaneID tempPlaneID = tempWireID.planeID();
193 
194  mf::LogDebug("FilterNoiseICARUS") << "thePlane: " << thePlane << ", WireID: " << tempWireID << ", channel: " <<
195  fGeometry->PlaneWireToChannel(tempWireID) << ", view: " << fGeometry->View(tempPlaneID) << std::endl;
196  }
197 
198  fFragmentOffset = channel / 576;
199 
200  produces<std::vector<raw::RawDigit>>();
201 
202  if (fOutputPedestalCor)
203  produces<std::vector<raw::RawDigit>>(fOutputPedCorPath);
204 
205  if (fOutputCorrection)
206  produces<std::vector<raw::RawDigit>>(fOutputCoherentPath);
207 
208  // Report.
209  mf::LogInfo("FilterNoiseICARUS") << "FilterNoiseICARUS configured\n";
210 }
211 
212 //----------------------------------------------------------------------------
213 /// Destructor.
215 {}
216 
217 //----------------------------------------------------------------------------
218 /// Reconfigure method.
219 ///
220 /// Arguments:
221 ///
222 /// pset - Fcl parameter set.
223 ///
224 void FilterNoiseICARUS::configure(fhicl::ParameterSet const & pset)
225 {
226  fFragmentsLabel = pset.get<art::InputTag>("FragmentsLabel", "daq:PHYSCRATEDATA");
227  fOutputPedestalCor = pset.get<bool >("OutputPedestalCor", false);
228  fOutputCorrection = pset.get<bool >("OutputCorrection", false);
229  fOutputPedCorPath = pset.get<std::string >("OutputPedCorPath", "RAW");
230  fOutputCoherentPath = pset.get<std::string >("OutputCoherentPath", "Cor");
231  fPlaneToSimulate = pset.get<unsigned int >("PlaneToSimulate", 2);
232 }
233 
234 //----------------------------------------------------------------------------
235 /// Begin job method.
236 void FilterNoiseICARUS::beginJob(art::ProcessingFrame const&)
237 {
238  return;
239 }
240 
241 //----------------------------------------------------------------------------
242 /// Produce method.
243 ///
244 /// Arguments:
245 ///
246 /// evt - Art event.
247 ///
248 /// This is the primary method.
249 ///
250 void FilterNoiseICARUS::produce(art::Event & event, art::ProcessingFrame const&)
251 {
252  ++fNumEvent;
253 
254  art::Handle<artdaq::Fragments> daq_handle;
255  event.getByLabel(fFragmentsLabel, daq_handle);
256 
257  mf::LogDebug("FilterNoiseICARUS") << "**** Processing raw data fragments ****" << std::endl;
258 
259  // Check the concurrency
260  int max_concurrency = tbb::this_task_arena::max_concurrency();
261 
262  mf::LogDebug("FilterNoiseICARUS") << " ==> concurrency: " << max_concurrency << std::endl;
263 
264  cet::cpu_timer theClockTotal;
265 
266  theClockTotal.start();
267 
268  ConcurrentRawDigitCol concurrentRawDigits;
269  ConcurrentRawDigitCol concurrentRawRawDigits;
270  ConcurrentRawDigitCol coherentRawDigits;
271 
272  // ... Launch multiple threads with TBB to do the deconvolution and find ROIs in parallel
273  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService>()->DataFor(event);
274  multiThreadFragmentProcessing fragmentProcessing(*this,
275  clockData,
276  daq_handle,
277  concurrentRawDigits,
278  concurrentRawRawDigits,
279  coherentRawDigits);
280 
281  tbb::parallel_for(tbb::blocked_range<size_t>(0, daq_handle->size()), fragmentProcessing);
282 
283  // Copy the raw digits from the concurrent vector to our output vector
284  RawDigitCollectionPtr rawDigitCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(concurrentRawDigits.begin()),
285  std::move_iterator(concurrentRawDigits.end()));
286 
287  // Want the RawDigits to be sorted in channel order... has to be done somewhere so why not now?
288  std::sort(rawDigitCollection->begin(),rawDigitCollection->end(),[](const auto& left,const auto&right){return left.Channel() < right.Channel();});
289 
290  // Now transfer ownership to the event store
291  event.put(std::move(rawDigitCollection));
292 
293  if (fOutputPedestalCor)
294  {
295  // Copy the raw digits from the concurrent vector to our output vector
296  RawDigitCollectionPtr rawRawDigitCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(concurrentRawRawDigits.begin()),
297  std::move_iterator(concurrentRawRawDigits.end()));
298  // Want the RawDigits to be sorted in channel order... has to be done somewhere so why not now?
299  std::sort(rawRawDigitCollection->begin(),rawRawDigitCollection->end(),[](const auto& left,const auto&right){return left.Channel() < right.Channel();});
300 
301  // Now transfer ownership to the event store
302  event.put(std::move(rawRawDigitCollection),fOutputPedCorPath);
303  }
304 
305  if (fOutputCorrection)
306  {
307  // Copy the raw digits from the concurrent vector to our output vector
308  RawDigitCollectionPtr coherentCollection = std::make_unique<std::vector<raw::RawDigit>>(std::move_iterator(coherentRawDigits.begin()),
309  std::move_iterator(coherentRawDigits.end()));
310  // Want the RawDigits to be sorted in channel order... has to be done somewhere so why not now?
311  std::sort(coherentCollection->begin(),coherentCollection->end(),[](const auto& left,const auto&right){return left.Channel() < right.Channel();});
312 
313  // Now transfer ownership to the event store
314  event.put(std::move(coherentCollection),fOutputCoherentPath);
315  }
316 
317  theClockTotal.stop();
318 
319  double totalTime = theClockTotal.accumulated_real_time();
320 
321  mf::LogInfo("FilterNoiseICARUS") << "==> FilterNoiseICARUS total time: " << totalTime << std::endl;
322 
323  return;
324 }
325 
327  detinfo::DetectorClocksData const& clockData,
328  art::Handle<artdaq::Fragments> fragmentHandle,
329  ConcurrentRawDigitCol& rawDigitCollection,
330  ConcurrentRawDigitCol& rawRawDigitCollection,
331  ConcurrentRawDigitCol& coherentCollection) const
332 {
333  cet::cpu_timer theClockProcess;
334 
335  theClockProcess.start();
336 
337  art::Ptr<artdaq::Fragment> fragmentPtr(fragmentHandle, idx);
338 
339  mf::LogDebug("FilterNoiseICARUS") << "--> Processing fragment ID: " << fragmentPtr->fragmentID() << std::endl;
340  mf::LogDebug("FilterNoiseICARUS") << " ==> Current thread index: " << tbb::this_task_arena::current_thread_index() << std::endl;
341 
342  // Recover pointer to the decoder needed here
343  IDecoderFilter* decoderTool = fDecoderToolVec[tbb::this_task_arena::current_thread_index()].get();
344 
345  //process_fragment(event, rawfrag, product_collection, header_collection);
346  decoderTool->process_fragment(clockData, *fragmentPtr);
347 
348  // Useful numerology
349  // convert fragment to Nevis fragment
350  icarus::PhysCrateFragment physCrateFragment(*fragmentPtr);
351 
352 // size_t nBoardsPerFragment = physCrateFragment.nBoards();
353 // size_t nChannelsPerBoard = physCrateFragment.nChannelsPerBoard();
354 
355  // Set base channel for both the board and the board/fragment
356 // size_t boardFragOffset = nChannelsPerBoard * nBoardsPerFragment * (fragmentPtr->fragmentID() + fFragmentOffset);
357 
358  theClockProcess.stop();
359 
360  double totalTime = theClockProcess.accumulated_real_time();
361 
362  // Save the filtered RawDigitsactive but for corrected raw digits pedestal is zero
363  const icarus_signal_processing::VectorFloat locPedsVec(decoderTool->getWaveLessCoherent().size(),0.);
364  const icarus_signal_processing::VectorInt& channelVec = decoderTool->getChannelIDs();
365 
366  saveRawDigits(decoderTool->getWaveLessCoherent(),locPedsVec,decoderTool->getTruncRMSVals(), channelVec, rawDigitCollection);
367 
368  // Optionally, save the pedestal corrected RawDigits
369  if (fOutputPedestalCor)
370  saveRawDigits(decoderTool->getRawWaveforms(),decoderTool->getPedestalVals(),decoderTool->getFullRMSVals(),channelVec, rawRawDigitCollection);
371 
372  // Also optional is to output the coherent corrections (note there will be many fewer of these! )
373  if (fOutputPedestalCor)
374  saveRawDigits(decoderTool->getCorrectedMedians(),decoderTool->getPedestalVals(),decoderTool->getFullRMSVals(),channelVec,coherentCollection);
375 
376  mf::LogDebug("FilterNoiseICARUS") << "--> Exiting fragment processing for thread: " << tbb::this_task_arena::current_thread_index() << ", time: " << totalTime << std::endl;
377  return;
378 }
379 
380 void FilterNoiseICARUS::saveRawDigits(const icarus_signal_processing::ArrayFloat& dataArray,
381  const icarus_signal_processing::VectorFloat& pedestalVec,
382  const icarus_signal_processing::VectorFloat& rmsVec,
383  const icarus_signal_processing::VectorInt& channelVec,
384  ConcurrentRawDigitCol& rawDigitCol) const
385 {
386  if (!dataArray.empty())
387  {
388  cet::cpu_timer theClockSave;
389 
390  theClockSave.start();
391 
392  raw::RawDigit::ADCvector_t wvfm(dataArray[0].size());
393 
394  mf::LogDebug("FilterNoiseICARUS") << " --> saving rawdigits for " << dataArray.size() << " channels" << std::endl;
395 
396  // Loop over the channels to recover the RawDigits after filtering
397  for(size_t chanIdx = 0; chanIdx != dataArray.size(); chanIdx++)
398  {
399  const icarus_signal_processing::VectorFloat& dataVec = dataArray[chanIdx];
400 
401  // Need to convert from float to short int
402  std::transform(dataVec.begin(),dataVec.end(),wvfm.begin(),[](const auto& val){return short(std::round(val));});
403 
404  ConcurrentRawDigitCol::iterator newObjItr = rawDigitCol.emplace_back(channelVec[chanIdx],wvfm.size(),wvfm);
405  newObjItr->SetPedestal(pedestalVec[chanIdx],rmsVec[chanIdx]);
406  }//loop over channel indices
407 
408  theClockSave.stop();
409 
410  double totalTime = theClockSave.accumulated_real_time();
411 
412  mf::LogDebug("FilterNoiseICARUS") << " --> done with save, time: " << totalTime << std::endl;
413  }
414 
415  return;
416 }
417 
418 //----------------------------------------------------------------------------
419 /// End job method.
420 void FilterNoiseICARUS::endJob(art::ProcessingFrame const&)
421 {
422  mf::LogInfo("FilterNoiseICARUS") << "Looked at " << fNumEvent << " events" << std::endl;
423 }
424 
425 } // end of namespace
std::string fOutputCoherentPath
Path to assign to the output if asked for.
std::vector< std::unique_ptr< IDecoderFilter > > fDecoderToolVec
Decoder tools.
virtual void beginJob(art::ProcessingFrame const &frame)
Begin job method.
virtual const icarus_signal_processing::VectorFloat getTruncRMSVals() const =0
Recover the truncated RMS noise.
Utilities related to art service access.
static constexpr Sample_t transform(Sample_t sample)
virtual const icarus_signal_processing::VectorInt getChannelIDs() const =0
Recover the channels for the processed fragment.
std::vector< raw::RawDigit > RawDigitCollection
tbb::concurrent_vector< raw::RawDigit > ConcurrentRawDigitCol
art::InputTag fFragmentsLabel
The input artdaq fragment label.
walls no right
Definition: selectors.fcl:105
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
std::unique_ptr< RawDigitCollection > RawDigitCollectionPtr
std::vector< short > ADCvector_t
Type representing a (compressed) vector of ADC counts.
Definition: RawDigit.h:73
IDecoderFilter interface class definiton.
size_t fFragmentOffset
The fragment offset to set channel numbering.
Definition of basic raw digits.
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
FilterNoiseICARUS(fhicl::ParameterSet const &pset, art::ProcessingFrame const &frame)
int fNumEvent
Number of events seen.
virtual const icarus_signal_processing::ArrayFloat getWaveLessCoherent() const =0
Recover the waveforms less coherent noise.
This provides an art tool interface definition for tools which &quot;decode&quot; artdaq fragments into LArSoft...
unsigned int fPlaneToSimulate
Use to get fragment offset.
virtual void process_fragment(detinfo::DetectorClocksData const &clockData, const artdaq::Fragment &fragment)=0
Given a set of recob hits, run DBscan to form 3D clusters.
virtual ~FilterNoiseICARUS()
Destructor.
bool fOutputPedestalCor
Should we output pedestal corrected (not noise filtered)?
virtual const icarus_signal_processing::ArrayFloat getCorrectedMedians() const =0
Recover the correction median values.
virtual void endJob(art::ProcessingFrame const &frame)
End job method.
std::string fOutputPedCorPath
Path to assign to the output if asked for.
virtual void produce(art::Event &e, art::ProcessingFrame const &frame)
multiThreadFragmentProcessing(FilterNoiseICARUS const &parent, detinfo::DetectorClocksData const &clockData, art::Handle< artdaq::Fragments > &fragmentsHandle, ConcurrentRawDigitCol &rawDigitCollection, ConcurrentRawDigitCol &rawRawDigitCollection, ConcurrentRawDigitCol &coherentCollection)
walls no left
Definition: selectors.fcl:105
Description of geometry of one entire detector.
geo::GeometryCore const * fGeometry
pointer to Geometry service
bool fOutputCorrection
Should we output the coherent noise correction vectors?
virtual void configure(fhicl::ParameterSet const &pset)
Contains all timing reference information for the detector.
virtual const icarus_signal_processing::VectorFloat getFullRMSVals() const =0
Recover the full RMS before coherent noise.
void processSingleFragment(size_t, detinfo::DetectorClocksData const &clockData, art::Handle< artdaq::Fragments >, ConcurrentRawDigitCol &, ConcurrentRawDigitCol &, ConcurrentRawDigitCol &) const
do i e
virtual const icarus_signal_processing::VectorFloat getPedestalVals() const =0
Recover the pedestals for each channel.
void operator()(const tbb::blocked_range< size_t > &range) const
void saveRawDigits(const icarus_signal_processing::ArrayFloat &, const icarus_signal_processing::VectorFloat &, const icarus_signal_processing::VectorFloat &, const icarus_signal_processing::VectorInt &, ConcurrentRawDigitCol &) const
virtual const icarus_signal_processing::ArrayFloat getRawWaveforms() const =0
Recover the original raw waveforms.
constexpr PlaneID const & planeID() const
Definition: geo_types.h:638
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
art framework interface to geometry description