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