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