Angular analysis of B+->K*+(K+pi0)mumu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

759 lines
33 KiB

  1. //Renata Kopecna
  2. #include <fstream>
  3. #include <TChain.h>
  4. #include <TH1D.h>
  5. #include <TF1.h>
  6. #include <TCanvas.h>
  7. #include <TFile.h>
  8. #include <TMath.h>
  9. #include <TColor.h>
  10. #include <TLegend.h>
  11. #include <TStyle.h>
  12. #include <TLatex.h>
  13. #include <TROOT.h>
  14. #include <string>
  15. #include <vector>
  16. #include <iostream>
  17. #include <sstream>
  18. #include <iomanip>
  19. #include <RooDataSet.h>
  20. #include <RooGaussian.h>
  21. #include <RooFitResult.h>
  22. #include <RooPlot.h>
  23. #include <RooRealVar.h>
  24. #include "EvaluateToys.hh"
  25. #include <design.hh>
  26. #include <helpers.hh>
  27. #include "ScriptHelpers.hh"
  28. #include <math.h>
  29. //This code is as broken as it gets, the string for latex names and var names should be in a struct so when one has to skip stuff one can also skip the name and value actually
  30. //This way it is error prone and god knows whether it even saves everything properly
  31. //And it should've been connected directly with the csv file... like... no wonder some stuff took that long before
  32. const bool UnbinnedFit = true;
  33. const bool UseCellColor = true;
  34. Int_t Idx = 0;
  35. const UInt_t nPDFs = 2;
  36. struct pullInfo{
  37. double sigma;
  38. double sigmaErr;
  39. double mean;
  40. double meanErr;
  41. double failRate;
  42. pullInfo(){
  43. sigma = DEFAULT_TREE_VAL;
  44. sigmaErr = DEFAULT_TREE_ERR;
  45. mean = DEFAULT_TREE_VAL;
  46. meanErr = DEFAULT_TREE_ERR;
  47. failRate = DEFAULT_TREE_VAL;
  48. }
  49. pullInfo(double sig, double sigErr, double mu, double muErr, double rate){
  50. sigma = sig;
  51. sigmaErr = sigErr;
  52. mean = mu;
  53. meanErr = muErr;
  54. failRate = rate;
  55. }
  56. };
  57. struct q2Bins{
  58. unsigned int nBins;
  59. std::vector<double> q2min;
  60. std::vector<double> q2max;
  61. q2Bins(basic_params params){
  62. nBins = params.nBins;
  63. q2min = get_TheQ2binsmin(nBins, params.reference);
  64. q2max = get_TheQ2binsmax(nBins, params.reference);
  65. }
  66. };
  67. const std::vector<std::vector<double>> bkg_340 = {{47.0,57.0},{0.0,15.0},{-10.0,0.0},{-25.0,-10.0},{-5.0,5.0},{-5.0,3.0},{-48.0,-38.0}};
  68. //draw legend to the pull plots
  69. void drawLegend(TLatex * leg, double q2min, double q2max, pullInfo info,
  70. int tot_fits, int oor_fits, int failed_fits){
  71. std::ostringstream bindescription;
  72. //draw q2 bin
  73. bindescription << std::setprecision(2) << std::fixed << "( " << q2min << " < q^{2} < " << q2max << " )";
  74. spdlog::trace(bindescription.str());
  75. leg->DrawLatex(0.21,0.88, bindescription.str().c_str());
  76. //draw mean value
  77. std::ostringstream sMean;
  78. sMean << std::fixed << std::setprecision(4) << std::fixed << info.mean << " #pm " << info.meanErr;
  79. spdlog::trace(sMean.str());
  80. leg->DrawLatex(0.13,0.80, "#bf{mean:}");
  81. leg->DrawLatex(0.13,0.77, sMean.str().c_str());
  82. //draw sigma value
  83. std::ostringstream sRMS;
  84. sRMS << std::fixed << std::setprecision(4) << std::fixed << info.sigma << " #pm " << info.sigmaErr;
  85. spdlog::trace(sRMS.str());
  86. leg->DrawLatex(0.13,0.73, "#bf{sigma:}");
  87. leg->DrawLatex(0.13,0.69, sRMS.str().c_str());
  88. //draw percentage of results in histo range
  89. //
  90. //std::ostringstream sInRange;
  91. //sInRange << std::fixed << std::setprecision(1) << std::fixed << 100. * (tot_fits - oor_fits - failed_fits) / (tot_fits - failed_fits) << "% in range";
  92. //spdlog::trace(sInRange.str());
  93. //leg->DrawLatex(0.13,0.64, sInRange.str().c_str());
  94. //draw failRate
  95. std::ostringstream sfailRate;
  96. if(!UnbinnedFit){
  97. sfailRate << std::fixed << std::setprecision(1) << std::fixed << info.failRate << "% failed";
  98. spdlog::trace(sfailRate.str());
  99. leg->DrawLatex(0.13,0.59, sfailRate.str().c_str());
  100. }
  101. return;
  102. }
  103. //function to load toy fit results of one angular observables and create pull (or residual) plots for each q2 bin.
  104. //In this function the histogram is fitted using a single Gaussian bell shape. Either a standard binned fit or a RooFit unbinned fit
  105. //weirdShape is there for the cases the fitter generates stuff with different parameters than it fits, eg different polynomial bkg description
  106. std::vector<pullInfo> eval_toys(std::string filename, std::string treename, basic_params params,
  107. bool doPulls, double pullRange_low, double pullRange_high, int whichPDf){
  108. const q2Bins bins(params);
  109. //configure TPad style format and suppress pop-up windows from TCanvas:
  110. gROOT->SetBatch(kTRUE);
  111. gROOT->SetStyle("Plain");
  112. TPad foo;
  113. set_gStyle();
  114. gStyle->SetOptTitle(0);
  115. gStyle->SetTitleFont(132, "t");
  116. gStyle->SetTextFont(132);
  117. gStyle->SetEndErrorSize(10.0);
  118. gErrorIgnoreLevel = kWarning;
  119. RooMsgService::instance().setGlobalKillBelow(RooFit::ERROR);
  120. //start loading the values from the toy fit results root files:
  121. std::vector<unsigned int> tot_fits(bins.nBins, 0); //counter for total fits
  122. std::vector<unsigned int> oor_fits(bins.nBins, 0); //counter for fit results outside the histogram range (oor=out of range)
  123. std::vector<unsigned int> failed_fits(bins.nBins, 0); //counter for fits with non-300 fit result
  124. std::vector<double> max_value(bins.nBins, -10.);
  125. std::vector<double> min_value(bins.nBins, +10.);
  126. std::vector<double>all_Values[bins.nBins];
  127. //load chain with all results of bootstrapping
  128. TChain * ch = new TChain(treename.c_str());
  129. Int_t nFiles = 0;
  130. //when wildcard [0-9] is used, add all files and the digits of the counter until no files are found
  131. //[0-9] stands for any digit, i.e. the combination 'file_[0-9][0-9][0-9][0-9].root' would add all files from 'file_0000.root' to 'file_9999.root'
  132. if(filename.find("[0-9]") != std::string::npos){
  133. Int_t addedFiles = 1;
  134. while(addedFiles > 0){
  135. addedFiles = ch->Add(filename.c_str());
  136. //add another wildcard to the filename in order to search for files with job IDs in the next order of magnitude
  137. filename.replace(filename.find("[0-9]"), 5, "[0-9][0-9]");
  138. //Can someone explain to me why the fuck shoudl this be needed?
  139. //add the number of found files to the total number of files
  140. nFiles += addedFiles;
  141. }
  142. }
  143. else{ //if no wildcard '[0-9]' or the general wildcard '*' is used, simply add all files:
  144. nFiles = ch->Add(filename.c_str());
  145. }
  146. //check that at least one file with at least one entry is found:
  147. if(nFiles == 0){
  148. spdlog::error("No files found for name='"+filename+"'.");
  149. return {};
  150. }
  151. UInt_t nEntries = ch->GetEntries();
  152. if(nEntries == 0){
  153. spdlog::error("No entries found in files for tree='"+treename+"'.");
  154. return {};
  155. }
  156. //make sure that the number of entries is equivalent to the number of files times the number of q2 bins times the number of simultaneous PDFs
  157. if(TMath::Abs((int)(nEntries/(nPDFs*bins.nBins))) != TMath::Abs(nFiles)){
  158. spdlog::error("Number of entries found in files for tree='"+treename+"' does not match the number of files.");
  159. return {};
  160. }
  161. spdlog::info("[LOAD]\t\tReading {0:d} events from {1:d} files for variable='{2:s}'.", nEntries, nFiles, treename);
  162. //link variables to branches
  163. double startvalue= DEFAULT_TREE_VAL; //TODO: check the start_value of the parameter is not changed anywhere, as it isn't a const it is very likely it is changed
  164. double value = DEFAULT_TREE_VAL;
  165. double error = DEFAULT_TREE_ERR;
  166. double errorup = DEFAULT_TREE_ERR;
  167. double errordown = DEFAULT_TREE_ERR;
  168. int migrad = DEFAULT_TREE_INT;
  169. int cov = DEFAULT_TREE_INT;
  170. int bin = DEFAULT_TREE_INT;
  171. int pdf = DEFAULT_TREE_INT;
  172. ch->SetBranchStatus("*",1); //TODO optimize
  173. ch->SetBranchAddress("value", &value);
  174. ch->SetBranchAddress("start_value", &startvalue);
  175. ch->SetBranchAddress("error", &error);
  176. ch->SetBranchAddress("error_up", &errorup);
  177. ch->SetBranchAddress("error_down", &errordown);
  178. ch->SetBranchAddress("migrad", &migrad);
  179. ch->SetBranchAddress("status_cov", &cov);
  180. ch->SetBranchAddress("bin", &bin);
  181. ch->SetBranchAddress("pdf", &pdf);
  182. //create a new simple tree that used the calculated pull or residual value, in case that unbinned fit is selected
  183. //this tree is used as input to the RooFitter
  184. TTree * unbinnedTree = nullptr;
  185. double x; //this variable is used for either the pull or residual value (depending on arg 'doPulls')
  186. if(UnbinnedFit){
  187. unbinnedTree = new TTree("tmp_tree", "tmp_tree");
  188. unbinnedTree->Branch("value", &x);
  189. unbinnedTree->Branch("bin", &bin);
  190. }
  191. //or else create histograms for the binned fit:
  192. TH1D * h_pull[bins.nBins];
  193. TH1D * h_values[bins.nBins];
  194. double binwidth = doPulls ? 0.5 : 0.05;//0.05;
  195. double xrange = doPulls ? 2.0*pullRange_high : 1.0;//2.0;
  196. if(!UnbinnedFit){
  197. for(UInt_t b = 0; b < bins.nBins; b++){ //FUCK PEOPLE WHO DON'T DO BRACKETS
  198. h_pull[b] = new TH1D((treename+"_bin"+std::to_string(b)).c_str(),
  199. (treename+" in q^{2} bin #"+std::to_string(b)+(doPulls ? ";(x-x_{nomi.})/#sigma" : ";(x-x_{nomi.})")+";entries").c_str(),
  200. 2*xrange/binwidth, -xrange, +xrange);
  201. }
  202. }
  203. spdlog::debug("Finished initializing the histograms");
  204. //load results from files:
  205. for(UInt_t e = 0; e < nEntries; e++){
  206. //since all PDFs are saved in the TTree, only use 8(5) q2bins out of 32(10) for the KS0(pi0) channel
  207. //Eeee... e?
  208. //if(e%(bins.nBins*nPDFs) > (bins.nBins-1)) continue;
  209. ch->GetEntry(e);
  210. if(pdf != whichPDf) continue;
  211. spdlog::trace("Parameter value at entry {0:d}: {1:f}", e, value);
  212. all_Values[bin].push_back(value);
  213. tot_fits.at(bin)++;
  214. //require convered migrad
  215. if(migrad != 0){
  216. failed_fits.at(bin)++;
  217. continue;
  218. }
  219. //require fitresult = 300 or 100 (or 200)
  220. if(!(cov == 1 || cov == 3 || cov == 2)){
  221. failed_fits.at(bin)++;
  222. continue;
  223. }
  224. //derive residual and pull
  225. double diff = value - startvalue;
  226. if(error == 0. || isnan(error)){
  227. spdlog::error("[{0:s}][BIN{1:d}]{2:d}\tError equal to zero!", treename, bin, e);
  228. return {};
  229. }
  230. double pull = diff/error;
  231. spdlog::trace("[{0:s}][BIN{1:d}]{2:d}\tdiff={3:f}\tpull={4:f}\terr={5:f}", treename, bin, e, diff, pull, error);
  232. if(UnbinnedFit){
  233. //assign pull or residual to 'x' and save in TTree
  234. x = doPulls ? pull : diff; //x, pull and diff is never used? //TODO
  235. unbinnedTree->Fill();
  236. }
  237. else{//Binned fit
  238. if(TMath::Abs(diff) <= xrange){
  239. if(doPulls){
  240. //fill pull to histogram:
  241. h_pull[bin]->Fill(pull);
  242. //determine range of pull values
  243. max_value.at(bin) = std::max(max_value.at(bin),pull);
  244. min_value.at(bin) = std::min(min_value.at(bin),pull);
  245. }
  246. else{
  247. h_pull[bin]->Fill(diff);
  248. //determine range of diff values
  249. max_value.at(bin) = std::max(max_value.at(bin),diff);
  250. min_value.at(bin) = std::min(min_value.at(bin),diff);
  251. }
  252. }
  253. else{
  254. oor_fits.at(bin)++;
  255. }
  256. }
  257. }
  258. spdlog::debug("Filled all histograms/TTrees with values of variable="+treename+".");
  259. spdlog::debug("Tree size="+treename+".");
  260. //vectors to store the measured mean and widths of the pull(residual) distributions
  261. std::vector<pullInfo> allInfo;
  262. //init some nullptr RooFit objects, to make the compiler happy. (These two are needed later in the plotting of the histograms)
  263. RooGaussian * roogaus[bins.nBins];
  264. RooDataSet * roodata[bins.nBins];
  265. RooRealVar * roovalue[bins.nBins];
  266. for(UInt_t b = 0; b < bins.nBins; b++){ //loop over q2bins to fit all distributions
  267. if(UnbinnedFit){
  268. //initialise RooFit objects for the unbinned fit:
  269. RooRealVar * roomean, * roosigma, * roobin;
  270. roovalue[b] = new RooRealVar("value", "value", pullRange_low, pullRange_high, "");
  271. roomean = new RooRealVar("mean", "mean", bin_center(pullRange_low,pullRange_high), pullRange_low, pullRange_high);
  272. roosigma = new RooRealVar("sigma", "sigma", doPulls ? 0.85: 0.1, 0., 2.);
  273. roobin = new RooRealVar("bin", "q2 bin", -1., 10.0, "");
  274. RooArgSet rooarg = RooArgSet(*roovalue[b]);
  275. rooarg.add(*roobin);
  276. roogaus[b] = new RooGaussian("RooGaus", "RooGaus", *roovalue[b], *roomean, *roosigma);
  277. //RooFitResult * result = new RooFitResult("FitResult","FitResult");
  278. spdlog::debug("Start fitting q2 bin {0:d} for par={1:s}.", b, treename);
  279. roodata[b] = new RooDataSet("RooDataSet", "RooDataSet", unbinnedTree, rooarg,
  280. ("abs(bin-"+std::to_string(b)+") < 0.1").c_str());
  281. spdlog::debug("Fit {0:d} events", roodata[b]->numEntries());
  282. if(roodata[b]->numEntries() == 0){
  283. spdlog::critical("Empty fit not possible for var={0:s} in q2bin={1:d}", treename, b);
  284. assert(0);
  285. }
  286. int fitstatus = roogaus[b]->fitTo(*roodata[b], RooFit::Save(kTRUE),RooFit::PrintLevel(spdlog_trace()?1 : -1))->status();
  287. spdlog::debug("[{0:s}][BIN{1:d}]\tFitstatus={2:d}", treename, b, fitstatus);
  288. allInfo.push_back(pullInfo(roosigma->getVal(),roosigma->getError(),
  289. roomean->getVal(),roomean->getError(),fitstatus));
  290. }//end unbinned fit
  291. else{//binned fit
  292. double entries = h_pull[b]->Integral();
  293. bool dofit = entries > 10.0 && h_pull[b]->GetRMS(1) > 0.001;
  294. spdlog::debug("var={0:s}\t q2bin={1:d}\t DOFIT={2:s}", treename, b, (dofit ? "TRUE" : "FALSE"));
  295. if(entries < 0.0){
  296. spdlog::warn("Negative entries for: q2bin={0:d}\t par={1:s}\t entries={2:d}", b, treename, entries);
  297. }
  298. int fitstatus = 0.0;
  299. if(tot_fits.at(b) > 0) fitstatus = (100.0 * failed_fits.at(b) / tot_fits.at(b));
  300. if(dofit){
  301. double minfit = -xrange;
  302. double maxfit = +xrange;
  303. TF1 * fGauss = new TF1("theGaussian", "gaus(0)", minfit, maxfit);
  304. fGauss->SetParameter(0, entries);
  305. fGauss->SetParameter(1, h_pull[b]->GetXaxis()->GetBinCenter(h_pull[b]->GetMaximumBin()));
  306. if(!doPulls){
  307. double mean_range = (treename.find("P") != std::string::npos || treename == "Fl") ? 0.05 : 0.01;
  308. fGauss->SetParLimits(1, h_pull[b]->GetXaxis()->GetBinCenter(h_pull[b]->GetMaximumBin()) - mean_range, h_pull[b]->GetXaxis()->GetBinCenter(h_pull[b]->GetMaximumBin()) + mean_range);
  309. }
  310. fGauss->SetParameter(2, h_pull[b]->GetRMS(1));
  311. fGauss->SetParLimits(2, 0.0, doPulls ? 1.5 : 0.1);
  312. fGauss->SetLineStyle(kDashed);
  313. fGauss->SetLineColor(kMagenta - 3);
  314. h_pull[b]->Fit(fGauss, "RQM+");
  315. //save values in a vector
  316. allInfo.push_back(pullInfo(fGauss->GetParameter(2),fGauss->GetParError(2),
  317. fGauss->GetParameter(1),fGauss->GetParError(1),fitstatus));
  318. }
  319. else{//only use RMS and MEAN obtained by TH1F
  320. allInfo.push_back(pullInfo(h_pull[b]->GetRMS(1),h_pull[b]->GetRMSError(1),
  321. h_pull[b]->GetMean(1),h_pull[b]->GetMeanError(1),fitstatus));
  322. }
  323. }//end of binned fit
  324. }//end of loops of q2 bins
  325. //save histogram with pulls (or residuals) and the value distributions to file
  326. TCanvas* c1 = new TCanvas("c1", "c1", 1600, 1200);
  327. c1->cd()->SetMargin(0.1,0.05,0.1,0.05);
  328. for(UInt_t b = 0; b < bins.nBins; b++){ //loop over bins.nBins
  329. spdlog::debug("Plotting bin {0:b}.",b);
  330. c1->cd();
  331. if(UnbinnedFit){
  332. RooPlot * rooframe = roovalue[b]->frame();
  333. roodata[b]->plotOn(rooframe);
  334. roogaus[b]->plotOn(rooframe);
  335. rooframe->Draw();
  336. }
  337. else{
  338. h_pull[b]->Draw();
  339. }
  340. //initiliaze and format a legend:
  341. TLatex * leg = getPrettyTex(0.07,13);
  342. leg->SetTextColor(kBlack);
  343. //draw variable name
  344. leg->DrawLatex(0.13,0.89, treename.c_str());
  345. leg->SetTextSize(0.04);
  346. drawLegend(leg,bins.q2min.at(b) ,bins.q2max.at(b),
  347. allInfo[b],tot_fits[b],oor_fits[b],failed_fits[b]);
  348. c1->Print((get_ToyPullPlot_tag(b,treename,params,false,doPulls) +".eps").c_str(), "eps");
  349. if(!UnbinnedFit) delete h_pull[b];
  350. double max = *max_element(all_Values[b].begin(), all_Values[b].end());
  351. double min = *min_element(all_Values[b].begin(), all_Values[b].end());
  352. h_values[b] = new TH1D(treename.c_str(),
  353. (treename+" in q^{2} bin #"+std::to_string(b)+";"+treename+";Entries").c_str(),
  354. nFiles/5, min, max);
  355. for (auto val: all_Values[b]){
  356. h_values[b]->Fill(val);
  357. }
  358. //save histogram with values to file
  359. plotAndSave(h_values[b],treename,get_ToyPullPlot_tag(b,treename,params,true, false),"eps");
  360. }//end loop over q2 bins
  361. delete c1;
  362. return allInfo;
  363. }
  364. //print the results of the toy studies to latex tables:
  365. int print_latex_tables(bool Pprimes, bool doPulls, std::vector< std::string> LaTeXnames, std::vector< std::vector<pullInfo> > lePullInfo, const q2Bins bins, int jobID){
  366. if(lePullInfo.size() == 0){
  367. spdlog::error("No results found for widths of pull/residual distributrionn");
  368. return 1;
  369. }
  370. //generate color palette:
  371. TPad foo;
  372. TColor::InitializeColors();
  373. Double_t stops[9] = { 0.0000, 0.1250, 0.2500, 0.3750, 0.5000, 0.6250, 0.7500, 0.8750, 1.0000};
  374. Double_t red[9] = { 55./255., 55./255., 55./255., 55./255., 55./255., 105./255., 155./255., 205./255., 255./255.};
  375. Double_t green[9] = { 55./255., 105./255., 155./255., 205./255., 255./255., 205./255., 155./255., 105./255., 55./255.};
  376. Double_t blue[9] = { 255./255., 205./255., 155./255., 105./255., 55./255., 55./255., 55./255., 55./255., 55./255.};
  377. Idx = TColor::CreateGradientColorTable(9, stops, red, green, blue, 255);
  378. //in what range should the colors be defined:
  379. double colorrange[] = {doPulls ? 0.2 : (Pprimes ? 0.2 : 0.05),
  380. doPulls ? 0.2 : (Pprimes ? 0.2 : 0.05),
  381. UnbinnedFit ? 2. : 20.};
  382. std::vector<std::string> tabnames = {"width", "mean"};//, (UnbinnedFit ? "fitstatus" : "failRate")};
  383. clear_Latex_noteFile(latex_toyFile()+"_"+std::to_string(jobID)+std::string(doPulls?"":"_res")); //First make sure you don't append stuff
  384. std::ofstream myFile; //TODO: fix the latex name file
  385. open_Latex_noteFile(latex_toyFile()+"_"+std::to_string(jobID)+std::string(doPulls?"":"_res"), myFile); //open latex file
  386. for(unsigned int i = 0; i < tabnames.size(); i++){
  387. myFile << "\\begin{frame} \\footnotesize \\centering" << std::endl;
  388. myFile << "\\begin{tabular}{|l|";
  389. for(unsigned int b = 0; b < bins.nBins; b++) myFile << "p{2.2cm}";
  390. myFile << "|}\\hline" << std::endl;
  391. myFile << "\\textbf{" << tabnames[i] << "}";
  392. //for(unsigned int b = 0; b < bins.nBins; b++)myFile << "\t& " << b;
  393. for(unsigned int b = 0; b < bins.nBins; b++)myFile << std::setprecision(2) << std::fixed << "\t&[" << bins.q2min.at(b) << "--" << bins.q2max.at(b) << "]";
  394. myFile << "\\\\" << std::endl;
  395. myFile << "\\hline\\hline" << std::endl;
  396. //TABLE CONTENT:
  397. for(unsigned int v = 0; v < lePullInfo.size(); v++){
  398. if (lePullInfo.at(v).size()==0) continue;
  399. myFile << "$" << LaTeXnames.at(v) << "$ ";
  400. for(unsigned int b = 0; b < bins.nBins; b++){
  401. //get correct value for mean,sigma,failRate at q2bin and variable
  402. double levalue = 0.0;
  403. double leerror = 0.0;
  404. if(i == 0){
  405. levalue = lePullInfo.at(v)[b].sigma;
  406. leerror = lePullInfo.at(v)[b].sigmaErr;
  407. }
  408. else if(i == 1){
  409. levalue = lePullInfo.at(v)[b].mean;
  410. leerror = lePullInfo.at(v)[b].meanErr;
  411. }
  412. else{
  413. levalue = lePullInfo.at(v)[b].failRate; //TODO
  414. }
  415. myFile << "\t&";
  416. //generate cell background color accordingly to the value:
  417. if(UseCellColor){
  418. //TColor * colour = gROOT->GetColor(Idx + TMath::Min(254, (int) ((TMath::Abs((doPulls && i == 0 ? levalue - 1. : levalue))/2./colorrange[i]+0.5)*255.)));
  419. int coloridx = ((doPulls && i == 0 ? levalue - 1.0 : levalue)/colorrange[i])*127;
  420. if(coloridx < -127)coloridx = -127;
  421. if(coloridx > 127)coloridx = 127;
  422. TColor * colour = gROOT->GetColor(Idx + 127 + coloridx);
  423. if(colour==nullptr)spdlog::error("Color with idx={0:d} not found", Idx + 127 + coloridx);
  424. else{
  425. std::string leColour(colour->AsHexString());
  426. std::transform(leColour.begin(), leColour.end(),leColour.begin(), ::toupper);
  427. myFile << "\\cellcolor[HTML]{" << leColour.substr(1,6) << "} ";
  428. }
  429. }
  430. //draw cell content
  431. myFile << "$";
  432. if(levalue>=0.0)myFile << "\\phantom{-}";//align columns by adding an invisible minus sign
  433. myFile << std::setprecision(3) << std::fixed << levalue << " \\pm " << leerror << "$";
  434. }
  435. myFile << "\\\\" << std::endl;
  436. }
  437. //END OF TABLE CONTENT
  438. myFile << "\\hline" << std::endl;
  439. myFile << "\\end{tabular}" << std::endl << std::endl;
  440. myFile << "\\end{frame}" << std::endl;
  441. }
  442. myFile.close();
  443. return 0;
  444. }
  445. void save2rootFile( basic_params params, std::vector< std::string> treeNames, std::vector< std::string> LaTeXnames, std::vector< std::vector<pullInfo> > lePullInfo, const q2Bins bins){
  446. TFile * file = new TFile((get_ToyPullPlot_folder(params)+"pullResults.root").c_str(), "RECREATE");
  447. spdlog::debug("Opening "+std::string(file->GetPath()));
  448. file->cd();
  449. for(UInt_t t = 0; t < treeNames.size(); t++){
  450. if (lePullInfo[t].size()==0) continue;
  451. TTree * tree = new TTree(treeNames[t].c_str(), LaTeXnames[t].c_str());
  452. spdlog::debug("Saving tree "+ treeNames[t]);
  453. double mean = DEFAULT_TREE_VAL;
  454. double width = DEFAULT_TREE_ERR;
  455. tree->Branch("mean", &mean, "mean/D");
  456. tree->Branch("width", &width, "width/D");
  457. for(UInt_t b = 0; b < bins.nBins; b++){
  458. mean = lePullInfo[t][b].mean;
  459. width = lePullInfo[t][b].sigma;
  460. spdlog::debug("mean:\t{0:f}",mean);
  461. spdlog::debug("width:\t{0:f}",width);
  462. tree->Fill();
  463. }
  464. tree->Write();
  465. delete tree;
  466. }
  467. file->Close();
  468. delete file;
  469. }
  470. const std::vector<std::string>colorPallete =
  471. {"0d3c7b","2b6d97","499eb3","67cfcf","85ffeb","7ce9c8","72d2a5","69b282",
  472. "5FA55F",
  473. "84BC70", "A8D281","CCE892","F0FEA2","DABF7A","C47F51","AE4029","970000"};
  474. /*
  475. const std::vector<std::string>colorPallete =
  476. {"93006A","751778","562D86","374494","185AA2","2A6D92","3C8081","4E9370",
  477. "5FA55F",
  478. "84BC70", "A8D281","CCE892","F0FEA2","DABF7A","C47F51","AE4029","970000"};
  479. */
  480. /*
  481. const std::vector<std::string>colorPallete =
  482. {"0d3c7b","0e5d85","0e7d8e","0f9d97","0fbda0","0cae7b","089f56","049031",
  483. "00800B",
  484. "3B9714", "76ae1d","b1c526","EBDB2e","d9a523","c76e17","B5370c","A30000"};
  485. */
  486. const std::vector<double> colStops = {-1.000,-0.8750,-0.7500,-0.6250,-0.5000,-0.3750,-0.2500,-0.1250,
  487. 0.0000,
  488. 0.1250, 0.2500, 0.3750, 0.5000, 0.6250, 0.7500, 0.8750, 1.0000};
  489. std::string getCol(double val){
  490. int len = colStops.size();
  491. for (int i = 0; i < len; i++){
  492. if (colStops[i+1]>val) return colorPallete[i];
  493. }
  494. return colorPallete[len-1];
  495. }
  496. int save2texFileNew(std::vector< std::string> LaTeXnames, std::vector< std::vector<pullInfo> > lePullInfo, const q2Bins bins, int jobID){
  497. if(lePullInfo.size() == 0){
  498. spdlog::error("No results found for widths of pull/residual distributrionn");
  499. return 1;
  500. }
  501. std::vector<std::string> tabnames = {"width", "mean"};//, (UnbinnedFit ? "fitstatus" : "failRate")};
  502. clear_Latex_noteFile(latex_toyFile()+"_"+std::to_string(jobID)); //First make sure you don't append stuff
  503. std::ofstream myFile; //TODO: fix the latex name file
  504. open_Latex_noteFile(latex_toyFile()+"_"+std::to_string(jobID), myFile); //open latex file
  505. for(unsigned int i = 0; i < tabnames.size(); i++){
  506. myFile << "\\begin{frame} \\footnotesize \\centering" << std::endl;
  507. myFile << "\\begin{tabular}{|l|";
  508. for(unsigned int b = 0; b < bins.nBins; b++) myFile << "p{2.2cm}";
  509. myFile << "|}\\hline" << std::endl;
  510. myFile << "\\textbf{" << tabnames[i] << "}";
  511. //for(unsigned int b = 0; b < bins.nBins; b++)myFile << "\t& " << b;
  512. for(unsigned int b = 0; b < bins.nBins; b++)myFile << std::setprecision(2) << std::fixed << "\t&[" << bins.q2min.at(b) << "--" << bins.q2max.at(b) << "]";
  513. myFile << "\\\\" << std::endl;
  514. myFile << "\\hline\\hline" << std::endl;
  515. //TABLE CONTENT:
  516. for(unsigned int v = 0; v < lePullInfo.size(); v++){
  517. if (lePullInfo.at(v).size()==0) continue;
  518. myFile << "$" << LaTeXnames.at(v) << "$ ";
  519. for(unsigned int b = 0; b < bins.nBins; b++){
  520. //get correct value for mean,sigma,failRate at q2bin and variable
  521. double levalue = 0.0;
  522. double leerror = 0.0;
  523. if(i == 0){
  524. levalue = lePullInfo.at(v)[b].sigma;
  525. leerror = lePullInfo.at(v)[b].sigmaErr;
  526. }
  527. else if(i == 1){
  528. levalue = lePullInfo.at(v)[b].mean;
  529. leerror = lePullInfo.at(v)[b].meanErr;
  530. }
  531. else{
  532. levalue = lePullInfo.at(v)[b].failRate; //TODO
  533. }
  534. myFile << "\t&";
  535. //generate cell background color accordingly to the value:
  536. if(UseCellColor){
  537. if (i==0) myFile << "\\cellcolor[HTML]{" << getCol(levalue-1.0) << "} ";
  538. else myFile << "\\cellcolor[HTML]{" << getCol(levalue) << "} ";
  539. }
  540. //draw cell content
  541. myFile << "$";
  542. if(levalue>=0.0)myFile << "\\phantom{-}";//align columns by adding an invisible minus sign
  543. myFile << std::setprecision(3) << std::fixed << levalue << " \\pm " << leerror << "$";
  544. }
  545. myFile << "\\\\" << std::endl;
  546. }
  547. //END OF TABLE CONTENT
  548. myFile << "\\hline" << std::endl;
  549. myFile << "\\end{tabular}" << std::endl << std::endl;
  550. myFile << "\\end{frame}" << std::endl;
  551. }
  552. myFile.close();
  553. return 0;
  554. }
  555. //MAIN FUNCTION to run over all observables and q2bin.
  556. //the function calls the loading and fitting function 'eval_toys()'
  557. //then runs the print and save functions
  558. int EvaluateToyStudy(const std::vector<std::string> obs, const std::vector<std::string> obs_latex, basic_params params, bool UseFolds, bool doPulls, bool Pprimes, bool onlySig, bool onlyBkg){
  559. //define names of observables and which foldings are taken for which observable
  560. std::vector<UInt_t> folding_idx;
  561. if(Pprimes) folding_idx = {3, 3, 0, 0, 1, 2, 3, 4};
  562. else folding_idx = {3, 3, 1, 2, 0, 3, 4, 0};
  563. std::vector<int> weirdRangeJobs = {340, 343, 344, 349, 350, 353, 354, 355, 362, 379, 382, 497,558, 559, 560, 561, 562, 563}; //jobIDs with off pull ranges
  564. double lowRange = -5.0;
  565. double highRange = 5.0;
  566. std::vector<int> ctkRange = {497, 558, 559, 560, 561, 562, 563, 566, 567, 568, 569, 570, 571, 620, 621, 622, 623, 624, 625, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648};
  567. //configure the path and tags of the toy study result files
  568. std::string PPtag = Pprimes ? "_Pprimes" : "";
  569. std::string suffix = ""; //TODO
  570. makeFolder(get_ToyPullPlot_folder(params));
  571. const q2Bins bins(params);
  572. //using this status for error propagation
  573. std::vector< std::vector<pullInfo>> leInfo = {};
  574. for(UInt_t p = 0; p < obs.size(); p++){
  575. lowRange = -5.0; //Reset the ranges again in case
  576. highRange = 5.0;
  577. if(params.reference && ( isInVec(obs.at(p),ANG_OBS) || isInVec(obs.at(p),SWAVE))){
  578. lowRange = -1.0; //Reset the ranges again in case
  579. highRange = 1.0;
  580. }
  581. if(params.reference && params.folding>-1 && ( isInVec(obs.at(p),ANG_OBS) || isInVec(obs.at(p),SWAVE))){
  582. lowRange = -0.5; //Reset the ranges again in case
  583. highRange = 0.5;
  584. }
  585. if(params.reference && params.folding==4 && ( isInVec(obs.at(p),ANG_OBS) || isInVec(obs.at(p),SWAVE))){
  586. lowRange = -5.0; //TODO
  587. highRange = 5.0;
  588. }
  589. if(params.reference && params.folding>-1 && obs.at(p)=="FS"){
  590. lowRange = -0.25; //Reset the ranges again in case
  591. highRange = 0.25;
  592. }
  593. if(UseFolds)params.folding = folding_idx.at(p);
  594. //get a filename accordingly to the basic_params settings, then replace the number 1111 by the wildcard
  595. //and then replace the folder ToysFit by the subfolder created by condor
  596. std::string files = final_result_name_toys(1111, params.reference, params.nBins, true, params, params.Run, false, false, onlySig, onlyBkg, false, true);
  597. replace(files, "1111", "*"); //integer replaced by a string *
  598. replace(files, "ToysFit/", "ToysFit/"+std::to_string(params.jobID)+"/");
  599. spdlog::info("Read pdfs from file='"+files+"'");
  600. //Set the range for weird pulls in ctk
  601. if (isInVec(params.jobID, weirdRangeJobs) && p>7 && p<15){ //This is a dirty hack
  602. lowRange = -50.0;
  603. highRange = +50.0;
  604. }
  605. if ((params.jobID==503 || (params.jobID>=509 && params.jobID<=512)) && (p==11 || p ==12)){ //This is a dirty hack
  606. lowRange = -50.0;
  607. highRange = +50.0;
  608. }
  609. if ((params.jobID==551 && (p==1))){ //This is a dirty hack
  610. leInfo.push_back({});
  611. continue;
  612. }
  613. if ((params.jobID==551 && (p==3))){
  614. lowRange = -10.0;
  615. highRange = 0.0;
  616. }
  617. if (params.jobID==566 && (p==9)){ //This is a dirty hack
  618. leInfo.push_back({});
  619. continue;
  620. }
  621. if (params.jobID==567 && (p==9)){ //This is a dirty hack
  622. leInfo.push_back({});
  623. continue;
  624. }
  625. if (isInVec(params.jobID,ctkRange) && (p==8|| p==9)){
  626. lowRange = -5.0;
  627. highRange = 15.0;
  628. }
  629. if (isInVec(params.jobID,ctkRange) && params.jobID>619 && (obs.at(p)=="cbkgctk1")){
  630. leInfo.push_back({});
  631. continue; //TODO WTF
  632. lowRange = 10.0;
  633. highRange = 30.0;
  634. }
  635. if (isInVec(params.jobID,ctkRange) && params.jobID>619 && (obs.at(p)=="cbkgctk2")){
  636. leInfo.push_back({});
  637. continue;//TODO WTF
  638. lowRange = 20.0;
  639. highRange = 45.0;
  640. }
  641. if (params.jobID==571 && (p==9)){ //This is a dirty hack
  642. leInfo.push_back({});
  643. continue;
  644. }
  645. if (params.jobID>619 && (obs.at(p)=="cbkgctl2")){ //This is a dirty hack
  646. leInfo.push_back({});
  647. continue;//TODO, actually anythig below zero possible depending on the bin
  648. lowRange = -15.0;
  649. highRange = -5.0;
  650. }
  651. //if (params.jobID==637 && (obs.at(p)=="SS5")){ //This is a dirty hack
  652. // continue;
  653. //}
  654. if (params.jobID==630 && (p==9)){ //This is a dirty hack
  655. leInfo.push_back({});
  656. continue;
  657. }
  658. if (params.jobID==650 && (p==9)){
  659. leInfo.push_back({});
  660. continue;
  661. }
  662. //evalute the files for this observable and check the status
  663. leInfo.push_back(eval_toys(files, obs.at(p), params, doPulls, lowRange, highRange, 1));
  664. }
  665. if (doPulls){
  666. //print results to latex table into 'cout' and save to a root file
  667. if (params.reference) save2rootFile(params,obs, obs_latex,leInfo, bins); //This could be done for each value
  668. return save2texFileNew(obs_latex,leInfo,bins,params.jobID);
  669. }
  670. else return print_latex_tables(params.usePprime,false,obs_latex,leInfo, bins, params.jobID);
  671. }