All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PIDAAlg.cxx
Go to the documentation of this file.
1 /*!
2  * Title: PIDA Algorithim Class
3  * Author: Wes Ketchum (wketchum@lanl.gov), based on ideas/code from Bruce Baller
4  *
5  * Description: Algorithm that calculates the PIDA from a calorimetry object
6  * Input: anab::Calorimetry
7  * Output: PIDA information
8 */
9 
10 #include <algorithm>
11 #include <cmath>
12 #include <iostream>
13 #include <sstream>
14 
15 #include "PIDAAlg.h"
18 
19 #include "fhiclcpp/ParameterSet.h"
20 
21 #include "TH1F.h"
22 #include "TTree.h"
23 
24 pid::PIDAAlg::PIDAAlg(fhicl::ParameterSet const& p) :
25  fPIDA_BOGUS(-9999),
26  fExponentConstant(p.get<float>("ExponentConstant",0.42)),
27  fMinResRange(p.get<float>("MinResRange",0)),
28  fMaxResRange(p.get<float>("MaxResRange",30)),
29  fMaxPIDAValue(p.get<float>("MaxPIDAValue",50)),
30  fKDEEvalMaxSigma(p.get<float>("KDEEvalMaxSigma",3)),
31  fKDEEvalStepSize(p.get<float>("KDEEvalStepSize",0.01)),
32  fKDEBandwidths(p.get< std::vector<float> >("KDEBandwidths")),
33  fnormalDist(util::NormalDistribution(fKDEEvalMaxSigma,fKDEEvalStepSize)),
34  fPIDAHistNbins(p.get<unsigned int>("PIDAHistNbins",100)),
35  fPIDAHistMin(p.get<float>("PIDAHistMin",0.0)),
36  fPIDAHistMax(p.get<float>("PIDAHistMax",50.0))
37 {
39 }
40 
42  fpida_mean = fPIDA_BOGUS;
43  fpida_sigma = fPIDA_BOGUS;
44  fpida_integral_dedx = fPIDA_BOGUS;
45  fpida_integral_pida = fPIDA_BOGUS;
46  fpida_values.clear();
47  fpida_errors.clear();
48 
49  fpida_kde_mp = std::vector<float>(fKDEBandwidths.size(),fPIDA_BOGUS);
50  fpida_kde_fwhm = std::vector<float>(fKDEBandwidths.size(),fPIDA_BOGUS);
51  fpida_kde_b = std::vector<float>(fKDEBandwidths.size(),fPIDA_BOGUS);
52  fkde_distribution = std::vector< std::vector<float> >(fKDEBandwidths.size());
53  fkde_dist_min = std::vector<float>(fKDEBandwidths.size(),fPIDA_BOGUS);
54  fkde_dist_max = std::vector<float>(fKDEBandwidths.size(),fPIDA_BOGUS);
55 }
56 
57 void pid::PIDAAlg::SetPIDATree(TTree *tree, TH1F* hist_vals, std::vector<TH1F*> hist_kde){
58 
59  if(hist_kde.size()>MAX_BANDWIDTHS)
60  throw "Error: input histograms larger than max allowed bandwidths.";
61  if(hist_kde.size()!=fKDEBandwidths.size())
62  throw "Error: input histograms do not have same size as bandwidths.";
63 
64  fPIDATree = tree;
65 
66  hPIDAvalues = hist_vals;
67  hPIDAvalues->SetNameTitle("hPIDAvalues","PIDA Distribution");
68  hPIDAvalues->SetBins(fPIDAHistNbins,fPIDAHistMin,fPIDAHistMax);
69 
70  for(size_t i_hist=0; i_hist<hist_kde.size(); i_hist++){
71  hPIDAKDE[i_hist] = hist_kde[i_hist];
72 
73  std::stringstream hname,htitle;
74  hname << "hPIDAKDE_" << i_hist;
75  htitle << "PIDA KDE-smoothed Distribution, Bandwidth=" << fKDEBandwidths.at(i_hist);
76 
77  hPIDAKDE[i_hist]->SetNameTitle(hname.str().c_str(),htitle.str().c_str());
78  hPIDAKDE[i_hist]->SetBins(fPIDAHistNbins,fPIDAHistMin,fPIDAHistMax);
79  }
80 
81  fPIDATree->Branch("pida",&fPIDAProperties,fPIDAProperties.leaf_structure.c_str());
82  fPIDATree->Branch("hpida_vals","TH1F",hPIDAvalues);
83  fPIDATree->Branch("n_bandwidths",&(fPIDAProperties.n_bandwidths),"n_bandwidths/i");
84  fPIDATree->Branch("kde_bandwidth",fPIDAProperties.kde_bandwidth,"kde_bandwidth[n_bandwidths]/F");
85  fPIDATree->Branch("kde_mp",fPIDAProperties.kde_mp,"kde_mp[n_bandwidths]/F");
86  fPIDATree->Branch("kde_fwhm",fPIDAProperties.kde_fwhm,"kde_fwhm[n_bandwidths]/F");
87  for(size_t i_hist=0; i_hist<hist_kde.size(); i_hist++){
88  std::stringstream bname;
89  bname << "hpida_kde_" << i_hist;
90  fPIDATree->Branch(bname.str().c_str(),"TH1F",hPIDAKDE[i_hist]);
91  }
92 
93 }
94 
96  if(fpida_mean==fPIDA_BOGUS)
97  calculatePIDAMean();
98 
99  return fpida_mean;
100 }
101 
103  if(fpida_sigma==fPIDA_BOGUS)
104  calculatePIDASigma();
105 
106  return fpida_sigma;
107 }
108 
109 float pid::PIDAAlg::getPIDAKDEMostProbable(const size_t i_b){
110  if(fpida_kde_mp[i_b]==fPIDA_BOGUS)
111  createKDE(i_b);
112 
113  return fpida_kde_mp[i_b];
114 }
115 
117  if(fpida_kde_fwhm[i_b]==fPIDA_BOGUS)
118  createKDE(i_b);
119 
120  return fpida_kde_fwhm[i_b];
121 }
122 
123 const std::vector<float>& pid::PIDAAlg::getPIDAValues(){
124  return fpida_values;
125 }
126 
127 const std::vector<float>& pid::PIDAAlg::getPIDAErrors(){
128  return fpida_errors;
129 }
130 
132  std::vector<float> const& resRange = calo.ResidualRange();
133  std::vector<float> const& dEdx = calo.dEdx();
134  RunPIDAAlg(resRange,dEdx);
135 }
136 
138  float& mean,
139  float& sigma)
140 {
141  RunPIDAAlg(calo);
142  mean = getPIDAMean();
143  sigma = getPIDASigma();
144 }
145 
146 void pid::PIDAAlg::RunPIDAAlg(std::vector<float> const& resRange,
147  std::vector<float> const& dEdx){
148 
149  ClearInternalData();
150 
151  fpida_values.reserve( resRange.size() );
152  fpida_errors.reserve( resRange.size() );
153 
154  std::map<double,double> range_dEdx_map;
155 
156  for(size_t i_r=0; i_r<resRange.size(); i_r++){
157  if(resRange[i_r]>fMaxResRange || resRange[i_r]<fMinResRange) continue;
158 
159  range_dEdx_map[ resRange[i_r] ] = dEdx[i_r];
160 
161  float val = dEdx[i_r]*std::pow(resRange[i_r],fExponentConstant);
162  if(val < fMaxPIDAValue){
163  fpida_values.push_back(val);
164  //fpida_errors.push_back(0);
165  }
166 
167  }
168 
169  calculatePIDAIntegral(range_dEdx_map);
170 
171  if(fpida_values.size()==0)
172  fpida_values.push_back(-99);
173 
174 }
175 
176 void pid::PIDAAlg::FillPIDATree(unsigned int run,
177  unsigned int event,
178  unsigned int calo_index,
179  anab::Calorimetry const& calo){
180  RunPIDAAlg(calo);
181  FillPIDAProperties(run,event,calo_index,calo);
182 }
183 
185 
186  if(fpida_values.size()==0)
187  throw "pid::PIDAAlg --- PIDA Values not filled!";
188 
189  fpida_mean = 0;
190  for(auto const& val : fpida_values)
191  fpida_mean += val;
192  fpida_mean /= fpida_values.size();
193 
194 }
195 
197 
198  if(fpida_mean==fPIDA_BOGUS)
199  calculatePIDAMean();
200 
201  fpida_sigma = 0;
202  for(auto const& val : fpida_values)
203  fpida_sigma += (fpida_mean-val)*(fpida_mean-val);
204 
205  fpida_sigma = std::sqrt(fpida_sigma)/fpida_values.size();
206 }
207 
208 void pid::PIDAAlg::calculatePIDAIntegral(std::map<double,double> const& range_dEdx_map){
209 
210  if(range_dEdx_map.size()<2) return;
211 
212  fpida_integral_dedx = 0;
213 
214  for( std::map<double,double>::const_iterator map_iter = range_dEdx_map.begin();
215  map_iter != std::prev(range_dEdx_map.end());
216  map_iter++)
217  {
218  double range_width = std::next(map_iter)->first - map_iter->first;
219  fpida_integral_dedx += range_width*( std::next(map_iter)->second + 0.5*(map_iter->second-std::next(map_iter)->second));
220  }
221 
222  fpida_integral_pida = fpida_integral_dedx * (1-fExponentConstant) *
223  std::pow( (std::prev(range_dEdx_map.end())->first - range_dEdx_map.begin()->first),(fExponentConstant-1) );
224 }
225 
226 void pid::PIDAAlg::createKDE(const size_t i_b){
227 
228  if(fpida_values.size()==0)
229  throw "pid::PIDAAlg --- PIDA Values not filled!";
230 
231  //if( fkde_distribution[i_b].size()!=0 ) return;
232 
233  if(fKDEBandwidths[i_b]<=0) {
234  calculatePIDASigma();
235  float bandwidth = fpida_sigma*1.06*std::pow((float)(fpida_values.size()),-0.2);
236  fpida_errors = std::vector<float>(fpida_values.size(),bandwidth);
237  fpida_kde_b[i_b] = bandwidth;
238  }
239  else{
240  fpida_errors = std::vector<float>(fpida_values.size(),fKDEBandwidths[i_b]);
241  fpida_kde_b[i_b] = fKDEBandwidths[i_b];
242  }
243 
244  const auto min_pida_iterator = std::min_element(fpida_values.begin(),fpida_values.end());
245  const size_t min_pida_location = std::distance(fpida_values.begin(),min_pida_iterator);
246  fkde_dist_min[i_b] = fpida_values[min_pida_location] - fKDEEvalMaxSigma*fpida_errors[min_pida_location];
247 
248  const auto max_pida_iterator = std::max_element(fpida_values.begin(),fpida_values.end());
249  const size_t max_pida_location = std::distance(fpida_values.begin(),max_pida_iterator);
250  fkde_dist_max[i_b] = fpida_values[max_pida_location] + fKDEEvalMaxSigma*fpida_errors[max_pida_location];
251 
252  //make the kde distribution, and get the max value
253  const size_t kde_dist_size = (size_t)( (fkde_dist_max[i_b] - fkde_dist_min[i_b])/fKDEEvalStepSize ) + 1;
254  fkde_distribution[i_b].resize(kde_dist_size);
255  float kde_max=0;
256  size_t step_max=0;
257  for(size_t i_step=0; i_step<kde_dist_size; i_step++){
258  float pida_val = fkde_dist_min[i_b] + i_step*fKDEEvalStepSize;
259  fkde_distribution[i_b][i_step]=0;
260 
261  for(size_t i_pida=0; i_pida<fpida_values.size(); i_pida++)
262  fkde_distribution[i_b][i_step] += fnormalDist.getValue((fpida_values[i_pida]-pida_val)/fpida_errors[i_pida])/fpida_errors[i_pida];
263 
264  if(fkde_distribution[i_b][i_step]>kde_max){
265  kde_max = fkde_distribution[i_b][i_step];
266  step_max = i_step;
267  fpida_kde_mp[i_b] = pida_val;
268  }
269  }
270 
271  //now get fwhm
272  float half_max = 0.5*fpida_kde_mp[i_b];
273  float low_width=0;
274  for(size_t i_step=step_max; i_step>0; i_step--){
275  if(fkde_distribution[i_b][i_step] < half_max) break;
276  low_width += fKDEEvalStepSize;
277  }
278  float high_width=0;
279  for(size_t i_step=step_max; i_step<kde_dist_size; i_step++){
280  if(fkde_distribution[i_b][i_step] < half_max) break;
281  high_width += fKDEEvalStepSize;
282  }
283  fpida_kde_fwhm[i_b] = low_width+high_width;
284 
285 }
286 
288  for(size_t i_b=0; i_b < fKDEBandwidths.size(); i_b++)
289  createKDE(i_b);
290 }
291 
292 void pid::PIDAAlg::FillPIDAProperties(unsigned int run,
293  unsigned int event,
294  unsigned int calo_index,
295  anab::Calorimetry const& calo){
296 
297  fPIDAProperties.run = run;
298  fPIDAProperties.event = event;
299  fPIDAProperties.calo_index = calo_index;
300  fPIDAProperties.planeid = calo.PlaneID().Plane;
301  fPIDAProperties.trk_range = calo.Range();
302  fPIDAProperties.calo_KE = calo.KineticEnergy();
303 
304  fPIDAProperties.n_bandwidths = fKDEBandwidths.size();
305  for(size_t i_b=0; i_b<fPIDAProperties.n_bandwidths; i_b++)
306 
307  calculatePIDASigma();
308  fPIDAProperties.n_pid_pts = fpida_values.size();
309  fPIDAProperties.mean = fpida_mean;
310  fPIDAProperties.sigma = fpida_sigma;
311 
312  fPIDAProperties.integral_dedx = fpida_integral_dedx;
313  fPIDAProperties.integral_pida = fpida_integral_pida;
314 
315  createKDEs();
316  for(size_t i_b=0; i_b<fPIDAProperties.n_bandwidths; i_b++){
317  fPIDAProperties.kde_mp[i_b] = fpida_kde_mp[i_b];
318  fPIDAProperties.kde_fwhm[i_b] = fpida_kde_fwhm[i_b];
319  fPIDAProperties.kde_bandwidth[i_b] = fpida_kde_b[i_b];
320  }
321 
322  hPIDAvalues->Reset();
323  for(auto const& val: fpida_values)
324  hPIDAvalues->Fill(val);
325 
326  for(size_t i_b=0; i_b<fPIDAProperties.n_bandwidths; i_b++){
327  hPIDAKDE[i_b]->Reset();
328  for(size_t i_step=0; i_step<fkde_distribution[i_b].size(); i_step++)
329  hPIDAKDE[i_b]->AddBinContent(hPIDAKDE[i_b]->FindBin(i_step*fKDEEvalStepSize+fkde_dist_min[i_b]),
330  fkde_distribution[i_b][i_step]);
331  }
332 
333  fPIDATree->Fill();
334 }
335 
337  for(size_t i_pida=0; i_pida<fpida_values.size(); i_pida++)
338  std::cout << "\tPIDA --- " << i_pida << "\t" << fpida_values[i_pida] << std::endl;
339 }
340 
341 util::NormalDistribution::NormalDistribution(float max_sigma, float step_size){
342 
343  if(step_size==0)
344  throw "util::NormalDistribution --- Cannot have zero step size!";
345 
346  const size_t vector_size = (size_t)(max_sigma / step_size);
347  fValues.resize(vector_size);
348 
349  const float AMPLITUDE = 1. / std::sqrt(2*M_PI);
350 
351  float integral=0;
352  for(size_t i_step=0; i_step<vector_size; i_step++){
353  float diff = i_step*step_size;
354  fValues[i_step] = AMPLITUDE * std::exp(-0.5*diff*diff);
355  integral+= fValues[i_step];
356  }
357 
358  for(size_t i_step=0; i_step<vector_size; i_step++)
359  fValues[i_step] /= (integral*2);
360 
361  fStepSize = step_size;
362  fMaxSigma = fStepSize * vector_size;
363 
364 }
365 
367 
368  x = std::abs(x);
369  if(x > fMaxSigma) return 0;
370 
371  size_t bin_low = x / fStepSize;
372  float remainder = (x - (bin_low*fStepSize)) / fStepSize;
373 
374  return fValues[bin_low]*(1-remainder) + remainder*fValues[bin_low+1];
375 
376 }
void SetPIDATree(TTree *, TH1F *, std::vector< TH1F * >)
Definition: PIDAAlg.cxx:57
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
process_name opflash particleana ie x
void FillPIDATree(unsigned int, unsigned int, unsigned int, anab::Calorimetry const &)
Definition: PIDAAlg.cxx:176
pdgs p
Definition: selectors.fcl:22
const geo::PlaneID & PlaneID() const
Definition: Calorimetry.h:116
PIDAAlg(fhicl::ParameterSet const &p)
Definition: PIDAAlg.cxx:24
float getPIDAMean()
Definition: PIDAAlg.cxx:95
void FillPIDAProperties(unsigned int, unsigned int, unsigned int, anab::Calorimetry const &)
Definition: PIDAAlg.cxx:292
void createKDE(const size_t)
Definition: PIDAAlg.cxx:226
void createKDEs()
Definition: PIDAAlg.cxx:287
const std::vector< float > & ResidualRange() const
Definition: Calorimetry.h:103
process_name can override from command line with o or output calo
Definition: pid.fcl:40
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
const std::vector< float > & getPIDAValues()
Definition: PIDAAlg.cxx:123
T abs(T value)
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
float getPIDAKDEMostProbable(const size_t)
Definition: PIDAAlg.cxx:109
float getPIDASigma()
Definition: PIDAAlg.cxx:102
float getValue(float)
Definition: PIDAAlg.cxx:366
void RunPIDAAlg(std::vector< float > const &, std::vector< float > const &)
Definition: PIDAAlg.cxx:146
const unsigned int MAX_BANDWIDTHS
Definition: PIDAAlg.h:46
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
void ClearInternalData()
Definition: PIDAAlg.cxx:41
void PrintPIDAValues()
Definition: PIDAAlg.cxx:336
Definition of data types for geometry description.
float dEdx(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, TP3D &tp3d)
Definition: PFPUtils.cxx:2687
const std::vector< float > & dEdx() const
Definition: Calorimetry.h:101
float getPIDAKDEFullWidthHalfMax(const size_t)
Definition: PIDAAlg.cxx:116
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
Definition: UtilFunc.cxx:13
void calculatePIDAIntegral(std::map< double, double > const &)
Definition: PIDAAlg.cxx:208
void calculatePIDAMean()
Definition: PIDAAlg.cxx:184
const float & KineticEnergy() const
Definition: Calorimetry.h:105
const std::vector< float > & getPIDAErrors()
Definition: PIDAAlg.cxx:127
const float & Range() const
Definition: Calorimetry.h:106
void calculatePIDASigma()
Definition: PIDAAlg.cxx:196
BEGIN_PROLOG could also be cout