OmnibusSigProc.cxx
Go to the documentation of this file.
2 
5 #include "WireCellUtil/String.h"
7 
10 
14 
15 #include "ROI_formation.h"
16 #include "ROI_refinement.h"
17 
19 
22 
23 
24 using namespace WireCell;
25 
26 using namespace WireCell::SigProc;
27 
29  const std::string& per_chan_resp_tn,
30  const std::string& field_response,
31  double fine_time_offset,
32  double coarse_time_offset,
33  double gain,
34  double shaping_time,
35  double inter_gain ,
36  double ADC_mV,
37  float th_factor_ind,
38  float th_factor_col,
39  int pad,
40  float asy,
41  int rebin,
42  double l_factor,
43  double l_max_th,
44  double l_factor1,
45  int l_short_length,
46  int l_jump_one_bin,
47  double r_th_factor ,
48  double r_fake_signal_low_th ,
49  double r_fake_signal_high_th,
50  double r_fake_signal_low_th_ind_factor,
51  double r_fake_signal_high_th_ind_factor,
52  int r_pad ,
53  int r_break_roi_loop ,
54  double r_th_peak ,
55  double r_sep_peak,
56  double r_low_peak_sep_threshold_pre ,
57  int r_max_npeaks ,
58  double r_sigma ,
59  double r_th_percent ,
60  int charge_ch_offset,
61  const std::string& wiener_tag,
62  const std::string& wiener_threshold_tag,
63  const std::string& gauss_tag,
64  bool use_roi_debug_mode,
65  const std::string& tight_lf_tag,
66  const std::string& loose_lf_tag,
67  const std::string& cleanup_roi_tag,
68  const std::string& break_roi_loop1_tag,
69  const std::string& break_roi_loop2_tag,
70  const std::string& shrink_roi_tag,
71  const std::string& extend_roi_tag )
72  : m_anode_tn (anode_tn)
73  , m_per_chan_resp(per_chan_resp_tn)
74  , m_field_response(field_response)
75  , m_fine_time_offset(fine_time_offset)
76  , m_coarse_time_offset(coarse_time_offset)
77  , m_period(0)
78  , m_nticks(0)
79  , m_fft_flag(0)
80  , m_gain(gain)
81  , m_shaping_time(shaping_time)
82  , m_inter_gain(inter_gain)
83  , m_ADC_mV(ADC_mV)
84  , m_th_factor_ind(th_factor_ind)
85  , m_th_factor_col(th_factor_col)
86  , m_pad(pad)
87  , m_asy(asy)
88  , m_rebin(rebin)
89  , m_l_factor(l_factor)
90  , m_l_max_th(l_max_th)
91  , m_l_factor1(l_factor1)
92  , m_l_short_length(l_short_length)
93  , m_l_jump_one_bin(l_jump_one_bin)
94  , m_r_th_factor(r_th_factor)
95  , m_r_fake_signal_low_th(r_fake_signal_low_th)
96  , m_r_fake_signal_high_th(r_fake_signal_high_th)
97  , m_r_fake_signal_low_th_ind_factor(r_fake_signal_low_th_ind_factor)
98  , m_r_fake_signal_high_th_ind_factor(r_fake_signal_high_th_ind_factor)
99  , m_r_pad(r_pad)
100  , m_r_break_roi_loop(r_break_roi_loop)
101  , m_r_th_peak(r_th_peak)
102  , m_r_sep_peak(r_sep_peak)
103  , m_r_low_peak_sep_threshold_pre(r_low_peak_sep_threshold_pre)
104  , m_r_max_npeaks(r_max_npeaks)
105  , m_r_sigma(r_sigma)
106  , m_r_th_percent(r_th_percent)
107  , m_charge_ch_offset(charge_ch_offset)
108  , m_wiener_tag(wiener_tag)
109  , m_wiener_threshold_tag(wiener_threshold_tag)
110  , m_gauss_tag(gauss_tag)
111  , m_frame_tag("sigproc")
112  , m_use_roi_debug_mode(use_roi_debug_mode)
113  , m_tight_lf_tag(tight_lf_tag)
114  , m_loose_lf_tag(loose_lf_tag)
115  , m_cleanup_roi_tag(cleanup_roi_tag)
116  , m_break_roi_loop1_tag(break_roi_loop1_tag)
117  , m_break_roi_loop2_tag(break_roi_loop2_tag)
118  , m_shrink_roi_tag(shrink_roi_tag)
119  , m_extend_roi_tag(extend_roi_tag)
120  , m_sparse(false)
121  , log(Log::logger("sigproc"))
122 {
123  // get wires for each plane
124 
125 
126  //std::cout << m_anode->channels().size() << " " << nwire_u << " " << nwire_v << " " << nwire_w << std::endl;
127 
128 }
129 
130 OmnibusSigProc::~OmnibusSigProc()
131 {
132 }
133 
135 {
136  std::stringstream ss;
137  ss<<"OspChan<c:"<<channel<<",w:"<<wire<<",p:"<<plane<<",i:"<<ident<<">";
138  return ss.str();
139 }
140 
141 
143 {
144  m_sparse = get(config, "sparse", false);
145 
146  m_fine_time_offset = get(config,"ftoffset",m_fine_time_offset);
148  m_anode_tn = get(config, "anode", m_anode_tn);
149 
150  //m_nticks = get(config,"nticks",m_nticks);
151  if (! config["nticks"].isNull() ) {
152  log->warn("OmnibusSigProc has not setting \"nticks\", ignoring value {}", config["nticks"].asInt());
153  }
154  //m_period = get(config,"period",m_period);
155  if (! config["period"].isNull() ) {
156  log->warn("OmnibusSigProc has not setting \"period\", ignoring value {}", config["period"].asDouble());
157  }
158 
159  m_fft_flag = get(config,"fft_flag",m_fft_flag);
160 
161  m_gain = get(config,"gain",m_gain);
162  m_shaping_time = get(config,"shaping",m_shaping_time);
163  m_inter_gain = get(config,"postgain", m_inter_gain);
164  m_ADC_mV = get(config,"ADC_mV", m_ADC_mV);
165 
166  m_per_chan_resp = get(config, "per_chan_resp", m_per_chan_resp);
167  m_field_response = get(config, "field_response", m_field_response);
168 
169  m_th_factor_ind = get(config,"troi_ind_th_factor",m_th_factor_ind);
170  m_th_factor_col = get(config,"troi_col_th_factor",m_th_factor_col);
171  m_pad = get(config,"troi_pad",m_pad);
172  m_asy = get(config,"troi_asy",m_asy);
173  m_rebin = get(config,"lroi_rebin",m_rebin);
174  m_l_factor = get(config,"lroi_th_factor",m_l_factor);
175  m_l_max_th = get(config,"lroi_max_th",m_l_max_th);
176  m_l_factor1 = get(config,"lroi_th_factor1",m_l_factor1);
177  m_l_short_length = get(config,"lroi_short_length",m_l_short_length);
178  m_l_jump_one_bin = get(config,"lroi_jump_one_bin",m_l_jump_one_bin);
179 
180  m_r_th_factor = get(config,"r_th_factor",m_r_th_factor);
181  m_r_fake_signal_low_th = get(config,"r_fake_signal_low_th",m_r_fake_signal_low_th);
182  m_r_fake_signal_high_th = get(config,"r_fake_signal_high_th",m_r_fake_signal_high_th);
183  m_r_fake_signal_low_th_ind_factor = get(config,"r_fake_signal_low_th_ind_factor",m_r_fake_signal_low_th_ind_factor);
184  m_r_fake_signal_high_th_ind_factor = get(config,"r_fake_signal_high_th_ind_factor",m_r_fake_signal_high_th_ind_factor);
185  m_r_pad = get(config,"r_pad",m_r_pad);
186  m_r_break_roi_loop = get(config,"r_break_roi_loop",m_r_break_roi_loop);
187  m_r_th_peak = get(config,"r_th_peak",m_r_th_peak);
188  m_r_sep_peak = get(config,"r_sep_peak",m_r_sep_peak);
189  m_r_low_peak_sep_threshold_pre = get(config,"r_low_peak_sep_threshold_pre",m_r_low_peak_sep_threshold_pre);
190  m_r_max_npeaks = get(config,"r_max_npeaks",m_r_max_npeaks);
191  m_r_sigma = get(config,"r_sigma",m_r_sigma);
192  m_r_th_percent = get(config,"r_th_percent",m_r_th_percent);
193 
194  m_charge_ch_offset = get(config,"charge_ch_offset",m_charge_ch_offset);
195 
196  m_wiener_tag = get(config,"wiener_tag",m_wiener_tag);
197  m_wiener_threshold_tag = get(config,"wiener_threshold_tag",m_wiener_threshold_tag);
198  m_gauss_tag = get(config,"gauss_tag",m_gauss_tag);
199  m_frame_tag = get(config,"frame_tag",m_frame_tag);
200 
201  m_use_roi_debug_mode = get(config,"use_roi_debug_mode",m_use_roi_debug_mode);
202  m_tight_lf_tag = get(config,"tight_lf_tag",m_tight_lf_tag);
203  m_loose_lf_tag = get(config,"loose_lf_tag",m_loose_lf_tag);
204  m_cleanup_roi_tag = get(config,"cleanup_roi_tag",m_cleanup_roi_tag);
205  m_break_roi_loop1_tag = get(config,"break_roi_loop1_tag",m_break_roi_loop1_tag);
206  m_break_roi_loop2_tag = get(config,"break_roi_loop2_tag",m_break_roi_loop2_tag);
207  m_shrink_roi_tag = get(config,"shrink_roi_tag",m_shrink_roi_tag);
208  m_extend_roi_tag = get(config,"extend_roi_tag",m_extend_roi_tag);
209 
210  // this throws if not found
211  m_anode = Factory::find_tn<IAnodePlane>(m_anode_tn);
212 
213  // Build up the channel map. The OSP channel must run contiguously
214  // first up the U, then V, then W "wires". Ie, face-major order,
215  // but we have plane-major order so make a temporary collection.
216  IChannel::vector plane_channels[3];
217  std::stringstream ss;
218  ss << "OmnibusSigproc: internal channel map for tags: gauss:\""
219  << m_gauss_tag << "\", wiener:\"" << m_wiener_tag << "\", frame:\"" << m_frame_tag << "\"\n";
220 
221  for (auto face : m_anode->faces()) {
222  if (!face) { // A null face means one sided AnodePlane.
223  continue; // Can be "back" or "front" face.
224  }
225  for (auto plane: face->planes()) {
226  int plane_index = plane->planeid().index();
227  auto& pchans = plane_channels[plane_index];
228  // These IChannel vectors are ordered in same order as wire-in-plane.
229  const auto& ichans = plane->channels();
230  // Append
231  pchans.reserve(pchans.size() + ichans.size());
232  pchans.insert(pchans.end(), ichans.begin(), ichans.end());
233  ss << "\tpind" << plane_index << " "
234  << "aid" << m_anode->ident() << " "
235  << "fid" << face->ident() << " "
236  << "pid" << plane->ident() << " "
237  << "cid" << ichans.front()->ident() << " -> cid" << ichans.back()->ident() << ", "
238  << "cind" << ichans.front()->index() << " -> cind" << ichans.back()->index() << ", "
239  << "(n="<<pchans.size()<<")\n";
240  }
241  }
242  log->debug(ss.str());
243 
244  int osp_channel_number = 0;
245  for (int iplane = 0; iplane < 3; ++iplane) {
246  m_nwires[iplane] = plane_channels[iplane].size();
247  int osp_wire_number = 0;
248  for (auto ichan : plane_channels[iplane]) {
249  const int wct_chan_ident = ichan->ident();
250  OspChan och(osp_channel_number, osp_wire_number, iplane, wct_chan_ident);
251  m_channel_map[wct_chan_ident] = och; // we could save some space by storing
252  m_channel_range[iplane].push_back(och);// wct ident here instead of a whole och.
253  ++osp_wire_number;
254  ++osp_channel_number;
255  }
256  }
257 
258 }
259 
261 {
263  cfg["anode"] = m_anode_tn;
264  cfg["ftoffset"] = m_fine_time_offset;
265  cfg["ctoffset"] = m_coarse_time_offset;
266  //cfg["nticks"] = m_nticks;
267  //cfg["period"] = m_period;
268 
269  cfg["fft_flag"] = m_fft_flag;
270 
271  cfg["gain"] = m_gain;
272  cfg["shaping"] = m_shaping_time;
273  cfg["inter_gain"] = m_inter_gain;
274  cfg["ADC_mV"] = m_ADC_mV;
275 
276  cfg["per_chan_resp"] = m_per_chan_resp;
277  cfg["field_response"] = m_field_response;
278 
279  cfg["troi_ind_th_factor"] = m_th_factor_ind;
280  cfg["troi_col_th_factor"] = m_th_factor_col;
281  cfg["troi_pad"] = m_pad;
282  cfg["troi_asy"] = m_asy;
283  cfg["lroi_rebin"] = m_rebin;
284  cfg["lroi_th_factor"] = m_l_factor;
285  cfg["lroi_max_th"] = m_l_max_th;
286  cfg["lroi_th_factor1"] = m_l_factor1;
287  cfg["lroi_short_length"] = m_l_short_length;
288  cfg["lroi_jump_one_bin"] = m_l_jump_one_bin;
289 
290  cfg["r_th_factor"] = m_r_th_factor;
291  cfg["r_fake_signal_low_th"] = m_r_fake_signal_low_th;
292  cfg["r_fake_signal_high_th"] = m_r_fake_signal_high_th;
293  cfg["r_fake_signal_low_th_ind_factor"] = m_r_fake_signal_low_th_ind_factor;
294  cfg["r_fake_signal_high_th_ind_factor"] = m_r_fake_signal_high_th_ind_factor;
295  cfg["r_pad"] = m_r_pad;
296  cfg["r_break_roi_loop"] = m_r_break_roi_loop;
297  cfg["r_th_peak"] = m_r_th_peak;
298  cfg["r_sep_peak"] = m_r_sep_peak;
299  cfg["r_low_peak_sep_threshold_pre"] = m_r_low_peak_sep_threshold_pre;
300  cfg["r_max_npeaks"] = m_r_max_npeaks;
301  cfg["r_sigma"] = m_r_sigma;
302  cfg["r_th_precent"] = m_r_th_percent;
303 
304  // fixme: unused?
305  cfg["charge_ch_offset"] = m_charge_ch_offset;
306 
307  cfg["wiener_tag"] = m_wiener_tag;
308  cfg["wiener_threshold_tag"] = m_wiener_threshold_tag;
309  cfg["gauss_tag"] = m_gauss_tag;
310  cfg["frame_tag"] = m_frame_tag;
311 
312  cfg["use_roi_debug_mode"] = m_use_roi_debug_mode; // default false
313  cfg["tight_lf_tag"] = m_tight_lf_tag;
314  cfg["loose_lf_tag"] = m_loose_lf_tag;
315  cfg["cleanup_roi_tag"] = m_cleanup_roi_tag;
316  cfg["break_roi_loop1_tag"] = m_break_roi_loop1_tag;
317  cfg["break_roi_loop2_tag"] = m_break_roi_loop2_tag;
318  cfg["shrink_roi_tag"] = m_shrink_roi_tag;
319  cfg["extend_roi_tag"] = m_extend_roi_tag;
320 
321  cfg["sparse"] = false;
322 
323  return cfg;
324 
325 }
326 
327 void OmnibusSigProc::load_data(const input_pointer& in, int plane){
328 
329  m_r_data = Array::array_xxf::Zero(m_fft_nwires[plane],m_fft_nticks);
330 
331  auto traces = in->traces();
332 
333  auto& bad = m_cmm["bad"];
334  int nbad = 0;
335 
336  for (auto trace : *traces.get()) {
337  int wct_channel_ident = trace->channel();
338  OspChan och = m_channel_map[wct_channel_ident];
339  if (plane != och.plane) {
340  continue; // we'll catch it in another call to load_data
341  }
342 
343  // fixme: this code uses tbin() but other places in this file will barf if tbin!=0.
344  int tbin = trace->tbin();
345  auto const& charges = trace->charge();
346  const int ntbins = std::min((int)charges.size(), m_nticks);
347  for (int qind = 0; qind < ntbins; ++qind) {
348  m_r_data(och.wire + m_pad_nwires[plane], tbin + qind) = charges[qind];
349  }
350 
351  //ensure dead channels are indeed dead ...
352  auto const& badch = bad.find(och.channel);
353  if (badch == bad.end()) {
354  continue;
355  }
356 
357  auto const& binranges = badch->second;
358  for (auto const& br : binranges) {
359  ++nbad;
360  for (int i = br.first; i != br.second; ++i) {
361  m_r_data(och.wire+m_pad_nwires[plane], i) = 0;
362  }
363  }
364 
365  }
366  log->debug("OmnibusSigProc: plane index: {} input data identifies {} bad regions",
367  plane, nbad);
368 
369 }
370 
371 // used in sparsifying below. Could use C++17 lambdas....
372 static bool ispositive(float x) { return x > 0.0; }
373 static bool isZero(float x) { return x == 0.0; }
374 
376  const std::vector<float>& perwire_rmses,
377  IFrame::trace_summary_t& threshold)
378 {
379  // reuse this temporary vector to hold charge for a channel.
380  ITrace::ChargeSequence charge(m_nticks, 0.0);
381 
382  double qtot = 0.0;
383  for (auto och : m_channel_range[plane]) { // ordered by osp channel
384 
385  // Post process: zero out any negative signal and that from "bad" channels.
386  // fixme: better if we move this outside of save_data().
387  for (int itick=0;itick!=m_nticks;itick++){
388  const float q = m_r_data(och.wire, itick);
389  // charge.at(itick) = q > 0.0 ? q : 0.0;
390  //charge.at(itick) = q ;
391  if (m_use_roi_debug_mode) charge.at(itick) = q ; // debug mode: save all decons
392  else charge.at(itick) = q > 0.0 ? q : 0.0; // default mode: only save positive
393  }
394  {
395  auto& bad = m_cmm["bad"];
396  auto badit = bad.find(och.channel);
397  if (badit != bad.end()) {
398  for (auto bad : badit->second) {
399  for (int itick=bad.first; itick < bad.second; ++itick) {
400  charge.at(itick) = 0.0;
401  }
402  }
403  }
404  }
405 
406 
407  // debug
408  for (int j=0;j!=m_nticks;j++){
409  qtot += charge.at(j);
410  }
411 
412  const float thresh = perwire_rmses[och.wire];
413 
414  // actually save out
415  if (m_sparse) {
416  // Save waveform sparsely by finding contiguous, positive samples.
417  std::vector<float>::const_iterator beg=charge.begin(), end=charge.end();
418  auto i1 = std::find_if(beg, end, ispositive); // first start
419  while (i1 != end) {
420  // stop at next zero or end and make little temp vector
421  auto i2 = std::find_if(i1, end, isZero);
422  const std::vector<float> q(i1,i2);
423 
424  // save out
425  const int tbin = i1 - beg;
426  SimpleTrace *trace = new SimpleTrace(och.ident, tbin, q);
427  const size_t trace_index = itraces.size();
428  indices.push_back(trace_index);
429  itraces.push_back(ITrace::pointer(trace));
430  threshold.push_back(thresh);
431 
432  // find start for next loop
433  i1 = std::find_if(i2, end, ispositive);
434  }
435  }
436  else {
437  // Save the waveform densely, including zeros.
438  SimpleTrace *trace = new SimpleTrace(och.ident, 0, charge);
439  const size_t trace_index = itraces.size();
440  indices.push_back(trace_index);
441  itraces.push_back(ITrace::pointer(trace));
442  threshold.push_back(thresh);
443  }
444  }
445 
446  // debug
447  if (indices.empty()) {
448  log->debug("OmnibusSigProc::save_data plane index: {} empty", plane);
449  }
450  else {
451  const int nadded = indices.back() - indices.front() + 1;
452  log->debug("OmnibusSigProc::save_data plane index: Qtot={} added {} traces to total {} indices:[{},{}]",
453  plane, qtot, nadded, indices.size(), indices.front(), indices.back());
454  }
455 }
456 
457 // save ROI into the out frame
459  int plane, std::vector<std::list<SignalROI*> >& roi_channel_list)
460 {
461  // reuse this temporary vector to hold charge for a channel.
462  ITrace::ChargeSequence charge(m_nticks, 0.0);
463 
464  for (auto och : m_channel_range[plane]) { // ordered by osp channel
465 
466  // std::cout << "[wgu] wire: " << och.wire << " roi_channel_list.size(): " << roi_channel_list.size() << std::endl;
467 
468  std::fill(charge.begin(), charge.end(), 0);
469 
470  // for (auto it = roi_channel_list.at(och.wire).begin(); it!= roi_channel_list.at(och.wire).end(); it++){
471  // SignalROI *roi = *it;
472  // int start = roi->get_start_bin();
473  // int end = roi->get_end_bin();
474  // std::cout << "[wgu] wire: " << och.wire << " ROI: " << start << " " << end << " channel: " << roi->get_chid() << " plane: " << roi->get_plane() << std::endl;
475  // }
476 
477  int prev_roi_end = -1;
478  for (auto signal_roi: roi_channel_list.at(och.wire) ) {
479  int start = signal_roi->get_start_bin();
480  int end = signal_roi->get_end_bin();
481  // if (och.wire==732)
482  // std::cout << "[wgu] OmnibusSigProc::save_roi() wire: " << och.wire << " channel: " << och.channel << " ROI: " << start << " " << end << " channel: " << signal_roi->get_chid() << " plane: " << signal_roi->get_plane() << " max height: " << signal_roi->get_max_height() << std::endl;
483  if (start<0 or end<0) continue;
484  for (int i=start; i<=end; i++) {
485  if (i-prev_roi_end<2) continue; // skip one bin for visibility of two adjacent ROIs
486  charge.at(i) = 10.; // arbitary constant number for ROI display
487  }
488  prev_roi_end = end;
489  }
490 
491  {
492  auto& bad = m_cmm["bad"];
493  auto badit = bad.find(och.channel);
494  if (badit != bad.end()) {
495  for (auto bad : badit->second) {
496  for (int itick=bad.first; itick < bad.second; ++itick) {
497  charge.at(itick) = 0.0;
498  }
499  }
500  }
501  }
502 
503 
504  // actually save out
505  if (m_sparse) {
506  // Save waveform sparsely by finding contiguous, positive samples.
507  std::vector<float>::const_iterator beg=charge.begin(), end=charge.end();
508  auto i1 = std::find_if(beg, end, ispositive); // first start
509  while (i1 != end) {
510  // stop at next zero or end and make little temp vector
511  auto i2 = std::find_if(i1, end, isZero);
512  const std::vector<float> q(i1,i2);
513 
514  // save out
515  const int tbin = i1 - beg;
516  SimpleTrace *trace = new SimpleTrace(och.ident, tbin, q);
517  const size_t trace_index = itraces.size();
518  indices.push_back(trace_index);
519  itraces.push_back(ITrace::pointer(trace));
520  // if (och.wire==67) std::cout << "[wgu] och channel: " << och.channel << " wire: " << och.wire << " plane: " << och.plane << " ident: " << och.ident << " tbin: " << tbin << " len: " << i2-i1 << std::endl;
521 
522  // find start for next loop
523  i1 = std::find_if(i2, end, ispositive);
524  }
525  }
526  else {
527  // Save the waveform densely, including zeros.
528  SimpleTrace *trace = new SimpleTrace(och.ident, 0, charge);
529  const size_t trace_index = itraces.size();
530  indices.push_back(trace_index);
531  itraces.push_back(ITrace::pointer(trace));
532  }
533  }
534 }
535 
537 {
538  m_period = frame->tick();
539  {
540  std::vector<int> tbins;
541  for (auto trace : *frame->traces()) {
542  const int tbin = trace->tbin();
543  const int nbins = trace->charge().size();
544  tbins.push_back(tbin);
545  tbins.push_back(tbin+nbins);
546  }
547  auto mme = std::minmax_element(tbins.begin(), tbins.end());
548  int tbinmin = *mme.first;
549  int tbinmax = *mme.second;
550  m_nticks = tbinmax-tbinmin;
551  log->debug("OmnibusSigProc: nticks={} tbinmin={} tbinmax={}",
552  m_nticks, tbinmin, tbinmax);
553 
554  if (m_fft_flag==0){
556  }else{
558  log->debug("OmnibusSigProc: enlarge window from {} to {}", m_nticks, m_fft_nticks);
559  }
560  //
561 
563  }
564 
565  auto ifr = Factory::find_tn<IFieldResponse>(m_field_response);
566  // Get full, "fine-grained" field responses defined at impact
567  // positions.
568  Response::Schema::FieldResponse fr = ifr->field_response();
569 
570  // Make a new data set which is the average FR
572 
573  for (int i=0;i!=3;i++){
574  //
575  if (m_fft_flag==0){
576  m_fft_nwires[i] = m_nwires[i];
577  }else{
578  m_fft_nwires[i] = fft_best_length(m_nwires[i]+fravg.planes[0].paths.size()-1,1);
579  log->debug("OmnibusSigProc: enlarge wire number in plane {} from {} to {}",
580  i, m_nwires[i], m_fft_nwires[i]);
581  }
582  m_pad_nwires[i] = (m_fft_nwires[i]-m_nwires[i])/2;
583  }
584 
585  // since we only do FFT along time, no need to change dimension for wire ...
586  const size_t fine_nticks = fft_best_length(fravg.planes[0].paths[0].current.size());
587  int fine_nwires = fravg.planes[0].paths.size();
588 
590  WireCell::Binning tbins(fine_nticks, 0, fine_nticks * fravg.period);
592  auto ewave = ce.generate(tbins);
593  Waveform::scale(ewave, m_inter_gain * m_ADC_mV * (-1));
594  elec = Waveform::dft(ewave);
595 
596  std::complex<float> fine_period(fravg.period,0);
597 
600  for (int i=0;i!=m_fft_nticks;i++){
601  ctbins.at(i) = i * m_period;
602  }
603 
604 
605 
606  Waveform::realseq_t ftbins(fine_nticks);
607  for (size_t i=0;i!=fine_nticks;i++){
608  ftbins.at(i) = i * fravg.period;
609  }
610 
611  // clear the overall response
612  for (int i=0;i!=3;i++){
613  overall_resp[i].clear();
614  }
615 
616  m_intrinsic_time_offset = fr.origin/fr.speed;
617 
618 
619  // Convert each average FR to a 2D array
620  for (int iplane=0; iplane<3; ++iplane) {
621  auto arr = Response::as_array(fravg.planes[iplane], fine_nwires, fine_nticks);
622 
623  // do FFT for response ...
624  Array::array_xxc c_data = Array::dft_rc(arr,0);
625  int nrows = c_data.rows();
626  int ncols = c_data.cols();
627 
628  for (int irow = 0; irow < nrows; ++irow){
629  for (int icol = 0; icol < ncols; ++ icol){
630  c_data(irow,icol) = c_data(irow,icol) * elec.at(icol) * fine_period;
631  }
632  }
633 
634  arr = Array::idft_cr(c_data,0);
635 
636 
637  // figure out how to do fine ... shift (good ...)
638  int fine_time_shift = m_fine_time_offset / fravg.period;
639  if (fine_time_shift>0){
640  Array::array_xxf arr1(nrows,ncols - fine_time_shift);
641  arr1 = arr.block(0,0,nrows,ncols - fine_time_shift);
642  Array::array_xxf arr2(nrows,fine_time_shift);
643  arr2 = arr.block(0,ncols-fine_time_shift,nrows,fine_time_shift);
644  arr.block(0,0,nrows,fine_time_shift) = arr2;
645  arr.block(0,fine_time_shift,nrows,ncols-fine_time_shift) = arr1;
646 
647  // Array::array_xxf arr1(nrows,fine_time_shift);
648  // arr1 = arr.block(0,0,nrows,fine_time_shift);
649  // Array::array_xxf arr2(nrows,ncols-fine_time_shift);
650  // arr2 = arr.block(0,fine_time_shift,nrows,ncols-fine_time_shift);
651  // arr.block(0,0,nrows,ncols-fine_time_shift) = arr2;
652  // arr.block(0,ncols-fine_time_shift,nrows,fine_time_shift) = arr1;
653  }
654 
655 
656  // redigitize ...
657  for (int irow = 0; irow < fine_nwires; ++ irow){
658  // gtemp = new TGraph();
659 
660  size_t fcount = 1;
661  for (int i=0;i!=m_fft_nticks;i++){
662  double ctime = ctbins.at(i);
663 
664  if (fcount < fine_nticks)
665  while(ctime > ftbins.at(fcount)){
666  fcount ++;
667  if (fcount >= fine_nticks) break;
668  }
669 
670 
671  if(fcount < fine_nticks){
672  wfs.at(i) = ((ctime - ftbins.at(fcount-1)) /fravg.period * arr(irow,fcount-1) + (ftbins.at(fcount)-ctime)/fravg.period * arr(irow,fcount)) ;// / (-1);
673  }else{
674  wfs.at(i) = 0;
675  }
676  }
677 
678  overall_resp[iplane].push_back(wfs);
679 
680  //wfs.clear();
681  } // loop inside wire ...
682 
683 
684  // calculated the wire shift ...
685  m_wire_shift[iplane] = (int(overall_resp[iplane].size())-1)/2;
686 
687 
688  }// loop over plane
689 
690 
691 
692 }
693 
695 
696  for (int i=0;i!=arr.rows();i++){
697  Waveform::realseq_t signal(arr.cols());
698  int ncount = 0;
699  for (int j=0;j!=arr.cols();j++){
700  if (arr(i,j)!=0){
701  signal.at(ncount) = arr(i,j);
702  ncount ++;
703  }
704  }
705  signal.resize(ncount);
706  float baseline = WireCell::Waveform::median(signal);
707 
708  Waveform::realseq_t temp_signal(arr.cols());
709  ncount = 0;
710  for (size_t j =0; j!=signal.size();j++){
711  if (fabs(signal.at(j)-baseline) < 500){
712  temp_signal.at(ncount) = signal.at(j);
713  ncount ++;
714  }
715  }
716  temp_signal.resize(ncount);
717 
718  baseline = WireCell::Waveform::median(temp_signal);
719 
720  for (int j=0;j!=arr.cols();j++){
721  if (arr(i,j)!=0)
722  arr(i,j) -= baseline;
723  }
724  }
725 }
726 
727 
729 
730  // data part ...
731  // first round of FFT on time
733 
734 
735  // now apply the ch-by-ch response ...
736  if (! m_per_chan_resp.empty()) {
737  log->debug("OmnibusSigProc: applying ch-by-ch electronics response correction");
738  auto cr = Factory::find_tn<IChannelResponse>(m_per_chan_resp);
739  auto cr_bins = cr->channel_response_binning();
740  if (cr_bins.binsize() != m_period) {
741  log->critical("OmnibusSigProc::decon_2D_init: channel response size mismatch");
742  THROW(ValueError() << errmsg{"OmnibusSigProc::decon_2D_init: channel response size mismatch"});
743  }
744  //starndard electronics response ...
745  // WireCell::Binning tbins(m_nticks, 0-m_period/2., m_nticks*m_period-m_period/2.);
746  // Response::ColdElec ce(m_gain, m_shaping_time);
747 
748  // temporary hack ...
749  //float scaling = 1./(1e-9*0.5/1.13312);
750  //WireCell::Binning tbins(m_nticks, (-5-0.5)*m_period, (m_nticks-5-0.5)*m_period-m_period);
751  //Response::ColdElec ce(m_gain*scaling, m_shaping_time);
752  //// this is moved into wirecell.sigproc.main production of
753  //// microboone-channel-responses-v1.json.bz2
754  WireCell::Binning tbins(m_fft_nticks, cr_bins.min(), cr_bins.min() + m_fft_nticks*m_period);
756 
757  const auto ewave = ce.generate(tbins);
758  const WireCell::Waveform::compseq_t elec = Waveform::dft(ewave);
759 
760  for (auto och : m_channel_range[plane]) {
761  //const auto& ch_resp = cr->channel_response(och.ident);
762  Waveform::realseq_t tch_resp = cr->channel_response(och.ident);
763  tch_resp.resize(m_fft_nticks,0);
764  const WireCell::Waveform::compseq_t ch_elec = Waveform::dft(tch_resp);
765 
766  const int irow = och.wire+m_pad_nwires[plane];
767  for (int icol = 0; icol != m_c_data.cols(); icol++){
768  const auto four = ch_elec.at(icol);
769  if (std::abs(four) != 0){
770  m_c_data(irow,icol) *= elec.at(icol) / four;
771  }else{
772  m_c_data(irow,icol) = 0;
773  }
774  }
775  }
776  }
777 
778 
779 
780 
781  //second round of FFT on wire
783 
784  //response part ...
785  Array::array_xxf r_resp = Array::array_xxf::Zero(m_r_data.rows(),m_fft_nticks);
786  for (size_t i=0;i!=overall_resp[plane].size();i++){
787  for (int j=0;j!=m_fft_nticks;j++){
788  r_resp(i,j) = overall_resp[plane].at(i).at(j);
789  }
790  }
791 
792  // do first round FFT on the resposne on time
793  Array::array_xxc c_resp = Array::dft_rc(r_resp,0);
794  // do second round FFT on the response on wire
795  c_resp = Array::dft_cc(c_resp,1);
796 
797 
798  //make ratio to the response and apply wire filter
799  m_c_data = m_c_data/c_resp;
800 
801  // apply software filter on wire
802  const std::vector<std::string> filter_names{"Wire_ind", "Wire_ind", "Wire_col"};
803  Waveform::realseq_t wire_filter_wf;
804  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter", filter_names[plane]);
805  wire_filter_wf = ncr1->filter_waveform(m_c_data.rows());
806  for (int irow=0; irow<m_c_data.rows(); ++irow) {
807  for (int icol=0; icol<m_c_data.cols(); ++icol) {
808  float val = abs(m_c_data(irow,icol));
809  if (std::isnan(val)) {
810  m_c_data(irow,icol) = -0.0;
811  }
812  if (std::isinf(val)) {
813  m_c_data(irow,icol) = 0.0;
814  }
815  m_c_data(irow,icol) *= wire_filter_wf.at(irow);
816  }
817  }
818 
819  //do the first round of inverse FFT on wire
821 
822  // do the second round of inverse FFT on time
824 
825  // do the shift in wire
826  const int nrows = m_r_data.rows();
827  const int ncols = m_r_data.cols();
828  {
829  Array::array_xxf arr1(m_wire_shift[plane], ncols) ;
830  arr1 = m_r_data.block(nrows-m_wire_shift[plane] , 0 , m_wire_shift[plane], ncols);
831  Array::array_xxf arr2(nrows-m_wire_shift[plane],ncols);
832  arr2 = m_r_data.block(0,0,nrows-m_wire_shift[plane],ncols);
833  m_r_data.block(0,0,m_wire_shift[plane],ncols) = arr1;
834  m_r_data.block(m_wire_shift[plane],0,nrows-m_wire_shift[plane],ncols) = arr2;
835  }
836 
837  //do the shift in time
839  if (time_shift > 0){
840  Array::array_xxf arr1(nrows,ncols - time_shift);
841  arr1 = m_r_data.block(0,0,nrows,ncols - time_shift);
842  Array::array_xxf arr2(nrows,time_shift);
843  arr2 = m_r_data.block(0,ncols-time_shift,nrows,time_shift);
844  m_r_data.block(0,0,nrows,time_shift) = arr2;
845  m_r_data.block(0,time_shift,nrows,ncols-time_shift) = arr1;
846  }
848 }
849 
850 
852  // apply software filter on time
853 
854  const std::vector<std::string> filter_names{"Wiener_tight_U", "Wiener_tight_V", "Wiener_tight_W"};
855  Waveform::realseq_t roi_hf_filter_wf;
856 
857  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter", filter_names[plane]);
858  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
859 
860  Array::array_xxc c_data_afterfilter(m_c_data.rows(),m_c_data.cols());
861  for (int irow=0; irow<m_c_data.rows(); ++irow) {
862  for (int icol=0; icol<m_c_data.cols(); ++icol) {
863  c_data_afterfilter(irow,icol) = m_c_data(irow,icol) * roi_hf_filter_wf.at(icol);
864  }
865  }
866 
867  //do the second round of inverse FFT on wire
868  Array::array_xxf tm_r_data = Array::idft_cr(c_data_afterfilter,0);
869  m_r_data = tm_r_data.block(m_pad_nwires[plane],0,m_nwires[plane],m_nticks);
871 }
872 
873 
875  // apply software filter on time
876 
877  Waveform::realseq_t roi_hf_filter_wf;
878  if (plane ==0){
879  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_U");
880  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
881  auto ncr2 = Factory::find<IFilterWaveform>("LfFilter","ROI_tight_lf");
882  auto temp_filter = ncr2->filter_waveform(m_c_data.cols());
883  for(size_t i=0;i!=roi_hf_filter_wf.size();i++){
884  roi_hf_filter_wf.at(i) *= temp_filter.at(i);
885  }
886  }else if (plane==1){
887  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_V");
888  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
889  auto ncr2 = Factory::find<IFilterWaveform>("LfFilter","ROI_tight_lf");
890  auto temp_filter = ncr2->filter_waveform(m_c_data.cols());
891  for(size_t i=0;i!=roi_hf_filter_wf.size();i++){
892  roi_hf_filter_wf.at(i) *= temp_filter.at(i);
893  }
894  }else{
895  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_W");
896  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
897  }
898 
899  Array::array_xxc c_data_afterfilter(m_c_data.rows(),m_c_data.cols());
900  for (int irow=0; irow<m_c_data.rows(); ++irow) {
901  for (int icol=0; icol<m_c_data.cols(); ++icol) {
902  c_data_afterfilter(irow,icol) = m_c_data(irow,icol) * roi_hf_filter_wf.at(icol);
903  }
904  }
905 
906  //do the second round of inverse FFT on wire
907  Array::array_xxf tm_r_data = Array::idft_cr(c_data_afterfilter,0);
908  m_r_data = tm_r_data.block(m_pad_nwires[plane],0,m_nwires[plane],m_nticks);
910 
911 }
912 
913 // same as above but with "tight" -> "tighter" for ROI filterss.
915  // apply software filter on time
916 
917  Waveform::realseq_t roi_hf_filter_wf;
918  if (plane ==0){
919  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_U");
920  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
921  auto ncr2 = Factory::find<IFilterWaveform>("LfFilter","ROI_tighter_lf");
922  auto temp_filter = ncr2->filter_waveform(m_c_data.cols());
923  for(size_t i=0;i!=roi_hf_filter_wf.size();i++){
924  roi_hf_filter_wf.at(i) *= temp_filter.at(i);
925  }
926  }else if (plane==1){
927  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_V");
928  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
929  auto ncr2 = Factory::find<IFilterWaveform>("LfFilter","ROI_tighter_lf");
930  auto temp_filter = ncr2->filter_waveform(m_c_data.cols());
931  for(size_t i=0;i!=roi_hf_filter_wf.size();i++){
932  roi_hf_filter_wf.at(i) *= temp_filter.at(i);
933  }
934  }else{
935  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_W");
936  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
937  }
938 
939  Array::array_xxc c_data_afterfilter(m_c_data.rows(),m_c_data.cols());
940  for (int irow=0; irow<m_c_data.rows(); ++irow) {
941  for (int icol=0; icol<m_c_data.cols(); ++icol) {
942  c_data_afterfilter(irow,icol) = m_c_data(irow,icol) * roi_hf_filter_wf.at(icol);
943  }
944  }
945 
946  //do the second round of inverse FFT on wire
947  Array::array_xxf tm_r_data = Array::idft_cr(c_data_afterfilter,0);
948  m_r_data = tm_r_data.block(m_pad_nwires[plane],0,m_nwires[plane],m_nticks);
950 
951 
952 }
953 
954 
956  if (plane == 2) {
957  return; // don't filter colleciton
958  }
959 
960  // apply software filter on time
961 
962  Waveform::realseq_t roi_hf_filter_wf;
963  Waveform::realseq_t roi_hf_filter_wf1;
964  Waveform::realseq_t roi_hf_filter_wf2;
965  if (plane ==0){
966  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_U");
967  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
968  roi_hf_filter_wf1 = roi_hf_filter_wf;
969  {
970  auto ncr2 = Factory::find<IFilterWaveform>("LfFilter","ROI_loose_lf");
971  auto temp_filter = ncr2->filter_waveform(m_c_data.cols());
972  for(size_t i=0;i!=roi_hf_filter_wf.size();i++){
973  roi_hf_filter_wf.at(i) *= temp_filter.at(i);
974  }
975  }
976  {
977  auto ncr2 = Factory::find<IFilterWaveform>("LfFilter","ROI_tight_lf");
978  auto temp_filter = ncr2->filter_waveform(m_c_data.cols());
979  for(size_t i=0;i!=roi_hf_filter_wf.size();i++){
980  roi_hf_filter_wf1.at(i) *= temp_filter.at(i);
981  }
982  }
983  }else if (plane==1){
984  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_V");
985  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
986  roi_hf_filter_wf1 = roi_hf_filter_wf;
987  {
988  auto ncr2 = Factory::find<IFilterWaveform>("LfFilter","ROI_loose_lf");
989  auto temp_filter = ncr2->filter_waveform(m_c_data.cols());
990  for(size_t i=0;i!=roi_hf_filter_wf.size();i++){
991  roi_hf_filter_wf.at(i) *= temp_filter.at(i);
992  }
993  }
994  {
995  auto ncr2 = Factory::find<IFilterWaveform>("LfFilter","ROI_tight_lf");
996  auto temp_filter = ncr2->filter_waveform(m_c_data.cols());
997  for(size_t i=0;i!=roi_hf_filter_wf.size();i++){
998  roi_hf_filter_wf1.at(i) *= temp_filter.at(i);
999  }
1000  }
1001  }else{
1002  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_W");
1003  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
1004  }
1005 
1006  const int n_lfn_nn = 2;
1007  const int n_bad_nn = plane ? 1 : 2;
1008 
1009  Array::array_xxc c_data_afterfilter(m_c_data.rows(),m_c_data.cols());
1010  for (auto och : m_channel_range[plane]) {
1011  const int irow = och.wire;
1012 
1013  roi_hf_filter_wf2 = roi_hf_filter_wf;
1014  if (masked_neighbors("bad", och, n_bad_nn) or
1015  masked_neighbors("lf_noisy", och, n_lfn_nn))
1016  {
1017  roi_hf_filter_wf2 = roi_hf_filter_wf1;
1018  }
1019 
1020  for (int icol=0; icol<m_c_data.cols(); ++icol) {
1021  c_data_afterfilter(irow,icol) = m_c_data(irow,icol) * roi_hf_filter_wf2.at(icol);
1022  }
1023  }
1024 
1025  //do the second round of inverse FFT on wire
1026  Array::array_xxf tm_r_data = Array::idft_cr(c_data_afterfilter,0);
1027  m_r_data = tm_r_data.block(m_pad_nwires[plane],0,m_nwires[plane],m_nticks);
1029 }
1030 
1031 // similar as decon_2D_looseROI() but without tightLF
1033  // apply software filter on time
1034  if (plane == 2) {
1035  return; // don't filter colleciton
1036  }
1037 
1038  Waveform::realseq_t roi_hf_filter_wf;
1039  if (plane ==0){
1040  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_U");
1041  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
1042  auto ncr2 = Factory::find<IFilterWaveform>("LfFilter","ROI_loose_lf");
1043  auto temp_filter = ncr2->filter_waveform(m_c_data.cols());
1044  for(size_t i=0;i!=roi_hf_filter_wf.size();i++){
1045  roi_hf_filter_wf.at(i) *= temp_filter.at(i);
1046  }
1047  }else if (plane==1){
1048  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_V");
1049  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
1050  auto ncr2 = Factory::find<IFilterWaveform>("LfFilter","ROI_loose_lf");
1051  auto temp_filter = ncr2->filter_waveform(m_c_data.cols());
1052  for(size_t i=0;i!=roi_hf_filter_wf.size();i++){
1053  roi_hf_filter_wf.at(i) *= temp_filter.at(i);
1054  }
1055  }else{
1056  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_tight_W");
1057  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
1058  }
1059 
1060  Array::array_xxc c_data_afterfilter(m_c_data.rows(),m_c_data.cols());
1061  for (int irow=0; irow<m_c_data.rows(); ++irow) {
1062  for (int icol=0; icol<m_c_data.cols(); ++icol) {
1063  c_data_afterfilter(irow,icol) = m_c_data(irow,icol) * roi_hf_filter_wf.at(icol);
1064  }
1065  }
1066 
1067  //do the second round of inverse FFT on wire
1068  Array::array_xxf tm_r_data = Array::idft_cr(c_data_afterfilter,0);
1069  m_r_data = tm_r_data.block(m_pad_nwires[plane],0,m_nwires[plane],m_nticks);
1071 
1072 
1073 }
1074 
1075 // return true if any channels w/in +/- nnn, inclusive, of the channel has the mask.
1076 bool OmnibusSigProc::masked_neighbors(const std::string& cmname, OspChan& ochan, int nnn)
1077 {
1078  // take care of boundary cases
1079  int lo_wire = ochan.wire - nnn;
1080  int lo_chan = ochan.channel - nnn;
1081  while (lo_wire < 0) {
1082  ++lo_wire;
1083  ++lo_chan;
1084  }
1085  const int nwires = m_nwires[ochan.plane];
1086  int hi_wire = ochan.wire + nnn;
1087  int hi_chan = ochan.channel + nnn;
1088  while (hi_wire >= nwires) {
1089  --hi_wire;
1090  --hi_chan;
1091  }
1092  if (hi_chan < lo_chan) { // how? bogus inputs?
1093  return false;
1094  }
1095 
1096  auto& cm = m_cmm[cmname];
1097  for (int och = lo_chan; och <= hi_chan; ++och) {
1098  if (cm.find(och) != cm.end()) {
1099  return true;
1100  }
1101  }
1102  return false;
1103 }
1104 
1106  // apply software filter on time
1107 
1108  Waveform::realseq_t roi_hf_filter_wf;
1109  if (plane ==0){
1110  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_wide_U");
1111  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
1112  }else if (plane==1){
1113  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_wide_V");
1114  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
1115  }else{
1116  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Wiener_wide_W");
1117  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
1118  }
1119 
1120  Array::array_xxc c_data_afterfilter(m_c_data.rows(),m_c_data.cols());
1121  for (int irow=0; irow<m_c_data.rows(); ++irow) {
1122  for (int icol=0; icol<m_c_data.cols(); ++icol) {
1123  c_data_afterfilter(irow,icol) = m_c_data(irow,icol) * roi_hf_filter_wf.at(icol);
1124  }
1125  }
1126 
1127  //do the second round of inverse FFT on wire
1128  Array::array_xxf tm_r_data = Array::idft_cr(c_data_afterfilter,0);
1129  m_r_data = tm_r_data.block(m_pad_nwires[plane],0,m_nwires[plane],m_nticks);
1130  if (plane==2) {
1132  }
1133 }
1134 
1136  // apply software filter on time
1137 
1138  Waveform::realseq_t roi_hf_filter_wf;
1139  if (plane ==0){
1140  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Gaus_wide");
1141  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
1142  }else if (plane==1){
1143  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Gaus_wide");
1144  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
1145  }else{
1146  auto ncr1 = Factory::find<IFilterWaveform>("HfFilter","Gaus_wide");
1147  roi_hf_filter_wf = ncr1->filter_waveform(m_c_data.cols());
1148  }
1149 
1150  Array::array_xxc c_data_afterfilter(m_c_data.rows(),m_c_data.cols());
1151  for (int irow=0; irow<m_c_data.rows(); ++irow) {
1152  for (int icol=0; icol<m_c_data.cols(); ++icol) {
1153  c_data_afterfilter(irow,icol) = m_c_data(irow,icol) * roi_hf_filter_wf.at(icol);
1154  }
1155  }
1156 
1157  //do the second round of inverse FFT on wire
1158  Array::array_xxf tm_r_data = Array::idft_cr(c_data_afterfilter,0);
1159  m_r_data = tm_r_data.block(m_pad_nwires[plane],0,m_nwires[plane],m_nticks);
1160  if (plane==2) {
1162  }
1163 }
1164 
1165 
1167 {
1168  out = nullptr;
1169  if (!in) {
1170  log->debug("OmnibusSigProc: see EOS");
1171  return true;
1172  }
1173  const size_t ntraces = in->traces()->size();
1174  if (ntraces) {
1175  log->debug("OmnibusSigProc: receive frame {} with {} traces",
1176  in->ident(), ntraces);
1177  }
1178  else{
1179  out = std::make_shared<SimpleFrame>(in->ident(), in->time(),
1180  std::make_shared<ITrace::vector>(),
1181  in->tick());
1182  log->debug("OmnibusSigProc: got and sending empty frame {}", out->ident());
1183  return true;
1184  }
1185 
1186  // Convert to OSP cmm indexed by OSB sequential channels, NOT WCT channel ID.
1187  m_cmm.clear();
1188  // double emap: name -> channel -> pair<int,int>
1189  for (auto cm : in->masks()) {
1190  const std::string name = cm.first;
1191  for (auto m: cm.second) {
1192  const int wct_channel_ident = m.first;
1193  const OspChan& och = m_channel_map[wct_channel_ident];
1194  if (och.plane < 0) {
1195  continue; // in case user gives us multi apa frame
1196  }
1197  m_cmm[name][och.channel] = m.second;
1198 
1199  }
1200  }
1201 
1202  ITrace::vector* itraces = new ITrace::vector; // will become shared_ptr.
1203  IFrame::trace_summary_t thresholds;
1204  IFrame::trace_list_t wiener_traces, gauss_traces, perframe_traces[3];
1205  // here are some trace lists for debug mode
1206  IFrame::trace_list_t tight_lf_traces, loose_lf_traces, cleanup_roi_traces, break_roi_loop1_traces, break_roi_loop2_traces, shrink_roi_traces, extend_roi_traces;
1207 
1208  // initialize the overall response function ...
1210 
1211  // create a class for ROIs ...
1214 
1215 
1216  const std::vector<float>* perplane_thresholds[3] = {
1217  &roi_form.get_uplane_rms(),
1218  &roi_form.get_vplane_rms(),
1219  &roi_form.get_wplane_rms()
1220  };
1221 
1222 
1223  for (int iplane = 0; iplane != 3; ++iplane){
1224  const std::vector<float>& perwire_rmses = *perplane_thresholds[iplane];
1225 
1226  // load data into EIGEN matrices ...
1227  load_data(in, iplane); // load into a large matrix
1228  // initial decon ...
1229  decon_2D_init(iplane); // decon in large matrix
1230 
1231  // Form tight ROIs
1232  if (iplane != 2){ // induction wire planes
1233  decon_2D_tighterROI(iplane);
1234  Array::array_xxf r_data_tight = m_r_data;
1235  // r_data_tight = m_r_data;
1236  decon_2D_tightROI(iplane);
1237  roi_form.find_ROI_by_decon_itself(iplane, m_r_data, r_data_tight);
1238  }else{ // collection wire planes
1239  decon_2D_tightROI(iplane);
1240  roi_form.find_ROI_by_decon_itself(iplane, m_r_data);
1241  }
1242 
1243  // [wgu] save decon result after tight LF
1244  std::vector<double> dummy;
1245  if (m_use_roi_debug_mode) save_data(*itraces, tight_lf_traces, iplane, perwire_rmses, dummy);
1246 
1247  // Form loose ROIs
1248  if (iplane != 2){
1249  // [wgu] save decon result after loose LF
1250  if (m_use_roi_debug_mode) {
1252  save_data(*itraces, loose_lf_traces, iplane, perwire_rmses, dummy);
1253  }
1254 
1255  decon_2D_looseROI(iplane);
1256  roi_form.find_ROI_loose(iplane,m_r_data);
1257  decon_2D_ROI_refine(iplane);
1258  }
1259 
1260  // [wgu] collection plane does not need loose LF
1261  // but save something to be consistent
1262  if (m_use_roi_debug_mode and iplane==2) save_data(*itraces, loose_lf_traces, iplane, perwire_rmses, dummy);
1263 
1264  // Refine ROIs
1265  roi_refine.load_data(iplane, m_r_data, roi_form);
1266  // roi_refine.refine_data(iplane, roi_form);
1267  if (not m_use_roi_debug_mode) // default: use_roi_debug_mode=false
1268  roi_refine.refine_data(iplane, roi_form);
1269  else { // CAVEAT: ONLY USE ME FOR DEBUGGING
1270 
1271  std::cout << "[wgu] CleanUpROIs ..." << std::endl;
1272  roi_refine.refine_data_debug_mode(iplane, roi_form, "CleanUpROIs");
1273  save_roi(*itraces, cleanup_roi_traces, iplane, roi_refine.get_rois_by_plane(iplane));
1274 
1275  std::cout << "[wgu] BreakROIs ..." << std::endl;
1276  roi_refine.refine_data_debug_mode(iplane, roi_form, "BreakROIs");
1277  save_roi(*itraces, break_roi_loop1_traces, iplane, roi_refine.get_rois_by_plane(iplane));
1278 
1279  std::cout << "[wgu] BreakROIs_2 ..." << std::endl;
1280  roi_refine.refine_data_debug_mode(iplane, roi_form, "BreakROIs");
1281  save_roi(*itraces, break_roi_loop2_traces, iplane, roi_refine.get_rois_by_plane(iplane));
1282 
1283  std::cout << "[wgu] ShrinkROIs ..." << std::endl;
1284  roi_refine.refine_data_debug_mode(iplane, roi_form, "ShrinkROIs");
1285  save_roi(*itraces, shrink_roi_traces, iplane, roi_refine.get_rois_by_plane(iplane));
1286 
1287  std::cout << "[wgu] ExtendROIs ..." << std::endl;
1288  roi_refine.refine_data_debug_mode(iplane, roi_form, "ExtendROIs");
1289  save_roi(*itraces, extend_roi_traces, iplane, roi_refine.get_rois_by_plane(iplane));
1290  }
1291 
1292 
1293  // merge results ...
1294  decon_2D_hits(iplane);
1295  roi_refine.apply_roi(iplane, m_r_data);
1296  //roi_form.apply_roi(iplane, m_r_data,1);
1297  save_data(*itraces, perframe_traces[iplane], iplane, perwire_rmses, thresholds);
1298  wiener_traces.insert(wiener_traces.end(), perframe_traces[iplane].begin(), perframe_traces[iplane].end());
1299 
1300  decon_2D_charge(iplane);
1301  roi_refine.apply_roi(iplane, m_r_data);
1302  //roi_form.apply_roi(iplane, m_r_data,1);
1303  std::vector<double> dummy_thresholds;
1304  save_data(*itraces, gauss_traces, iplane, perwire_rmses, dummy_thresholds);
1305 
1306  m_c_data.resize(0,0); // clear memory
1307  m_r_data.resize(0,0); // clear memory
1308  }
1309 
1310  SimpleFrame* sframe = new SimpleFrame(in->ident(), in->time(),
1311  ITrace::shared_vector(itraces),
1312  in->tick(), m_cmm);
1313  sframe->tag_frame(m_frame_tag);
1314 
1315  // this assumes save_data produces itraces in OSP channel order
1316  // std::vector<float> perplane_thresholds[3] = {
1317  // roi_form.get_uplane_rms(),
1318  // roi_form.get_vplane_rms(),
1319  // roi_form.get_wplane_rms()
1320  // };
1321 
1322  // IFrame::trace_summary_t threshold;
1323  // for (int iplane=0; iplane<3; ++iplane) {
1324  // for (float val : perplane_thresholds[iplane]) {
1325  // threshold.push_back((double)val);
1326  // }
1327  // }
1328 
1329  sframe->tag_traces(m_wiener_tag, wiener_traces);
1330  sframe->tag_traces(m_wiener_threshold_tag, wiener_traces, thresholds);
1331  sframe->tag_traces(m_gauss_tag, gauss_traces);
1332 
1333  if (m_use_roi_debug_mode) {
1334  sframe->tag_traces(m_tight_lf_tag, tight_lf_traces);
1335  sframe->tag_traces(m_loose_lf_tag, loose_lf_traces);
1336  sframe->tag_traces(m_cleanup_roi_tag, cleanup_roi_traces);
1337  sframe->tag_traces(m_break_roi_loop1_tag, break_roi_loop1_traces);
1338  sframe->tag_traces(m_break_roi_loop2_tag, break_roi_loop2_traces);
1339  sframe->tag_traces(m_shrink_roi_tag, shrink_roi_traces);
1340  sframe->tag_traces(m_extend_roi_tag, extend_roi_traces);
1341  }
1342 
1343  log->debug("OmnibusSigProc: produce {} traces: {} {}, {} {}, frame tag: {}",
1344  itraces->size(),
1345  wiener_traces.size(), m_wiener_tag,
1346  gauss_traces.size(), m_gauss_tag, m_frame_tag);
1347 
1348  out = IFrame::pointer(sframe);
1349 
1350  return true;
1351 }
1352 
1353 // Local Variables:
1354 // mode: c++
1355 // c-basic-offset: 2
1356 // End:
static QCString name
Definition: declinfo.cpp:673
const int nwires
static const double m
Definition: Units.h:79
std::shared_ptr< const ITrace > pointer
Definition: IData.h:19
void init_overall_response(IFrame::pointer frame)
array_xxc dft_cc(const array_xxc &arr, int dim=1)
Definition: Array.cxx:67
array_xxf idft_cr(const array_xxc &arr, int dim=0)
Definition: Array.cxx:153
std::map< int, OspChan > m_channel_map
Sequence< real_t > realseq_t
Definition: Waveform.h:31
static bool isZero(float x)
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
virtual void configure(const WireCell::Configuration &config)
Accept a configuration.
boost::error_info< struct tag_errmsg, std::string > errmsg
Definition: Exceptions.h:54
std::size_t fft_best_length(size_t nsamples, bool keep_odd_even=false)
struct vector vector
Schema::FieldResponse wire_region_average(const Schema::FieldResponse &fr)
Definition: Response.cxx:99
Eigen::ArrayXXcf array_xxc
A complex, 2D array.
Definition: Array.h:57
STL namespace.
array_xxc dft_rc(const array_xxf &arr, int dim=0)
Definition: Array.cxx:40
intermediate_table::const_iterator const_iterator
double period
The sampling period of the response function.
Definition: Response.h:92
std::vector< OspChan > m_channel_range[3]
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)
The calling signature:
Binning tbins(nticks, t0, t0+readout_time)
void tag_frame(const tag_t &tag)
Definition: SimpleFrame.cxx:71
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:72
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:87
Array::array_xxf as_array(const Schema::PlaneResponse &pr)
Definition: Response.cxx:279
real_t median(realseq_t &wave)
Definition: Waveform.cxx:76
T abs(T value)
std::shared_ptr< const IFrame > input_pointer
Definition: IFunctionNode.h:39
WIRECELL_FACTORY(OmnibusSigProc, WireCell::SigProc::OmnibusSigProc, WireCell::IFrameFilter, WireCell::IConfigurable) using namespace WireCell
compseq_t dft(realseq_t seq)
Definition: Waveform.cxx:141
void load_data(const input_pointer &in, int plane)
dummy_int isinf(...)
Definition: format.h:276
array_xxc idft_cc(const array_xxc &arr, int dim=1)
Definition: Array.cxx:125
static Config * config
Definition: config.cpp:1054
WireCell::Waveform::realseq_t generate(const WireCell::Waveform::Domain &domain, int nsamples)
FIXME: eradicate Domain in favor of Binning.
Definition: Response.cxx:303
std::vector< double > trace_summary_t
Definition: IFrame.h:39
constexpr std::array< std::size_t, geo::vect::dimension< Vector >)> indices()
Returns a sequence of indices valid for a vector of the specified type.
#define THROW(e)
Definition: Exceptions.h:25
std::vector< PlaneResponse > planes
List of PlaneResponse objects.
Definition: Response.h:78
std::vector< float > & get_wplane_rms()
Definition: ROI_formation.h:55
virtual WireCell::Configuration default_configuration() const
Optional, override to return a hard-coded default configuration.
std::shared_ptr< const IFrame > output_pointer
Definition: IFunctionNode.h:40
void load_data(int plane, const Array::array_xxf &r_data, ROI_formation &roi_form)
logptr_t logger(std::string name)
Definition: Logging.cxx:71
Thrown when a wrong value has been encountered.
Definition: Exceptions.h:37
void log(source_loc source, level::level_enum lvl, const char *fmt, const Args &...args)
Definition: spdlog.h:165
void apply_roi(int plane, Array::array_xxf &r_data)
Definition: Main.h:22
static bool ispositive(float x)
void find_ROI_by_decon_itself(int plane, const Array::array_xxf &r_data)
void scale(Sequence< Val > &seq, Val scalar)
Scale (multiply) sequence values by scalar.
Definition: Waveform.h:146
Waveform::ChannelMaskMap m_cmm
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
SignalROIChList & get_rois_by_plane(int plane)
def fill(s)
Definition: translator.py:93
void save_roi(ITrace::vector &itraces, IFrame::trace_list_t &indices, int plane, std::vector< std::list< SignalROI * > > &roi_channel_list)
Json::Value Configuration
Definition: Configuration.h:50
cet::LibraryManager dummy("noplugin")
bool masked_neighbors(const std::string &cmname, OspChan &ochan, int nnn)
static const double cm
Definition: Units.h:76
list x
Definition: train.py:276
void save_data(ITrace::vector &itraces, IFrame::trace_list_t &indices, int plane, const std::vector< float > &perwire_rmses, IFrame::trace_summary_t &threshold)
void restore_baseline(WireCell::Array::array_xxf &arr)
unsigned nrows(sqlite3 *db, std::string const &tablename)
Definition: helpers.cc:84
def rebin(a, args)
Definition: arrays.py:2
std::vector< float > & get_uplane_rms()
Definition: ROI_formation.h:53
Sequence< complex_t > compseq_t
A complex-valued sequence, eg for discrete spectrum powers.
Definition: Waveform.h:34
std::vector< float > ChargeSequence
Sequential collection of charge.
Definition: ITrace.h:21
std::vector< size_t > trace_list_t
Definition: IFrame.h:36
std::vector< Waveform::realseq_t > overall_resp[3]
std::shared_ptr< const vector > shared_vector
Definition: IData.h:22
Hold info about multiple plane responses in the detector.
Definition: Response.h:75
void refine_data(int plane, ROI_formation &roi_form)
QTextStream & endl(QTextStream &s)
std::vector< float > & get_vplane_rms()
Definition: ROI_formation.h:54
dummy_int isnan(...)
Definition: format.h:278
Eigen::ArrayXXf array_xxf
A real, 2D array.
Definition: Array.h:54
void refine_data_debug_mode(int plane, ROI_formation &roi_form, const std::string &cmd)
void find_ROI_loose(int plane, const Array::array_xxf &r_data)