3 * @author Christian Holm Christensen <cholm@nbi.dk>
4 * @date Thu Nov 17 12:08:04 2011
6 * @brief Class to plot QA trends
8 * @ingroup pwglf_forward_qa_scripts
15 # include <TGraphErrors.h>
16 # include <TGraphAsymmErrors.h>
17 # include <TMultiGraph.h>
30 class TGraphAsymmErrors;
41 * Class to plot QA trends
43 * @ingroup pwglf_forward_qa_scripts
45 struct QAPlotter : public QABase
50 struct Ring : public QARing
57 * @param useVar Use variance for errors (not min/max)
59 Ring(UShort_t d, Char_t r, Bool_t useVar=false)
73 fGChi2 = new TGraphAsymmErrors;
74 fGC = new TGraphAsymmErrors;
75 fGDelta = new TGraphAsymmErrors;
76 fGXi = new TGraphAsymmErrors;
77 fGSigma = new TGraphAsymmErrors;
79 fGSingles = new TGraph;
82 fGOccupancy = new TGraphAsymmErrors;
84 SetAtt(fGChi2, "chi2", "#LT#chi^{2}/#nu#GT");
85 SetAtt(fGC, "c", "Constant");
86 SetAtt(fGDelta, "delta", "#LT#Delta_{p}#GT");
87 SetAtt(fGXi, "xi", "#LT#xi#GT");
88 SetAtt(fGSigma, "sigma", "#LT#sigma#GT");
89 SetAtt(fGLow, "low", "# of low statistics bins");
90 SetAtt(fGSingles, "singles", "Fraction of single hits");
91 SetAtt(fGLoss, "loss", "Data lossed due to cuts");
92 SetAtt(fGOccupancy, "occupancy","#LTOccupancy#GT");
93 SetAtt(fGBeta, "beta", "Correlation of methods");
97 * Static member function to get the ring color
99 * @param d Detector number
100 * @param r Ring identifer
104 static Color_t RingColor(UShort_t d, Char_t r)
106 return ((d == 1 ? kRed : (d == 2 ? kGreen : kBlue))
107 + ((r == 'I' || r == 'i') ? 2 : -3));
110 * Set graph attributes
113 * @param name Name of graph
115 void SetAtt(TGraph* g, const char* name, const char* /*title=""*/)
117 Color_t c = RingColor(fD, fR);
118 g->SetName(Form("FMD%d%c_%s", fD, fR, name));
119 // g->SetTitle(Form("FMD%d%c %s", fD, fR,
120 // !title || title[0] == '\0' ? name : title));
121 Int_t marker = 20+(fD-1) + (fR == 'I' ? 0 : 4);
122 g->SetTitle(Form("FMD%d%c", fD, fR));
125 g->SetMarkerColor(c);
126 g->SetMarkerStyle(marker);
129 case 20: g->SetMarkerSize(1.2); break;
130 case 21: g->SetMarkerSize(1.2); break;
131 case 22: g->SetMarkerSize(1.3); break;
132 case 26: g->SetMarkerSize(1.1); break;
136 * Update a graph from a RingQuantity
138 * @param g Graph to update
140 * @param runNo Run number
142 void UpdateGraph(TGraphAsymmErrors* g, RingQuantity& q,
143 UInt_t runNo, UInt_t /* n */)
146 Double_t el = y-q.min;
147 Double_t eh = q.max-y;
149 //Info("UpdateGraph", "Setting errors on %s to variance",g->GetName());
153 if (TMath::Abs(y) < 1e-6) return;
155 g->SetPoint(i, runNo, y);
156 g->SetPointError(i, 0, 0, el, eh);
161 * @param n Entry number (not used)
162 * @param runNo Run number
164 * @return true on success
166 Bool_t Update(UInt_t n, UInt_t runNo)
168 UpdateGraph(fGChi2, *fChi2, runNo, n);
169 UpdateGraph(fGC, *fC, runNo, n);
170 UpdateGraph(fGDelta, *fDelta, runNo, n);
171 UpdateGraph(fGXi, *fXi, runNo, n);
172 UpdateGraph(fGSigma, *fSigma, runNo, n);
173 UpdateGraph(fGOccupancy, *fOccupancy, runNo, n);
175 fGLow->SetPoint(n, runNo, fFitStatus->nLow);
177 if (fMerge->one > 1e-6)
178 fGSingles->SetPoint(fGSingles->GetN(), runNo, fMerge->one);
179 if (fCorrelation->beta > 1e-6)
180 fGBeta->SetPoint(fGBeta->GetN(), runNo, fCorrelation->beta);
181 if (-fDataLoss->full > 1e-6)
182 fGLoss->SetPoint(fGLoss->GetN(), runNo, -fDataLoss->full);
185 TGraphAsymmErrors* fGChi2; // Graph of ELoss reduced chi-square
186 TGraphAsymmErrors* fGC; // Graph of ELoss constant
187 TGraphAsymmErrors* fGDelta; // Graph of ELoss MPV
188 TGraphAsymmErrors* fGXi; // Graph of ELoss Landau width
189 TGraphAsymmErrors* fGSigma; // Graph of ELoss Gaus width
190 TGraph* fGLow; // Graph of bins with low statistics
191 TGraph* fGSingles; // Graph of fraction of singles
192 TGraph* fGLoss; // Graph of 'lost' data
193 TGraph* fGBeta; // Graph of Poisson vs ELoss correlation
194 TGraphAsymmErrors* fGOccupancy;// Graph of mean occupancy
195 Bool_t fUseVar; // Use variance
197 // =================================================================
199 * Compatiblity constructor
201 * @param prodYear Year
202 * @param prodLetter Letter
203 * @param useVar Use variance
205 QAPlotter(Long_t prodYear, Char_t prodLetter, Bool_t useVar)
206 : QABase("", (prodYear < 2000 ? 2000 : 0) + prodYear,
207 Form("LHC%02d%c", int(prodYear % 100), prodLetter), "pass0"),
212 Info("QAPlotter", "Do we use variance? %s", fUseVar ? "yes" : "no");
213 fFMD1i = new Ring(1, 'I', useVar);
214 fFMD2i = new Ring(2, 'I', useVar);
215 fFMD2o = new Ring(2, 'O', useVar);
216 fFMD3i = new Ring(3, 'I', useVar);
217 fFMD3o = new Ring(3, 'O', useVar);
218 fNAccepted = new TGraph;
219 fNAccepted->SetName("nAccepted");
220 fNAccepted->SetMarkerStyle(20);
221 fNAccepted->SetLineWidth(2);
223 fVz = new TGraphErrors;
225 fVz->SetMarkerStyle(20);
226 fVz->SetLineWidth(2);
231 QAPlotter(const TString& dataType,
233 const TString& period,
236 : QABase(dataType, year, period, pass),
241 Info("QAPlotter", "Do we use variance? %s", fUseVar ? "yes" : "no");
242 fFMD1i = new Ring(1, 'I', useVar);
243 fFMD2i = new Ring(2, 'I', useVar);
244 fFMD2o = new Ring(2, 'O', useVar);
245 fFMD3i = new Ring(3, 'I', useVar);
246 fFMD3o = new Ring(3, 'O', useVar);
247 fNAccepted = new TGraph;
248 fNAccepted->SetName("nAccepted");
249 fNAccepted->SetMarkerStyle(20);
250 fNAccepted->SetLineWidth(2);
252 fVz = new TGraphErrors;
254 fVz->SetMarkerStyle(20);
255 fVz->SetLineWidth(2);
258 * Add a file to be processed
260 * @param filename Name of file
262 void AddFile(const char* filename)
264 fFiles.Add(new TObjString(filename));
266 const char* GetUserInfo(TList* l, const char* name, const char* def) const
269 Warning("GetUserInfo", "No user information list");
273 TObject* o = l->FindObject(name);
275 Warning("GetUserInfo", "User information %s not found", name);
280 Info("GetUserInfo", "Got user information %s=%s", name, o->GetTitle());
281 return o->GetTitle();
286 * @param read If true, read from file
288 * @return True on success
290 Bool_t MakeTree(bool read)
292 if (fFiles.GetEntriesFast() <= 0) return QABase::MakeTree(read);
293 if (fFiles.GetEntriesFast() == 1 && read) {
294 TFile* file = TFile::Open(fFiles.At(0)->GetName(), "READ");
296 fTree = static_cast<TTree*>(file->Get("T"));
300 TChain* chain = new TChain("T", "T");
301 if (!chain->AddFileInfoList(&fFiles)) return false;
316 Error("Run", "No input tree");
322 UInt_t nEntries = fTree->GetEntries();
325 Info("Run", "Got %d runs", nEntries);
326 TList* l = fTree->GetUserInfo();
327 fPeriod = GetUserInfo(l, "period", "?");
328 fPass = GetUserInfo(l, "pass", "?");
329 fDataType = GetUserInfo(l, "type", "?");
332 for (UInt_t i = 0; i < nEntries; i++) {
335 UInt_t run = fGlobal->runNo;
336 UInt_t nev = fGlobal->nAccepted;
338 fFirst = TMath::Min(run, fFirst);
339 fLast = TMath::Max(run, fLast);
342 Info("Run", "Got run %d with %d accepted events", run, nev);
343 fNAccepted->SetPoint(i, run, nev);
344 fVz->SetPoint(i, run, fGlobal->meanVz);
345 fVz->SetPointError(i, 0, fGlobal->sigmaVz);
347 if (nev <= 100) continue;
348 static_cast<Ring*>(fFMD1i)->Update(j, run);
349 static_cast<Ring*>(fFMD2i)->Update(j, run);
350 static_cast<Ring*>(fFMD2o)->Update(j, run);
351 static_cast<Ring*>(fFMD3i)->Update(j, run);
352 static_cast<Ring*>(fFMD3o)->Update(j, run);
364 // fTeXName = Form("trend_%09d_%09d", fFirst, fLast);
366 if (!fPeriod.IsNull() && !fPass.IsNull())
367 title.Form("QA trends for %s/%s runs %d --- %d",
368 fPeriod.Data(), fPass.Data(), fFirst, fLast);
370 title.Form("QA trends for runs %d --- %d", fFirst, fLast);
373 CanvasTitle("# of accepted events");
374 fNAccepted->Draw("apl");
375 PutCanvasTitle("# of accepted events");
376 AddRuns(fNAccepted->GetHistogram(), "# of accepted events");
378 TLine* l = new TLine(fFirst, 100, fLast, 100);
379 l->SetLineColor(kRed+2);
382 PrintCanvas("nAccepted");
384 CanvasTitle("#LTv_{z}#GT");
386 PutCanvasTitle("Mean z coordinate of interaction point");
387 AddRuns(fVz->GetHistogram(), "#LTv_{z}#GT");
390 TMultiGraph* chi2 = new TMultiGraph;
391 TMultiGraph* c = new TMultiGraph;
392 TMultiGraph* delta = new TMultiGraph;
393 TMultiGraph* xi = new TMultiGraph;
394 TMultiGraph* sigma = new TMultiGraph;
395 TMultiGraph* low = new TMultiGraph;
396 TMultiGraph* singles = new TMultiGraph;
397 TMultiGraph* loss = new TMultiGraph;
398 TMultiGraph* occ = new TMultiGraph;
399 TMultiGraph* beta = new TMultiGraph;
400 chi2 ->SetName("chi2");
402 delta ->SetName("delta");
404 sigma ->SetName("sigma");
405 low ->SetName("low");
406 singles ->SetName("singles");
407 loss ->SetName("loss");
408 beta ->SetName("beta");
409 occ ->SetName("occupancy");
412 AddToMulti(fFMD1i,chi2, c, delta, xi, sigma, low, singles, loss, beta, occ);
413 AddToMulti(fFMD2i,chi2, c, delta, xi, sigma, low, singles, loss, beta, occ);
414 AddToMulti(fFMD2o,chi2, c, delta, xi, sigma, low, singles, loss, beta, occ);
415 AddToMulti(fFMD3i,chi2, c, delta, xi, sigma, low, singles, loss, beta, occ);
416 AddToMulti(fFMD3o,chi2, c, delta, xi, sigma, low, singles, loss, beta, occ);
418 PlotMulti(chi2, "#LT#chi^{2}/#nu#GT from #Delta fits", true);
419 PlotMulti(c, "#LTc#GT from #Delta fits");
420 PlotMulti(delta, "#LT#Delta_{p}#GT from #Delta fits");
421 PlotMulti(xi, "#LT#xi#GT from #Delta fits");
422 PlotMulti(sigma, "#LT#sigma#GT from #Delta fits");
423 PlotMulti(low, "Bins with too low statistics");
424 PlotMulti(singles, "Fraction of single hits");
425 PlotMulti(loss, "% of hits 'lost' due to merging+cuts");
426 PlotMulti(occ, "#LTOccupancy#GT [%]", true);
427 PlotMulti(beta, "Correlation of methods");
441 std::ofstream doc(".doc");
442 doc << fPeriod << " " << fPass << " ("
443 << fDataType << ")" << std::endl;
446 Close(false); // Do not delete PNGs
449 * Add graphs from a ring to the multi graphs
452 * @param chi2 ELoss reduced chi-square
453 * @param c ELoss constant
454 * @param delta ELoss MPV
455 * @param xi ELoss Landau width
456 * @param sigma ELoss Gaus width
457 * @param low bins with low statistics
458 * @param singles fraction of singles
459 * @param loss 'lost' data
460 * @param beta Poisson vs ELoss correlation
461 * @param occupancy mean occupancy
463 void AddToMulti(QARing* qr,
470 TMultiGraph* singles,
473 TMultiGraph* occupancy)
475 Ring* r = static_cast<Ring*>(qr);
476 chi2 ->Add(r->fGChi2);
478 delta ->Add(r->fGDelta);
480 sigma ->Add(r->fGSigma);
482 singles ->Add(r->fGSingles);
483 loss ->Add(r->fGLoss);
484 occupancy ->Add(r->fGOccupancy);
485 beta ->Add(r->fGBeta);
490 * @param mg Multi graph
492 * @param logy If true, make @f$\log@f$ scale
494 void PlotMulti(TMultiGraph* mg, const char* title, Bool_t logy=false)
497 // fCanvas->SetBottomMargin(.15);
498 fCanvas->SetLeftMargin(.08);
499 fCanvas->SetTopMargin(.1);
500 fCanvas->SetLogy(logy);
501 // fCanvas->SetRightMargin(.2);
504 TH1* h = mg->GetHistogram();
505 Double_t max = h->GetMaximum();
506 Double_t min = h->GetMinimum();
507 if (h->GetMinimum() == 0) {
508 min = min - .1*(max-min);
511 Int_t x1 = h->GetXaxis()->GetXmin();
512 Int_t x2 = h->GetXaxis()->GetXmax();
514 TLegend* l = new TLegend(.1, .91, .97, .95);
520 TIter next(mg->GetListOfGraphs());
521 mg->GetListOfGraphs();
524 // Get the runs we have here
525 TArrayI runs(fRuns.GetSize());
528 while ((g = static_cast<TGraph*>(next()))) {
529 l->AddEntry(g, g->GetTitle(), "lp");
530 Double_t* xs = g->GetX();
532 for (Int_t i = 0; i < n; i++) {
533 if (FindRun(runs, Int_t(xs[i])) >= 0) continue;
534 runs.SetAt(xs[i], j++);
536 Double_t ymean = g->GetMean(2);
537 Double_t xh = x2 - .03 * Double_t(x2-x1);
538 TLine* lm = new TLine(x1, ymean, xh, ymean);
539 lm->SetLineColor(g->GetLineColor());
543 TLatex* al = new TLatex(xh, ymean, g->GetTitle());
544 al->SetTextColor(g->GetLineColor());
546 al->SetTextSize(.02);
547 al->SetTextAlign(12);
554 AddRuns(h, title, &runs, &areas);
556 PrintCanvas(mg->GetName(), &areas);
561 * @param runs List of runs
562 * @param run Run to find
564 * @return Index of run in run list
566 Int_t FindRun(const TArrayI& runs, Int_t run)
568 std::sort(&(runs.fArray[0]), &(runs.fArray[runs.GetSize()]));
569 Int_t idx = TMath::BinarySearch(runs.GetSize(), runs.fArray, run);
570 if (idx >= runs.GetSize() || idx < 0 || runs[idx] != run) return -1;
574 * Add run labels at appropriate places on the plot
576 * @param h Frame histogram
578 * @param runs List of runs, if any
579 * @param areas Other areas
581 void AddRuns(TH1* h, const char* title, TArrayI* runs=0,
584 h->GetXaxis()->SetNoExponent();
585 // h->GetXaxis()->SetTitleOffset(1);
586 TString ytitle(title);
587 if (fUseVar) ytitle.Append(" (errors: variance)");
588 else ytitle.Append(" (errors: min/max)");
589 h->SetYTitle(ytitle.Data());
590 h->SetXTitle("Run #");
591 // Info("AddRuns", "%s: %s vs %s", h->GetName(),
592 // h->GetXaxis()->GetTitle(), h->GetYaxis()->GetTitle());
594 Int_t r1 = h->GetXaxis()->GetXmin();
595 Int_t r2 = h->GetXaxis()->GetXmax();
597 Double_t tx = .025; // (r2 - r1) / 18;
598 Double_t wx = 1 - fCanvas->GetLeftMargin() - fCanvas->GetRightMargin();
600 Double_t y = fCanvas->GetBottomMargin()+dy;
601 for (Int_t i = 0; i < fRuns.GetSize(); i++) {
603 Double_t x = fCanvas->GetLeftMargin() + wx*Double_t(r-r1)/(r2-r1);
605 // Skip runs out of range
606 if (r < r1 || r > r2) continue;
608 // Skip runs not in the graphs
610 if (FindRun(*runs, r) < 0) {
616 if (TMath::Abs(x - lx) < tx) y += dy;
617 else y = fCanvas->GetBottomMargin() + dy;
620 // Info(h->GetName(), "%6d (x,y)=(%12f,%12f) |lx-x|=|%f-x|=%f",
621 // r, x, y, lx, TMath::Abs(lx-x));
624 Double_t* xa = fNAccepted->GetX();
625 Int_t na = fNAccepted->GetN();
626 Int_t idx = TMath::BinarySearch(na, xa, Double_t(r));
627 Color_t color = kBlue+3;
628 if (idx >= 0 && idx < na && r == xa[idx] &&
629 fNAccepted->GetY()[idx] < 10000)
632 TLatex* ll = new TLatex(x, y, Form("%d", r));
634 ll->SetTextAlign(21);
635 ll->SetTextSize(0.02);
636 ll->SetTextColor(color);
638 // ll->SetTextAngle(90);
640 TLine* tl = new TLine(x, y, x, 1-fCanvas->GetTopMargin());
641 tl->SetBit(TLine::kLineNDC);
643 tl->SetLineColor(color);
646 if (!areas) continue;
648 TObjString* area = new TObjString;
649 TString& spec = area->String();
650 spec.Form("<span style=\"left: %d%%; bottom: %d%%;\" "
651 "onClick='window.location=\"%09d/index.html\"' "
652 "onMouseOver='this.style.cursor=\"pointer\"' "
655 UInt_t(100*x)-2, UInt_t(100*y), r, r, r);
658 spec.Form("<area shape='rect' alt='%d' title='%d' href='qa_%09d.html' "
659 "coords='%d,%d,%d,%d'>", r, r, r,
660 UInt_t(cw*(x-tx)), 0, UInt_t(cw*(x+tx)), ch);
666 * Output list of runs
668 * @param o Output stream
670 void WriteRuns(std::ostream& o)
672 o << "<div class='jobid'><!--JOBID--></div>\n"
673 << "<div class='runs'>\n"
675 for (Int_t i = 0; i < fRuns.GetSize(); i++) {
676 o << "<a href='" << Form("%09d", fRuns[i]) << "/index.html'>"
677 << fRuns[i] << "</a> " << std::flush;
680 << "</div>" << std::endl;
689 QABase::WriteFooter();
692 * Write out image footer
694 * @param o Output stream
695 * @param pngName Name of the PNG file
697 void WriteImageFooter(std::ostream& o, const char* pngName)
700 QABase::WriteImageFooter(o, pngName);
702 TGraph* fNAccepted; // Graph of number of accepted events
703 TGraphErrors* fVz; // Graph of mean vertex
704 UInt_t fFirst; // First run
705 UInt_t fLast; // Last run
706 TArrayI fRuns; // Seen runs
708 Bool_t fUseVar; // Use variance rather than min/max