All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CutOptimizer.cxx
Go to the documentation of this file.
2 
3 #include "TH1.h"
4 
5 #include <iostream>
6 
7 namespace ana
8 {
9  // --------------------------------------------------------------------------
11  const Cut& sigcut,
12  const Cut& presel,
13  const std::vector<HistAxis>& axes,
14  const std::vector<double>& cut_pos,
15  std::vector<Spectrum>& sigs,
16  std::vector<Spectrum>& bkgs)
17  {
18  assert(cut_pos.size() == axes.size());
19 
20  sigs.reserve(axes.size());
21  bkgs.reserve(axes.size());
22 
23  for(unsigned int i = 0; i < axes.size(); ++i){
24  Cut nminusone = presel;
25  for(unsigned j = 0; j < axes.size(); ++j){
26  if(j == i) continue;
27  // TODO support cuts with a < sign
28  nminusone = nminusone && axes[j].GetVars()[0] > cut_pos[j];
29  } // end for j
30 
31  sigs.emplace_back(loader, axes[i], nminusone && sigcut);
32  bkgs.emplace_back(loader, axes[i], nminusone && !sigcut);
33  } // end for i
34  }
35 
36  // --------------------------------------------------------------------------
37  double FindOptimumCut(TH1* hsig, TH1* hbkg, double& best_fom)
38  {
39  double nsig = 0;
40  double nbkg = 0;
41  best_fom = 0;
42  double best_cut = -1;
43 
44  for(int binIdx = hsig->GetNbinsX()+1; binIdx >= 0; --binIdx){
45  nsig += hsig->GetBinContent(binIdx);
46  nbkg += hbkg->GetBinContent(binIdx);
47  const double fom = nsig ? nsig/sqrt(nsig+nbkg) : 0;
48  if(fom > best_fom){
49  best_fom = fom;
50  best_cut = hsig->GetXaxis()->GetBinLowEdge(binIdx);
51  }
52  } // end for binIdx
53 
54  return best_cut;
55  }
56 
57  // --------------------------------------------------------------------------
58  double OptimizeOneCut(const std::string& wildcard,
59  double pot,
60  const Cut& sigcut,
61  const Cut& presel,
62  const std::vector<HistAxis>& axes,
63  std::vector<double>& cut_pos)
64  {
65  SpectrumLoader loader(wildcard);
66  std::vector<Spectrum> sigs, bkgs;
67  MakeNMinusOneSpectra(loader, sigcut, presel, axes, cut_pos, sigs, bkgs);
68  loader.Go();
69 
70  double best_fom = 0;
71  double best_cut = -1;
72  int best_idx = -1;
73 
74  for(unsigned int cutIdx = 0; cutIdx < axes.size(); ++cutIdx){
75  TH1* hsig = sigs[cutIdx].ToTH1(pot, kRed);
76  TH1* hbkg = bkgs[cutIdx].ToTH1(pot, kBlue);
77  // TODO support multiple background spectra, such as cosmics
78 
79  double fom;
80  const double cut = FindOptimumCut(hsig, hbkg, fom);
81 
82  if(fom > best_fom){
83  best_fom = fom;
84  best_cut = cut;
85  best_idx = cutIdx;
86  }
87 
88  // TODO plot distributions and optimized cuts at each phase
89  } // end for cutIdx
90 
91  std::cout << "Updated cut on '" << axes[best_idx].GetLabels()[0] << "' to " << best_cut << ". FOM now " << best_fom << std::endl;
92 
93  // Store the result
94  cut_pos[best_idx] = best_cut;
95  return best_fom;
96  }
97 
98  // --------------------------------------------------------------------------
99  void OptimizeCuts(const std::string& wildcard,
100  double pot,
101  const Cut& sigcut,
102  const Cut& presel,
103  const std::vector<HistAxis>& axes,
104  std::vector<double>& cut_pos)
105  {
106  std::cout << "Initial cuts:" << std::endl;
107  for(unsigned int i = 0; i < axes.size(); ++i){
108  std::cout << " " << axes[i].GetLabels()[0] << " > " << cut_pos[i] << std::endl;
109  }
110 
111  double fom = 0;
112  while(true){
113  const double new_fom = OptimizeOneCut(wildcard, pot, sigcut, presel, axes, cut_pos);
114  // Give up once the new FOM is not more than a 1% improvement
115  if(new_fom < fom*1.01) break;
116  fom = new_fom;
117  }
118 
119  std::cout << "Final optimized cuts:" << std::endl;
120  for(unsigned int i = 0; i < axes.size(); ++i){
121  std::cout << " " << axes[i].GetLabels()[0] << " > " << cut_pos[i] << std::endl;
122  }
123  }
124 }
void OptimizeCuts(const std::string &wildcard, double pot, const Cut &sigcut, const Cut &presel, const std::vector< HistAxis > &axes, std::vector< double > &cut_pos)
Repeatedly invoke OptimizeOneCut until the FOM increase becomes small.
tuple loader
Definition: demo.py:7
void MakeNMinusOneSpectra(SpectrumLoader &loader, const Cut &sigcut, const Cut &presel, const std::vector< HistAxis > &axes, const std::vector< double > &cut_pos, std::vector< Spectrum > &sigs, std::vector< Spectrum > &bkgs)
Make a series of spectra leaving out one cut in turn.
process_name opflashCryoW ana
double FindOptimumCut(TH1 *hsig, TH1 *hbkg, double &best_fom)
Search for optimum cut position given signal and background histograms.
virtual void Go() override
Load all the registered spectra.
Collaborates with Spectrum and OscillatableSpectrum to fill spectra from CAF files.
Template for Cut and SpillCut.
Definition: Cut.h:16
BEGIN_PROLOG could also be cout
double OptimizeOneCut(const std::string &wildcard, double pot, const Cut &sigcut, const Cut &presel, const std::vector< HistAxis > &axes, std::vector< double > &cut_pos)
Scan all cuts and update the one giving the largest FOM gain.