LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
EvaluateROIEff_module.cc
Go to the documentation of this file.
1 // Class: EvaluateROIEff
3 // Plugin Type: analyzer (art v3_05_00)
4 // File: EvaluateROIEff_module.cc
5 //
6 // Generated at Sun May 3 23:16:14 2020 by Tingjun Yang using cetskelgen
7 // from cetlib version v3_10_00.
8 //
9 // Author: Tingjun Yang, tjyang@fnal.gov
10 // Wanwei Wu, wwu@fnal.gov
11 //
12 // About: ROI efficiency and purity evaluation using "signal". Here, "signal"
13 // is consecutive energy deposits based on tdc ticks.
15 
23 #include "larevt/CalibrationDBI/Interface/ChannelStatusProvider.h"
24 #include "larevt/CalibrationDBI/Interface/ChannelStatusService.h"
25 
31 #include "art_root_io/TFileService.h"
34 #include "fhiclcpp/ParameterSet.h"
36 
37 #include "TEfficiency.h"
38 #include "TH1D.h"
39 
40 #include <cstdlib> // std::abs()
41 #include <string>
42 #include <vector>
43 
44 namespace nnet {
45  class EvaluateROIEff;
46 }
47 
49 public:
50  explicit EvaluateROIEff(fhicl::ParameterSet const& p);
51  // The compiler-generated destructor is fine for non-base
52  // classes without bare pointers or other resource use.
53 
54  // Plugins should not be copied or assigned.
55  EvaluateROIEff(EvaluateROIEff const&) = delete;
56  EvaluateROIEff(EvaluateROIEff&&) = delete;
57  EvaluateROIEff& operator=(EvaluateROIEff const&) = delete;
59 
60  // Required functions.
61  void analyze(art::Event const& e) override;
62 
63 private:
64  void beginJob() override;
65  void endJob() override;
66  bool isSignalInROI(int starttick, int endtick, int maxtick, int roistart, int roiend);
67  // Declare member data here.
70  fSimulationProducerLabel; // The name of the producer that tracked simulated particles through the detector
71 
72  TH1D* h_energy[3];
73  TH1D* h_energy_roi[3];
74 
75  TEfficiency* eff_energy[3];
76 
77  TH1D* h_purity[3];
78  TH1D* h_purity_all;
79 
80  TH1D* h_roi[3];
81  TH1D* h1_roi_max[3];
82  TH1D* h1_roi_max_sim[3];
83 
84  TH1D* h1_tickdiff_max[3];
85 
86  int fCount_Roi_sig[3] = {0, 0, 0};
87  int fCount_Roi_total[3] = {0, 0, 0};
88 };
89 
91  : EDAnalyzer{p}
92  , fWireProducerLabel(p.get<art::InputTag>("WireProducerLabel", ""))
93  , fSimulationProducerLabel(p.get<art::InputTag>("SimulationProducerLabel", "largeant"))
94 // More initializers here.
95 {
96  // Call appropriate consumes<>() for any products to be retrieved by this module.
97 }
98 
100 {
101 
102  auto const* geo = lar::providerFrom<geo::Geometry>();
103  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService>()->DataFor(e);
104  auto const detProp =
106  auto const& chStatus = art::ServiceHandle<lariov::ChannelStatusService>()->GetProvider();
107 
108  art::Handle<std::vector<recob::Wire>> wireListHandle;
109  std::vector<art::Ptr<recob::Wire>> wires;
110  if (e.getByLabel(fWireProducerLabel, wireListHandle)) {
111  art::fill_ptr_vector(wires, wireListHandle);
112  }
113 
114  auto simChannelHandle = e.getValidHandle<std::vector<sim::SimChannel>>(fSimulationProducerLabel);
115 
116  // efficiency: according to each simulated energy deposit
117  // ... Loop over simChannels
118  for (auto const& channel : (*simChannelHandle)) {
119 
120  // .. get simChannel channel number
121  const raw::ChannelID_t ch1 = channel.Channel();
122  if (chStatus.IsBad(ch1)) continue;
123 
124  if (ch1 % 1000 == 0) mf::LogInfo("EvaluateROIEFF") << ch1;
125  int view = geo->View(ch1);
126  auto const& timeSlices = channel.TDCIDEMap();
127 
128  // time slice from simChannel is for individual tick
129  // group neighboring time slices into a "signal"
130  int tdctick_previous = -999;
131  double totalE = 0.;
132  double maxE = -999.;
133  int maxEtick = -999;
134  std::vector<int> signal_starttick;
135  std::vector<int> signal_endtick;
136  std::vector<double> signal_energydeposits;
137  std::vector<double> signal_energy_max;
138  std::vector<double> signal_max_tdctick;
139 
140  for (auto const& timeSlice : timeSlices) {
141  auto const tpctime = timeSlice.first;
142  auto const& energyDeposits = timeSlice.second;
143  int tdctick = static_cast<int>(clockData.TPCTDC2Tick(double(tpctime)));
144  if (tdctick < 0 || tdctick > int(detProp.ReadOutWindowSize()) - 1) continue;
145 
146  // for a time slice, there may exist more than one energy deposit.
147  double e_deposit = 0;
148  for (auto const& energyDeposit : energyDeposits) {
149  e_deposit += energyDeposit.energy;
150  }
151 
152  if (tdctick_previous == -999) {
153  signal_starttick.push_back(tdctick);
154  totalE += e_deposit;
155  maxE = e_deposit;
156  maxEtick = tdctick;
157  }
158  else if (tdctick - tdctick_previous != 1) {
159  signal_starttick.push_back(tdctick);
160  signal_endtick.push_back(tdctick_previous);
161  signal_energydeposits.push_back(totalE);
162  signal_energy_max.push_back(maxE);
163  signal_max_tdctick.push_back(maxEtick);
164  totalE = e_deposit;
165  maxE = e_deposit;
166  maxEtick = tdctick;
167  }
168  else if (tdctick - tdctick_previous == 1) {
169  totalE += e_deposit;
170  if (maxE < e_deposit) {
171  maxE = e_deposit;
172  maxEtick = tdctick;
173  }
174  }
175 
176  tdctick_previous = tdctick;
177 
178  } // loop over timeSlices timeSlice
179 
180  signal_endtick.push_back(tdctick_previous); // for last one
181  signal_energydeposits.push_back(totalE); // for last one
182  signal_energy_max.push_back(maxE); // for last one
183  signal_max_tdctick.push_back(maxEtick); // for last one
184 
185  if (signal_starttick.size() == 0 ||
186  (signal_endtick.size() == 1 && signal_endtick.back() == -999))
187  continue;
188 
189  for (auto& wire : wires) {
190  if (wire->Channel() != ch1) continue;
191 
192  const recob::Wire::RegionsOfInterest_t& signalROI = wire->SignalROI();
193 
194  std::vector<float> vecADC =
195  wire->Signal(); // a zero-padded full length vector filled with RoI signal.
196 
197  // loop over signals:
198  // a) if signal s is not in any ROI (including the case no ROI), fill h_energy
199  // with signal_energy_max[s];
200  // b) if signal s is in a ROI, check following signals that are also in this ROI,
201  // then use the maximum of signal_energy_max to fill h_energy and h_energy_roi.
202  // After this, the loop will skip to the signal that is not in this ROI.
203  for (size_t s = 0; s < signal_starttick.size(); s++) {
204  // case a: signal is not in any ROI
205  bool IsSignalOutside = true;
206  for (const auto& range : signalROI.get_ranges()) {
207  //const auto& waveform = range.data();
208  raw::TDCtick_t roiFirstBinTick = range.begin_index();
209  raw::TDCtick_t roiLastBinTick = range.end_index();
210 
211  if (isSignalInROI(signal_starttick[s],
212  signal_endtick[s],
213  signal_max_tdctick[s],
214  roiFirstBinTick,
215  roiLastBinTick)) {
216  IsSignalOutside = false;
217  break;
218  }
219  } // loop over range
220 
221  if (IsSignalOutside) {
222  //cout << "This signal is not in any ROI: " << signal_starttick[s] << " -> " << signal_endtick[s] << endl;
223  h_energy[view]->Fill(signal_energy_max[s]);
224  h1_tickdiff_max[view]->Fill(-99);
225  continue;
226  }
227 
228  // signal is in one ROI
229  for (const auto& range : signalROI.get_ranges()) {
230  //const auto& waveform = range.data();
231  raw::TDCtick_t roiFirstBinTick = range.begin_index();
232  raw::TDCtick_t roiLastBinTick = range.end_index();
233 
234  if (isSignalInROI(signal_starttick[s],
235  signal_endtick[s],
236  signal_max_tdctick[s],
237  roiFirstBinTick,
238  roiLastBinTick)) {
239  // maximum pulse height and postion for this ROI
240  double maxadc_sig = 0;
241  int maxadc_tick = -99;
242  for (int k = roiFirstBinTick; k < roiLastBinTick; k++) {
243  if (vecADC[k] > maxadc_sig) {
244  maxadc_sig = vecADC[k];
245  maxadc_tick = k;
246  }
247  }
248 
249  double maxE_roi = -999.;
250  double maxE_roi_tick = -999.;
251 
252  if (maxE_roi < signal_energy_max[s]) {
253  maxE_roi = signal_energy_max[s];
254  maxE_roi_tick = signal_max_tdctick[s];
255  }
256 
257  // check the following signals in the same ROI
258  for (size_t s2 = s + 1; s2 < signal_starttick.size(); s2++) {
259  if (isSignalInROI(signal_starttick[s2],
260  signal_endtick[s2],
261  signal_max_tdctick[s2],
262  roiFirstBinTick,
263  roiLastBinTick)) {
264  if (maxE_roi < signal_energy_max[s2]) {
265  maxE_roi = signal_energy_max[s2];
266  maxE_roi_tick = signal_max_tdctick[s2];
267  }
268  if (s2 == signal_starttick.size() - 1) { s = s2; }
269  }
270  else {
271  s = s2 - 1;
272  break;
273  }
274  } // loop over s2
275 
276  // finish this ROI
277  h_energy[view]->Fill(maxE_roi);
278  h_energy_roi[view]->Fill(maxE_roi);
279  h1_tickdiff_max[view]->Fill(maxE_roi_tick - maxadc_tick);
280  break;
281  } // isSignalInROI
282  } // loop over range
283 
284  } // loop over signals s
285  } // loop over wires wire
286  } // loop simChannels
287 
288  // purity: # signals in ROI / (#signals in ROI + #non-signals in ROI). Because we only consider the maximum signal in the ROI, this is quivalent to purity of ( number of ROIs with signal / number of ROIs)
289  double roi_sig[3] = {0., 0., 0.}; // number of roi contains signal in an event
290  double roi_total[3] = {0., 0., 0.}; // number of roi in an event
291 
292  for (auto& wire : wires) {
293  const raw::ChannelID_t wirechannel = wire->Channel();
294  if (chStatus.IsBad(wirechannel)) continue;
295 
296  int view = wire->View();
297 
298  const recob::Wire::RegionsOfInterest_t& signalROI = wire->SignalROI();
299 
300  if (signalROI.get_ranges().empty()) continue;
301 
302  std::vector<float> vecADC =
303  wire->Signal(); // a zero-padded full length vector filled with RoI signal.
304 
305  roi_total[view] += signalROI.get_ranges().size();
306  fCount_Roi_total[view] += signalROI.get_ranges().size();
307 
308  for (const auto& range : signalROI.get_ranges()) {
309  bool IsSigROI = false;
310 
311  raw::TDCtick_t roiFirstBinTick = range.begin_index();
312  raw::TDCtick_t roiLastBinTick = range.end_index();
313 
314  double maxadc_sig = -99.;
315  for (int k = roiFirstBinTick; k < roiLastBinTick; k++) {
316  if (std::abs(vecADC[k]) > maxadc_sig) maxadc_sig = std::abs(vecADC[k]);
317  }
318  h1_roi_max[view]->Fill(maxadc_sig);
319 
320  // check simulation: ideally we could put this part outside loop over range to make the algorithm more efficient. However, as there are only one or two ROIs in a channel for most of cases, we keep this style to make the algorithm more readable. Also, signal information are kept here.
321  for (auto const& channel : (*simChannelHandle)) {
322  if (wirechannel != channel.Channel()) continue;
323 
324  int tdctick_previous = -999;
325  double totalE = 0.;
326  double maxE = -999.;
327  int maxEtick = -999;
328  std::vector<int> signal_starttick;
329  std::vector<int> signal_endtick;
330  std::vector<double> signal_energydeposits;
331  std::vector<double> signal_energy_max;
332  std::vector<double> signal_max_tdctick;
333 
334  auto const& timeSlices = channel.TDCIDEMap();
335 
336  for (auto const& timeSlice : timeSlices) {
337  auto const tpctime = timeSlice.first;
338  auto const& energyDeposits = timeSlice.second;
339  int tdctick = static_cast<int>(clockData.TPCTDC2Tick(double(tpctime)));
340  if (tdctick < 0 || tdctick > int(detProp.ReadOutWindowSize()) - 1) continue;
341 
342  double e_deposit = 0;
343  for (auto const& energyDeposit : energyDeposits) {
344  e_deposit += energyDeposit.energy;
345  }
346 
347  if (tdctick_previous == -999) {
348  signal_starttick.push_back(tdctick);
349  totalE += e_deposit;
350  maxE = e_deposit;
351  maxEtick = tdctick;
352  }
353  else if (tdctick - tdctick_previous != 1) {
354  signal_starttick.push_back(tdctick);
355  signal_endtick.push_back(tdctick_previous);
356  signal_energydeposits.push_back(totalE);
357  signal_energy_max.push_back(maxE);
358  signal_max_tdctick.push_back(maxEtick);
359  totalE = e_deposit;
360  maxE = e_deposit;
361  maxEtick = tdctick;
362  }
363  else if (tdctick - tdctick_previous == 1) {
364  totalE += e_deposit;
365  if (maxE < e_deposit) {
366  maxE = e_deposit;
367  maxEtick = tdctick;
368  }
369  }
370 
371  tdctick_previous = tdctick;
372 
373  } // loop over timeSlices timeSlice
374 
375  signal_endtick.push_back(tdctick_previous); // for last one
376  signal_energydeposits.push_back(totalE); // for last one
377  signal_energy_max.push_back(maxE); // for last one
378  signal_max_tdctick.push_back(maxEtick); // for last one
379 
380  if (signal_starttick.size() == 0 ||
381  (signal_endtick.size() == 1 && signal_endtick.back() == -999))
382  continue;
383 
384  // check if signal/signals in this ROI
385  for (size_t s = 0; s < signal_starttick.size(); s++) {
386  if (isSignalInROI(signal_starttick[s],
387  signal_endtick[s],
388  signal_max_tdctick[s],
389  roiFirstBinTick,
390  roiLastBinTick)) {
391  IsSigROI = true;
392  break;
393  }
394  } // loop over s
395  } // loop simChannels
396 
397  h_roi[view]->Fill(0); // total roi
398  if (IsSigROI) {
399  roi_sig[view] += 1.;
400  fCount_Roi_sig[view] += 1;
401  h_roi[view]->Fill(1); // sig roi
402  h1_roi_max_sim[view]->Fill(maxadc_sig);
403  }
404  } // loop ranges of signalROI
405  } // loop wires
406 
407  // purity of each plane for each event
408  for (int i = 0; i < 3; i++) {
409  if (roi_total[i]) {
410  double purity = roi_sig[i] / roi_total[i];
411  if (purity == 1) purity = 1. - 1.e-6;
412  h_purity[i]->Fill(purity);
413  }
414  }
415 
416  // combined purity for each event
417  if (roi_total[0] + roi_total[1] + roi_total[2]) {
418  double purity =
419  (roi_sig[0] + roi_sig[1] + roi_sig[2]) / (roi_total[0] + roi_total[1] + roi_total[2]);
420  if (purity == 1) purity = 1. - 1.e-6;
421  h_purity_all->Fill(purity);
422  }
423 }
424 
426 {
427 
429 
430  for (int i = 0; i < 3; ++i) {
431  h_energy[i] =
432  tfs->make<TH1D>(Form("h_energy_%d", i), Form("Plane %d; Energy (MeV);", i), 100, 0, 1);
433  h_energy_roi[i] =
434  tfs->make<TH1D>(Form("h_energy_roi_%d", i), Form("Plane %d; Energy (MeV);", i), 100, 0, 1);
435 
436  h_purity[i] = tfs->make<TH1D>(Form("h_purity_%d", i), Form("Plane %d; Purity;", i), 20, 0, 1);
437  h_roi[i] = tfs->make<TH1D>(Form("h_roi_%d", i),
438  Form("Plane %d; Purity;", i),
439  5,
440  0,
441  5); // index 0: total rois; index 1: total sig rois
442 
443  h1_roi_max[i] =
444  tfs->make<TH1D>(Form("h1_roi_max_%d", i), Form("Plane %d; Max adc;", i), 50, 0, 50);
445  h1_roi_max_sim[i] =
446  tfs->make<TH1D>(Form("h1_roi_max_sim_%d", i), Form("Plane %d; Max adc;", i), 50, 0, 50);
447 
448  h1_tickdiff_max[i] = tfs->make<TH1D>(Form("h1_tickdiff_max_%d", i),
449  Form("Plane %d; tick diff (maxE - max pulse);", i),
450  100,
451  -50,
452  50);
453  }
454 
455  h_purity_all = tfs->make<TH1D>("h_purity_all", "All Planes; Purity;", 20, 0, 1);
456 }
457 
459 {
461 
462  for (int i = 0; i < 3; ++i) {
463  if (TEfficiency::CheckConsistency(*(h_energy_roi[i]), *(h_energy[i]))) {
464  eff_energy[i] = tfs->make<TEfficiency>(*(h_energy_roi[i]), *(h_energy[i]));
465  eff_energy[i]->Write(Form("eff_energy_%d", i));
466  }
467  }
468 }
469 
471  int endtick,
472  int maxtick,
473  int roistart,
474  int roiend)
475 {
476  // For a signal in the ROI, two cases are considered:
477  // (i) signal is totally in the ROI
478  // (ii) signal is partially in the ROI
479  // Equivalently, we can just check whether the maxtick is in the ROI (simple one).
480  return roistart <= maxtick && maxtick < roiend;
481 }
482 
art::InputTag fSimulationProducerLabel
Utilities related to art service access.
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
constexpr auto abs(T v)
Returns the absolute value of the argument.
const range_list_t & get_ranges() const
Returns the internal list of non-void ranges.
EvaluateROIEff(fhicl::ParameterSet const &p)
EDAnalyzer(fhicl::ParameterSet const &pset)
Definition: EDAnalyzer.cc:6
int TDCtick_t
Type representing a TDC tick.
Definition: RawTypes.h:25
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
void analyze(art::Event const &e) override
Definition: EmTrack.h:40
EvaluateROIEff & operator=(EvaluateROIEff const &)=delete
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
bool isSignalInROI(int starttick, int endtick, int maxtick, int roistart, int roiend)
object containing MC truth information necessary for making RawDigits and doing back tracking ...
Declaration of basic channel signal object.
unsigned int ChannelID_t
Type representing the ID of a readout channel.
Definition: RawTypes.h:28
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:306
double maxE
Definition: plot_hist.C:8
Float_t e
Definition: plot.C:35
Namespace collecting geometry-related classes utilities.
art framework interface to geometry description