AlgoCFD.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // AlgoCFD source
4 //
5 ////////////////////////////////////////////////////////////////////////
6 
7 #include "AlgoCFD.h"
8 #include "UtilFunc.h"
9 
10 #include "fhiclcpp/ParameterSet.h"
11 
12 #include <unordered_map>
13 
14 namespace pmtana{
15 
16  //*********************************************************************
18  : PMTPulseRecoBase(name)
19  //*********************************************************************
20  {}
21 
22  //*********************************************************************
24  //AlgoCFD::AlgoCFD(const ::fcllite::PSet &pset,
25  const std::string name)
26  : PMTPulseRecoBase(name)
27  //*********************************************************************
28  {
29 
30  _F = pset.get<float>("Fraction");
31  _D = pset.get<int> ("Delay");
32 
33  //_number_presample = pset.get<int> ("BaselinePreSample");
34  _peak_thresh = pset.get<double>("PeakThresh");
35  _start_thresh = pset.get<double>("StartThresh");
36  _end_thresh = pset.get<double>("EndThresh");
37 
38  Reset();
39 
40  }
41 
42  //***************************************************************
44  //***************************************************************
45  {
47  }
48 
49  //***************************************************************
51  const pmtana::PedestalMean_t& mean_v,
52  const pmtana::PedestalSigma_t& sigma_v)
53  //***************************************************************
54  {
55 
56  Reset();
57 
58  std::vector<double> cfd; cfd.reserve(wf.size());
59 
60  // follow cfd procedure: invert waveform, multiply by constant fraction
61  // add to delayed waveform.
62  for (unsigned int k = 0; k < wf.size(); ++k) {
63 
64  auto delayed = -1.0 * _F * ( (float) wf.at(k) - mean_v.at(k) );
65 
66  if ((int)k < _D)
67 
68  cfd.push_back( delayed );
69 
70  else
71 
72  cfd.push_back(delayed + ( (float) wf.at(k - _D) - mean_v.at(k) ) );
73  }
74 
75 
76  // Get the zero point crossings, how can I tell which are meaningful?
77  // go to each crossing, see if waveform is above pedestal (high above pedestal)
78 
79  auto crossings = LinearZeroPointX(cfd);
80 
81  // lambda criteria to determine if inside pulse
82 
83  auto in_peak = [&wf,&sigma_v,&mean_v](int i, float thresh) -> bool
84  { return wf.at(i) > sigma_v.at(i) * thresh + mean_v.at(i); };
85 
86  // loop over CFD crossings
87  for(const auto& cross : crossings) {
88 
89  if( in_peak( cross.first, _peak_thresh) ) {
91 
92  int i = cross.first;
93 
94  //backwards
95  while ( in_peak(i, _start_thresh) ){
96  i--;
97  if ( i < 0 ) { i = 0; break; }
98  }
99  _pulse.t_start = i;
100 
101  //walk a little further backwards to see if we can get 5 low RMS
102  // while ( !in_peak(i,_start_thresh) ) {
103  // if (i == ( _pulse.t_start - _number_presample ) ) break;
104  // i--;
105  // if ( i < 0 ) { i = 0; break; }
106  // }
107 
108  // auto before_mean = double{0.0};
109 
110  // if ( _pulse.t_start - i > 0 )
111  // before_mean = std::accumulate(std::begin(mean_v) + i,
112  // std::begin(mean_v) + _pulse.t_start, 0.0) / ((double) (_pulse.t_start - i));
113 
114  i = _pulse.t_start + 1;
115 
116  //forwards
117  while ( in_peak(i,_end_thresh) ) {
118  i++;
119  if ( i > (int)(wf.size()) - 1 ) { i = (int)(wf.size()) - 1; break; }
120  }
121 
122  _pulse.t_end = i;
123 
124  // //walk a little further forwards to see if we can get 5 low RMS
125  // while ( !in_peak(i,_end_thresh) ) {
126  // if (i == ( _pulse.t_end + _number_presample ) ) break;
127  // i++;
128  // if ( i > wf.size() - 1 ) { i = wf.size() - 1; break; }
129  // }
130 
131  // auto after_mean = double{0.0};
132 
133  // if( i - _pulse.t_end > 0)
134  // after_mean = std::accumulate(std::begin(mean_v) + _pulse.t_end + 1,
135  // std::begin(mean_v) + i + 1, 0.0) / ((double) (i - _pulse.t_end));
136 
137 
138  //how to decide before or after? set before for now
139  //if ( wf.size() < 1500 ) //it's cosmic discriminator
140  //before_mean = mean_v.front();
141 
142  // if( after_mean <= 0 and before_mean <= 0 ) {
143  // std::cerr << "\033[93m<<" << __FUNCTION__ << ">>\033[00m Could not find good pedestal for CDF"
144  // << " both before_mean and after_mean are zero or less? Ignoring this crossing." << std::endl;
145  // continue;
146  // }
147 
148  //x
149 
150  auto start_ped = mean_v.at(_pulse.t_start);
151  auto end_ped = mean_v.at(_pulse.t_end);
152 
153  //just take the "smaller one"
154  _pulse.ped_mean = start_ped <= end_ped ? start_ped : end_ped;
155 
156  if(wf.size() < 50) _pulse.ped_mean = mean_v.front(); //is COSMIC DISCRIMINATOR
157 
158  auto it = std::max_element(std::begin(wf) + _pulse.t_start, std::begin(wf) + _pulse.t_end);
159 
160  _pulse.t_max = it - std::begin(wf);
161  _pulse.peak = *it - _pulse.ped_mean;
162  _pulse.t_cfdcross = cross.second;
163 
164  for(auto k = _pulse.t_start; k <= _pulse.t_end; ++k) {
165  auto a = wf.at(k) - _pulse.ped_mean;
166  if ( a > 0 ) _pulse.area += a;
167  }
168 
169  _pulse_v.push_back(_pulse);
170  }
171 
172  }
173 
174  // Vic:
175  // Very close in time pulses have multiple CFD
176  // crossing points. Should we check that pulses now have
177  // some multiplicity? No lets just delete them.
178 
179  auto pulses_copy = _pulse_v;
180  _pulse_v.clear();
181 
182  std::unordered_map<unsigned,pulse_param> delta;
183 
184  //unsigned width = 0;
185  for( const auto& p : pulses_copy ) {
186 
187  if ( delta.count(p.t_start) ) {
188  if ( (p.t_end - p.t_start) > (delta[p.t_start].t_end - delta[p.t_start].t_start) )
189  delta[p.t_start] = p;
190  else
191  continue;
192  }
193  else {
194  delta[p.t_start] = p;
195  }
196  }
197 
198  for(const auto & p : delta)
199  _pulse_v.push_back(p.second);
200 
201 
202  //do the same now ensure t_final's are all unique
203  //width = 0;
204 
205  pulses_copy.clear();
206  pulses_copy = _pulse_v;
207 
208  _pulse_v.clear();
209  delta.clear();
210 
211  for( const auto& p : pulses_copy ) {
212 
213  if ( delta.count(p.t_end) ) {
214  if ( (p.t_end - p.t_start) > (delta[p.t_end].t_end - delta[p.t_end].t_start) )
215  delta[p.t_end] = p;
216  else
217  continue;
218  }
219  else {
220  delta[p.t_end] = p;
221  }
222  }
223 
224  for(const auto & p : delta)
225  _pulse_v.push_back(p.second);
226 
227  //there should be no overlapping pulses now...
228 
229  return true;
230 
231  }
232 
233  // currently returns ALL zero point crossings, we really just want ones associated with peak...
234  const std::map<unsigned,double> AlgoCFD::LinearZeroPointX(const std::vector<double>& trace) {
235 
236  std::map<unsigned,double> crossing;
237 
238  //step through the trace and find where slope is POSITIVE across zero
239  for ( unsigned i = 0; i < trace.size() - 1; ++i) {
240 
241  auto si = ::pmtana::sign(trace.at(i));
242  auto sf = ::pmtana::sign(trace.at(i+1));
243 
244  if ( si == sf ) //no sign flip, no zero cross
245  continue;
246 
247  if ( sf < si ) //this is a negative slope, continue
248  continue;
249 
250  //calculate the crossing X based on linear interpolation bt two pts
251 
252  crossing[i] = (double) i - trace.at(i) * ( 1.0 / ( trace.at(i+1) - trace.at(i) ) );
253 
254  }
255 
256 
257  return crossing;
258 
259  }
260 
261 
262 }
static QCString name
Definition: declinfo.cpp:673
const std::map< unsigned, double > LinearZeroPointX(const std::vector< double > &trace)
Definition: AlgoCFD.cxx:234
std::vector< double > PedestalSigma_t
virtual void Reset()
A method to be called event-wise to reset parameters.
void Reset()
Implementation of AlgoCFD::reset() method.
Definition: AlgoCFD.cxx:43
std::string string
Definition: nybbler.cc:12
double _end_thresh
Definition: AlgoCFD.h:64
pulse_param _pulse
A subject pulse_param object to be filled with the last reconstructed pulse parameters.
M::value_type trace(const M &m)
double _start_thresh
Definition: AlgoCFD.h:63
AlgoCFD(const std::string name="CFD")
Default constructor.
Definition: AlgoCFD.cxx:17
const double a
Class definition file of AlgoCFD.
T get(std::string const &key) const
Definition: ParameterSet.h:271
std::vector< short > Waveform_t
p
Definition: test.py:223
int sign(double val)
Definition: UtilFunc.cxx:104
double _peak_thresh
Definition: AlgoCFD.h:62
bool RecoPulse(const pmtana::Waveform_t &, const pmtana::PedestalMean_t &, const pmtana::PedestalSigma_t &)
Implementation of AlgoCFD::reco() method.
Definition: AlgoCFD.cxx:50
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
Vector cross(Vector const &a, Vector const &b)
Return cross product of two vectors.
std::vector< double > PedestalMean_t
pulse_param_array _pulse_v
A container array of pulse_param struct objects to store (possibly multiple) reconstructed pulse(s)...