ViewVC Help
View File | Revision Log | Show Annotations | Root Listing
root/cvsroot/UserCode/cbrown/AnalysisFramework/Plotting/Modules/GeneralToolBox.C
Revision: 1.28
Committed: Fri Aug 26 10:37:21 2011 UTC (13 years, 8 months ago) by buchmann
Content type: text/plain
Branch: MAIN
Changes since 1.27: +58 -0 lines
Log Message:
Added a neat little feature to have CBAF write the limit chart in TeX for us

File Contents

# User Rev Content
1 buchmann 1.1 #include <iostream>
2 fronga 1.17 #include <iomanip>
3 buchmann 1.1 #include <sstream>
4 buchmann 1.13 #include <fstream>
5 buchmann 1.1 #include <vector>
6     #include <stdio.h>
7     #include <stdlib.h>
8     #include <sys/types.h>
9     #include <sys/stat.h>
10 buchmann 1.15 #include <limits>
11 buchmann 1.1
12     #include <TFile.h>
13     #include <TTree.h>
14     #include <TCut.h>
15     #include <TLegend.h>
16     #include <TLatex.h>
17     #include <TText.h>
18     #include <TGraph.h>
19     #include <TH1.h>
20 buchmann 1.2 #include <TF1.h>
21 buchmann 1.1 #include <TMath.h>
22     #include <TStyle.h>
23     #include <TCanvas.h>
24     #include <TError.h>
25 buchmann 1.3 #include <TVirtualPad.h>
26 buchmann 1.1 #include <TGraphAsymmErrors.h>
27 buchmann 1.7 #include <TPaveText.h>
28 buchmann 1.1 #include <TRandom.h>
29     #ifndef Verbosity
30     #define Verbosity 0
31     #endif
32    
33     /*
34     #ifndef SampleClassLoaded
35     #include "SampleClass.C"
36     #endif
37     */
38     #define GeneralToolBoxLoaded
39    
40     using namespace std;
41    
42     bool dopng=false;
43     bool doC=false;
44     bool doeps=false;
45 buchmann 1.5 bool dopdf=false;
46 buchmann 1.1 string basedirectory="";
47 buchmann 1.26 float generaltoolboxlumi;
48 buchmann 1.1
49 buchmann 1.26 TLegend* make_legend(string title,float posx,float posy, bool drawleg);
50     TText* write_title(bool, string);
51 buchmann 1.1 TText* write_title_low(string title);
52    
53     TText* write_text(float xpos,float ypos,string title);
54     float computeRatioError(float a, float da, float b, float db);
55     float computeProductError(float a, float da, float b, float db);
56     TGraphAsymmErrors *histRatio(TH1F *h1,TH1F *h2, int id, vector<float>binning);
57     void setlumi(float l);
58 buchmann 1.26 void DrawPrelim(float writelumi);
59 buchmann 1.1 void CompleteSave(TCanvas *can, string filename, bool feedback);
60 buchmann 1.3 void CompleteSave(TVirtualPad *can, string filename, bool feedback);
61 buchmann 1.1 void write_warning(string funcname, string text);
62     void write_error(string funcname, string text);
63     void write_info(string funcname, string text);
64 buchmann 1.13 string get_directory();
65 buchmann 1.1 //-------------------------------------------------------------------------------------
66 buchmann 1.13
67 buchmann 1.15 template<typename U>
68     inline bool isanyinf(U value)
69     {
70     return !(value >= std::numeric_limits<U>::min() && value <=
71     std::numeric_limits<U>::max());
72     }
73 buchmann 1.13
74 buchmann 1.1 template<class A>
75     string any2string(const A& a){
76     ostringstream out;
77     out << a;
78     return out.str();
79     }
80    
81     void do_png(bool s) { dopng=s;}
82     void do_eps(bool s) { doeps=s;}
83     void do_C(bool s) { doC=s;}
84 buchmann 1.5 void do_pdf(bool s) { dopdf=s;}
85 buchmann 1.1
86     string topdir(string child) {
87     string tempdirectory=child;
88     if(tempdirectory.substr(tempdirectory.length()-1,1)=="/") tempdirectory=tempdirectory.substr(0,tempdirectory.length());
89     //we now have a directory without the trailing slash so we can just look for the last non-slash character :-)
90     for(int ichar=tempdirectory.length()-1;ichar>=0;ichar--) {
91     if(tempdirectory.substr(ichar,1)=="/") {
92     return tempdirectory.substr(0,ichar);
93     }
94     }
95     }
96    
97 buchmann 1.12 template < typename CHAR_TYPE,
98     typename TRAITS_TYPE = std::char_traits<CHAR_TYPE> >
99    
100     struct basic_teebuf : public std::basic_streambuf< CHAR_TYPE, TRAITS_TYPE >
101     {
102     typedef std::basic_streambuf< CHAR_TYPE, TRAITS_TYPE > streambuf_type ;
103     typedef typename TRAITS_TYPE::int_type int_type ;
104    
105     basic_teebuf( streambuf_type* buff_a, streambuf_type* buff_b )
106     : first(buff_a), second(buff_b) {}
107    
108     protected:
109     virtual int_type overflow( int_type c )
110     {
111     const int_type eof = TRAITS_TYPE::eof() ;
112     if( TRAITS_TYPE::eq_int_type( c, eof ) )
113     return TRAITS_TYPE::not_eof(c) ;
114     else
115     {
116     const CHAR_TYPE ch = TRAITS_TYPE::to_char_type(c) ;
117     if( TRAITS_TYPE::eq_int_type( first->sputc(ch), eof ) ||
118     TRAITS_TYPE::eq_int_type( second->sputc(ch), eof ) )
119     return eof ;
120     else return c ;
121     }
122     }
123    
124     virtual int sync()
125     { return !first->pubsync() && !second->pubsync() ? 0 : -1 ; }
126    
127     private:
128     streambuf_type* first ;
129     streambuf_type* second ;
130     };
131    
132     template < typename CHAR_TYPE,
133     typename TRAITS_TYPE = std::char_traits<CHAR_TYPE> >
134     struct basic_teestream : public std::basic_ostream< CHAR_TYPE, TRAITS_TYPE >
135     {
136     typedef std::basic_ostream< CHAR_TYPE, TRAITS_TYPE > stream_type ;
137     typedef basic_teebuf< CHAR_TYPE, TRAITS_TYPE > streambuff_type ;
138    
139     basic_teestream( stream_type& first, stream_type& second )
140     : stream_type( &stmbuf), stmbuf( first.rdbuf(), second.rdbuf() ) {}
141    
142     ~basic_teestream() { stmbuf.pubsync() ; }
143    
144     private: streambuff_type stmbuf ;
145     };
146    
147     typedef basic_teebuf<char> teebuf ;
148     typedef basic_teestream<char> teestream ;
149    
150 buchmann 1.13 std::ofstream file("LOG.txt",ios::app) ;
151 buchmann 1.28 std::ofstream texfile("Tex.txt") ;
152 buchmann 1.14 std::ofstream efile("LOGerr.txt",ios::app) ;
153 buchmann 1.13 teestream dout( file, std::cout ) ; // double out
154     teestream eout( efile, std::cout ) ; // double out (errors)
155 buchmann 1.12
156 buchmann 1.28 template < typename CHAR_TYPE,
157     typename TRAITS_TYPE = std::char_traits<CHAR_TYPE> >
158    
159     struct basic_tripbuf : public std::basic_streambuf< CHAR_TYPE, TRAITS_TYPE >
160     {
161     typedef std::basic_streambuf< CHAR_TYPE, TRAITS_TYPE > streambuf_type ;
162     typedef typename TRAITS_TYPE::int_type int_type ;
163    
164     basic_tripbuf( streambuf_type* buff_a, streambuf_type* buff_b, streambuf_type* buff_c )
165     : first(buff_a), second(buff_b), third(buff_c) {}
166    
167     protected:
168     virtual int_type overflow( int_type d )
169     {
170     const int_type eof = TRAITS_TYPE::eof() ;
171     if( TRAITS_TYPE::eq_int_type( d, eof ) )
172     return TRAITS_TYPE::not_eof(d) ;
173     else
174     {
175     const CHAR_TYPE ch = TRAITS_TYPE::to_char_type(d) ;
176     if( TRAITS_TYPE::eq_int_type( first->sputc(ch), eof ) ||
177     TRAITS_TYPE::eq_int_type( second->sputc(ch), eof )||
178     TRAITS_TYPE::eq_int_type( third->sputc(ch), eof ) )
179     return eof ;
180     else return d ;
181     }
182     }
183    
184     virtual int sync()
185     { return !first->pubsync() && !second->pubsync() && !third->pubsync() ? 0 : -1 ; }
186    
187     private:
188     streambuf_type* first ;
189     streambuf_type* second ;
190     streambuf_type* third ;
191     };
192    
193     template < typename CHAR_TYPE,
194     typename TRAITS_TYPE = std::char_traits<CHAR_TYPE> >
195     struct basic_tripstream : public std::basic_ostream< CHAR_TYPE, TRAITS_TYPE >
196     {
197     typedef std::basic_ostream< CHAR_TYPE, TRAITS_TYPE > stream_type ;
198     typedef basic_tripbuf< CHAR_TYPE, TRAITS_TYPE > streambuff_type ;
199    
200     basic_tripstream( stream_type& first, stream_type& second, stream_type& third )
201     : stream_type( &stmbuf), stmbuf( first.rdbuf(), second.rdbuf(), third.rdbuf() ) {}
202    
203     ~basic_tripstream() { stmbuf.pubsync() ; }
204    
205     private: streambuff_type stmbuf ;
206     };
207    
208     //typedef basic_tripbuf<char> teebuf ;
209     typedef basic_tripstream<char> tripplestream ;
210    
211     tripplestream tout( file, texfile , std::cout ) ; // tripple out
212    
213 buchmann 1.1 void ensure_directory_exists(string thisdirectory) {
214     struct stat st;
215     if(stat(thisdirectory.c_str(),&st) == 0) {
216 buchmann 1.13 if(Verbosity>0) dout << "Directory " << thisdirectory << " exists!" << endl;
217 buchmann 1.1 }
218     else {
219 buchmann 1.13 if(Verbosity>0) dout << "Directory " << thisdirectory << " does not exist. Need to create it!" << endl;
220 buchmann 1.1 ensure_directory_exists(topdir(thisdirectory));
221     if (mkdir(thisdirectory.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH))
222 buchmann 1.13 if(Verbosity>0) dout << "Created the directory " << thisdirectory << endl;
223 buchmann 1.1 }
224     }
225    
226 buchmann 1.13 void initialize_log() {
227 buchmann 1.14 dout << "____________________________________________________________" << endl;
228     dout << endl;
229 buchmann 1.13 dout << " " << endl;
230     dout << " JJJJJJJJJJJZZZZZZZZZZZZZZZZZZZBBBBBBBBBBBBBBBBB " << endl;
231     dout << " J:::::::::JZ:::::::::::::::::ZB::::::::::::::::B " << endl;
232     dout << " J:::::::::JZ:::::::::::::::::ZB::::::BBBBBB:::::B " << endl;
233     dout << " JJ:::::::JJZ:::ZZZZZZZZ:::::Z BB:::::B B:::::B" << endl;
234     dout << " J:::::J ZZZZZ Z:::::Z B::::B B:::::B" << endl;
235     dout << " J:::::J Z:::::Z B::::B B:::::B" << endl;
236     dout << " J:::::J Z:::::Z B::::BBBBBB:::::B " << endl;
237     dout << " J:::::j Z:::::Z B:::::::::::::BB " << endl;
238     dout << " J:::::J Z:::::Z B::::BBBBBB:::::B " << endl;
239     dout << "JJJJJJJ J:::::J Z:::::Z B::::B B:::::B" << endl;
240     dout << "J:::::J J:::::J Z:::::Z B::::B B:::::B" << endl;
241     dout << "J::::::J J::::::J ZZZ:::::Z ZZZZZ B::::B B:::::B" << endl;
242     dout << "J:::::::JJJ:::::::J Z::::::ZZZZZZZZ:::ZBB:::::BBBBBB::::::B" << endl;
243     dout << " JJ:::::::::::::JJ Z:::::::::::::::::ZB:::::::::::::::::B " << endl;
244     dout << " JJ:::::::::JJ Z:::::::::::::::::ZB::::::::::::::::B " << endl;
245     dout << " JJJJJJJJJ ZZZZZZZZZZZZZZZZZZZBBBBBBBBBBBBBBBBB " << endl;
246     dout << " " << endl;
247     dout << endl << endl;
248     dout << "____________________________________________________________" << endl;
249     time_t rawtime;
250     struct tm * timeinfo;
251     time ( &rawtime );
252     dout << " Analysis run on " << asctime (localtime ( &rawtime ));
253     dout << "____________________________________________________________" << endl;
254     dout << " Results saved in : " << get_directory() << endl << endl;
255     }
256    
257 buchmann 1.1 void set_directory(string basedir="") {
258     if(basedir.substr(0,1)=="/") basedir=basedir.substr(1,basedir.length()-1);
259     if(basedir.substr(basedir.length()-1,1)!="/") basedir+="/";
260     char currentpath[1024];
261     getcwd(currentpath,1024);
262 buchmann 1.20 basedirectory=(string)currentpath+"/Plots/"+basedir;
263 buchmann 1.1 ensure_directory_exists(basedirectory);
264 buchmann 1.13 initialize_log();
265 buchmann 1.1 }
266    
267 buchmann 1.6 string get_directory() {
268     return basedirectory;
269     }
270    
271 buchmann 1.1 string extract_directory(string savethis) {
272     bool foundslash=false;
273     int position=savethis.length();
274     while(!foundslash&&position>0) {
275     position--;
276     if(savethis.substr(position,1)=="/") foundslash=true;
277     }
278     if(position>0) return savethis.substr(0,position+1);
279     else return "";
280     }
281    
282 fronga 1.18 void CompleteSave(TCanvas *can, string filename, bool feedback=false, bool redraw=true) {
283 buchmann 1.3 //any change you make here should also be done below in the CompleteSave function for virtual pads
284 buchmann 1.1 Int_t currlevel=gErrorIgnoreLevel;
285     if(!feedback) gErrorIgnoreLevel=1001;
286 fronga 1.18 if(redraw) can->RedrawAxis();
287 buchmann 1.1 ensure_directory_exists(extract_directory(basedirectory+filename));
288     if(dopng) can->SaveAs((basedirectory+filename+".png").c_str());
289     if(doeps) can->SaveAs((basedirectory+filename+".eps").c_str());
290 buchmann 1.5 if(dopdf) can->SaveAs((basedirectory+filename+".pdf").c_str());
291 buchmann 1.1 if(doC) can->SaveAs((basedirectory+filename+".C").c_str());
292     gErrorIgnoreLevel=currlevel;
293 buchmann 1.13 dout << "Saved " << filename << " in all requested formats" << endl;
294 buchmann 1.1 }
295 buchmann 1.3
296 fronga 1.18 void CompleteSave(TVirtualPad *can, string filename, bool feedback=false, bool redraw=true) {
297 buchmann 1.3 Int_t currlevel=gErrorIgnoreLevel;
298     if(!feedback) gErrorIgnoreLevel=1001;
299 fronga 1.18 if(redraw) can->RedrawAxis();
300 buchmann 1.3 ensure_directory_exists(extract_directory(basedirectory+filename));
301     if(dopng) can->SaveAs((basedirectory+filename+".png").c_str());
302     if(doeps) can->SaveAs((basedirectory+filename+".eps").c_str());
303     if(doC) can->SaveAs((basedirectory+filename+".C").c_str());
304     gErrorIgnoreLevel=currlevel;
305 buchmann 1.13 dout << "Saved " << filename << " in all requested formats" << endl;
306 buchmann 1.3 }
307    
308 buchmann 1.1
309     void setlumi(float l) {
310 buchmann 1.24 generaltoolboxlumi=l;
311 buchmann 1.1 }
312    
313     int write_first_line(vector<vector<string> > &entries) {
314     if(entries.size()>0) {
315     vector<string> firstline = entries[0];
316     int ncolumns=firstline.size();
317     int ndividers=ncolumns+1;
318     int cellwidth=(int)(((float)(60-ndividers))/(ncolumns));
319 buchmann 1.13 dout << " |";
320 buchmann 1.1 for(int idiv=0;idiv<ncolumns;idiv++) {
321 buchmann 1.13 for(int isig=0;isig<cellwidth;isig++) dout << "-";
322     dout << "|";
323 buchmann 1.1 }
324 buchmann 1.13 dout << endl;
325 buchmann 1.1 return ncolumns;
326     } else {
327     return 0;
328     }
329     }
330    
331     void write_entry(string entry,int width,int iline=0,int ientry=0) {
332     int currwidth=entry.size();
333     while(currwidth<width) {
334     entry=" "+entry;
335     if(entry.size()<width) entry=entry+" ";
336     currwidth=entry.size();
337     }
338     bool do_special=false;
339 buchmann 1.13 if(iline==1&&ientry==1) { dout << "\033[1;32m" << entry << "\033[0m|";do_special=true;}//observed
340     if(iline==1&&ientry==2) { dout << "\033[1;34m" << entry << "\033[0m|";do_special=true;}//predicted (1)
341     if(iline==2&&ientry==1) { dout << "\033[1;34m" << entry << "\033[0m|";do_special=true;}//predicted (1)
342     if(iline==2&&ientry==2) { dout << "\033[1;34m" << entry << "\033[0m|";do_special=true;}//predicted (1)
343     if(!do_special) dout << entry << "|";
344 buchmann 1.1 }
345    
346     void make_nice_table(vector<vector <string> > &entries) {
347     int ncolumns=write_first_line(entries);
348     int cellwidth=(int)(((float)(60-(ncolumns+1)))/(ncolumns));
349     for(int iline=0;iline<entries.size();iline++) {
350     vector<string> currline = entries[iline];
351 buchmann 1.13 dout << " |";
352 buchmann 1.1 for(int ientry=0;ientry<currline.size();ientry++) {
353     write_entry(currline[ientry],cellwidth);
354     }
355 buchmann 1.13 dout << endl;
356 buchmann 1.1 if(iline==0) write_first_line(entries);
357     }
358     write_first_line(entries);
359     }
360    
361     void make_nice_jzb_table(vector<vector <string> > &entries) {
362     int ncolumns=write_first_line(entries);
363     int cellwidth=(int)(((float)(60-(ncolumns+1)))/(ncolumns));
364     for(int iline=0;iline<entries.size();iline++) {
365     vector<string> currline = entries[iline];
366 buchmann 1.13 dout << " |";
367 buchmann 1.1 for(int ientry=0;ientry<currline.size();ientry++) {
368     write_entry(currline[ientry],cellwidth,iline,ientry);
369     }
370 buchmann 1.13 dout << endl;
371 buchmann 1.1 if(iline==0) write_first_line(entries);
372     }
373     write_first_line(entries);
374     }
375    
376    
377     void write_warning(string funcname, string text) {
378 buchmann 1.13 eout << endl << endl;
379     eout << "\033[1;33m" << " _ " << endl;
380     eout << "\033[1;33m" << " (_) " << endl;
381     eout << "\033[1;33m" << "__ ____ _ _ __ _ __ _ _ __ __ _ " << endl;
382     eout << "\033[1;33m" << "\\ \\ /\\ / / _` | '__| '_ \\| | '_ \\ / _` |" << endl;
383     eout << "\033[1;33m" << " \\ V V / (_| | | | | | | | | | | (_| |" << endl;
384     eout << "\033[1;33m" << " \\_/\\_/ \\__,_|_| |_| |_|_|_| |_|\\__, |" << endl;
385     eout << "\033[1;33m" << " __/ |" << endl;
386     eout << "\033[1;33m" << " |___/ " << endl;
387     eout << endl;
388     eout << "\033[1;33m [" << funcname << "] " << text << " \033[0m" << endl;
389     eout << endl << endl;
390 buchmann 1.1 }
391     void write_error(string funcname, string text) {
392 buchmann 1.13 eout << endl << endl;
393     eout << "\033[1;31m ___ _ __ _ __ ___ _ __ " << endl;
394     eout << "\033[1;31m / _ \\ __| __/ _ \\| '__|" << endl;
395     eout << "\033[1;31m| __/ | | | | (_) | | " << endl;
396     eout << "\033[1;31m \\___|_| |_| \\___/|_| " << endl;
397     eout << endl;
398     eout << "\033[1;31m [" << funcname << "] " << text << " \033[0m" << endl;
399     eout << endl << endl;
400 buchmann 1.1 }
401    
402     void write_info(string funcname, string text) {
403 buchmann 1.13 dout << endl << endl;
404     dout << "\033[1;34m _____ __ " << endl;
405     dout << "\033[1;34m |_ _| / _| " << endl;
406     dout << "\033[1;34m | | _ __ | |_ ___ " << endl;
407     dout << "\033[1;34m | | | '_ \\| _/ _ \\ " << endl;
408     dout << "\033[1;34m _| |_| | | | || (_) | " << endl;
409     dout << "\033[1;34m |_____|_| |_|_| \\___/ " << endl;
410     dout << endl;
411     dout << "\033[1;34m [" << funcname << "] " << text << " \033[0m" << endl;
412     dout << endl << endl;
413 buchmann 1.1 }
414    
415     TText* write_text(float xpos,float ypos,string title)
416     {
417     TLatex* titlebox = new TLatex (xpos,ypos,title.c_str());
418     titlebox->SetNDC(true);
419     titlebox->SetTextFont(42);
420     titlebox->SetTextSize(0.04);
421     titlebox->SetTextAlign(21);
422     return titlebox;
423     }
424    
425     TText* write_title(string title)
426     {
427 buchmann 1.15 TText* titlebox = write_text(0.5,0.945,title);
428 buchmann 1.1 return titlebox;
429     }
430    
431 buchmann 1.7 TText* write_cut_on_canvas(string cut) {
432     // TLatex *normbox = new TLatex(0.96,0.5,cut.c_str());
433     TLatex *normbox = new TLatex(0.96,0.5,"");//currently deactivated
434     normbox->SetNDC(true);
435     normbox->SetTextFont(42);
436     normbox->SetTextSize(0.01);
437     normbox->SetTextAlign(21);
438     normbox->SetTextAngle(270);
439     return normbox;
440     }
441    
442 buchmann 1.1 TText* write_title_low(string title)
443     {
444     TText* titlebox = write_text(0.5,0.94,title);
445     return titlebox;
446     }
447    
448 buchmann 1.27 void DrawPrelim(float writelumi=generaltoolboxlumi,bool isMC=false) {
449 buchmann 1.26 string barn="pb";
450     if(writelumi>=1000)
451     {
452     writelumi/=1000;
453     barn="fb";
454     }
455    
456     stringstream prelimtext;
457     //prelimtext << "CMS Preliminary 2011 , #sqrt{s}= 7 TeV, L= O(1) fb^{-1}"; //temporary replacement
458 buchmann 1.27 if(isMC) prelimtext << "CMS MC simulation , #sqrt{s}= 7 TeV, L= " << std::setprecision(2) <<writelumi<<" "<<barn<<"^{-1}";
459     else prelimtext << "CMS Preliminary 2011 , #sqrt{s}= 7 TeV, L= " << std::setprecision(2) <<writelumi<<" "<<barn<<"^{-1}";
460 buchmann 1.26 TPaveText *eventSelectionPaveText = new TPaveText(0.27, 0.93,0.77, 1.0,"blNDC");
461     eventSelectionPaveText->SetFillStyle(4000);
462     eventSelectionPaveText->SetBorderSize(0.1);
463     eventSelectionPaveText->SetFillColor(kWhite);
464     eventSelectionPaveText->SetTextFont(42);
465     eventSelectionPaveText->SetTextSize(0.042);
466     eventSelectionPaveText->AddText(prelimtext.str().c_str());
467     eventSelectionPaveText->Draw();
468     }
469    
470 buchmann 1.27 void DrawMCPrelim(float writelumi=generaltoolboxlumi) {
471     DrawPrelim(writelumi,true);
472     }
473    
474 buchmann 1.26 TLegend* make_legend(string title="", float posx=0.6, float posy=0.55, bool drawleg=true)
475 buchmann 1.1 {
476     gStyle->SetTextFont(42);
477 buchmann 1.7 TLegend *leg = new TLegend(posx,posy,0.89,0.89);
478 buchmann 1.1 if(title!="") leg->SetHeader(title.c_str());
479     leg->SetTextFont(42);
480 fronga 1.17 leg->SetTextSize(0.04);
481 buchmann 1.1 leg->SetFillColor(kWhite);
482     leg->SetBorderSize(0);
483     leg->SetLineColor(kWhite);
484 buchmann 1.26 if(drawleg) DrawPrelim();
485 buchmann 1.1 return leg;
486     }
487    
488 buchmann 1.26 TLegend* make_legend(bool drawleg, string title) {
489     return make_legend(title,0.6,0.55,drawleg);
490     }
491    
492 buchmann 1.1 TGraph* make_nice_ratio(int nbins,float binning[],TH1F* histo)
493     {
494     float errorsquared[nbins];
495     float errors[nbins];
496     float bincontent[nbins];
497     for (int i=0;i<nbins;i++) {
498     errorsquared[i]=0;
499     bincontent[i]=0;
500     errors[i]=0;
501     }
502     float currlimit=binning[0];
503     int currtoplim=1;
504     for(int ibin=1;ibin<=histo->GetNbinsX();ibin++)
505     {
506     if(binning[currtoplim]<histo->GetBinCenter(ibin)) currtoplim++;
507 buchmann 1.13 dout << "Bin i=" << ibin << " with bin center " << histo->GetBinCenter(ibin) << " contains " << histo->GetBinContent(ibin) << " is within " << binning[currtoplim-1] << " and " << binning[currtoplim] << endl;
508 buchmann 1.1
509     }
510    
511     return 0;
512     }
513    
514     float statErrorN(float x){return x - 0.5*TMath::ChisquareQuantile(0.3173/2,2*x);}
515     float statErrorP(float x){return 0.5*TMath::ChisquareQuantile(1-0.3173/2,2*(x+1))-x;}
516     float lowLimit(float a, float x){return 0.5*TMath::ChisquareQuantile(a,2*x);}
517     float highLimit(float a,float x){return 0.5*TMath::ChisquareQuantile(1-a,2*(x+1));}
518    
519     float computeRatioError(float a, float da, float b, float db)
520     {
521     float val=0.;
522     float errorSquare = (a/b)*(a/b)*( (da/a)*(da/a) + (db/b)*(db/b));
523     val = TMath::Sqrt(errorSquare);
524     return val;
525    
526     }
527     float computeProductError(float a, float da, float b, float db)
528     {
529     float val=0.;
530     float errorSquare = (a*b)*(a*b)*( (da/a)*(da/a) + (db/b)*(db/b));
531     val = TMath::Sqrt(errorSquare);
532     return val;
533     }
534    
535 buchmann 1.23 TGraphAsymmErrors *histRatio(TH1F *h1,TH1F *h2, int id, vector<float>binning, bool precise=false)
536 buchmann 1.1 {
537     int absJZBbinsNumber = binning.size()-1;
538     TGraphAsymmErrors* graph = new TGraphAsymmErrors(absJZBbinsNumber);
539    
540     for(unsigned int i=0;i<absJZBbinsNumber;i++)
541     {
542     float xCenter=h1->GetBinCenter(i+1);
543     float xWidth=(h1->GetBinWidth(i+1))*0.5;
544     float nominatorError = h1->GetBinError(i+1);
545     float nominator=h1->GetBinContent(i+1);
546     float denominatorError=h2->GetBinError(i+1);
547     float denominator=h2->GetBinContent(i+1);
548     float errorN = 0;
549     float errorP = computeRatioError(nominator,nominatorError,denominator,denominatorError);
550     if(id==1) // (is data)
551     {
552 buchmann 1.23 if(!precise) errorP = computeRatioError(nominator,statErrorP(nominator),denominator,statErrorP(denominator));
553     else errorP = computeRatioError(nominator,nominatorError,denominator,denominatorError);
554 buchmann 1.1 errorN = errorP; // symmetrize using statErrorP
555     } else {
556     errorN = computeRatioError(nominator,nominatorError,denominator,denominatorError);
557 buchmann 1.23 errorP = errorN;
558 buchmann 1.1 }
559     if(denominator!=0) {
560     graph->SetPoint(i, xCenter, nominator/denominator);
561     graph->SetPointError(i,xWidth,xWidth,errorN,errorP);
562     }
563     else {
564     graph->SetPoint(i, xCenter, -999);
565     graph->SetPointError(i,xWidth,xWidth,errorN,errorP);
566     }
567     }
568     return graph;
569     }
570    
571     string print_range(float cent, float down, float up) {//note that up&down can be flipped, we don't care, but the central value needs to come 1st!
572     float uperr=0,downerr=0;
573     if(down>up&&down>cent) uperr=down-cent;
574     if(up>down&&up>cent) uperr=up-cent;
575     if(down<cent&&down<up) downerr=cent-down;
576     if(up<cent&&up<down) downerr=cent-up;
577     if(cent>up&&cent>down&&(up!=0&&down!=0)) write_error("print_range"," WATCH OUT: THE CENTRAL VALUE SEEMS TO BE LARGER THAN BOTH UP&DOWN!");
578     if(cent<up&&cent<down&&(up!=0&&down!=0)) write_error("print_range"," WATCH OUT: THE CENTRAL VALUE SEEMS TO BE SMALLER THAN BOTH UP&DOWN!");
579     stringstream result;
580     result << cent << " + " << uperr << " - " << downerr;
581     return result.str();
582     }
583    
584     void bubbleSort ( int arr [ ], int size, int order [ ]) // nice way to sort an array (called arr) which is currently in a random order (indices in (order")
585     {
586     int last = size - 2;
587     int isChanged = 1;
588    
589     while ( last >= 0 && isChanged )
590     {
591     isChanged = 0;
592     for ( int k = 0; k <= last; k++ )
593     if ( arr[k] > arr[k+1] )
594     {
595     swap ( arr[k], arr[k+1] );
596     isChanged = 1;
597     int bkp=order[k];
598     order[k]=order[k+1];
599     order[k+1]=bkp;
600     }
601     last--;
602     }
603     }
604    
605     void swapvec(vector<float> &vec,int j, int k) {
606     float bkp=vec[j];
607     vec[j]=vec[k];
608     vec[k]=bkp;
609     }
610    
611     void bubbleSort ( vector<float> &arr , vector<int> &order) // nice way to sort an array (called arr) which is currently in a random order (indices in (order")
612     {
613     int last = arr.size() - 2;
614     int isChanged = 1;
615    
616     while ( last >= 0 && isChanged )
617     {
618     isChanged = 0;
619     for ( int k = 0; k <= last; k++ )
620     if ( arr[k] > arr[k+1] )
621     {
622     swapvec (arr,k,k+1);
623     isChanged = 1;
624     int bkp=order[k];
625     order[k]=order[k+1];
626     order[k+1]=bkp;
627     }
628     last--;
629     }
630     }
631    
632     int numerichistoname=0;
633 buchmann 1.16 bool givingnumber=false;
634 buchmann 1.1 string GetNumericHistoName() {
635 buchmann 1.16 while(givingnumber) sleep(1);
636     givingnumber=true;
637 buchmann 1.1 stringstream b;
638     b << "h_" << numerichistoname;
639     numerichistoname++;
640 buchmann 1.16 givingnumber=false;
641 buchmann 1.1 return b.str();
642     }
643    
644     //********************** BELOW : CUT INTERPRETATION **************************//
645     void splitupcut(string incut, vector<string> &partvector)
646     {
647     //idea: go thru the string called incut; if a parantheses is opened, then the cut cannot be split up until the parantheses is closed.
648     //ok anyway screw the parantheses.
649     int paranthesis_open=0;
650     int substr_start=0;
651     string currchar="";
652     for (int ichar=0;ichar<incut.length();ichar++)
653     {
654     currchar=incut.substr(ichar,1);
655     // if(currchar=="(") paranthesis_open++;
656     // if(currchar==")") paranthesis_open--;
657     if(currchar=="&"&&incut.substr(ichar+1,1)=="&"&&paranthesis_open==0) {
658     partvector.push_back(incut.substr(substr_start,ichar-substr_start));
659     substr_start=ichar+2;
660     }
661     }
662     partvector.push_back(incut.substr(substr_start,incut.length()-substr_start));
663     if(Verbosity>1) {
664 buchmann 1.13 dout << "[ splitupcut() ] : The cut vector now contains the following elements: "<< endl;
665 buchmann 1.1 for (int ipart=0;ipart<partvector.size();ipart++)
666     {
667 buchmann 1.13 dout << " - " << partvector[ipart] << endl;
668 buchmann 1.1 }
669     }
670     }
671    
672     int atleastvalue(string expression, int &morethanlessthan) // takes in an expression such as ">2" or ">=3" and returns e.g. 3 (in both examples)
673     {
674     int retval=0;
675     if(expression.substr(0,1)==">"&&expression.substr(1,1)=="=") {
676 buchmann 1.13 // dout << "The expression " << expression << " is saying that we have at least " << atoi(expression.substr(2,1).c_str()) << " jets" << endl;
677 buchmann 1.1 morethanlessthan=1;
678     return atoi(expression.substr(2,1).c_str());
679     }
680     if(expression.substr(0,1)=="="&&expression.substr(1,1)=="=") {
681 buchmann 1.13 // dout << "The expression " << expression << " is saying that we have at least " << atoi(expression.substr(1,1).c_str())+1 << " jets" << endl;
682 buchmann 1.1 morethanlessthan=0;
683     return atoi(expression.substr(1,1).c_str());
684     }
685     if(expression.substr(0,1)=="<"&&expression.substr(1,1)=="=") {
686 buchmann 1.13 // dout << "The expression " << expression << " is saying that we have at least " << atoi(expression.substr(1,1).c_str())+1 << " jets" << endl;
687 buchmann 1.1 morethanlessthan=-1;
688     return 1+atoi(expression.substr(1,1).c_str());
689     }
690     if(expression.substr(0,1)==">") {
691 buchmann 1.13 // dout << "The expression " << expression << " is saying that we have at least " << atoi(expression.substr(2,1).c_str()) << " jets" << endl;
692 buchmann 1.1 morethanlessthan=1;
693     return 1+atoi(expression.substr(2,1).c_str());
694     }
695     if(expression.substr(0,1)=="<"&&expression.substr(1,1)=="=") {
696 buchmann 1.13 // dout << "The expression " << expression << " is saying that we have at least " << atoi(expression.substr(2,1).c_str()) << " jets" << endl;
697 buchmann 1.1 morethanlessthan=-1;
698     return 1+atoi(expression.substr(2,1).c_str());
699     }
700     }
701    
702     int do_jet_cut(string incut, int *nJets) {
703     string expression=(incut.substr(12,incut.size()-12));
704 buchmann 1.13 dout << "Going to analyze the jet cut : " << expression << " with 0,1 being " << expression.substr(0,1) << " and 1,1 being " << expression.substr(1,1) << endl;
705 buchmann 1.1 if(expression.substr(0,1)=="<"&&expression.substr(1,1)=="=") {
706     int nJet=atoi(expression.substr(2,1).c_str());
707     for(int i=nJet+1;i<20;i++) nJets[i]=0;
708 buchmann 1.13 dout << "Is of type <=" << endl;
709 buchmann 1.1 return 0;
710     }
711     if(expression.substr(0,1)=="="&&expression.substr(1,1)=="=") {
712     int nJet=atoi(expression.substr(2,1).c_str());
713     for(int i=0;i<20&&i!=nJet;i++) nJets[i]=0;
714 buchmann 1.13 dout << "Is of type ==" << endl;
715 buchmann 1.1 return 0;
716     }
717     if(expression.substr(0,1)==">"&&expression.substr(1,1)=="=") {
718     int nJet=atoi(expression.substr(2,1).c_str());
719     for(int i=0;i<nJet&&i!=nJet;i++) nJets[i]=0;
720 buchmann 1.13 dout << "Is of type >=" << endl;
721 buchmann 1.1 return 0;
722     }
723     if(expression.substr(0,1)=="<") {
724     int nJet=atoi(expression.substr(1,1).c_str());
725     for(int i=nJet;i<20;i++) nJets[i]=0;
726 buchmann 1.13 dout << "Is of type <" << endl;
727 buchmann 1.1 return 0;
728     }
729     if(expression.substr(0,1)==">") {
730     int nJet=atoi(expression.substr(1,1).c_str());
731     for(int i=0;i<nJet+1&&i!=nJet;i++) nJets[i]=0;
732 buchmann 1.13 dout << "Is of type >" << endl;
733 buchmann 1.1 return 0;
734     }
735     }
736    
737     string interpret_cut(string incut, bool &isJetCut, int *permittednJets)
738     {
739     // isJetCut=false;nJets=-1;
740     if(incut=="()") return "";
741     while(incut.substr(0,1)=="(") incut=incut.substr(1,incut.length()-1);
742     while(incut.length()>0&&incut.substr(incut.length()-1,1)==")") incut=incut.substr(0,incut.length()-1);
743     // if(incut.substr(0,1)=="("&&incut.substr(incut.length()-1,1)==")") incut=incut.substr(1,incut.length()-2); //this is to make (cut) to cut.
744    
745     if(Verbosity>0) {
746 buchmann 1.13 dout << "Now interpreting cut " << incut << endl;
747 buchmann 1.1 }
748     /*
749     if(incut=="ch1*ch2<0") return "OS";
750     if(incut=="id1==id2") return "SF";
751     if(incut=="id1!=id2") return "OF";
752     */
753     if(incut=="ch1*ch2<0") return "";
754 buchmann 1.5 if(incut=="(mll>55&&mll<70)||(mll>112&&mll<160)") return "SB";
755     if(incut=="(mll>61&&mll<70)||(mll>112&&mll<190)") return "SB'";
756 buchmann 1.1 if(incut=="id1==id2") return "";
757     if(incut=="id1!=id2") return "";
758     if(incut=="mll>2") return "";
759    
760     if(incut=="mll>0") return ""; // my typical "fake cut"
761    
762     if(incut=="passed_triggers||!is_data") return "Triggers";
763     if(incut=="pfjzb[0]>-998") return "";
764    
765    
766     if(incut=="id1==0") return "ee";
767     if(incut=="id1==1") return "#mu#mu";
768     if(incut=="abs(mll-91.2)<20") return "|m_{l^{+}l^{-}}-m_{Z}|<20";
769     if(incut=="pfJetGoodID[0]") return "";
770     if(incut=="pfJetGoodID[1]") return "";
771     if((int)incut.find("pfJetGoodNum")>-1) {
772     //do_jet_cut(incut,permittednJets);
773     stringstream result;
774     result << "nJets" << incut.substr(12,incut.size()-12);
775 buchmann 1.13 /* dout << "Dealing with a jet cut: " << incut << endl;
776 buchmann 1.1 stringstream result;
777     result << "nJets" << incut.substr(12,incut.size()-12);
778     isJetCut=true;
779     if(exactjetcut(incut,nJets))
780     // nJets=atleastvalue((incut.substr(12,incut.size()-12)),morethanlessthan);
781     return result.str();*/
782     return result.str();
783     }
784     return incut;
785     }
786    
787     string interpret_nJet_range(int *nJets) {
788 buchmann 1.13 for (int i=0;i<20;i++) dout << i << " : " << nJets[i] << endl;
789 buchmann 1.1 return "hello";
790     }
791    
792     string interpret_cuts(vector<string> &cutparts)
793     {
794     stringstream nicecut;
795     int nJets;
796     bool isJetCut;
797     int finalJetCut=-1;
798     int permittednJets[20];
799     for(int ijet=0;ijet<20;ijet++) permittednJets[ijet]=1;
800     int morethanlessthan=0;//-1: less than, 0: exactly, 1: more than
801     for(int icut=0;icut<cutparts.size();icut++)
802     {
803     if(icut==0) nicecut<<interpret_cut(cutparts[icut],isJetCut,permittednJets);
804     else {
805     string nice_this_cut = interpret_cut(cutparts[icut],isJetCut,permittednJets);//blublu
806     if(nice_this_cut.length()>0&&nicecut.str().length()>0) {
807     if(!isJetCut) nicecut<<"&&"<<nice_this_cut;
808     else {
809     if(nJets>finalJetCut) finalJetCut=nJets;
810     }
811     }
812     if(nice_this_cut.length()>0&&nicecut.str().length()==0) {
813     if(!isJetCut) {
814     nicecut<<nice_this_cut;
815     }
816     else {
817     if(nJets>finalJetCut) finalJetCut=nJets;
818     }
819     }
820     }
821     }
822     if(finalJetCut>-1) {
823     if(nicecut.str().length()==0) {
824     nicecut << "nJets#geq" << finalJetCut;
825     }
826     else
827     {
828     nicecut << "&&nJets#geq " << finalJetCut;
829     }
830     }
831    
832 buchmann 1.13 // dout << "The nJet allowed range is given by: " << interpret_nJet_range(permittednJets) << endl;
833 buchmann 1.1
834     return nicecut.str();
835     }
836    
837     string decipher_cut(TCut originalcut,TCut ignorethispart)
838     {
839     string incut=(const char*)originalcut;
840     string ignore=(const char*)ignorethispart;
841    
842     if(ignore.length()>0 && incut.find(ignore)!=string::npos) incut=incut.replace(incut.find(ignore),ignore.length(),"");
843    
844     vector<string>cutparts;
845     splitupcut(incut,cutparts);
846     string write_cut=interpret_cuts(cutparts);
847     return write_cut;
848     }
849    
850     //********************** ABOVE : CUT INTERPRETATION **************************//
851 buchmann 1.2
852     Double_t GausRandom(Double_t mu, Double_t sigma) {
853     return gRandom->Gaus(mu,sigma);// real deal
854     //return mu;//debugging : no smearing.
855     }
856    
857 buchmann 1.3 int functionalhistocounter=0;
858 buchmann 1.2 TH1F * makehistofromfunction(TF1 *f1,TH1F *model) {
859     TH1F *histo = (TH1F*)model->Clone();
860 buchmann 1.3 functionalhistocounter++;
861     stringstream histoname;
862     histoname << "histo_based_on_function_" << f1->GetName() << "__"<<functionalhistocounter;
863     histo->SetTitle(histoname.str().c_str());
864     histo->SetName(histoname.str().c_str());
865 buchmann 1.2 int nbins=histo->GetNbinsX();
866     float low=histo->GetBinLowEdge(1);
867     float hi=histo->GetBinLowEdge(histo->GetNbinsX())+histo->GetBinWidth(histo->GetNbinsX());
868    
869     for(int i=0;i<=nbins;i++) {
870 buchmann 1.4 histo->SetBinContent(i,(f1->Integral(histo->GetBinLowEdge(i),histo->GetBinLowEdge(i)+histo->GetBinWidth(i)))/histo->GetBinWidth(i));
871     histo->SetBinError(i,TMath::Sqrt(histo->GetBinContent(i)));
872 buchmann 1.2 }
873    
874     return histo;
875 buchmann 1.4 }
876    
877     float hintegral(TH1 *histo, float low, float high) {
878     float sum=0;
879     for(int i=1;i<histo->GetNbinsX();i++) {
880     if((histo->GetBinLowEdge(i)>=low)&&(histo->GetBinLowEdge(i)+histo->GetBinWidth(i))<=high) sum+=histo->GetBinContent(i);
881     //now on to the less clear cases!
882     if(histo->GetBinLowEdge(i)<low&&(histo->GetBinLowEdge(i)+histo->GetBinWidth(i))>low) {
883     //need to consider this case still ... the bin is kind of in range but not sooooo much.
884     }
885     if(histo->GetBinLowEdge(i)<high&&(histo->GetBinLowEdge(i)+histo->GetBinWidth(i))>high) {
886     //need to consider this case still ... the bin is kind of in range but not sooooo much.
887     }
888    
889     }
890     return sum;
891 buchmann 1.5 }
892    
893 buchmann 1.6 string newjzbexpression(string oldexpression,float shift) {
894     stringstream ss;
895     if(shift>0) ss<<"("<<oldexpression<<"+"<<shift<<")";
896     if(shift<0) ss<<"("<<oldexpression<<shift<<")";
897     if(shift==0) ss<<oldexpression;
898     return ss.str();
899     }
900    
901 buchmann 1.11 double Round(double num, unsigned int dig)
902     {
903     num *= pow(10, dig);
904     if (num >= 0)
905     num = floor(num + 0.5);
906     else
907     num = ceil(num - 0.5);
908     num/= pow(10, dig);
909     return num;
910 buchmann 1.16 }
911    
912     // The two functions below are for distributed processing
913    
914     int get_job_number(float ipoint, float Npoints,float Njobs) {
915     float pointposition=(ipoint/Npoints);
916     int njob=floor(pointposition*Njobs);
917     if(njob>=Njobs) njob--;
918     // cout << "Looking at point " << ipoint << " out of " << Npoints << " which is at position " << pointposition << " corresponding to " << pointposition*Njobs << " --> JOB " << njob << endl;
919     return njob;
920     }
921    
922    
923     bool do_this_point(int ipoint, int Npoints, int jobnumber, int Njobs) {
924     if(get_job_number(ipoint,Npoints,Njobs)==jobnumber) return true;
925     return false;
926     }
927 buchmann 1.19
928     Double_t DoIntegral(TH1F *histo, Int_t binx1, Int_t binx2, Int_t biny1, Int_t biny2, Int_t binz1, Int_t binz2, Double_t & error ,
929     Option_t *option, Bool_t doError)
930     {
931     // internal function compute integral and optionally the error between the limits
932     // specified by the bin number values working for all histograms (1D, 2D and 3D)
933    
934     Int_t nbinsx = histo->GetNbinsX();
935     if (binx1 < 0) binx1 = 0;
936     if (binx2 > nbinsx+1 || binx2 < binx1) binx2 = nbinsx+1;
937     if (histo->GetDimension() > 1) {
938     Int_t nbinsy = histo->GetNbinsY();
939     if (biny1 < 0) biny1 = 0;
940     if (biny2 > nbinsy+1 || biny2 < biny1) biny2 = nbinsy+1;
941     } else {
942     biny1 = 0; biny2 = 0;
943     }
944     if (histo->GetDimension() > 2) {
945     Int_t nbinsz = histo->GetNbinsZ();
946     if (binz1 < 0) binz1 = 0;
947     if (binz2 > nbinsz+1 || binz2 < binz1) binz2 = nbinsz+1;
948     } else {
949     binz1 = 0; binz2 = 0;
950     }
951    
952     // - Loop on bins in specified range
953     TString opt = option;
954     opt.ToLower();
955     Bool_t width = kFALSE;
956     if (opt.Contains("width")) width = kTRUE;
957    
958    
959     Double_t dx = 1.;
960     Double_t dy = 1.;
961     Double_t dz = 1.;
962     Double_t integral = 0;
963     Double_t igerr2 = 0;
964     for (Int_t binx = binx1; binx <= binx2; ++binx) {
965     if (width) dx = histo->GetXaxis()->GetBinWidth(binx);
966     for (Int_t biny = biny1; biny <= biny2; ++biny) {
967     if (width) dy = histo->GetYaxis()->GetBinWidth(biny);
968     for (Int_t binz = binz1; binz <= binz2; ++binz) {
969     if (width) dz = histo->GetZaxis()->GetBinWidth(binz);
970     Int_t bin = histo->GetBin(binx, biny, binz);
971     if (width) integral += histo->GetBinContent(bin)*dx*dy*dz;
972     else integral += histo->GetBinContent(bin);
973     if (doError) {
974     if (width) igerr2 += histo->GetBinError(bin)*histo->GetBinError(bin)*dx*dx*dy*dy*dz*dz;
975     else igerr2 += histo->GetBinError(bin)*histo->GetBinError(bin);
976     }
977     }
978     }
979     }
980    
981     if (doError) error = TMath::Sqrt(igerr2);
982     return integral;
983     }
984    
985     Double_t IntegralAndError(TH1F *histo, Int_t binx1, Int_t binx2, Double_t & error, Option_t *option)
986     {
987     //Return integral of bin contents in range [binx1,binx2] and its error
988     // By default the integral is computed as the sum of bin contents in the range.
989     // if option "width" is specified, the integral is the sum of
990     // the bin contents multiplied by the bin width in x.
991     // the error is computed using error propagation from the bin errors assumming that
992     // all the bins are uncorrelated
993     return DoIntegral(histo,binx1,binx2,0,-1,0,-1,error,option,kTRUE);
994 buchmann 1.21 }
995    
996     void print_usage() {
997     cout << "Some distributed model calculations call Create_All_Plots.exec with the argument \"1\" to calculate some basic quantities, such as the peak position in MC and data, observed and predicted, and so on. If you want to test this, you can just run this program with argument 1 yourself :-) " << endl;
998 buchmann 1.22 }
999    
1000    
1001     string format_number( int value )
1002     {
1003     if( value == 0 ) return "00";
1004     if( value < 10 ) return "0"+any2string(value);
1005     return any2string(value);
1006     }
1007    
1008     string seconds_to_time(int seconds) {
1009     const static unsigned int SECONDS_IN_AN_HOUR = 3600;
1010     const static unsigned int SECONDS_IN_A_MINUTE = 60;
1011     stringstream answer;
1012     if( seconds > 0 )
1013     {
1014     answer << format_number( (unsigned int)(seconds / SECONDS_IN_AN_HOUR) ) << ":";
1015     answer << format_number( (unsigned int)((seconds % SECONDS_IN_AN_HOUR) / SECONDS_IN_A_MINUTE) ) << ":";
1016     answer << format_number( (unsigned int)((seconds % SECONDS_IN_AN_HOUR) % (SECONDS_IN_A_MINUTE)) );
1017     }
1018     else
1019     {
1020     answer << "00:00:00";
1021     }
1022     return answer.str();
1023     }
1024