LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
PIDAAlg.cxx
Go to the documentation of this file.
1 
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 
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 {
47  fpida_values.clear();
48  fpida_errors.clear();
49 
50  fpida_kde_mp = std::vector<float>(fKDEBandwidths.size(), fPIDA_BOGUS);
51  fpida_kde_fwhm = std::vector<float>(fKDEBandwidths.size(), fPIDA_BOGUS);
52  fpida_kde_b = std::vector<float>(fKDEBandwidths.size(), fPIDA_BOGUS);
53  fkde_distribution = std::vector<std::vector<float>>(fKDEBandwidths.size());
54  fkde_dist_min = std::vector<float>(fKDEBandwidths.size(), fPIDA_BOGUS);
55  fkde_dist_max = std::vector<float>(fKDEBandwidths.size(), fPIDA_BOGUS);
56 }
57 
58 void pid::PIDAAlg::SetPIDATree(TTree* tree, TH1F* hist_vals, std::vector<TH1F*> hist_kde)
59 {
60 
61  if (hist_kde.size() > MAX_BANDWIDTHS)
62  throw "Error: input histograms larger than max allowed bandwidths.";
63  if (hist_kde.size() != fKDEBandwidths.size())
64  throw "Error: input histograms do not have same size as bandwidths.";
65 
66  fPIDATree = tree;
67 
68  hPIDAvalues = hist_vals;
69  hPIDAvalues->SetNameTitle("hPIDAvalues", "PIDA Distribution");
71 
72  for (size_t i_hist = 0; i_hist < hist_kde.size(); i_hist++) {
73  hPIDAKDE[i_hist] = hist_kde[i_hist];
74 
75  std::stringstream hname, htitle;
76  hname << "hPIDAKDE_" << i_hist;
77  htitle << "PIDA KDE-smoothed Distribution, Bandwidth=" << fKDEBandwidths.at(i_hist);
78 
79  hPIDAKDE[i_hist]->SetNameTitle(hname.str().c_str(), htitle.str().c_str());
81  }
82 
83  fPIDATree->Branch("pida", &fPIDAProperties, fPIDAProperties.leaf_structure.c_str());
84  fPIDATree->Branch("hpida_vals", "TH1F", hPIDAvalues);
85  fPIDATree->Branch("n_bandwidths", &(fPIDAProperties.n_bandwidths), "n_bandwidths/i");
86  fPIDATree->Branch(
87  "kde_bandwidth", fPIDAProperties.kde_bandwidth, "kde_bandwidth[n_bandwidths]/F");
88  fPIDATree->Branch("kde_mp", fPIDAProperties.kde_mp, "kde_mp[n_bandwidths]/F");
89  fPIDATree->Branch("kde_fwhm", fPIDAProperties.kde_fwhm, "kde_fwhm[n_bandwidths]/F");
90  for (size_t i_hist = 0; i_hist < hist_kde.size(); i_hist++) {
91  std::stringstream bname;
92  bname << "hpida_kde_" << i_hist;
93  fPIDATree->Branch(bname.str().c_str(), "TH1F", hPIDAKDE[i_hist]);
94  }
95 }
96 
98 {
100 
101  return fpida_mean;
102 }
103 
105 {
107 
108  return fpida_sigma;
109 }
110 
112 {
113  if (fpida_kde_mp[i_b] == fPIDA_BOGUS) createKDE(i_b);
114 
115  return fpida_kde_mp[i_b];
116 }
117 
119 {
120  if (fpida_kde_fwhm[i_b] == fPIDA_BOGUS) createKDE(i_b);
121 
122  return fpida_kde_fwhm[i_b];
123 }
124 
125 const std::vector<float>& pid::PIDAAlg::getPIDAValues()
126 {
127  return fpida_values;
128 }
129 
130 const std::vector<float>& pid::PIDAAlg::getPIDAErrors()
131 {
132  return fpida_errors;
133 }
134 
136 {
137  std::vector<float> const& resRange = calo.ResidualRange();
138  std::vector<float> const& dEdx = calo.dEdx();
139  RunPIDAAlg(resRange, dEdx);
140 }
141 
142 void pid::PIDAAlg::RunPIDAAlg(anab::Calorimetry const& calo, float& mean, float& sigma)
143 {
144  RunPIDAAlg(calo);
145  mean = getPIDAMean();
146  sigma = getPIDASigma();
147 }
148 
149 void pid::PIDAAlg::RunPIDAAlg(std::vector<float> const& resRange, std::vector<float> const& dEdx)
150 {
151 
153 
154  fpida_values.reserve(resRange.size());
155  fpida_errors.reserve(resRange.size());
156 
157  std::map<double, double> range_dEdx_map;
158 
159  for (size_t i_r = 0; i_r < resRange.size(); i_r++) {
160  if (resRange[i_r] > fMaxResRange || resRange[i_r] < fMinResRange) continue;
161 
162  range_dEdx_map[resRange[i_r]] = dEdx[i_r];
163 
164  float val = dEdx[i_r] * std::pow(resRange[i_r], fExponentConstant);
165  if (val < fMaxPIDAValue) {
166  fpida_values.push_back(val);
167  //fpida_errors.push_back(0);
168  }
169  }
170 
171  calculatePIDAIntegral(range_dEdx_map);
172 
173  if (fpida_values.size() == 0) fpida_values.push_back(-99);
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 {
181  RunPIDAAlg(calo);
182  FillPIDAProperties(run, event, calo_index, calo);
183 }
184 
186 {
187 
188  if (fpida_values.size() == 0) throw "pid::PIDAAlg --- PIDA Values not filled!";
189 
190  fpida_mean = 0;
191  for (auto const& val : fpida_values)
192  fpida_mean += val;
193  fpida_mean /= fpida_values.size();
194 }
195 
197 {
198 
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 
211  if (range_dEdx_map.size() < 2) return;
212 
214 
215  for (std::map<double, double>::const_iterator map_iter = range_dEdx_map.begin();
216  map_iter != std::prev(range_dEdx_map.end());
217  map_iter++) {
218  double range_width = std::next(map_iter)->first - map_iter->first;
219  fpida_integral_dedx += range_width * (std::next(map_iter)->second +
220  0.5 * (map_iter->second - std::next(map_iter)->second));
221  }
222 
225  std::pow((std::prev(range_dEdx_map.end())->first - range_dEdx_map.begin()->first),
226  (fExponentConstant - 1));
227 }
228 
229 void pid::PIDAAlg::createKDE(const size_t i_b)
230 {
231 
232  if (fpida_values.size() == 0) throw "pid::PIDAAlg --- PIDA Values not filled!";
233 
234  //if( fkde_distribution[i_b].size()!=0 ) return;
235 
236  if (fKDEBandwidths[i_b] <= 0) {
238  float bandwidth = fpida_sigma * 1.06 * std::pow((float)(fpida_values.size()), -0.2);
239  fpida_errors = std::vector<float>(fpida_values.size(), bandwidth);
240  fpida_kde_b[i_b] = bandwidth;
241  }
242  else {
243  fpida_errors = std::vector<float>(fpida_values.size(), fKDEBandwidths[i_b]);
244  fpida_kde_b[i_b] = fKDEBandwidths[i_b];
245  }
246 
247  const auto min_pida_iterator = std::min_element(fpida_values.begin(), fpida_values.end());
248  const size_t min_pida_location = std::distance(fpida_values.begin(), min_pida_iterator);
249  fkde_dist_min[i_b] =
250  fpida_values[min_pida_location] - fKDEEvalMaxSigma * fpida_errors[min_pida_location];
251 
252  const auto max_pida_iterator = std::max_element(fpida_values.begin(), fpida_values.end());
253  const size_t max_pida_location = std::distance(fpida_values.begin(), max_pida_iterator);
254  fkde_dist_max[i_b] =
255  fpida_values[max_pida_location] + fKDEEvalMaxSigma * fpida_errors[max_pida_location];
256 
257  //make the kde distribution, and get the max value
258  const size_t kde_dist_size =
259  (size_t)((fkde_dist_max[i_b] - fkde_dist_min[i_b]) / fKDEEvalStepSize) + 1;
260  fkde_distribution[i_b].resize(kde_dist_size);
261  float kde_max = 0;
262  size_t step_max = 0;
263  for (size_t i_step = 0; i_step < kde_dist_size; i_step++) {
264  float pida_val = fkde_dist_min[i_b] + i_step * fKDEEvalStepSize;
265  fkde_distribution[i_b][i_step] = 0;
266 
267  for (size_t i_pida = 0; i_pida < fpida_values.size(); i_pida++)
268  fkde_distribution[i_b][i_step] +=
269  fnormalDist.getValue((fpida_values[i_pida] - pida_val) / fpida_errors[i_pida]) /
270  fpida_errors[i_pida];
271 
272  if (fkde_distribution[i_b][i_step] > kde_max) {
273  kde_max = fkde_distribution[i_b][i_step];
274  step_max = i_step;
275  fpida_kde_mp[i_b] = pida_val;
276  }
277  }
278 
279  //now get fwhm
280  float half_max = 0.5 * fpida_kde_mp[i_b];
281  float low_width = 0;
282  for (size_t i_step = step_max; i_step > 0; i_step--) {
283  if (fkde_distribution[i_b][i_step] < half_max) break;
284  low_width += fKDEEvalStepSize;
285  }
286  float high_width = 0;
287  for (size_t i_step = step_max; i_step < kde_dist_size; i_step++) {
288  if (fkde_distribution[i_b][i_step] < half_max) break;
289  high_width += fKDEEvalStepSize;
290  }
291  fpida_kde_fwhm[i_b] = low_width + high_width;
292 }
293 
295 {
296  for (size_t i_b = 0; i_b < fKDEBandwidths.size(); i_b++)
297  createKDE(i_b);
298 }
299 
300 void pid::PIDAAlg::FillPIDAProperties(unsigned int run,
301  unsigned int event,
302  unsigned int calo_index,
303  anab::Calorimetry const& calo)
304 {
305 
306  fPIDAProperties.run = run;
307  fPIDAProperties.event = event;
308  fPIDAProperties.calo_index = calo_index;
312 
314  for (size_t i_b = 0; i_b < fPIDAProperties.n_bandwidths; i_b++)
315 
320 
323 
324  createKDEs();
325  for (size_t i_b = 0; i_b < fPIDAProperties.n_bandwidths; i_b++) {
326  fPIDAProperties.kde_mp[i_b] = fpida_kde_mp[i_b];
329  }
330 
331  hPIDAvalues->Reset();
332  for (auto const& val : fpida_values)
333  hPIDAvalues->Fill(val);
334 
335  for (size_t i_b = 0; i_b < fPIDAProperties.n_bandwidths; i_b++) {
336  hPIDAKDE[i_b]->Reset();
337  for (size_t i_step = 0; i_step < fkde_distribution[i_b].size(); i_step++)
338  hPIDAKDE[i_b]->AddBinContent(
339  hPIDAKDE[i_b]->FindBin(i_step * fKDEEvalStepSize + fkde_dist_min[i_b]),
340  fkde_distribution[i_b][i_step]);
341  }
342 
343  fPIDATree->Fill();
344 }
345 
347 {
348  for (size_t i_pida = 0; i_pida < fpida_values.size(); i_pida++)
349  std::cout << "\tPIDA --- " << i_pida << "\t" << fpida_values[i_pida] << std::endl;
350 }
351 
352 util::NormalDistribution::NormalDistribution(float max_sigma, float step_size)
353 {
354 
355  if (step_size == 0) throw "util::NormalDistribution --- Cannot have zero step size!";
356 
357  const size_t vector_size = (size_t)(max_sigma / step_size);
358  fValues.resize(vector_size);
359 
360  const float AMPLITUDE = 1. / std::sqrt(2 * M_PI);
361 
362  float integral = 0;
363  for (size_t i_step = 0; i_step < vector_size; i_step++) {
364  float diff = i_step * step_size;
365  fValues[i_step] = AMPLITUDE * std::exp(-0.5 * diff * diff);
366  integral += fValues[i_step];
367  }
368 
369  for (size_t i_step = 0; i_step < vector_size; i_step++)
370  fValues[i_step] /= (integral * 2);
371 
372  fStepSize = step_size;
373  fMaxSigma = fStepSize * vector_size;
374 }
375 
377 {
378 
379  x = std::abs(x);
380  if (x > fMaxSigma) return 0;
381 
382  size_t bin_low = x / fStepSize;
383  float remainder = (x - (bin_low * fStepSize)) / fStepSize;
384 
385  return fValues[bin_low] * (1 - remainder) + remainder * fValues[bin_low + 1];
386 }
Float_t x
Definition: compare.C:6
std::vector< float > fpida_errors
Definition: PIDAAlg.h:88
TH1F * hPIDAKDE[MAX_BANDWIDTHS]
Definition: PIDAAlg.h:117
void SetPIDATree(TTree *, TH1F *, std::vector< TH1F * >)
Definition: PIDAAlg.cxx:58
Namespace for general, non-LArSoft-specific utilities.
Definition: PIDAAlg.h:26
TH1F * hPIDAvalues
Definition: PIDAAlg.h:116
std::string leaf_structure
Definition: PIDAAlg.h:140
float fPIDAHistMin
Definition: PIDAAlg.h:119
TTree * fPIDATree
Definition: PIDAAlg.h:115
float kde_bandwidth[MAX_BANDWIDTHS]
Definition: PIDAAlg.h:136
float fpida_integral_pida
Definition: PIDAAlg.h:92
void FillPIDATree(unsigned int, unsigned int, unsigned int, anab::Calorimetry const &)
Definition: PIDAAlg.cxx:176
util::NormalDistribution fnormalDist
Definition: PIDAAlg.h:113
float fMaxPIDAValue
Definition: PIDAAlg.h:82
std::vector< float > fkde_dist_min
Definition: PIDAAlg.h:110
const geo::PlaneID & PlaneID() const
Definition: Calorimetry.h:140
constexpr auto abs(T v)
Returns the absolute value of the argument.
PIDAAlg(fhicl::ParameterSet const &p)
Definition: PIDAAlg.cxx:24
STL namespace.
float getPIDAMean()
Definition: PIDAAlg.cxx:97
intermediate_table::const_iterator const_iterator
std::vector< std::vector< float > > fkde_distribution
Definition: PIDAAlg.h:109
std::vector< float > fpida_kde_mp
Definition: PIDAAlg.h:104
float fMinResRange
Definition: PIDAAlg.h:80
void FillPIDAProperties(unsigned int, unsigned int, unsigned int, anab::Calorimetry const &)
Definition: PIDAAlg.cxx:300
void createKDE(const size_t)
Definition: PIDAAlg.cxx:229
float fMaxResRange
Definition: PIDAAlg.h:81
void createKDEs()
Definition: PIDAAlg.cxx:294
unsigned int n_bandwidths
Definition: PIDAAlg.h:135
const std::vector< float > & ResidualRange() const
Definition: Calorimetry.h:105
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
float fKDEEvalMaxSigma
Definition: PIDAAlg.h:83
const std::vector< float > & getPIDAValues()
Definition: PIDAAlg.cxx:125
float fKDEEvalStepSize
Definition: PIDAAlg.h:84
std::vector< float > fkde_dist_max
Definition: PIDAAlg.h:111
std::vector< float > fpida_kde_fwhm
Definition: PIDAAlg.h:105
unsigned int fPIDAHistNbins
Definition: PIDAAlg.h:118
float kde_fwhm[MAX_BANDWIDTHS]
Definition: PIDAAlg.h:138
float fPIDAHistMax
Definition: PIDAAlg.h:120
float getPIDAKDEMostProbable(const size_t)
Definition: PIDAAlg.cxx:111
const float fPIDA_BOGUS
Definition: PIDAAlg.h:77
float getPIDASigma()
Definition: PIDAAlg.cxx:104
float getValue(float)
Definition: PIDAAlg.cxx:376
void RunPIDAAlg(std::vector< float > const &, std::vector< float > const &)
Definition: PIDAAlg.cxx:149
const unsigned int MAX_BANDWIDTHS
Definition: PIDAAlg.h:48
std::vector< float > fpida_values
Definition: PIDAAlg.h:87
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:481
void ClearInternalData()
Definition: PIDAAlg.cxx:41
void PrintPIDAValues()
Definition: PIDAAlg.cxx:346
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:2675
const std::vector< float > & dEdx() const
Definition: Calorimetry.h:97
float getPIDAKDEFullWidthHalfMax(const size_t)
Definition: PIDAAlg.cxx:118
float fpida_sigma
Definition: PIDAAlg.h:90
std::vector< float > fpida_kde_b
Definition: PIDAAlg.h:106
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
decltype(auto) get(T &&obj)
ADL-aware version of std::to_string.
Definition: StdUtils.h:120
float fExponentConstant
Definition: PIDAAlg.h:79
void calculatePIDAMean()
Definition: PIDAAlg.cxx:185
const float & KineticEnergy() const
Definition: Calorimetry.h:113
std::vector< float > fKDEBandwidths
Definition: PIDAAlg.h:85
const std::vector< float > & getPIDAErrors()
Definition: PIDAAlg.cxx:130
float fpida_mean
Definition: PIDAAlg.h:89
PIDAProperties_t fPIDAProperties
Definition: PIDAAlg.h:147
float fpida_integral_dedx
Definition: PIDAAlg.h:91
const float & Range() const
Definition: Calorimetry.h:117
void calculatePIDASigma()
Definition: PIDAAlg.cxx:196
float kde_mp[MAX_BANDWIDTHS]
Definition: PIDAAlg.h:137
calorimetry
Event finding and building.