HighLAND
SystematicTools.cxx
1 #include "SystematicTools.hxx"
2 #include "WeightTools.hxx"
3 #include <TGraphAsymmErrors.h>
4 #include <math.h>
5 #include <TMath.h>
6 
7 #include <sstream>
8 
9 
10 /*
11 
12 //! [SystematicTools_cov]
13 \htmlonly
14 Systematic errors are propagated using toy experiments. The covariance for the bins \(i\) and \(j\) reads:
15 
16 \[
17  C_{ij} = \sum_{t=1}^{N_{toys}} [(N_i^t)^W-N_i^{avg}] [(N_j^t)^W-N_j^{avg}]\cdot w^t
18 \]
19 
20 In the above expression \(w^t\) is the toy experiment weight (i.e. the probability of this toy to occur). When random throws are used to generate the toy, it is just:
21 
22 \[
23  w^t = \frac{1}{N_{toys}}
24 \]
25 
26 \((N_i^t)^W\) is the number of selected events for toy \(t\) and bin \(i\) once weight systematics (efficiency-like and normalization systematics,
27 described above) have been applied (hence the superindex ``W''):
28 
29 \[
30  (N_i^t)^W = \sum_{e=1}^{N_{events}} (W^t)_e \cdot (\delta_i^t)_e
31 \]
32 
33 
34 being \((W^t)_e\) the total weight for toy \(t\) and event \(e\). This will be the product of individual weights for each systematic, \((W^t)_e = \prod_{s=1}^{N_s} (W^t)_e^s \).
35 The expression \((\delta_i^t)_e\) has value 1 or 0 depending on whether the selection was passed
36 for event \(e\) and toy \(t\) and the event felt in bin \(i\).
37 
38 Finally, \(N_i^{avg}\) is the average number of events for bin \(i\) when no weight systematics
39 where applied:
40 
41 \[
42  N_i^{avg} = \sum_{t=1}^{N_{toys}} w^t \cdot N_i^t = \sum_{t=1}^{N_{toys}} w^t \cdot \sum_{e=1}^{N_{events}} (\delta_i^t)_e
43 \]
44 \endhtmlonly
45 //! [SystematicTools_cov]
46  */
47 
48 //********************************************************************
49 SystematicsTools::SystematicsTools(){
50  //********************************************************************
51  errdebug=false;
52 
53  _softwareVersion="";
54 }
55 
56 //*********************************************************
57 void SystematicsTools::FillSystematicHistos(TTree* tree, const std::string& var, int nx, double* xbins, const std::string& cut, int NTOYS, const std::string& uopt,
58  TH2_h* h2, TH2_h* h1w){
59  //*********************************************************
60  if(errdebug) std::cout<<"FillSystematicHistos \n============================= "<<std::endl;
61 
62  /*
63  This function fills all necessary histos to compute the systematics:
64  - h2: toy_index vs var
65  - h1w: toy_index vs var, weighted by weight_syst
66  */
67 
68  (void)nx;
69  (void)xbins;
70  (void)NTOYS;
71  (void)uopt;
72 
73  std::string cut2=cut;
74  if (cut2=="") cut2="1==1";
75 
76  cut2 = weightTools::ApplyWeights(tree,cut2,uopt);
77 
78  // This is the weighted number of events for each toy experiment t and each bin i: N_i^t
79  // In the microtree: t=toy_index, and i is given by the histogram binning
80  tree->Project("h2",("toy_index:"+var).c_str(),("("+cut2+")").c_str());
81 
82  /* TODO. To review. In principle we should just compare the average of the toys with each of the toys (with the weights applied in both cases)
83  The cut cames already with the weights applied
84  if (uopt.find("SSYS")==std::string::npos && uopt.find("SYS")!=std::string::npos){
85  // Project the number of events weighted by systematic weights
86  cut2 = weightTools::ApplyWeights(tree,cut2,uopt);
87  tree->Project("h1w",("toy_index:"+var).c_str(),("("+cut2+")").c_str());
88  }
89  else{
90  */
91  // just copy h2 into h1w. TODO: since now h2 and h1w are the same thing we could probably get rid of one of them
92  for (int i=0;i<nx;i++)
93  for (int j=0;j<NTOYS;j++)
94  h1w->SetBinContent(i+1,j+1,h2->GetBinContent(i+1,j+1));
95  // }
96 }
97 
98 //*********************************************************
99 void SystematicsTools::UpdateSystematicCov(HistoStack* hs, TTree* tree, const std::string& var, int nx, double* xbins, const std::string& cut, int NTOYS, const std::string& uopt){
100  //*********************************************************
101 
102  /*
103  This method allows the use of several trees (in general using Experiment) for computing the systematic covariance. The results for each tree are updated inside a HistoStack.
104  */
105 
106  // Create 2Ds histo with the specified variable in the x axis and the toy experiment index in the y axis.
107  TH2_h h2("h2","h2",nx,xbins,NTOYS,0,NTOYS);
108  TH2_h h1w("h1w","h1w",nx,xbins,NTOYS,0,NTOYS);
109 
110  // Unused histos
111  TH2_h h1("h1","h1",nx,xbins,NTOYS,0,NTOYS);
112 
113  // Fill the histograms that are necessary to compute the systematics
114  FillSystematicHistos(tree,var,nx,xbins,cut,NTOYS,uopt,&h2,&h1w);
115 
116  // Add them to the HistoStack
117  hs->AddSystHistos(&h1,&h2,&h1w);
118 }
119 
120 //*********************************************************
121 const TMatrixD& SystematicsTools::GetSystematicCovBase(HistoStack* hs1, HistoStack* hs2, const std::string& uopt, const std::string& group){
122  //*********************************************************
123 
124  // 2D histos
125  TH2_h* h2, *h1w;
126 
127  // Compute the covariance matrix
128 
129  if (group!=""){
130  GetSystematicHistos(group,hs1, hs2,h2,h1w);
131  return GetSystematicCovBase(*h2,*h1w,uopt);
132  }
133 
134  std::vector<std::string> syst_groups = hs2->GetSystHistosGroups();
135  std::vector<std::string>::iterator it;
136  for (it=syst_groups.begin();it!=syst_groups.end();it++){
137  GetSystematicHistos(*it,hs1, hs2,h2,h1w);
138  const TMatrixD& C = GetSystematicCovBase(*h2,*h1w,uopt);
139  if (it==syst_groups.begin()){
140  int nx = h2->GetNbinsX();
141  _covTotal.ResizeTo(nx, nx);
142  _covTotal = C;
143  }
144  else
145  _covTotal = _covTotal + C;
146  }
147 
148  return _covTotal;
149 }
150 
151 //*********************************************************
152 void SystematicsTools::GetSystematicHistos(const std::string& group, HistoStack* hs1, HistoStack* hs2, TH2_h*& h2, TH2_h*& h1w){
153  //*********************************************************
154 
155  // Unused histos
156  TH2_h* h1;
157  // 2D histos
158  TH2_h* h2_1, *h1w_1;
159  TH2_h* h2_2, *h1w_2;
160 
161  if (!hs1){
162  hs2->GetSystHistos(group,h1,h2,h1w);
163  return;
164  }
165 
166  // Get the systematic histos from the stack
167  hs1->GetSystHistos(group,h1,h2_1,h1w_1);
168  hs2->GetSystHistos(group,h1,h2_2,h1w_2);
169 
170  TH2_h h2_1p(*h2_1);
171  TH2_h h1w_1p(*h1w_1);
172 
173  if (h2_2->GetNbinsY() > h2_1->GetNbinsY()){
174  h2_1p = TH2_h(*h2_2);
175  h1w_1p = TH2_h(*h1w_2);
176  for (Int_t i=0;i<h2_2->GetNbinsX();i++){
177  for (Int_t j=0;j<h2_2->GetNbinsY();j++){
178  h2_1p.SetBinContent(i+1,j+1,h2_1->GetBinContent(i+1,1));
179  h1w_1p.SetBinContent(i+1,j+1,h1w_1->GetBinContent(i+1,1));
180  }
181  }
182  }
183 
184 
185  // compute the ratio
186  h2 = new TH2_h(*h2_2);
187  h2->Divide(&h2_1p, h2_2);
188 
189  h1w = new TH2_h(*h1w_2);
190  h1w->Divide(&h1w_1p, h1w_2);
191 
192 }
193 
194 //*********************************************************
195 const TMatrixD& SystematicsTools::GetSystematicCov(HistoStack* hs, const std::string& uopt, const std::string& group){
196  //*********************************************************
197  if(errdebug) std::cout<<"GetSystematicCov \n============================= "<<std::endl;
198 
199 
200  if (uopt.find("DUMMY")!=std::string::npos){
201  _cov.ResizeTo(1, 1);
202  return _cov;
203  }
204 
205  /*
206  Compute the covariance matrix from the histos stored in the HistoStack
207  */
208 
209  // Compute the covariance matrix
210  return GetSystematicCovBase(NULL,hs,uopt,group);
211 }
212 
213 //*********************************************************
214 const TMatrixD& SystematicsTools::GetRatioSystematicCov(HistoStack* hs1, HistoStack* hs2, const std::string& uopt, const std::string& group){
215  //*********************************************************
216  if(errdebug) std::cout<<"GetSystematicCov \n============================= "<<std::endl;
217 
218  /*
219  Compute the covariance matrix from the histos stored in the HistoStack
220  */
221 
222  // Compute the covariance matrix
223  return GetSystematicCovBase(hs1,hs2,uopt+" RATIO",group);
224 
225 
226  // 2D histos
227  TH2_h* h1, * h2_1, *h1w_1;
228 
229  TH2_h* h2_2, *h1w_2;
230 
231  // Get the systematic histos from the stack
232  hs1->GetSystHistos("default",h1,h2_1,h1w_1);
233  hs2->GetSystHistos("default",h1,h2_2,h1w_2);
234 
235  TH2_h h2_1p(*h2_1);
236  TH2_h h1w_1p(*h1w_1);
237 
238  if (h2_2->GetNbinsY() > h2_1->GetNbinsY()){
239  h2_1p = TH2_h(*h2_2);
240  h1w_1p = TH2_h(*h1w_2);
241  for (Int_t i=0;i<h2_2->GetNbinsX();i++){
242  for (Int_t j=0;j<h2_2->GetNbinsY();j++){
243  h2_1p.SetBinContent(i+1,j+1,h2_1->GetBinContent(i+1,1));
244  h1w_1p.SetBinContent(i+1,j+1,h1w_1->GetBinContent(i+1,1));
245  }
246  }
247  }
248 
249 
250  // compute the ratio
251  TH2_h h2_ratio(*h2_2);
252  h2_ratio.Divide(&h2_1p, h2_2);
253 
254  TH2_h h1w_ratio(*h1w_2);
255  h1w_ratio.Divide(&h1w_1p, h1w_2);
256 
257  // Compute the covariance matrix
258  return GetSystematicCovBase(h2_ratio,h1w_ratio,uopt+" RATIO");
259 
260 }
261 
262 //*********************************************************
263 const TMatrixD& SystematicsTools::GetSystematicCov(TTree* tree, const std::string& var, int nx, double* xbins, const std::string& cut, int NTOYS, const std::string& uopt){
264  //*********************************************************
265  if(errdebug) std::cout<<"GetSystematicCov \n============================= "<<std::endl;
266 
267  /*
268  Compute the covariance matrix for a single tree
269 TODO: Use the method for HistoStack
270 */
271 
272 
273  // If the covariance has bin already computed for the same binning and cut just return it
274  if (CheckSystComputed(tree,NULL,var,nx,xbins,cut,"",1,NTOYS,uopt)){
275  return _cov;
276  }
277 
278  // Create 2Ds histo with the specified variable in the x axis and the toy experiment index in the y axis.
279  TH2_h h2("h2","h2",nx,xbins,NTOYS,0,NTOYS);
280  TH2_h h1w("h1w","h1w",nx,xbins,NTOYS,0,NTOYS);
281 
282  // Unused histos
283  TH2_h h1("h1","h1",nx,xbins,NTOYS,0,NTOYS);
284 
285  // Fill the histograms that are necessary to compute the systematics
286  FillSystematicHistos(tree,var,nx,xbins,cut,NTOYS,uopt,&h2,&h1w);
287 
288  // Compute the covariance matrix
289  return GetSystematicCovBase(h2,h1w, uopt);
290 }
291 
292 //*********************************************************
293 const TMatrixD& SystematicsTools::GetSystematicCovBase(TH2_h& h2,TH2_h& h1w,const std::string& uopt){
294  //*********************************************************
295  // Compute the covariance matrix from the 1D and 2D histograms
296  /*
297  Computes the standard (or variation) systematic covariance matrix for both the method with random throws and the method with binned PDF.
298  In fact the only difference between both is the number of toys (larger for throws) and the fact that for throws the weight is the same for all toys
299  while it is different for binned PDF
300  */
301 
302  int nx = h2.GetNbinsX();
303  int NTOYS = h2.GetNbinsY();
304  // int toy_ref=0; //TODO
305 
306  std::vector< std::vector<double> > na;
307  std::vector< std::vector<double> > wa;
308  std::vector<double> avg;
309 
310  std::vector<double> wpdf;
311  std::vector<double> na_tot;
312  std::vector<double> norm;
313  double avg_tot=0;
314 
315  na.resize(nx);
316  wa.resize(nx);
317  avg.resize(nx);
318 
319  na_tot.resize(NTOYS);
320  norm.resize(NTOYS);
321  wpdf.resize(NTOYS);
322 
323  for (int itoy=0;itoy<NTOYS;itoy++){
324  na_tot[itoy]=0;
325  norm[itoy]=1.;
326  wpdf[itoy]=1./NTOYS;
327  }
328 
329  for (int i=0;i<nx;i++){
330  avg[i]=0;
331  na[i].resize(NTOYS);
332  wa[i].resize(NTOYS);
333 
334  for (int itoy=0;itoy<NTOYS;itoy++){
335  // The reference toy must be skipped for new trees since there is an extra toy for the reference toy
336  // if (itoy == toy_ref && _softwareVersion!="") continue;
337  // this is the number of events with systematic applied in each bin and toy experiment (N_i^t)_w
338  na[i][itoy]=h1w.GetBinContent(i+1,itoy+1);
339  // This is the average number of events (with no systematic weights): N_avg_i = sum_t N_i^t*w^t
340  // for weight systematics, for each toy h2.GetBinContent is the same
341  // for variation system. it is different.
342  avg[i]+=h2.GetBinContent(i+1,itoy+1)*wpdf[itoy];
343  //for variation systematic wa=1
344  if (h2.GetBinContent(i+1,itoy+1)>0)
345  wa[i][itoy]=na[i][itoy]/h2.GetBinContent(i+1,itoy+1);
346  else
347  wa[i][itoy]=0;
348 
349  // Total number of events for this toy experiment
350  if (IsValidWeight(wa[i][itoy]))
351  na_tot[itoy]+=na[i][itoy];
352  }
353  // Average of the total number of events
354  avg_tot +=avg[i];
355  }
356 
357 
358  // compute normalization factor for shapeonly systematics
359  if (uopt.find("SHAPEONLY")!=std::string::npos){
360  for (int itoy=0;itoy<NTOYS;itoy++){
361  if (na_tot[itoy]!=0)
362  norm[itoy] = avg_tot/na_tot[itoy];
363  else
364  norm[itoy] = 0.;
365  }
366  }
367 
368  // Give the appropriate dimensions to the output cov matrix
369  _cov.ResizeTo(nx, nx);
370  for (int i=0;i<nx;i++){
371  for (int j=0;j<nx;j++){
372  _cov(i,j)=0;
373  for (int itoy=0;itoy<NTOYS;itoy++){
374  // The reference toy must be skipped for new trees since there is an extra toy for the reference toy
375  // if (itoy == toy_ref && _softwareVersion!="") continue;
376  if (!IsValidWeight(wa[i][itoy])) continue;
377  if (!IsValidWeight(wa[j][itoy])) continue;
378  if (na[i][itoy]< 0 || na[j][itoy]<0) continue;
379  _cov(i,j) += (norm[itoy]*na[i][itoy]- avg[i])*(norm[itoy]*na[j][itoy]- avg[j])*wpdf[itoy];
380  // std::cout<<itoy<<" wpdf "<<wpdf[itoy]<<std::endl;
381  //_cov(i,j) += (na[i][itoy]- avg[i])*(na[j][itoy]- avg[j])*wpdf[itoy];
382 
383  }
384 
385  // compute relative errors when requested
386  if (uopt.find("RELATIVE")!=std::string::npos){
387  if (avg[i]*avg[j]!=0 && ((avg[i]>1 && avg[j]>1) || uopt.find("RATIO")!=std::string::npos)){
388  _cov(i,j) /= (avg[i]*avg[j]);
389  }
390  else
391  _cov(i,j) = 0;
392  }
393  }
394  }
395 
396  return _cov;
397 }
398 
399 //*********************************************************
400 bool SystematicsTools::CheckSystComputed(TTree* tree1, TTree* tree2, const std::string& var, int nx, double* xbins, const std::string& cut1, const std::string& cut2, double norm, int NTOYS, const std::string& uopt){
401  //*********************************************************
402 
403  /*
404  Check whether systematics were already computed for this particular conditions
405  */
406 
407 
408  if (_syst_computed && _tree1_syst==tree1 && _tree2_syst==tree2 && _var_syst==var && _nbins_syst==nx && _cut_syst1==cut1 && _cut_syst2==cut2 && _norm_syst==norm && _NTOYS_syst==NTOYS && _uopt_syst == uopt){
409 
410  bool diff=false;
411  for (int i=0;i<=nx;i++){
412  if (xbins[i] != _xbins_syst[i]) diff=true;
413  }
414  if (!diff)
415  return true;
416  }
417 
418  _tree1_syst = tree1;
419  _tree2_syst = tree2;
420  _var_syst=var;
421  _nbins_syst=nx;
422  _cut_syst1=cut1;
423  _cut_syst2=cut2;
424  _norm_syst = norm;
425  _NTOYS_syst = NTOYS;
426  _uopt_syst=uopt;
427  _syst_computed=true;
428 
429  for (int i=0;i<=nx;i++){
430  _xbins_syst[i] = xbins[i];
431  }
432 
433  return false;
434 }
435 
436 
437 
438 //*********************************************************
439 bool SystematicsTools::TreeHasVar(TTree* tree, const std::string& var){
440  //*********************************************************
441 
442  if (tree->FindLeaf(var.c_str()))
443  return true;
444  else
445  return false;
446 }
447 
448 
449 //*********************************************************
450 int SystematicsTools::GetVarFromTree(TTree* tree, const std::string& var){
451  //*********************************************************
452 
453  if (!TreeHasVar(tree,var)) return 0;
454 
455  TH1F h0("v","v",1,0,1);
456  tree->Project("v","0.5",("(1==1)*"+var).c_str(),"",1);
457  return (int)(h0.GetBinContent(1));
458 }
459 
460 
461 //*********************************************************
462 std::string SystematicsTools::GetString(int code){
463  //*********************************************************
464 
465  std::stringstream scode;
466  scode << code;
467 
468  return scode.str();
469 }
470 
471 //*********************************************************
472 bool SystematicsTools::IsValidWeight(Double_t weight){
473  //*********************************************************
474 
475 
476  if (!TMath::Finite(weight)) return false;
477  if (weight!=weight) return false;
478  if (weight<0 || weight>10) return false;
479 
480  return true;
481 }
void UpdateSystematicCov(HistoStack *hs, TTree *tree, const std::string &var, int nx, double *xbins, const std::string &cut, int NTOYS, const std::string &uopt)
Update the histos necesary to compute the covariance matrix.
std::vector< std::string > GetSystHistosGroups() const
get the vector of groups of systemtic histos
Definition: HistoStack.hxx:97
void AddSystHistos(TH2_h *h1, TH2_h *h2, TH2_h *h1w)
Add histos for updating systematics when using several files.
Definition: HistoStack.cxx:391
void GetSystHistos(const std::string &group, TH2_h *&h1, TH2_h *&h2, TH2_h *&h1w)
Get Histos for updating systematics when using several files.
Definition: HistoStack.cxx:421