12 #include <Eigen/Dense> 20 using namespace
Eigen;
22 using namespace WireCell::SigProc;
29 double fine_time_offset ,
30 double coarse_time_offset )
33 , m_postgain(postgain)
35 , m_fine_time_offset(fine_time_offset)
36 , m_coarse_time_offset(coarse_time_offset)
42 L1SPFilter::~L1SPFilter()
51 auto ifr = Factory::find_tn<IFieldResponse>(get<std::string>(
m_cfg,
"fields",
"FieldResponse"));
60 auto ewave = ce.generate(
tbins);
64 std::complex<float> fine_period(fravg.
period,0);
84 double intrinsic_time_offset = fravg.
origin/fravg.
speed;
88 double xstep = fravg.
period;
102 cfg[
"fields"] =
"FieldResponse";
105 cfg[
"filter"] = Json::arrayValue;
109 cfg[
"adctag"] =
"raw";
113 cfg[
"sigtag"] =
"gauss";
116 cfg[
"outtag"] =
"l1sp";
119 cfg[
"raw_ROI_th_nsigma"] = 4;
121 cfg[
"raw_ROI_th_adclimit"] = 10;
123 cfg[
"overall_time_offset"] = 0;
125 cfg[
"collect_time_offset"] = 3.0;
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;
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;
145 cfg[
"l1_resp_scale"] = 0.5;
146 cfg[
"l1_col_scale"] = 1.15;
147 cfg[
"l1_ind_scale"] = 0.5;
149 cfg[
"peak_threshold"] = 1000;
150 cfg[
"mean_threshold"] = 500;
193 roi_pad =
get(
m_cfg,
"roi_pad",roi_pad);
195 raw_pad =
get(
m_cfg,
"raw_pad",raw_pad);
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);
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";
239 std::map<int,std::set<int>> init_map;
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;
248 for (
int qi = 0;
qi < ntbins;
qi++){
250 time_ticks.insert(tbin+
qi);
254 init_map[ch] = time_ticks;
263 std::map<int,std::shared_ptr<const WireCell::ITrace>> adctrace_ch_map;
265 for (
auto trace : adctraces) {
266 int ch =
trace->channel();
268 adctrace_ch_map[ch] =
trace;
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];
275 if (ntot_ticks < ntbins)
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;
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);
303 std::map<int, std::vector<std::pair<int,int>>> map_ch_rois;
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));
312 std::vector<std::pair<int,int>> rois;
313 std::vector<std::pair<int,int>> rois_save;
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);
320 rois.push_back(std::make_pair(time_slices.at(i),time_slices.at(i)));
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;
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;
342 rois_save.push_back(*it);
346 if (rois_save.size()>0)
347 map_ch_rois[wire_index] = rois_save;
354 std::map<int, std::vector<int> > map_ch_flag_rois;
356 for (
auto trace : sigtraces) {
357 auto newtrace = std::make_shared<SimpleTrace>(
trace->channel(),
trace->tbin(),
trace->charge());
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;
364 bool flag_shorted =
false;
365 for (
size_t i1 = 0; i1!=rois_save.size(); i1++){
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);
371 for (
int time_tick = rois_save.at(i1).first; time_tick!=rois_save.at(i1).second+1; time_tick++){
373 if (newtrace->charge().at(time_tick-
trace->tbin())<0)
374 newtrace->charge().at(time_tick-
trace->tbin())=0;
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;
384 if (map_ch_flag_rois[
trace->channel()].at(i1)==1){
386 }
else if (map_ch_flag_rois[
trace->channel()].at(i1)==2){
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;
391 }
else if (map_ch_flag_rois[
trace->channel()].at(i1)==0){
392 flag_shorted =
false;
394 prev_time_tick = rois_save.at(i1).second;
397 if (rois_save.size()>0){
398 prev_time_tick = rois_save.back().second + 2000;
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;
403 if (map_ch_flag_rois[
trace->channel()].at(i1)==1){
405 }
else if (map_ch_flag_rois[
trace->channel()].at(i1)==2){
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;
410 }
else if (map_ch_flag_rois[
trace->channel()].at(i1)==0){
411 flag_shorted =
false;
413 prev_time_tick = rois_save.at(i1).first;
423 out_traces.push_back(newtrace);
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];
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;
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){
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){
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;
469 out_traces.at(i2) = new_trace;
474 std::cerr <<
"L1SPFilter: frame: " << in->ident() <<
" " 475 << adctag <<
"[" << adctraces.size() <<
"] + " 476 << sigtag <<
"[" << sigtraces.size() <<
"] --> " 477 << outtag <<
"[" << out_traces.size() <<
"]\n";
484 std::iota(tl.begin(), tl.end(), 0);
486 auto sf =
new SimpleFrame(in->ident(), in->time(), out_traces, in->tick());
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){
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);
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);
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);
515 double mean_threshold =
get(
m_cfg,
"mean_threshold",mean_threshold);
516 double peak_threshold =
get(
m_cfg,
"peak_threshold",peak_threshold);
519 std::vector<double> smearing_vec = get< std::vector<double> >(
m_cfg,
"filter");
522 const int nbin_fit = end_tick-start_tick;
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);
530 double temp1_sum = 0;
531 double temp2_sum = 0;
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()) ;
538 if (max_val < init_W(i)) max_val = init_W(i);
539 if (min_val > init_W(i)) min_val = init_W(i);
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));
552 if (temp_sum/(temp1_sum*adc_sum_rescaling*1.0/nbin_fit)>adc_ratio_threshold && temp1_sum>adc_sum_threshold){
554 }
else if (temp1_sum*adc_sum_rescaling*1.0/nbin_fit < adc_sum_rescaling_limit){
556 }
else if (temp2_sum > 30 * nbin_fit && temp1_sum < 2.0*nbin_fit && max_val - min_val < 22){
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));
576 boundaries.push_back(nbin_fit);
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);
586 MatrixXd
G = MatrixXd::Zero(temp_nbin_fit, temp_nbin_fit*2);
588 for (
int i=0;i!=temp_nbin_fit;i++){
591 for (
int j=0;j!=temp_nbin_fit;j++){
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;
602 double lambda = l1_lambda;
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);
615 for (
int i=0;i!=nbin_fit;i++){
616 sum1 += final_beta(i);
617 sum2 += final_beta(nbin_fit+i);
620 if (sum1 > adc_l1_threshold){
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;
626 int mid_bin = (smearing_vec.size()-1)/2;
628 for (
int j=0;j!=nbin_fit;j++){
629 double content = l1_signal.at(j);
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);
639 for (
int j=0;j!=nbin_fit;j++){
640 if (l2_signal.at(j)<l1_decon_limit/l1_scaling_factor){
643 l1_signal.at(j) = l2_signal.at(j) * l1_scaling_factor;
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);
656 bool flag_start =
false;
657 int start_bin=-1,end_bin=-1;
658 for (
size_t j=0;j!=nonzero_bins.size();j++){
660 start_bin = nonzero_bins.at(j);
661 end_bin = nonzero_bins.at(j);
664 if (nonzero_bins.at(j) - end_bin == 1){
665 end_bin = nonzero_bins.at(j);
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);
674 ROIs.push_back(std::make_pair(start_bin,end_bin));
676 for (
size_t j=0;j!=ROIs.size();j++){
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);
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++){
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);
710 }
else if (flag_l1==2){
712 for (
int time_tick = start_tick; time_tick!= end_tick; time_tick++){
714 newtrace->charge().at(time_tick-newtrace->tbin())=0;
std::shared_ptr< const IFrame > pointer
virtual void configure(const WireCell::Configuration &config)
IConfigurable interface.
linterp< double > * lin_W
linterp< double > * lin_V
void tag_traces(const tag_t &tag, const IFrame::trace_list_t &indices, const IFrame::trace_summary_t &summary=IFrame::trace_summary_t(0))
boost::error_info< struct tag_errmsg, std::string > errmsg
double period
The sampling period of the response function.
std::vector< pointer > vector
A functional object caching gain and shape.
virtual bool operator()(const input_pointer &in, output_pointer &out)
IFrameFilter interface.
Binning tbins(nticks, t0, t0+readout_time)
Array::array_xxf as_array(const Schema::PlaneResponse &pr)
std::shared_ptr< const IFrame > input_pointer
Schema::FieldResponse average_1D(const Schema::FieldResponse &fr)
double m_fine_time_offset
std::vector< PlaneResponse > planes
List of PlaneResponse objects.
Eigen::VectorXd & Getbeta()
virtual WireCell::Configuration default_configuration() const
Optional, override to return a hard-coded default configuration.
WIRECELL_FACTORY(L1SPFilter, WireCell::SigProc::L1SPFilter, WireCell::IFrameFilter, WireCell::IConfigurable) using namespace Eigen
std::shared_ptr< const IFrame > output_pointer
virtual void SetData(Eigen::MatrixXd X, Eigen::VectorXd y)
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)
Json::Value Configuration
QTextStream & bin(QTextStream &s)
Thrown when an error occurs during the data processing.
second_as<> second
Type of time stored in seconds, in double precision.
std::vector< size_t > trace_list_t
double mean(sqlite3 *db, std::string const &table_name, std::string const &column_name)
double m_coarse_time_offset
Hold info about multiple plane responses in the detector.
double speed
The nominal drift speed.