All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ROIFinder_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // ROIFinder class - An ROI finding module for complete deconvolved waveforms
4 //
5 // usher@slac.stanford.edu
6 //
7 ////////////////////////////////////////////////////////////////////////
8 
9 // C/C++ standard libraries
10 #include <string>
11 #include <vector>
12 #include <utility> // std::pair<>
13 #include <memory> // std::unique_ptr<>
14 #include <iomanip>
15 #include <fstream>
16 #include <random>
17 
18 // framework libraries
19 #include "fhiclcpp/ParameterSet.h"
20 #include "messagefacility/MessageLogger/MessageLogger.h"
21 #include "art/Framework/Core/ModuleMacros.h"
22 #include "art/Framework/Core/EDProducer.h"
23 #include "art/Framework/Principal/Event.h"
24 #include "art/Framework/Principal/Handle.h"
25 #include "art/Utilities/make_tool.h"
26 #include "canvas/Persistency/Common/Ptr.h"
27 #include "canvas/Persistency/Common/PtrVector.h"
28 #include "art/Framework/Services/Registry/ServiceHandle.h"
29 #include "art_root_io/TFileService.h"
30 #include "canvas/Utilities/Exception.h"
31 
32 #include "cetlib_except/coded_exception.h"
33 
34 // LArSoft libraries
35 #include "larcoreobj/SimpleTypesAndConstants/RawTypes.h" // raw::ChannelID_t
38 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom()
44 
47 
49 
50 #include "icarus_signal_processing/WaveformTools.h"
51 #include "icarus_signal_processing/Denoising.h"
52 
54 
55 #include "tbb/parallel_for.h"
56 #include "tbb/blocked_range.h"
57 #include "tbb/task_arena.h"
58 #include "tbb/spin_mutex.h"
59 #include "tbb/concurrent_hash_map.h"
60 
61 
62 namespace {
63 
64  /// Helper: lazily returns the expanded content of a set of `recob::Wires`.
65 struct PlaneWireData
66 {
67  std::size_t size() const { return wires.size(); }
68  void resize(std::size_t nWires)
69  { wires.clear(); wires.resize(nWires, nullptr); }
70  void addWire(std::size_t iWire, recob::Wire const& wire)
71  { wires.at(iWire) = &wire; }
72  icarus_signal_processing::ArrayFloat operator() () const
73  {
74  icarus_signal_processing::ArrayFloat data;
75  data.resize(wires.size());
76  for (auto [ iWire, wire ]: util::enumerate(wires))
77  {
78  if (wire) data[iWire] = wire->Signal();
79  else data[iWire] = std::vector<float>(4096,0.);
80  }
81  return data;
82  }
83  const recob::Wire* getWirePtr(size_t idx) const {return wires[idx];}
84 private:
85  std::vector<recob::Wire const*> wires;
86 }; // PlaneWireData
87 
88 } // local namespace
89 
90 
91 ///creation of calibrated signals on wires
92 namespace caldata {
93 
94  tbb::spin_mutex roifinderSpinMutex;
95 
96 class ROIFinder : public art::EDProducer
97 {
98 public:
99 // create calibrated signals on wires. this class runs
100 // an fft to remove the electronics shaping.
101  explicit ROIFinder(fhicl::ParameterSet const& pset);
102  virtual ~ROIFinder();
103  void produce(art::Event& evt);
104  void beginJob();
105  void endJob();
106  void reconfigure(fhicl::ParameterSet const& p);
107 private:
108  using PlaneIDToDataPair = std::pair<std::vector<raw::ChannelID_t>,PlaneWireData>;
109  using PlaneIDToDataPairMap = std::map<geo::PlaneID,PlaneIDToDataPair>;
110  using PlaneIDVec = std::vector<geo::PlaneID>;
111 
112  // Define a class to handle processing for individual threads
114  {
115  public:
117  art::Event& event,
118  const PlaneIDVec& planeIDVec,
119  const PlaneIDToDataPairMap& planeIDToDataPairMap,
120  std::vector<recob::Wire>& wireColVec,
121  std::vector<recob::Wire>& morphedVec,
122  std::vector<recob::ChannelROI>& channelROIVec)
123  : fROIFinder(parent),
124  fEvent(event),
125  fPlaneIDVec(planeIDVec),
126  fPlaneIDToDataPairMap(planeIDToDataPairMap),
127  fWireColVec(wireColVec),
128  fMorphedVec(morphedVec),
129  fChannelROIVec(channelROIVec)
130  {}
131  void operator()(const tbb::blocked_range<size_t>& range) const
132  {
133  for (size_t idx = range.begin(); idx < range.end(); idx++)
135  }
136  private:
138  art::Event& fEvent;
141  std::vector<recob::Wire>& fWireColVec;
142  std::vector<recob::Wire>& fMorphedVec;
143  std::vector<recob::ChannelROI>& fChannelROIVec;
144  };
145 
146  // Function to do the work
147  void processPlane(size_t,
148  art::Event&,
149  const PlaneIDVec&,
150  const PlaneIDToDataPairMap&,
151  std::vector<recob::Wire>&,
152  std::vector<recob::Wire>&,
153  std::vector<recob::ChannelROI>&) const;
154 
155  // This is for the baseline...
156  float getMedian(const icarus_signal_processing::VectorFloat, const unsigned int) const;
157 
158  std::vector<art::InputTag> fWireModuleLabelVec; ///< vector of modules that made digits
159  std::vector<std::string> fOutInstanceLabelVec; ///< The output instance labels to apply
160  bool fCorrectROIBaseline; ///< Correct the ROI baseline
161  size_t fMinSizeForCorrection; ///< Minimum ROI length to do correction
162  size_t fMaxSizeForCorrection; ///< Maximum ROI length for baseline correction
163  bool fOutputMorphed; ///< Output the morphed waveforms
164  bool fDiagnosticOutput; ///< secret diagnostics flag
165  bool fOutputHistograms; ///< Output tuples/histograms?
166  size_t fEventCount; ///< count of event processed
167 
168  std::map<size_t,std::unique_ptr<icarus_tool::IROILocator>> fROIToolMap;
169 
170  const geo::GeometryCore* fGeometry = lar::providerFrom<geo::Geometry>();
171 
172 }; // class ROIFinder
173 
174 DEFINE_ART_MODULE(ROIFinder)
175 
176 //-------------------------------------------------
177 ROIFinder::ROIFinder(fhicl::ParameterSet const& pset) : EDProducer{pset}
178 {
179  this->reconfigure(pset);
180 
181  for(const auto& wireLabel : fOutInstanceLabelVec)
182  {
183  produces< std::vector<recob::Wire>>(wireLabel);
184  produces< std::vector<recob::ChannelROI>>(wireLabel);
185 
186  if (fOutputMorphed) produces<std::vector<recob::Wire>>(wireLabel+ "M");
187  }
188 }
189 
190 //-------------------------------------------------
192 {
193 }
194 
195 //////////////////////////////////////////////////////
196 void ROIFinder::reconfigure(fhicl::ParameterSet const& pset)
197 {
198  // Recover the parameters
199  fWireModuleLabelVec = pset.get<std::vector<art::InputTag>>("WireModuleLabelVec", std::vector<art::InputTag>()={"decon1droi"});
200  fOutInstanceLabelVec = pset.get<std::vector<std::string>> ("OutInstanceLabelVec", {"PHYSCRATEDATA"});
201  fCorrectROIBaseline = pset.get<bool >("CorrectROIBaseline", false);
202  fMinSizeForCorrection = pset.get<size_t >("MinSizeForCorrection", 12);
203  fMaxSizeForCorrection = pset.get<size_t >("MaxSizeForCorrection", 512);
204  fOutputMorphed = pset.get< bool >("OutputMorphed", true);
205  fDiagnosticOutput = pset.get< bool >("DaignosticOutput", false);
206  fOutputHistograms = pset.get< bool >("OutputHistograms", false);
207 
208  // Access ART's TFileService, which will handle creating and writing
209  // histograms and n-tuples for us.
210  art::ServiceHandle<art::TFileService> tfs;
211 
212  // Recover the list of ROI finding tools
213  const fhicl::ParameterSet& roiFinderTools = pset.get<fhicl::ParameterSet>("ROIFinderToolVec");
214 
215  // Make a mapping between plane id and a plane's ROI finder
216  // This allows different ROI finders per plane but, more important, different parameters
217  for(const std::string& roiFinderTool : roiFinderTools.get_pset_names())
218  {
219  const fhicl::ParameterSet& roiFinderToolParamSet = roiFinderTools.get<fhicl::ParameterSet>(roiFinderTool);
220  size_t planeIdx = roiFinderToolParamSet.get<size_t>("Plane");
221 
222  fROIToolMap[planeIdx] = art::make_tool<icarus_tool::IROILocator> (roiFinderToolParamSet);
223 
224  if (fOutputHistograms)
225  {
226  std::string dirName = "ROIFinder_" + std::to_string(planeIdx);
227 
228  art::TFileDirectory dir = tfs->mkdir(dirName);
229 
230  fROIToolMap[planeIdx]->initializeHistograms(dir);
231  }
232  }
233 
234  return;
235 }
236 
237 //-------------------------------------------------
239 {
240  fEventCount = 0;
241 } // beginJob
242 
243 //////////////////////////////////////////////////////
245 {
246 }
247 
248 //////////////////////////////////////////////////////
249 void ROIFinder::produce(art::Event& evt)
250 {
251  // We need to loop through the list of Wire data we have been given
252  for(size_t labelIdx = 0; labelIdx < fWireModuleLabelVec.size(); labelIdx++)
253  {
254  const art::InputTag& wireLabel = fWireModuleLabelVec[labelIdx];
255 
256  // make a collection of Wires
257  std::unique_ptr<std::vector<recob::Wire>> wireCol(new std::vector<recob::Wire>);
258 
259  std::unique_ptr<std::vector<recob::Wire>> morphedCol(new std::vector<recob::Wire>);
260 
261  // make a collection of ChannelROI objects
262  std::unique_ptr<std::vector<recob::ChannelROI>> channelROICol(new std::vector<recob::ChannelROI>);
263 
264  mf::LogInfo("ROIFinder") << "ROIFinder, looking for decon1droi data at " << wireLabel << std::endl;
265 
266  // Read in the collection of full length deconvolved waveforms
267  // Note we assume this list is sorted in increasing channel number!
268  art::Handle< std::vector<recob::Wire>> wireVecHandle;
269 
270  evt.getByLabel(wireLabel, wireVecHandle);
271 
272  mf::LogInfo("ROIFinder") << "--> Recovered wire data, size: " << wireVecHandle->size() << std::endl;
273 
274  if (!wireVecHandle->size())
275  {
276  evt.put(std::move(wireCol), wireLabel.instance());
277  fEventCount++;
278 
279  return;
280  }
281 
282  // The first step is to break up into groups by logical TPC/plane in order to do the parallel loop
283  PlaneIDToDataPairMap planeIDToDataPairMap;
284  PlaneIDVec planeIDVec;
285  size_t numChannels(0);
286 
287  for(const auto& wire : *wireVecHandle)
288  {
289  raw::ChannelID_t channel = wire.Channel();
290 
291  std::vector<geo::WireID> wireIDVec = fGeometry->ChannelToWire(channel);
292 
293  if (wireIDVec.empty()) continue;
294 
295  for(const auto& wireID : wireIDVec)
296  {
297  const geo::PlaneID& planeID = wireID.planeID();
298 
299  PlaneIDToDataPairMap::iterator mapItr = planeIDToDataPairMap.find(planeID);
300 
301  // Make sure the array is initialized
302  if (mapItr == planeIDToDataPairMap.end())
303  {
304  unsigned int nWires = fGeometry->Nwires(planeID);
305 
306  std::pair<PlaneIDToDataPairMap::iterator,bool> mapInsert = planeIDToDataPairMap.insert({planeID,PlaneIDToDataPair()});
307 
308  if (!mapInsert.second) std::cout << "Failed to insert, is this possible?" << std::endl;
309 
310  mapItr = mapInsert.first;
311 
312  mapItr->second.first.resize(nWires);
313  mapItr->second.second.resize(nWires);
314 
315  planeIDVec.emplace_back(planeID);
316  }
317 
318  // Add waveform to the 2D array
319  mapItr->second.first[wireID.Wire] = channel;
320  mapItr->second.second.addWire(wireID.Wire, wire);
321  numChannels++;
322  }
323  }
324 
325  // We might need this... it allows a temporary wire object to prevent crashes when some data is missing
326  std::vector<recob::Wire> tempWireVec(numChannels/4);
327 
328  // Check integrity of map
329  for(auto& mapInfo : planeIDToDataPairMap)
330  {
331  const std::vector<raw::ChannelID_t>& channelVec = mapInfo.second.first;
332  const icarus_signal_processing::ArrayFloat& dataArray = mapInfo.second.second();
333 
334  for(size_t idx = 0; idx < channelVec.size(); idx++)
335  {
336  if (dataArray[idx].size() < 100)
337  {
338  mf::LogInfo("ROIFinder") << " **> Found truncated wire, size: " << dataArray[idx].size() << ", channel: " << channelVec[idx] << std::endl;
339 
340  std::vector<float> zeroVec(4096,0.);
342 
343  ROIVec.add_range(0, std::move(zeroVec));
344 
345  std::vector<geo::WireID> wireIDVec = fGeometry->ChannelToWire(channelVec[idx]);
346 
347  // Given channel a large number so we know to not save
348  mapInfo.second.first[idx] = 100000 + idx;
349 
350  tempWireVec.emplace_back(recob::WireCreator(std::move(ROIVec),idx,fGeometry->View(wireIDVec[0].planeID())).move());
351 
352  mapInfo.second.second.addWire(idx,tempWireVec.back());
353  }
354  }
355  }
356 
357  // Reserve the room for the output
358  wireCol->reserve(wireVecHandle->size());
359 
360  // ... Launch multiple threads with TBB to do the deconvolution and find ROIs in parallel
361  multiThreadDeconvolutionProcessing deconvolutionProcessing(*this, evt, planeIDVec, planeIDToDataPairMap, *wireCol, *morphedCol, *channelROICol);
362 
363  tbb::parallel_for(tbb::blocked_range<size_t>(0, planeIDVec.size()), deconvolutionProcessing);
364 
365  // Time to stroe everything
366  if(wireCol->size() == 0) mf::LogWarning("ROIFinder") << "No wires made for this event.";
367 
368  evt.put(std::move(wireCol), fOutInstanceLabelVec[labelIdx]);
369  evt.put(std::move(channelROICol), fOutInstanceLabelVec[labelIdx]);
370 
371  if (fOutputMorphed) evt.put(std::move(morphedCol), fOutInstanceLabelVec[labelIdx]+"M");
372  }
373 
374  fEventCount++;
375 
376  return;
377 } // produce
378 
379 void ROIFinder::processPlane(size_t idx,
380  art::Event& event,
381  const PlaneIDVec& planeIDVec,
382  const PlaneIDToDataPairMap& planeIDToDataPairMap,
383  std::vector<recob::Wire>& wireColVec,
384  std::vector<recob::Wire>& morphedVec,
385  std::vector<recob::ChannelROI>& channelROIVec) const
386 {
387  // Recover the planeID for this thread
388  const geo::PlaneID& planeID = planeIDVec[idx];
389 
390  // And the data array
391  PlaneIDToDataPairMap::const_iterator mapItr = planeIDToDataPairMap.find(planeID);
392 
393  if (mapItr == planeIDToDataPairMap.end())
394  {
395  std::cout << "We know this cannot happen" << std::endl;
396  return;
397  }
398 
399  const PlaneIDToDataPair& planeIDToDataPair = mapItr->second;
400 
401  const icarus_signal_processing::ArrayFloat& dataArray = planeIDToDataPair.second();
402  const std::vector<raw::ChannelID_t>& channelVec = planeIDToDataPair.first;
403 
404  // Keep track of our selected values
405  icarus_signal_processing::ArrayFloat outputArray(dataArray.size(),icarus_signal_processing::VectorFloat(dataArray[0].size(),0.));
406  icarus_signal_processing::ArrayBool selectedVals(dataArray.size(),icarus_signal_processing::VectorBool(dataArray[0].size(),false));
407 
408  fROIToolMap.at(planeID.Plane)->FindROIs(event, dataArray, channelVec, mapItr->first, outputArray, selectedVals);
409 
410 // icarus_signal_processing::ArrayFloat morphedWaveforms(dataArray.size());
411 
412  // Copy the "morphed" array
413  if (fOutputMorphed)
414  {
415  for(size_t waveIdx = 0; waveIdx < outputArray.size(); waveIdx++)
416  {
417  // skip if a bad channbel
418  if (channelVec[idx] >= 100000) continue;
419 
420  // First get a lock to make sure we don't conflict
421  tbb::spin_mutex::scoped_lock lock(roifinderSpinMutex);
422 
424 
425  ROIVec.add_range(0, std::move(outputArray[waveIdx]));
426 
427  raw::ChannelID_t channel = channelVec[waveIdx];
428  geo::View_t view = fGeometry->View(channel);
429 
430  std::vector<geo::WireID> chanIDVec = fGeometry->ChannelToWire(channel);
431 
432  morphedVec.push_back(recob::WireCreator(std::move(ROIVec),channel,view).move());
433  }
434  }
435 
436  // Ok, now go through the refined selected values array and find ROIs
437  // Define the ROI and its container
438  using CandidateROI = std::pair<size_t, size_t>;
439  using CandidateROIVec = std::vector<CandidateROI>;
440 
441  size_t leadTrail(0);
442 
443  for(size_t waveIdx = 0; waveIdx < selectedVals.size(); waveIdx++)
444  {
445  // Skip if a bad channel
446  if (channelVec[waveIdx] >= 100000)
447  {
448  std::cout << "==> found an unexpected channel number: " << channelVec[waveIdx] << std::endl;
449  continue;
450  }
451 
452  // Set up an object...
453  CandidateROIVec candidateROIVec;
454 
455  // Search for ROIs in current waveform
456  const icarus_signal_processing::VectorBool& selVals = selectedVals[waveIdx];
457 
458  size_t idx(2);
459 
460  while(idx < selVals.size())
461  {
462  if (selVals[idx])
463  {
464  Size_t startTick = idx >= leadTrail ? idx - leadTrail : 0;
465 
466  while(idx < selVals.size() && selVals[idx]) idx++;
467 
468  size_t stopTick = idx < selVals.size() - leadTrail ? idx + leadTrail : selVals.size();
469 
470  candidateROIVec.emplace_back(startTick, stopTick);
471  }
472 
473  idx++;
474  }
475 
476  // merge overlapping (or touching) ROI's
477  if(candidateROIVec.size() > 1)
478  {
479  // temporary vector for merged ROIs
480  CandidateROIVec tempRoiVec;
481 
482  // Loop through candidate roi's
483  size_t startRoi = candidateROIVec.front().first;
484  size_t stopRoi = candidateROIVec.front().second; //startRoi;
485 
486  for(auto& roi : candidateROIVec)
487  {
488  // Should we merge roi's?
489  if (roi.first <= stopRoi)
490  {
491  // Make sure the merge gets the right start/end times
492  startRoi = std::min(startRoi,roi.first);
493  stopRoi = std::max(stopRoi,roi.second);
494  }
495  else
496  {
497  tempRoiVec.emplace_back(startRoi,stopRoi);
498 
499  startRoi = roi.first;
500  stopRoi = roi.second;
501  }
502  }
503 
504  // Make sure to get the last one
505  tempRoiVec.emplace_back(startRoi,stopRoi);
506 
507  candidateROIVec = tempRoiVec;
508  }
509 
510  // If no candidates no need for further effort
511  if (!candidateROIVec.empty())
512  {
513  // vector that will be moved into the Wire object
516 
517  // Check if we have possible overlap wires where we need to merge the previous results with new results
518  if (planeID.Plane > 0)
519  {
520  raw::ChannelID_t channel = channelVec[waveIdx];
521 
522  std::vector<geo::WireID> wireIDVec = fGeometry->ChannelToWire(channel);
523 
524  if (wireIDVec.size() > 1)
525  {
526  std::vector<recob::Wire>::iterator wireItr = std::find_if(wireColVec.begin(),wireColVec.end(),[channel](const auto& wire){return wire.Channel() == channel;});
527 
528  if (wireItr != wireColVec.end())
529  {
530  ROIVec = wireItr->SignalROI();
531 
532  // Avoid duplicate entries by erasing the previous instance
533  wireColVec.erase(wireItr);
534  }
535 
536  std::vector<recob::ChannelROI>::iterator channelItr = std::find_if(channelROIVec.begin(),channelROIVec.end(),[channel](const auto& channelROI){return channelROI.Channel() == channel;});
537 
538  if (channelItr != channelROIVec.end())
539  {
540  intROIVec = channelItr->SignalROI();
541 
542  // Avoid duplicate entries by erasing the previous instance
543  channelROIVec.erase(channelItr);
544  }
545  }
546  }
547 
548  if (ROIVec.size() != intROIVec.size())
549  throw art::Exception(art::errors::LogicError) << "===> ROIVec mismatch to intROIVec, ROIVec size: " << ROIVec.size() << ", intROIVec size: " << intROIVec.size() << "\n";
550 
551  const icarus_signal_processing::VectorFloat& waveform = dataArray[waveIdx];
552 
553  // We need to copy the deconvolved (and corrected) waveform ROI's
554  for(const auto& candROI : candidateROIVec)
555  {
556  // First up: copy out the relevent ADC bins into the ROI holder
557  size_t roiLen = candROI.second - candROI.first;
558  size_t firstBin = candROI.first;
559 
560  icarus_signal_processing::VectorFloat holder(roiLen);
561 
562  std::copy(waveform.begin()+candROI.first, waveform.begin()+candROI.second, holder.begin());
563 
564  // Now we do the baseline determination and correct the ROI
565  // For now we are going to reset to the minimum element
566  // Get slope/offset from first to last ticks
567  if (fCorrectROIBaseline && holder.size() > fMinSizeForCorrection && holder.size() < fMaxSizeForCorrection)
568  {
569  // Try to find the minimum value in the leading and trailing bins
570  size_t nBins = holder.size()/3;
571  icarus_signal_processing::VectorFloat::iterator firstItr = std::min_element(holder.begin(),holder.begin()+nBins);
572  icarus_signal_processing::VectorFloat::iterator lastItr = std::min_element(holder.end()-nBins,holder.end());
573 
574  size_t newSize = std::distance(firstItr,lastItr) + 1;
575  float dADC = (*lastItr - *firstItr) / float(newSize);
576  float offset = *firstItr;
577 
578  for(size_t binIdx = 0; binIdx < newSize; binIdx++)
579  {
580  holder[binIdx] = *(firstItr + binIdx) - offset;
581  offset += dADC;
582  }
583 
584  firstBin += std::distance(holder.begin(),firstItr);
585 
586  holder.resize(newSize);
587  }
588 
589  // Now make the short int version
590  icarus_signal_processing::VectorShort intHolder(holder.size());
591 
592  for(size_t binIdx = 0; binIdx < holder.size(); binIdx++) intHolder[binIdx] = std::round(holder[binIdx]);
593 
594  // add the range into ROIVec
595  ROIVec.add_range(firstBin, std::move(holder));
596  intROIVec.add_range(firstBin, std::move(intHolder));
597  }
598 
599  // Check for emptiness
600  if (!ROIVec.empty())
601  {
602  // First get a lock to make sure we don't conflict
603  tbb::spin_mutex::scoped_lock lock(roifinderSpinMutex);
604 
605  raw::ChannelID_t channel = channelVec[waveIdx];
606  geo::View_t view = fGeometry->View(channel);
607 
608  // Since we process logical TPC images we need to watch for duplicating entries
609  // We can do that by checking to see if a channel has already been added...
610  std::vector<geo::WireID> wireIDVec = fGeometry->ChannelToWire(channel);
611 
612  if (channelROIVec.size() != wireColVec.size())
613  throw art::Exception(art::errors::LogicError) << "===> ROI output mismatch, channelROIVec, size: " << channelROIVec.size() << ", wireColVec, size: " << wireColVec.size() << "\n";
614 
615  channelROIVec.push_back(recob::ChannelROICreator(std::move(intROIVec),channel).move());
616  wireColVec.push_back(recob::WireCreator(std::move(ROIVec),channel,view).move());
617  }
618  }
619  }
620 
621  return;
622 }
623 
624 float ROIFinder::getMedian(icarus_signal_processing::VectorFloat vals, const unsigned int nVals) const
625 {
626  float median(0.);
627 
628  if (nVals > 2)
629  {
630  if (nVals % 2 == 0)
631  {
632  const auto m1 = vals.begin() + nVals / 2 - 1;
633  const auto m2 = vals.begin() + nVals / 2;
634  std::nth_element(vals.begin(), m1, vals.begin() + nVals);
635  const auto e1 = *m1;
636  std::nth_element(vals.begin(), m2, vals.begin() + nVals);
637  const auto e2 = *m2;
638  median = (e1 + e2) / 2.0;
639  }
640  else
641  {
642  const auto m = vals.begin() + nVals / 2;
643  std::nth_element(vals.begin(), m, vals.begin() + nVals);
644  median = *m;
645  }
646  }
647 
648  return median;
649 }
650 
651 } // end namespace caldata
multiThreadDeconvolutionProcessing(ROIFinder const &parent, art::Event &event, const PlaneIDVec &planeIDVec, const PlaneIDToDataPairMap &planeIDToDataPairMap, std::vector< recob::Wire > &wireColVec, std::vector< recob::Wire > &morphedVec, std::vector< recob::ChannelROI > &channelROIVec)
BEGIN_PROLOG TPC Trig offset(g4 rise time) ProjectToHeight
Definition: CORSIKAGen.fcl:7
Utilities related to art service access.
std::vector< geo::PlaneID > PlaneIDVec
size_type size() const
Returns the size of the vector.
Definition of util::enumerate().
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
Helper functions to create a wire.
pdgs p
Definition: selectors.fcl:22
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
const datarange_t & add_range(size_type offset, ITER first, ITER last)
Adds a sequence of elements as a range with specified offset.
Definition of basic raw digits.
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
for pfile in ack l reconfigure(.*) override"` do echo "checking $
Wire && move()
Prepares the constructed wire to be moved away.
Definition: WireCreator.h:133
Class managing the creation of a new recob::Wire object.
Definition: WireCreator.h:53
std::map< size_t, std::unique_ptr< icarus_tool::IROILocator > > fROIToolMap
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
size_t fMinSizeForCorrection
Minimum ROI length to do correction.
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
Definition: enumerate.h:69
std::vector< std::string > fOutInstanceLabelVec
The output instance labels to apply.
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
const geo::GeometryCore * fGeometry
raw::ChannelID_t Channel() const
Returns the ID of the channel (or InvalidChannelID)
Definition: Wire.h:231
bool fCorrectROIBaseline
Correct the ROI baseline.
std::map< geo::PlaneID, PlaneIDToDataPair > PlaneIDToDataPairMap
bool fOutputHistograms
Output tuples/histograms?
void produce(art::Event &evt)
float getMedian(const icarus_signal_processing::VectorFloat, const unsigned int) const
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.
size_t fMaxSizeForCorrection
Maximum ROI length for baseline correction.
std::vector< float > Signal() const
Return a zero-padded full length vector filled with RoI signal.
Definition: Wire.cxx:47
tuple dir
Definition: dropbox.py:28
bool fOutputMorphed
Output the morphed waveforms.
Helper functions to create a wire.
tbb::spin_mutex roifinderSpinMutex
std::string to_string(WindowPattern const &pattern)
bool empty() const
Returns whether the vector is empty.
Class managing the creation of a new recob::Wire object.
Declaration of basic channel signal object for ICARUS.
This provides an interface for tools which are tasked with finding ROI&#39;s in input waveforms...
T copy(T const &v)
Class holding the regions of interest of signal from a channel.
Definition: Wire.h:118
void operator()(const tbb::blocked_range< size_t > &range) const
Declaration of basic channel signal object.
void processPlane(size_t, art::Event &, const PlaneIDVec &, const PlaneIDToDataPairMap &, std::vector< recob::Wire > &, std::vector< recob::Wire > &, std::vector< recob::ChannelROI > &) const
art::ServiceHandle< art::TFileService > tfs
TCEvent evt
Definition: DataStructs.cxx:8
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
size_t fEventCount
count of event processed
void reconfigure(fhicl::ParameterSet const &p)
process_name can override from command line with o or output caldata
Definition: pid.fcl:40
ROIFinder(fhicl::ParameterSet const &pset)
physics pm2 e1
art framework interface to geometry description
BEGIN_PROLOG could also be cout
std::pair< std::vector< raw::ChannelID_t >, PlaneWireData > PlaneIDToDataPair
bool fDiagnosticOutput
secret diagnostics flag
std::vector< art::InputTag > fWireModuleLabelVec
vector of modules that made digits