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