L1SPFilter.cxx
Go to the documentation of this file.
3 
5 
7 
9 
12 #include <Eigen/Dense>
13 
14 #include <numeric>
15 #include <iostream>
16 
19 
20 using namespace Eigen;
21 using namespace WireCell;
22 using namespace WireCell::SigProc;
23 
24 
25 L1SPFilter::L1SPFilter(double gain,
26  double shaping,
27  double postgain ,
28  double ADC_mV,
29  double fine_time_offset ,
30  double coarse_time_offset )
31  : m_gain(gain)
32  , m_shaping(shaping)
33  , m_postgain(postgain)
34  , m_ADC_mV(ADC_mV)
35  , m_fine_time_offset(fine_time_offset)
36  , m_coarse_time_offset(coarse_time_offset)
37  , lin_V(0)
38  , lin_W(0)
39 {
40 }
41 
42 L1SPFilter::~L1SPFilter()
43 {
44  delete lin_V;
45  delete lin_W;
46 }
47 
49  if (lin_V==0 && lin_W==0){
50  // get field response ...
51  auto ifr = Factory::find_tn<IFieldResponse>(get<std::string>(m_cfg, "fields", "FieldResponse"));
52  Response::Schema::FieldResponse fr = ifr->field_response();
53  // Make a new data set which is the average FR, make an average for V and Y planes ...
55 
56  //get electronics response
58  WireCell::Binning tbins(Response::as_array(fravg.planes[0]).cols(), 0, Response::as_array(fravg.planes[0]).cols() * fravg.period);
60  auto ewave = ce.generate(tbins);
61  Waveform::scale(ewave, m_postgain * m_ADC_mV * (-1)); // ADC to electron ...
62  elec = Waveform::dft(ewave);
63 
64  std::complex<float> fine_period(fravg.period,0);
65 
66  // do a convolution here ...
67  WireCell::Waveform::realseq_t resp_V = fravg.planes[1].paths[0].current ;
68  WireCell::Waveform::realseq_t resp_W = fravg.planes[2].paths[0].current ;
69 
70  auto spectrum_V = WireCell::Waveform::dft(resp_V);
71  auto spectrum_W = WireCell::Waveform::dft(resp_W);
72 
73  WireCell::Waveform::scale(spectrum_V,elec);
74  WireCell::Waveform::scale(spectrum_W,elec);
75 
76  WireCell::Waveform::scale(spectrum_V,fine_period);
77  WireCell::Waveform::scale(spectrum_W,fine_period);
78 
79  // Now this response is ADC for 1 electron .
80  resp_V = WireCell::Waveform::idft(spectrum_V);
81  resp_W = WireCell::Waveform::idft(spectrum_W);
82 
83  // convolute with V and Y average responses ...
84  double intrinsic_time_offset = fravg.origin/fravg.speed;
85  //std::cout << intrinsic_time_offset << " " << m_fine_time_offset << " " << m_coarse_time_offset << " " << m_gain << " " << 14.0 * units::mV/units::fC << " " << m_shaping << " " << fravg.period << std::endl;
86 
87  double x0 = (- intrinsic_time_offset - m_coarse_time_offset + m_fine_time_offset);
88  double xstep = fravg.period;
89 
90  // boost::math::cubic_b_spline<double> spline_v(resp_V.begin(), resp_V.end(), x0, xstep);
91  // boost::math::cubic_b_spline<double> spline_w(resp_W.begin(), resp_W.end(), x0, xstep);
92  lin_V = new linterp<double>(resp_V.begin(), resp_V.end(), x0, xstep);
93  lin_W = new linterp<double>(resp_W.begin(), resp_W.end(), x0, xstep);
94  }
95 }
96 
98 {
100 
101  /// Name of component providing field responses
102  cfg["fields"] = "FieldResponse";
103 
104  /// An array holding a waveform to use as the "smearing" filter.
105  cfg["filter"] = Json::arrayValue;
106 
107  /// The tag identifying traces which represent "raw" (not
108  /// deconvolved) ADC values.
109  cfg["adctag"] = "raw";
110 
111  /// The tag identifying traces which represent "signal" processed
112  /// (deconvolved) waveforms.
113  cfg["sigtag"] = "gauss";
114 
115  /// The tag to place on the output waveforms
116  cfg["outtag"] = "l1sp";
117 
118  // 4 sigma for raw waveform ROI identification
119  cfg["raw_ROI_th_nsigma"] = 4;
120  // 10 ADC for upper limit on ADC ...
121  cfg["raw_ROI_th_adclimit"] = 10;
122  // global offset
123  cfg["overall_time_offset"] = 0;
124  // need 3 us offset for collection plane relative to the induction plane ...
125  cfg["collect_time_offset"] = 3.0;
126 
127  // ROI padding ticks ...
128  cfg["roi_pad"] = 3;
129  cfg["raw_pad"] = 15;
130 
131  // L1 fit parameters ...
132  cfg["adc_l1_threshold"] = 6;
133  cfg["adc_sum_threshold"] = 160;
134  cfg["adc_sum_rescaling"] = 90.;
135  cfg["adc_sum_rescaling_limit"] = 50.;
136  cfg["adc_ratio_threshold"] = 0.2;
137 
138  cfg["l1_seg_length"] = 120;
139  cfg["l1_scaling_factor"] = 500;
140  cfg["l1_lambda"] = 5;
141  cfg["l1_epsilon"] = 0.05;
142  cfg["l1_niteration"] = 100000;
143  cfg["l1_decon_limit"] = 100; // 100 electrons
144 
145  cfg["l1_resp_scale"] = 0.5;
146  cfg["l1_col_scale"] = 1.15;
147  cfg["l1_ind_scale"] = 0.5;
148 
149  cfg["peak_threshold"] = 1000;
150  cfg["mean_threshold"] = 500;
151 
152 
153  cfg["gain"] = m_gain;
154  cfg["shaping"] = m_shaping;
155  cfg["postgain"] = m_postgain;
156  cfg["ADC_mV"] = m_ADC_mV;
157 
158  cfg["fine_time_offset"] = m_fine_time_offset;
159  cfg["coarse_time_offset"] = m_coarse_time_offset;
160 
161 
162  return cfg;
163 }
164 
166 {
167  m_cfg = cfg;
168 
169  m_gain = get(cfg,"gain",m_gain);
170  m_shaping = get(cfg,"shaping",m_shaping);
171  m_postgain = get(cfg,"postgain", m_postgain);
172  m_ADC_mV = get(cfg,"ADC_mV", m_ADC_mV);
173 
174  m_fine_time_offset = get(cfg,"fine_time_offset", m_fine_time_offset);
175  m_coarse_time_offset = get(cfg,"coarse_time_offset", m_coarse_time_offset);
176 }
177 
179 {
180  out = nullptr;
181  if (!in) {
182  return true; // eos
183  }
184 
185  std::string adctag = get<std::string>(m_cfg, "adctag");
186  std::string sigtag = get<std::string>(m_cfg, "sigtag");
187  std::string outtag = get<std::string>(m_cfg, "outtag");
188 
189 
190  // std::cout << smearing_vec.size() << std::endl;
191 
192  int roi_pad = 0;
193  roi_pad = get(m_cfg,"roi_pad",roi_pad);
194  int raw_pad = 0;
195  raw_pad = get(m_cfg,"raw_pad",raw_pad);
196 
197  double raw_ROI_th_nsigma = get(m_cfg,"raw_ROI_th_nsigma",raw_ROI_th_nsigma);
198  double raw_ROI_th_adclimit = get(m_cfg,"raw_ROI_th_adclimit",raw_ROI_th_adclimit);
199 
200 
201  // std::cout << "Xin: " << raw_ROI_th_nsigma << " " << raw_ROI_th_adclimit << " " << overall_time_offset << " " << collect_time_offset << " " << roi_pad << " " << adc_l1_threshold << " " << adc_sum_threshold << " " << adc_sum_rescaling << " " << adc_sum_rescaling_limit << " " << l1_seg_length << " " << l1_scaling_factor << " " << l1_lambda << " " << l1_epsilon << " " << l1_niteration << " " << l1_decon_limit << " " << l1_resp_scale << " " << l1_col_scale << " " << l1_ind_scale << std::endl;
202  init_resp();
203 
204 
205 
206 
207  // std::cout << (*lin_V)(0*units::us) << " " << (*lin_W)(0*units::us) << std::endl;
208  // std::cout << (*lin_V)(1*units::us) << " " << (*lin_W)(1*units::us) << std::endl;
209  // for (size_t i=0; i!=resp_V.size(); i++){
210  // std::cout << (i*fravg.period - intrinsic_time_offset - m_coarse_time_offset + m_fine_time_offset)/units::us << " " << resp_V.at(i) << " " << resp_W.at(i) << " " << ewave.at(i) << std::endl;
211  //}
212  // std::complex<float> fine_period(fravg.period,0);
213  // int fine_nticks = Response::as_array(fravg.planes[0]).cols();
214  // Waveform::realseq_t ftbins(fine_nticks);
215  // for (int i=0;i!=fine_nticks;i++){
216  // ftbins.at(i) = i * fravg.period;
217  //}
218 
219 
220 
221  auto adctraces = FrameTools::tagged_traces(in, adctag);
222  auto sigtraces = FrameTools::tagged_traces(in, sigtag);
223 
224  if (adctraces.empty() or sigtraces.empty() or adctraces.size() != sigtraces.size()) {
225  std::cerr << "L1SPFilter got unexpected input: "
226  << adctraces.size() << " ADC traces and "
227  << sigtraces.size() << " signal traces\n";
228  THROW(RuntimeError() << errmsg{"L1SPFilter: unexpected input"});
229  }
230 
231  m_period = in->tick();
232 
233  //std::cout << m_period/units::us << std::endl;
234 
235  /// here, use the ADC and signal traces to do L1SP
236  /// put result in out_traces
237  ITrace::vector out_traces;
238 
239  std::map<int,std::set<int>> init_map;
240  // do ROI from the decon signal
241  for (auto trace : sigtraces) {
242  int ch = trace->channel();
243  int tbin = trace->tbin();
244  auto const& charges = trace->charge();
245  const int ntbins = charges.size();
246  std::set<int> time_ticks;
247 
248  for (int qi = 0; qi < ntbins; qi++){
249  if (charges[qi]>0){
250  time_ticks.insert(tbin+qi);
251  }
252  }
253 
254  init_map[ch] = time_ticks;
255  // if (time_ticks.size()>0){
256  // std::cout << ch << " " << time_ticks.size() << std::endl;
257  // }
258  }
259 
260  // do ROI from the raw signal
261  int ntot_ticks=0;
262 
263  std::map<int,std::shared_ptr<const WireCell::ITrace>> adctrace_ch_map;
264 
265  for (auto trace : adctraces) {
266  int ch = trace->channel();
267 
268  adctrace_ch_map[ch] = trace;
269 
270  int tbin = trace->tbin();
271  auto const& charges = trace->charge();
272  const int ntbins = charges.size();
273  std::set<int>& time_ticks = init_map[ch];
274 
275  if (ntot_ticks < ntbins)
276  ntot_ticks = ntbins;
277 
278  Waveform::realseq_t tmp_charge = charges;
279  double mean = Waveform::percentile(tmp_charge,0.5);
280  double mean_p1sig = Waveform::percentile(tmp_charge,0.5+0.34);
281  double mean_n1sig = Waveform::percentile(tmp_charge,0.5-0.34);
282  double cut = raw_ROI_th_nsigma * sqrt((pow(mean_p1sig-mean,2)+pow(mean_n1sig-mean,2))/2.);
283  if (cut < raw_ROI_th_adclimit) cut = raw_ROI_th_adclimit;
284 
285  // if (ch==4090)
286  // std::cout << cut << " " << raw_pad << std::endl;
287 
288  for (int qi = 0; qi < ntbins; qi++){
289  if (fabs(charges[qi])>cut){
290  for (int qii = -raw_pad; qii!=raw_pad+1;qii++){
291  if (tbin+qi+qii >=0 && tbin+qi+qii<ntot_ticks)
292  time_ticks.insert(tbin+qi+qii);
293  }
294  }
295  }
296  // if (time_ticks.size()>0){
297  // std::cout << ch << " " << time_ticks.size() << std::endl;
298  // }
299  }
300 
301 
302  // create ROIs ...
303  std::map<int, std::vector<std::pair<int,int>>> map_ch_rois;
304 
305  for (auto it = init_map.begin(); it!=init_map.end(); it++){
306  int wire_index = it->first;
307  std::set<int>& time_slices_set = it->second;
308  if (time_slices_set.size()==0) continue;
309  std::vector<int> time_slices;
310  std::copy(time_slices_set.begin(), time_slices_set.end(), std::back_inserter(time_slices));
311 
312  std::vector<std::pair<int,int>> rois;
313  std::vector<std::pair<int,int>> rois_save;
314 
315  rois.push_back(std::make_pair(time_slices.front(),time_slices.front()));
316  for (size_t i=1; i<time_slices.size();i++){
317  if (time_slices.at(i) - rois.back().second <= roi_pad*2){
318  rois.back().second = time_slices.at(i);
319  }else{
320  rois.push_back(std::make_pair(time_slices.at(i),time_slices.at(i)));
321  }
322  }
323 
324  // extend the rois to both side according to the bin content
325  for (auto it = rois.begin(); it!= rois.end(); it++){
326  int start_bin = it->first;
327  int end_bin = it->second;
328  start_bin = start_bin - roi_pad;
329  end_bin = end_bin + roi_pad;
330  if (start_bin <0) start_bin = 0;
331  if (end_bin>ntot_ticks-1) end_bin = ntot_ticks-1;
332  it->first = start_bin;
333  it->second = end_bin;
334  }
335 
336  for (auto it = rois.begin(); it!= rois.end(); it++){
337  if (rois_save.size()==0){
338  rois_save.push_back(*it);
339  }else if (it->first <= rois_save.back().second){
340  rois_save.back().second = it->second;
341  }else{
342  rois_save.push_back(*it);
343  }
344  }
345 
346  if (rois_save.size()>0)
347  map_ch_rois[wire_index] = rois_save;
348  // for (auto it = rois_save.begin(); it!=rois_save.end(); it++){
349  // std::cout << wire_index << " " << it->first << " " << it->second +1 << std::endl;
350  // }
351  }
352 
353 
354  std::map<int, std::vector<int> > map_ch_flag_rois;
355  // prepare for the output signal ...
356  for (auto trace : sigtraces) {
357  auto newtrace = std::make_shared<SimpleTrace>(trace->channel(), trace->tbin(), trace->charge());
358  // How to access the sigtraces together ???
359  if (map_ch_rois.find(trace->channel()) != map_ch_rois.end()){
360  std::vector<std::pair<int,int>>& rois_save = map_ch_rois[trace->channel()];
361  std::vector<int> flag_rois;
362  map_ch_flag_rois[trace->channel()] = flag_rois;
363 
364  bool flag_shorted = false;
365  for (size_t i1 = 0; i1!=rois_save.size(); i1++){
366  //
367 
368  int temp_flag = L1_fit(newtrace, adctrace_ch_map[trace->channel()], rois_save.at(i1).first, rois_save.at(i1).second+1, flag_shorted);
369  map_ch_flag_rois[trace->channel()].push_back(temp_flag);
370 
371  for (int time_tick = rois_save.at(i1).first; time_tick!=rois_save.at(i1).second+1; time_tick++){
372  // temporary hack to reset the data ...
373  if (newtrace->charge().at(time_tick-trace->tbin())<0)
374  newtrace->charge().at(time_tick-trace->tbin())=0;
375  }
376  }
377 
378 
379  flag_shorted = false;
380  int prev_time_tick = -2000;
381  for (size_t i1 = 0; i1!=rois_save.size(); i1++){
382  if (rois_save.at(i1).first - prev_time_tick > 20) flag_shorted = false;
383 
384  if (map_ch_flag_rois[trace->channel()].at(i1)==1){
385  flag_shorted = true;
386  }else if (map_ch_flag_rois[trace->channel()].at(i1)==2){
387  if (flag_shorted){
388  L1_fit(newtrace, adctrace_ch_map[trace->channel()], rois_save.at(i1).first, rois_save.at(i1).second+1, flag_shorted);
389  map_ch_flag_rois[trace->channel()].at(i1) = 0;
390  }
391  }else if (map_ch_flag_rois[trace->channel()].at(i1)==0){
392  flag_shorted = false;
393  }
394  prev_time_tick = rois_save.at(i1).second;
395  }
396 
397  if (rois_save.size()>0){
398  prev_time_tick = rois_save.back().second + 2000;
399 
400  for (size_t i1 = 0; i1!=rois_save.size(); i1++){
401  if (prev_time_tick - rois_save.at(rois_save.size()-1-i1).second > 20) flag_shorted = false;
402 
403  if (map_ch_flag_rois[trace->channel()].at(i1)==1){
404  flag_shorted = true;
405  }else if (map_ch_flag_rois[trace->channel()].at(i1)==2){
406  if (flag_shorted){
407  L1_fit(newtrace, adctrace_ch_map[trace->channel()], rois_save.at(i1).first, rois_save.at(i1).second+1, flag_shorted);
408  map_ch_flag_rois[trace->channel()].at(i1) = 0;
409  }
410  }else if (map_ch_flag_rois[trace->channel()].at(i1)==0){
411  flag_shorted = false;
412  }
413  prev_time_tick = rois_save.at(i1).first;
414  }
415  }
416 
417 
418 
419  }
420 
421 
422  // std::cout << trace->channel() << std::endl;
423  out_traces.push_back(newtrace);
424  }
425 
426  for (size_t i2 = 0; i2!=out_traces.size(); i2++){
427  auto new_trace = std::make_shared<SimpleTrace>(out_traces.at(i2)->channel(), out_traces.at(i2)->tbin(), out_traces.at(i2)->charge());
428  int ch = out_traces.at(i2)->channel();
429  if (map_ch_rois.find(ch) != map_ch_rois.end()){
430  std::vector<std::pair<int,int>>& rois_save = map_ch_rois[ch];
431  std::vector<std::pair<int,int> > next_rois_save;
432  if (map_ch_rois.find(ch+1)!=map_ch_rois.end())
433  next_rois_save = map_ch_rois[ch+1];
434  std::vector<std::pair<int,int> > prev_rois_save;
435  if (map_ch_rois.find(ch-1)!=map_ch_rois.end())
436  prev_rois_save = map_ch_rois[ch-1];
437 
438  for (size_t i1 = 0; i1!=rois_save.size(); i1++){
439  if ( map_ch_flag_rois[ch].at(i1) == 2 ){
440  bool flag_shorted = false;
441  // need to check now ...
442  for (size_t i3 = 0; i3 != next_rois_save.size(); i3++){
443  if (map_ch_flag_rois[ch+1].at(i3)==1){
444  if (rois_save.at(i1).first - 3 <= next_rois_save.at(i3).second + 3 &&
445  rois_save.at(i1).second + 3 >= next_rois_save.at(i3).first - 3){
446  flag_shorted = true;
447  break;
448  }
449  }
450  }
451  if (!flag_shorted)
452  for (size_t i3 = 0; i3 != prev_rois_save.size(); i3++){
453  if (map_ch_flag_rois[ch-1].at(i3)==1){
454  if (rois_save.at(i1).first - 3 <= prev_rois_save.at(i3).second + 3 &&
455  rois_save.at(i1).second + 3 >= prev_rois_save.at(i3).first - 3){
456  flag_shorted = true;
457  break;
458  }
459  }
460  }
461  if(flag_shorted){
462  for (int time_tick = rois_save.at(i1).first; time_tick!=rois_save.at(i1).second+1; time_tick++){
463  new_trace->charge().at(time_tick-out_traces.at(i2)->tbin())=0;
464  }
465  }
466  }
467  }
468  }
469  out_traces.at(i2) = new_trace;
470  }
471 
472 
473 
474  std::cerr << "L1SPFilter: frame: " << in->ident() << " "
475  << adctag << "[" << adctraces.size() << "] + "
476  << sigtag << "[" << sigtraces.size() << "] --> "
477  << outtag << "[" << out_traces.size() << "]\n";
478 
479 
480 
481  // Finally, we save the traces to an output frame with tags.
482 
483  IFrame::trace_list_t tl(out_traces.size());
484  std::iota(tl.begin(), tl.end(), 0);
485 
486  auto sf = new SimpleFrame(in->ident(), in->time(), out_traces, in->tick());
487  sf->tag_traces(outtag, tl);
488  out = IFrame::pointer(sf);
489 
490  return true;
491 }
492 
493 
494 int L1SPFilter::L1_fit(std::shared_ptr<WireCell::SimpleTrace>& newtrace, std::shared_ptr<const WireCell::ITrace>& adctrace, int start_tick, int end_tick, bool flag_shorted){
495 
496  double overall_time_offset = get(m_cfg,"overall_time_offset",overall_time_offset) * units::us;
497  double collect_time_offset = get(m_cfg,"collect_time_offset",collect_time_offset) * units::us;
498  double adc_l1_threshold = get(m_cfg,"adc_l1_threshold",adc_l1_threshold);
499  double adc_sum_threshold= get(m_cfg,"adc_sum_threshold",adc_sum_threshold);
500  double adc_sum_rescaling= get(m_cfg,"adc_sum_rescaling",adc_sum_rescaling);
501  double adc_sum_rescaling_limit= get(m_cfg,"adc_sum_rescaling_limit",adc_sum_rescaling_limit);
502  double adc_ratio_threshold = get(m_cfg,"adc_ratio_threshold",adc_ratio_threshold);
503 
504  double l1_seg_length= get(m_cfg,"l1_seg_length",l1_seg_length);
505  double l1_scaling_factor= get(m_cfg,"l1_scaling_factor",l1_scaling_factor);
506  double l1_lambda= get(m_cfg,"l1_lambda",l1_lambda);
507  double l1_epsilon= get(m_cfg,"l1_epsilon",l1_epsilon);
508  double l1_niteration= get(m_cfg,"l1_niteration",l1_niteration);
509  double l1_decon_limit= get(m_cfg,"l1_decon_limit",l1_decon_limit);
510 
511  double l1_resp_scale = get(m_cfg,"l1_resp_scale",l1_resp_scale);
512  double l1_col_scale = get(m_cfg,"l1_col_scale",l1_col_scale);
513  double l1_ind_scale = get(m_cfg,"l1_ind_scale",l1_ind_scale);
514 
515  double mean_threshold = get(m_cfg,"mean_threshold",mean_threshold);
516  double peak_threshold = get(m_cfg,"peak_threshold",peak_threshold);
517 
518 
519  std::vector<double> smearing_vec = get< std::vector<double> >(m_cfg, "filter");
520 
521  // algorithm
522  const int nbin_fit = end_tick-start_tick;
523 
524  // fill the data ...
525  VectorXd init_W = VectorXd::Zero(nbin_fit);
526  VectorXd init_beta = VectorXd::Zero(nbin_fit);
527  VectorXd final_beta = VectorXd::Zero(nbin_fit*2);
528 
529  double temp_sum = 0;
530  double temp1_sum = 0;
531  double temp2_sum = 0;
532  double max_val = -1;
533  double min_val = 1;
534  for (int i=0; i!= nbin_fit; i++){
535  init_W(i) = adctrace->charge().at(i+start_tick-newtrace->tbin()) ;
536  init_beta(i) = newtrace->charge().at(i+start_tick-newtrace->tbin()) ;
537 
538  if (max_val < init_W(i)) max_val = init_W(i);
539  if (min_val > init_W(i)) min_val = init_W(i);
540 
541  if (fabs(init_W(i))>adc_l1_threshold) {
542  temp_sum += init_W(i);
543  temp1_sum += fabs(init_W(i));
544  temp2_sum += fabs(init_beta(i));
545  }
546  }
547 
548 
549 
550  int flag_l1 = 0; // do nothing
551  // 1 do L1
552  if (temp_sum/(temp1_sum*adc_sum_rescaling*1.0/nbin_fit)>adc_ratio_threshold && temp1_sum>adc_sum_threshold){
553  flag_l1 = 1; // do L1 ...
554  }else if (temp1_sum*adc_sum_rescaling*1.0/nbin_fit < adc_sum_rescaling_limit){
555  flag_l1 = 2; //remove signal ...
556  }else if (temp2_sum > 30 * nbin_fit && temp1_sum < 2.0*nbin_fit && max_val - min_val < 22){
557  flag_l1 = 2;
558  }
559 
560 
561 
562  // if (adctrace->channel() == 4079){
563  // std::cout << adctrace->channel() << " " << nbin_fit << " " << start_tick << " " << end_tick << " " << temp_sum << " " << temp1_sum << " " << temp2_sum << " " << max_val << " " << min_val << " " << flag_l1 << std::endl;
564  // }
565 
566  // std::cout << temp_sum << " " << temp1_sum << " " << temp_sum/(temp1_sum*adc_sum_rescaling*1.0/nbin_fit) << " " << adc_ratio_threshold << " " << temp1_sum*adc_sum_rescaling*1.0/nbin_fit << " " << flag_l1 << std::endl;
567 
568  if (flag_l1==1){
569  // do L1 fit ...
570  int n_section = std::round(nbin_fit/l1_seg_length*1.0);
571  if (n_section ==0) n_section =1;
572  std::vector<int> boundaries;
573  for (int i=0;i!=n_section;i++){
574  boundaries.push_back(int(i * nbin_fit /n_section));
575  }
576  boundaries.push_back(nbin_fit);
577 
578  for (int i=0;i!=n_section;i++){
579  int temp_nbin_fit = boundaries.at(i+1)-boundaries.at(i);
580  VectorXd W = VectorXd::Zero(temp_nbin_fit);
581  for (int j=0;j!=temp_nbin_fit;j++){
582  W(j) = init_W(boundaries.at(i)+j);
583  }
584 
585  //for matrix G
586  MatrixXd G = MatrixXd::Zero(temp_nbin_fit, temp_nbin_fit*2);
587 
588  for (int i=0;i!=temp_nbin_fit;i++){
589  // X
590  double t1 = i/2.*units::us; // us, measured time
591  for (int j=0;j!=temp_nbin_fit;j++){
592  // Y ...
593  double t2 = j/2.*units::us; // us, real signal time
594  double delta_t = t1 - t2;
595  if (delta_t >-15*units::us - overall_time_offset && delta_t < 10*units::us - overall_time_offset){
596  G(i,j) = (*lin_W)(delta_t+overall_time_offset+collect_time_offset) * l1_scaling_factor * l1_resp_scale;
597  G(i,temp_nbin_fit+j) = (*lin_V)(delta_t+overall_time_offset) * l1_scaling_factor * l1_resp_scale;
598  }
599  }
600  }
601 
602  double lambda = l1_lambda;//1/2.;
603  WireCell::LassoModel m2(lambda, l1_niteration, l1_epsilon);
604  m2.SetData(G, W);
605  m2.Fit();
606  VectorXd beta = m2.Getbeta();
607  for (int j=0;j!=temp_nbin_fit;j++){
608  final_beta(boundaries.at(i)+j) = beta(j);
609  final_beta(nbin_fit + boundaries.at(i)+j) = beta(temp_nbin_fit+j);
610  }
611  }
612 
613  double sum1 = 0;
614  double sum2 = 0;
615  for (int i=0;i!=nbin_fit;i++){
616  sum1 += final_beta(i);
617  sum2 += final_beta(nbin_fit+i);
618  }
619 
620  if (sum1 > adc_l1_threshold){
621  Waveform::realseq_t l1_signal(nbin_fit,0);
622  Waveform::realseq_t l2_signal(nbin_fit,0);
623  for (int j=0;j!=nbin_fit;j++){
624  l1_signal.at(j) = final_beta(j) * l1_col_scale + final_beta(nbin_fit+j) * l1_ind_scale;
625  }
626  int mid_bin = (smearing_vec.size()-1)/2;
627  //std::cout << smearing_vec.size() << " " << mid_bin << std::endl;
628  for (int j=0;j!=nbin_fit;j++){
629  double content = l1_signal.at(j);
630  if (content>0){
631  for (size_t k=0;k!=smearing_vec.size();k++){
632  int bin = j+k-mid_bin;
633  if (bin>=0&&bin<nbin_fit)
634  l2_signal.at(bin) += content * smearing_vec.at(k);
635  }
636  }
637  }
638 
639  for (int j=0;j!=nbin_fit;j++){
640  if (l2_signal.at(j)<l1_decon_limit/l1_scaling_factor){ // 50 electrons
641  l1_signal.at(j) = 0;
642  }else{
643  l1_signal.at(j) = l2_signal.at(j) * l1_scaling_factor;
644  }
645  }
646 
647  {
648  // go through the new data and clean the small peaks ...
649  std::vector<int> nonzero_bins;
650  std::vector<std::pair<int,int>> ROIs;
651  for (int j=0;j!=nbin_fit;j++){
652  if (l1_signal.at(j)>0)
653  nonzero_bins.push_back(j);
654  }
655 
656  bool flag_start = false;
657  int start_bin=-1,end_bin=-1;
658  for (size_t j=0;j!=nonzero_bins.size();j++){
659  if (!flag_start){
660  start_bin = nonzero_bins.at(j);
661  end_bin = nonzero_bins.at(j);
662  flag_start = true;
663  }else{
664  if (nonzero_bins.at(j) - end_bin == 1){
665  end_bin = nonzero_bins.at(j);
666  }else{
667  ROIs.push_back(std::make_pair(start_bin,end_bin));
668  start_bin = nonzero_bins.at(j);
669  end_bin = nonzero_bins.at(j);
670  }
671  }
672  }
673  if (start_bin >=0)
674  ROIs.push_back(std::make_pair(start_bin,end_bin));
675 
676  for (size_t j=0;j!=ROIs.size();j++){
677  double max_val = -1;
678  double mean_val1 = 0;
679  double mean_val2 = 0;
680  for (int k=ROIs.at(j).first; k<=ROIs.at(j).second; k++){
681  if (l1_signal.at(k) > max_val) max_val = l1_signal.at(k);
682  mean_val1 += l1_signal.at(k);
683  mean_val2 ++;
684  }
685  if (mean_val2!=0)
686  mean_val1 /= mean_val2;
687  if (max_val < peak_threshold && mean_val1 < mean_threshold){
688  for (int k=ROIs.at(j).first; k<=ROIs.at(j).second; k++){
689  l1_signal.at(k) = 0;
690  }
691  }
692  //std::cout << max_val << " " << mean_val1 << std::endl;
693 
694  }
695 
696  // std::cout << nonzero_bins.front() << " X " << nonzero_bins.back() << std::endl;
697  // std::cout << ROIs.size() << std::endl;
698  // for (size_t i=0;i!=ROIs.size();i++){
699  // std::cout << ROIs.at(i).first << " " << ROIs.at(i).second << std::endl;
700  // }
701 
702  // finish cleaning ...
703  }
704 
705 
706  for (int time_tick = start_tick; time_tick!= end_tick; time_tick++){
707  newtrace->charge().at(time_tick-newtrace->tbin())=l1_signal.at(time_tick-start_tick);
708  }
709  }
710  }else if (flag_l1==2){
711  if (flag_shorted){
712  for (int time_tick = start_tick; time_tick!= end_tick; time_tick++){
713  // temporary hack to reset the data ...
714  newtrace->charge().at(time_tick-newtrace->tbin())=0;
715  }
716  }
717  }
718 
719  return flag_l1;
720 
721 }
ITrace::vector tagged_traces(IFrame::pointer frame, IFrame::tag_t tag)
Definition: FrameTools.cxx:111
std::shared_ptr< const IFrame > pointer
Definition: IData.h:19
virtual void configure(const WireCell::Configuration &config)
IConfigurable interface.
Definition: L1SPFilter.cxx:165
linterp< double > * lin_W
Definition: L1SPFilter.h:53
linterp< double > * lin_V
Definition: L1SPFilter.h:52
Sequence< real_t > realseq_t
Definition: Waveform.h:31
void tag_traces(const tag_t &tag, const IFrame::trace_list_t &indices, const IFrame::trace_summary_t &summary=IFrame::trace_summary_t(0))
Definition: SimpleFrame.cxx:76
std::string string
Definition: nybbler.cc:12
Val sum2(const Sequence< Val > &seq)
Return sum of square of all entries in sequence.
Definition: Waveform.h:184
boost::error_info< struct tag_errmsg, std::string > errmsg
Definition: Exceptions.h:54
constexpr T pow(T x)
Definition: pow.h:72
double period
The sampling period of the response function.
Definition: Response.h:92
cfg
Definition: dbjson.py:29
std::vector< pointer > vector
Definition: IData.h:21
A functional object caching gain and shape.
Definition: Response.h:165
virtual bool operator()(const input_pointer &in, output_pointer &out)
IFrameFilter interface.
Definition: L1SPFilter.cxx:178
Binning tbins(nticks, t0, t0+readout_time)
Array::array_xxf as_array(const Schema::PlaneResponse &pr)
Definition: Response.cxx:279
std::shared_ptr< const IFrame > input_pointer
Definition: IFunctionNode.h:39
compseq_t dft(realseq_t seq)
Definition: Waveform.cxx:141
Schema::FieldResponse average_1D(const Schema::FieldResponse &fr)
Definition: Response.cxx:224
#define THROW(e)
Definition: Exceptions.h:25
std::vector< PlaneResponse > planes
List of PlaneResponse objects.
Definition: Response.h:78
Eigen::VectorXd & Getbeta()
Definition: LinearModel.h:16
virtual WireCell::Configuration default_configuration() const
Optional, override to return a hard-coded default configuration.
Definition: L1SPFilter.cxx:97
WIRECELL_FACTORY(L1SPFilter, WireCell::SigProc::L1SPFilter, WireCell::IFrameFilter, WireCell::IConfigurable) using namespace Eigen
std::shared_ptr< const IFrame > output_pointer
Definition: IFunctionNode.h:40
real_t percentile(realseq_t &wave, real_t percentage)
Definition: Waveform.cxx:87
virtual void SetData(Eigen::MatrixXd X, Eigen::VectorXd y)
Definition: LinearModel.h:18
Definition: Main.h:22
int L1_fit(std::shared_ptr< WireCell::SimpleTrace > &newtrace, std::shared_ptr< const WireCell::ITrace > &adctrace, int start_tick, int end_tick, bool flag_shorted=false)
Definition: L1SPFilter.cxx:494
void scale(Sequence< Val > &seq, Val scalar)
Scale (multiply) sequence values by scalar.
Definition: Waveform.h:146
realseq_t idft(compseq_t spec)
Definition: Waveform.cxx:149
static const double m2
Definition: Units.h:80
Json::Value Configuration
Definition: Configuration.h:50
QTextStream & bin(QTextStream &s)
T copy(T const &v)
static const double us
Definition: Units.h:105
Thrown when an error occurs during the data processing.
Definition: Exceptions.h:49
second_as<> second
Type of time stored in seconds, in double precision.
Definition: spacetime.h:80
Sequence< complex_t > compseq_t
A complex-valued sequence, eg for discrete spectrum powers.
Definition: Waveform.h:34
std::vector< size_t > trace_list_t
Definition: IFrame.h:36
double mean(sqlite3 *db, std::string const &table_name, std::string const &column_name)
Definition: statistics.cc:15
Hold info about multiple plane responses in the detector.
Definition: Response.h:75
double speed
The nominal drift speed.
Definition: Response.h:95