All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ShowerBayesianTrucatingdEdx_tool.cc
Go to the documentation of this file.
1 //############################################################################
2 //### Name: ShowerBayesianTrucatingdEdx ###
3 //### Author: Dominic Barker ###
4 //### Date: 13.05.19 ###
5 //### Description: Recursively adds values from the dEdx vectors and stops ###
6 //### when the probability of getting that dEdx value is too ###
7 //### low. This is done for both the a electron prior and ###
8 //### photon prior. The posterior is calculated and the prior ###
9 //### with the highest posterior is taken. Currently can ###
10 //### only be used with the sliding calo dEdx ###
11 //############################################################################
12 
13 //Framework Includes
14 #include "art/Utilities/ToolMacros.h"
15 
16 //LArSoft Includes
18 
19 //ROOT Includes
20 #include "TFile.h"
21 #include "TH1.h"
22 #include "TAxis.h"
23 
24 namespace ShowerRecoTools {
25 
27 
28  public:
29  ShowerBayesianTrucatingdEdx(const fhicl::ParameterSet& pset);
30 
31  //Generic Direction Finder
32  int CalculateElement(const art::Ptr<recob::PFParticle>& pfparticle,
33  art::Event& Event,
34  reco::shower::ShowerElementHolder& ShowerEleHolder) override;
35 
36  private:
37  double CalculatePosterior(std::string priorname,
38  std::vector<double>& values,
39  int& minprob,
40  float& mean,
41  float& likelihood);
42  double CalculatePosterior(std::string priorname, std::vector<double>& values);
43 
44  bool
45  isProbabilityGood(float& old_prob, float& new_prob)
46  {
47  return (old_prob - new_prob) < fProbSeedCut;
48  }
49 
50  bool
51  isPosteriorProbabilityGood(double& prob, double& old_posteior)
52  {
53  return (old_posteior - prob) < fPostiorCut;
54  }
55 
56  bool CheckPoint(std::string priorname, double& value);
57 
58  std::vector<double> GetLikelihooddEdxVec(double& electronprob,
59  double& photonprob,
60  std::string prior,
61  std::vector<double>& dEdxVec);
62 
63  std::vector<double> MakeSeed(std::vector<double>& dEdxVec);
64 
65  void ForceSeedToFit(std::vector<double>& SeedTrack,
66  std::string& prior,
67  float& mean,
68  double& posterior);
69 
70  void RecurivelyAddHit(std::vector<double>& SeedTrack,
71  std::vector<double>& dEdxVec,
72  std::string& prior,
73  int& SkippedHitsNum,
74  float& old_mean,
75  double& old_posteior);
76 
79 
80  //fcl params
81  int fVerbose;
82  std::string fdEdxInputLabel;
84  float fProbSeedCut;
86  float fPostiorCut;
91  };
92 
94  : IShowerTool(pset.get<fhicl::ParameterSet>("BaseTools"))
95  , fVerbose(pset.get<int>("Verbose"))
96  , fdEdxInputLabel(pset.get<std::string>("dEdxInputLabel"))
97  , fNumSeedHits(pset.get<int>("NumSeedHits"))
98  , fProbSeedCut(pset.get<float>("ProbSeedCut"))
99  , fProbPointCut(pset.get<float>("ProbPointCut"))
100  , fPostiorCut(pset.get<float>("PostiorCut"))
101  , fnSkipHits(pset.get<int>("nSkipHits"))
102  , fShowerdEdxOutputLabel(pset.get<std::string>("ShowerdEdxOutputLabel"))
103  , fDefineBestPlane(pset.get<bool>("DefineBestPlane"))
104  , fShowerBestPlaneOutputLabel(pset.get<std::string>("ShowerBestPlaneOutputLabel"))
105  {
106 
107  //Get the prior file name
108  std::string fname;
109  cet::search_path sp("FW_SEARCH_PATH");
110  auto PriorPath = pset.get<std::string>("PriorFname");
111  if (!sp.find_file(PriorPath, fname)) {
112  throw cet::exception("ShowerBayesianTrucatingdEdx") << "Could not find the prior file";
113  }
114  std::string electron_histoname = pset.get<std::string>("PriorElectronHistoName");
115  std::string photon_histoname = pset.get<std::string>("PriorPhotonHistoName");
116 
117  TFile fin(fname.c_str(), "READ");
118  if (!fin.IsOpen()) {
119  throw cet::exception("ShowerBayesianTrucatingdEdx") << "Could read the prior file. Stopping";
120  }
121 
122  //Get the histograms.
123  electronpriorHist = dynamic_cast<TH1F*>(fin.Get(electron_histoname.c_str()));
124  if (!electronpriorHist) {
125  throw cet::exception("ShowerBayesianTrucatingdEdx") << "Could not read the electron hist";
126  }
127  photonpriorHist = dynamic_cast<TH1F*>(fin.Get(photon_histoname.c_str()));
128  if (!photonpriorHist) {
129  throw cet::exception("ShowerBayesianTrucatingdEdx") << "Could not read the photon hist ";
130  }
131 
132  if (electronpriorHist->GetNbinsX() != photonpriorHist->GetNbinsX()) {
133  throw cet::exception("ShowerBayesianTrucatingdEdx") << "Histrogram bins do not match";
134  }
135 
136  //Normalise the histograms.
137  electronpriorHist->Scale(1 / electronpriorHist->Integral());
138  photonpriorHist->Scale(1 / photonpriorHist->Integral());
139  }
140 
141  int
142  ShowerBayesianTrucatingdEdx::CalculateElement(const art::Ptr<recob::PFParticle>& pfparticle,
143  art::Event& Event,
144  reco::shower::ShowerElementHolder& ShowerEleHolder)
145  {
146 
147  //The idea , to some peoples distaste, is to attempt to improve the dEdx value by assuming
148  //The particle is either a) electron b) a e-e+ pair.
149  //We will take the start of track and work down until a few hits destory our postier probability.
150 
151  //Note: tried takeing the postior with the highest sum of the probabilitys on all three
152  // planes and on the 2 planes with the most hits. Made things worse.
153 
154  //Get the vectors of the dEdx Elements
155  if (!ShowerEleHolder.CheckElement(fdEdxInputLabel)) {
156  if (fVerbose)
157  mf::LogError("ShowerBayesianTrucatingdEdx")
158  << "Start position not set, returning " << std::endl;
159  return 1;
160  }
161 
162  std::map<int, std::vector<double>> dEdx_plane_final;
163  std::map<int, std::vector<double>> dEdx_vec_planes;
164  ShowerEleHolder.GetElement(fdEdxInputLabel, dEdx_vec_planes);
165 
166  //Do this for each plane;
167  for (auto const& dEdx_vec_plane : dEdx_vec_planes) {
168 
169  //Set up out final value if we don't have any points.
170  if (dEdx_vec_plane.second.size() < 1) {
171  dEdx_plane_final[dEdx_vec_plane.first] = {};
172  continue;
173  }
174 
175  std::vector<double> dEdx_vec = dEdx_vec_plane.second;
176 
177  double electronprob_eprior = 0;
178  double photonprob_eprior = 0;
179 
180  double electronprob_pprior = 0;
181  double photonprob_pprior = 0;
182 
183  std::vector<double> dEdx_electronprior =
184  GetLikelihooddEdxVec(electronprob_eprior, photonprob_eprior, "electron", dEdx_vec);
185  std::vector<double> dEdx_photonprior =
186  GetLikelihooddEdxVec(electronprob_pprior, photonprob_pprior, "photon", dEdx_vec);
187 
188  //Use the vector which maximises both priors.
189  if (electronprob_eprior < photonprob_pprior) {
190  dEdx_plane_final[dEdx_vec_plane.first] = dEdx_photonprior;
191  }
192  else {
193  dEdx_plane_final[dEdx_vec_plane.first] = dEdx_electronprior;
194  }
195 
196  } //Plane Loop
197 
198  //Calculate the median of the of dEdx.
199  std::vector<double> dEdx_final;
200  std::vector<double> dEdx_finalErr;
201 
202  int max_hits = -999;
203  int best_plane = -999;
204 
205  bool check = false;
206  for (auto const& dEdx_plane : dEdx_plane_final) {
207 
208  //Redefine the best plane
209  if ((int)(dEdx_plane.second).size() > max_hits) {
210  best_plane = dEdx_plane.first;
211  max_hits = (dEdx_plane.second).size();
212  }
213 
214  if ((dEdx_plane.second).empty()) {
215  dEdx_final.push_back(-999);
216  dEdx_finalErr.push_back(-999);
217  continue;
218  }
219 
220  dEdx_final.push_back(TMath::Median((dEdx_plane.second).size(), &(dEdx_plane.second)[0]));
221  dEdx_finalErr.push_back(-999);
222  check = true;
223  }
224 
225  //Check at least one plane has the information
226  if (!check) return 1;
227 
228  if (fDefineBestPlane) { ShowerEleHolder.SetElement(best_plane, fShowerBestPlaneOutputLabel); }
229 
230  ShowerEleHolder.SetElement(dEdx_final, dEdx_finalErr, fShowerdEdxOutputLabel);
231 
232  return 0;
233  }
234 
235  double
237  std::vector<double>& values)
238  {
239  int minprob_iter = -999;
240  float mean = -999;
241  float likelihood = -999;
242  return CalculatePosterior(priorname, values, minprob_iter, mean, likelihood);
243  }
244 
245  double
247  std::vector<double>& values,
248  int& minprob_iter,
249  float& mean,
250  float& likelihood)
251  {
252 
253  //Posterior prob;
254  float posterior = 1;
255  float meanprob = 0;
256  float likelihood_other = 1;
257  likelihood = 1;
258 
259  //Minimum probability temp
260  float minprob_temp = 9999;
261  minprob_iter = 0;
262 
263  TH1F* prior_hist = nullptr;
264  TH1F* other_hist = nullptr;
265 
266  if (priorname == "electron") {
267  prior_hist = electronpriorHist;
268  other_hist = photonpriorHist;
269  }
270  if (priorname == "photon") {
271  prior_hist = photonpriorHist;
272  other_hist = electronpriorHist;
273  }
274 
275  TAxis* xaxis = prior_hist->GetXaxis();
276 
277  //Loop over the hits and calculate the probability
278  for (int i = 0; i < (int)values.size(); ++i) {
279 
280  float value = values[i];
281 
282  Int_t bin = xaxis->FindBin(value);
283 
284  float prob = -9999;
285  float other_prob = -9999;
286 
287  if (bin != xaxis->GetNbins() || bin == 0) {
288  //Calculate the likelihood
289  prob = prior_hist->GetBinContent(bin);
290  other_prob = other_hist->GetBinContent(bin);
291  }
292  else {
293  prob = 0;
294  other_prob = 0;
295  }
296 
297  if (prob < minprob_temp) {
298  minprob_temp = prob;
299  minprob_iter = i;
300  }
301 
302  if (prob == 0 && other_prob == 0) { continue; }
303 
304  //Calculate the posterior the mean probability and liklihood
305  meanprob += prior_hist->GetBinContent(bin);
306  likelihood *= prob;
307  likelihood_other *= other_prob;
308  }
309 
310  posterior = likelihood / (likelihood + likelihood_other);
311 
312  meanprob /= values.size();
313  mean = meanprob;
314  return posterior;
315  }
316 
317  bool
318  ShowerBayesianTrucatingdEdx::CheckPoint(std::string priorname, double& value)
319  {
320 
321  TH1F* prior_hist = nullptr;
322 
323  if (priorname == "electron") { prior_hist = electronpriorHist; }
324  if (priorname == "photon") { prior_hist = photonpriorHist; }
325 
326  TAxis* xaxis = prior_hist->GetXaxis();
327 
328  Int_t bin = xaxis->FindBin(value);
329 
330  float prob = -9999;
331 
332  if (bin != xaxis->GetNbins() + 1 || bin == 0) {
333  //Calculate the likelihood
334  prob = prior_hist->GetBinContent(bin);
335  }
336  else {
337  prob = 0;
338  }
339 
340  //Return the probability of getting that point.
341  return prob > fProbPointCut;
342  }
343 
344  std::vector<double>
346  double& photonprob,
347  std::string prior,
348  std::vector<double>& dEdxVec)
349  {
350 
351  //have a pool
352  std::vector<double> dEdxVec_temp = dEdxVec;
353 
354  //Get The seed track.
355  std::vector<double> SeedTrack = MakeSeed(dEdxVec_temp);
356  // if(SeedTrack.size() < 1){
357  // return SeedTrack;
358  // }
359 
360  //Force the seed the be a good likelihood.
361  float mean = 999;
362  double posterior = 999;
363  ForceSeedToFit(SeedTrack, prior, mean, posterior);
364 
365  //Recursively add dEdx
366  int SkippedHitsNum = 0;
367  RecurivelyAddHit(SeedTrack, dEdxVec_temp, prior, SkippedHitsNum, mean, posterior);
368 
369  //Calculate the likelihood of the vector with the photon and electron priors.
370  electronprob = CalculatePosterior("electron", SeedTrack);
371  photonprob = CalculatePosterior("photon", SeedTrack);
372 
373  return SeedTrack;
374  }
375 
376  std::vector<double>
377  ShowerBayesianTrucatingdEdx::MakeSeed(std::vector<double>& dEdxVec)
378  {
379 
380  std::vector<double> seed_vector;
381 
382  //Add the first hits to the seed
383  int MaxHit = fNumSeedHits;
384  if (fNumSeedHits > (int)dEdxVec.size()) { MaxHit = (int)dEdxVec.size(); }
385 
386  // if(MaxHit == 0){
387  // mf::LogError("ShowerBayesianTrucatingdEdx") << "Size of the vector is 0 cannot perform the dEdx cutting "<< std::endl;
388  //}
389 
390  for (int hit_iter = 0; hit_iter < MaxHit; ++hit_iter) {
391  seed_vector.push_back(dEdxVec[0]);
392  dEdxVec.erase(dEdxVec.begin());
393  }
394 
395  return seed_vector;
396  }
397 
398  void
399  ShowerBayesianTrucatingdEdx::ForceSeedToFit(std::vector<double>& SeedTrack,
400  std::string& prior,
401  float& mean,
402  double& posterior)
403  {
404 
405  int minprob_iter = 999;
406  float likelihood = -999;
407  float prob = CalculatePosterior(prior, SeedTrack, minprob_iter, mean, likelihood);
408  while ((mean < fProbSeedCut || prob <= 0) && SeedTrack.size() > 1) {
409 
410  //Remove the the worse point.
411  // std::cout << "removing hit with dEdx: " << SeedTrack.at(minprob_iter) << std::endl;
412  SeedTrack.erase(SeedTrack.begin() + minprob_iter);
413  minprob_iter = 999;
414 
415  //Recalculate
416  prob = CalculatePosterior(prior, SeedTrack, minprob_iter, mean, likelihood);
417  }
418  posterior = prob;
419  // std::cout << "seed has been fit with size: " << SeedTrack.size() << std::endl;
420  return;
421  }
422 
423  void
424  ShowerBayesianTrucatingdEdx::RecurivelyAddHit(std::vector<double>& SeedTrack,
425  std::vector<double>& dEdxVec,
426  std::string& prior,
427  int& SkippedHitsNum,
428  float& old_mean,
429  double& old_posteior)
430  {
431 
432  //If we have no more hits to add then lets finish.
433  if (dEdxVec.size() < 1) { return; }
434 
435  bool ok = CheckPoint(prior, dEdxVec[0]);
436  // int minprob_iter=999;
437  // float mean = -999;
438  // float likelihood =999;
439  // if(ok){std::cout << "passed first cut" << std::endl;}
440  // else{std::cout << "failed first cut" << std::endl;}
441  // double prob = CalculatePosterior(prior,SeedTrack,minprob_iter,mean,likelihood);
442  // ok *= isProbabilityGood(mean,old_mean);
443  // if(ok){std::cout << "passed second cut" << std::endl;}
444  // else{std::cout << "failed second cut" << std::endl;}
445  // ok *= isPosteriorProbabilityGood(prob,old_posteior);
446  // if(ok){std::cout << "passed this cut" << std::endl;}
447  // else{std::cout << "failed third cut" << std::endl;}
448 
449  //If we failed lets try the next hits
450  if (!ok) {
451  // std::cout << "failed the pass point: " << dEdxVec[0] << " trying another hit" << SkippedHitsNum << std::endl;
452  //if(SeedTrack.size() > 1){SeedTrack.pop_back();}
453  ++SkippedHitsNum;
454  if (SkippedHitsNum > fnSkipHits) { return; }
455  }
456  else {
457  //Add the next point in question.
458  // std::cout << "adding value: " << dEdxVec[0] << std::endl;
459  //Reset the skip number
460  SkippedHitsNum = 0;
461  SeedTrack.push_back(dEdxVec[0]);
462  }
463 
464  //We have analysed this hit now lets remove it.
465  dEdxVec.erase(dEdxVec.begin());
466 
467  RecurivelyAddHit(SeedTrack, dEdxVec, prior, SkippedHitsNum, old_mean, old_posteior);
468 
469  return;
470  }
471 }
472 
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
bool isProbabilityGood(float &old_prob, float &new_prob)
string fname
Definition: demo.py:5
std::vector< double > GetLikelihooddEdxVec(double &electronprob, double &photonprob, std::string prior, std::vector< double > &dEdxVec)
void SetElement(T &dataproduct, const std::string &Name, bool checktag=false)
static constexpr bool
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
int CalculateElement(const art::Ptr< recob::PFParticle > &pfparticle, art::Event &Event, reco::shower::ShowerElementHolder &ShowerEleHolder) override
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
bool isPosteriorProbabilityGood(double &prob, double &old_posteior)
bool CheckElement(const std::string &Name) const
process_name tightIsolTest check
std::vector< double > MakeSeed(std::vector< double > &dEdxVec)
int GetElement(const std::string &Name, T &Element) const
void ForceSeedToFit(std::vector< double > &SeedTrack, std::string &prior, float &mean, double &posterior)
double CalculatePosterior(std::string priorname, std::vector< double > &values, int &minprob, float &mean, float &likelihood)
void RecurivelyAddHit(std::vector< double > &SeedTrack, std::vector< double > &dEdxVec, std::string &prior, int &SkippedHitsNum, float &old_mean, double &old_posteior)
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
Definition: UtilFunc.cxx:13
temporary value
bool CheckPoint(std::string priorname, double &value)