]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - FMD/AliFMDQAChecker.cxx
Better formulas for the track seeding
[u/mrichter/AliRoot.git] / FMD / AliFMDQAChecker.cxx
index 1d60b187da089b6daca78455c079b9d7959c8c2e..6e499aba5f02a62e114ef20258abf56b977c82d1 100644 (file)
 #include <TFile.h> 
 #include <iostream>
 #include <TCanvas.h>
-#include <TPaveText.h>
 #include <TStyle.h>
 #include <TLatex.h>
 #include <TFitResult.h>
 #include <TParameter.h>
 #include <TMacro.h>
+#include <TPaveText.h>
+#include <TVirtualFitter.h>
 
 // --- AliRoot header files ---
 #include "AliLog.h"
 #include "AliQAv1.h"
 #include "AliQAChecker.h"
 #include "AliFMDQAChecker.h"
+#include "AliFMDQADataMakerRec.h"
 #include "AliRecoParam.h"
 #include <AliCDBManager.h>
 #include <AliCDBEntry.h>
@@ -234,7 +236,7 @@ namespace {
 
     func->SetParLimits(1, 0,    xmax);
     func->SetParLimits(2, 0,    xmax);
-    func->SetParLimits(3, 0.01, 0.4);
+    func->SetParLimits(3, 0.01, 1);
     
     if (sigmaN < 0) func->FixParameter(4, 0);
     else            func->SetParLimits(4, 0, xmax);
@@ -256,8 +258,12 @@ AliFMDQAChecker::AliFMDQAChecker()
     fELossMinEntries(1000),
     fELossMaxEntries(-1),
     fELossGoodParError(0.1),
+    fELossMinSharing(0.1),
     fROErrorsBad(0.3), 
-    fROErrorsFkup(0.5)
+    fROErrorsFkup(0.5),
+    fMaxNProblem(10),
+    fMaxNBad(10),
+    fNoFits(false)
 {
 }          
 
@@ -272,13 +278,21 @@ AliFMDQAChecker::ProcessExternalParams()
   ProcessExternalParam("ELossGoodParError",    fELossGoodParError);
   ProcessExternalParam("ROErrorsBad",          fROErrorsBad);
   ProcessExternalParam("ROErrorsFkup",         fROErrorsFkup);
+  ProcessExternalParam("ELossMinSharing",       fELossMinSharing);
   Double_t tmp = 0;
-  ProcessExternalParam("CommonScale",          tmp);
-  fDoScale = tmp > 0;
-  ProcessExternalParam("ELossMinEntries",      tmp);
-  fELossMinEntries = tmp;
-  ProcessExternalParam("ELossMaxEntries",      tmp);
-  fELossMaxEntries = tmp;
+  ProcessExternalParam("CommonScale", tmp);
+  fDoScale = tmp > 0; tmp = fELossMinEntries;
+  ProcessExternalParam("ELossMinEntries", tmp);
+  fELossMinEntries = tmp; tmp = fELossMaxEntries;
+  ProcessExternalParam("ELossMaxEntries", tmp);
+  fELossMaxEntries = tmp; tmp = fMaxNProblem;
+  ProcessExternalParam("MaxNProblem", tmp);
+  fMaxNProblem = tmp; tmp = 0;
+  fELossMaxEntries = tmp; tmp = fMaxNBad;
+  ProcessExternalParam("MaxNBad", tmp);
+  fMaxNBad = tmp; tmp = 0;
+  ProcessExternalParam("NoFits", tmp);
+  fNoFits = tmp > 0; tmp = 0;
 
   GetThresholds();
 
@@ -337,6 +351,8 @@ AliFMDQAChecker::GetThresholds()
     else if (name.EqualTo("ELossGoodParError"))  fELossGoodParError = val;
     else if (name.EqualTo("ROErrorsBad"))        fROErrorsBad       = val;
     else if (name.EqualTo("ROErrorsFkup"))       fROErrorsFkup      = val;    
+    else if (name.EqualTo("MaxNProblem"))        fMaxNProblem       = val;
+    else if (name.EqualTo("MaxNBad"))            fMaxNBad           = val;
     AliDebugF(3, "Threshold %s=%f", name.Data(), val);
   }
 }
@@ -406,6 +422,41 @@ AliFMDQAChecker::CheckESD(AliRecoParam::EventSpecie_t /* specie*/,
 {
   return BasicCheck(hist);
 }
+namespace {
+  Double_t Chi2Scale(TH1* h, Double_t base=10000) 
+  {
+    return 1. / TMath::Max(1., h->GetEntries() / base);
+  }
+  void AddLine(TObjArray* lines, 
+              Double_t x1, Double_t x2, Double_t x3, 
+              Double_t y, Double_t dy,
+              const char* name, Double_t val, Double_t lim, 
+              Bool_t ok, Int_t color)
+  {
+    TString n; n.Form("%s:", name);
+    TLatex* ltx = new TLatex(x1, y, n);
+    ltx->SetNDC(true);
+    ltx->SetTextSize(dy-0.01);
+    ltx->SetTextColor(color);
+    lines->Add(ltx);
+    
+    n.Form("%7.3f", val);
+    ltx = new TLatex(x2, y, n);
+    ltx->SetNDC(true);
+    ltx->SetTextSize(dy-0.01);
+    ltx->SetTextColor(color);
+    lines->Add(ltx);
+    
+    if (lim < 0) n = "(ignored)";
+    else  n.Form("%c %4.2f", ok ? '<' : '>', lim);
+    ltx = new TLatex(x3, y, n);
+    ltx->SetNDC(true);
+    ltx->SetTextSize(dy-0.01);
+    ltx->SetTextColor(color);
+    lines->Add(ltx);
+  }
+}
+
 //__________________________________________________________________
 UShort_t
 AliFMDQAChecker::CheckFit(TH1* hist, const TFitResultPtr& res, 
@@ -413,19 +464,29 @@ AliFMDQAChecker::CheckFit(TH1* hist, const TFitResultPtr& res,
 {
   color = kGreen+4;
 
+  // Check if there's indeed a result - if not, flag as OK
+  if (!res.Get()) return 0;
+
   UShort_t   ret   = 0;
   Int_t      nPar  = res->NPar();
   Double_t   dy    = .06;
   Double_t   x     = .2;
+  Double_t   x2    = .3;
+  Double_t   x3    = .4;
   Double_t   y     = .9-dy;
   Double_t   chi2  = res->Chi2();
   Int_t      nu    = res->Ndf();
+  Double_t   s     = Chi2Scale(hist,fELossMinEntries);
   Double_t   red   = (nu == 0 ? fELossFkupChi2Nu : chi2 / nu);
   TObjArray* lines = 0;
   // TLatex*    lRed  = 0;
   TLatex*    ltx   = 0;
   Int_t      chi2Check = 0;
   Double_t   chi2Lim   = fELossBadChi2Nu;
+  if (AliDebugLevel() > 0) 
+    printf("FIT: %s, 1, %d, %f, %f\n", hist->GetName(),
+           Int_t(hist->GetEntries()), red, s * red);
+  red *= s;
   if (red > fELossBadChi2Nu) { // || res->Prob() < .01) { 
     // AliWarningF("Fit gave chi^2/nu=%f/%d=%f>%f (%f)", 
     //             res->Chi2(), res->Ndf(), red, fELossBadChi2Nu, 
@@ -443,29 +504,13 @@ AliFMDQAChecker::CheckFit(TH1* hist, const TFitResultPtr& res,
     lines = new TObjArray(nPar+3);
     lines->SetName("lines");
     lines->SetOwner(true);
-    
-    ltx = new TLatex(x, y, Form("#chi^{2}/#nu: %7.3f %c %6.2f",
-                               red, chi2Check < 1 ? '<' : '>', 
-                               chi2Lim));
-    ltx->SetNDC(true);
-    ltx->SetTextColor(chi2Check < 1 ? color : 
-                     chi2Check < 2 ? kOrange+2 : kRed+2);
-    // ltx->SetTextColor(color);
-    ltx->SetTextSize(dy-.01);
-    lines->Add(ltx);
-    // lRed = ltx;
+
+    AddLine(lines, x, x2, x3, y, dy, "#chi^{2}/#nu", red, chi2Lim,
+           chi2Check < 1, chi2Check < 1 ? color : 
+           chi2Check < 2 ? kOrange+2 : kRed+2);
     
     Double_t x1 = .85;
     Double_t y1 = .5;
-#if 0
-    ltx = new TLatex(x1, y1, Form("[thresholds: %6.2f, %6.2f]", 
-                               fELossBadChi2Nu, fELossFkupChi2Nu));
-    ltx->SetTextColor(kGray+3);
-    ltx->SetTextSize(dy-.01);
-    ltx->SetNDC(true);
-    ltx->SetTextAlign(31);
-    // lines->Add(ltx);    
-#endif 
 
     // y1 -= dy;
     ltx = new TLatex(x1, y1, Form("Fit range: [%6.2f,%6.2f]", low, high));
@@ -484,6 +529,17 @@ AliFMDQAChecker::CheckFit(TH1* hist, const TFitResultPtr& res,
     ltx->SetTextAlign(31);
     ltx->SetNDC(true);
     lines->Add(ltx);
+
+    y1 -= dy;
+    ltx = new TLatex(x1, y1, Form("%s: %f #pm %f", 
+                                 res->ParName(1).c_str(),
+                                 res->Parameter(1),
+                                 res->ParError(1)));
+    ltx->SetTextColor(kGray+3);
+    ltx->SetTextSize(dy-.01);
+    ltx->SetTextAlign(31);
+    ltx->SetNDC(true);
+    lines->Add(ltx);
   }
   
   // Now check the relative error on the fit parameters 
@@ -497,17 +553,10 @@ AliFMDQAChecker::CheckFit(TH1* hist, const TFitResultPtr& res,
     Bool_t   ok  = (i == 3) || (rel < thr);
     if (lines) {
       y -= dy;
-      TString txt(Form("#delta%s/%s: %7.3f ", 
-                      res->ParName(i).c_str(),
-                      res->ParName(i).c_str(),
-                      /*pv, pe,*/ rel));
-      if (i != 3) txt.Append(Form("%c %4.2f", ok ? '<' : '>', thr));
-      else        txt.Append("(ignored)");
-      ltx = new TLatex(x, y, txt);
-      ltx->SetNDC(true);
-      ltx->SetTextSize(dy-.01);
-      ltx->SetTextColor(ok ? color : kOrange+2);
-      lines->Add(ltx);
+      AddLine(lines, x, x2, x3, y, dy,Form("#delta%s/%s", 
+                                          res->ParName(i).c_str(),
+                                          res->ParName(i).c_str()),
+             rel, (i == 3 ? -1 : thr), ok, ok ? color : kOrange+2);
     }
     if (i == 3) continue; // Skip sigma 
     if (ok) parsOk++;
@@ -517,84 +566,20 @@ AliFMDQAChecker::CheckFit(TH1* hist, const TFitResultPtr& res,
   if (ret > 1) color = kRed+2;
   if (ret > 0) color = kOrange+2;
 
-  TList*   lf  = hist->GetListOfFunctions();
-  TObject* old = lf->FindObject(lines->GetName());
-  if (old) {
-    lf->Remove(old);
-    delete old;
+  if (lines) {
+    TList*   lf  = hist->GetListOfFunctions();
+    TObject* old = lf->FindObject(lines->GetName());
+    if (old) {
+      lf->Remove(old);
+      delete old;
+    }
+    lf->Add(lines);
   }
-  lf->Add(lines);
   hist->SetStats(false);
     
   return ret;
 }
 
-//__________________________________________________________________
-void
-AliFMDQAChecker::AddFitResults(TH1* hist, const TFitResultPtr& res, 
-                              Int_t color, Double_t low, Double_t high) const
-{
-  // Obsolete - not used
-  if (!fShowFitResults) return; 
-
-  Int_t      nPar  = res->NPar();
-  TObjArray* lines = new TObjArray(nPar+1);
-  lines->SetOwner(kTRUE);
-  lines->SetName("fitResults");
-
-  Double_t   dy    = .06;
-  Double_t   x     = .2;
-  Double_t   y     = .9-dy;
-  Double_t   chi2  = res->Chi2();
-  Int_t      nu    = res->Ndf();
-  Double_t   red   = (nu == 0 ? fELossFkupChi2Nu : chi2 / nu);
-  
-  TLatex* ltx = new TLatex(x, y, Form("#chi^{2}/#nu: %7.3f",red));
-  ltx->SetNDC(true);
-  ltx->SetTextColor(color);
-  ltx->SetTextSize(dy-.01);
-  lines->Add(ltx);
-  
-  y -= dy;
-  ltx = new TLatex(x, y, Form("[thresholds: %6.2f, %6.2f]", 
-                             fELossBadChi2Nu, fELossFkupChi2Nu));
-  ltx->SetTextColor(kGray+3);
-  ltx->SetTextSize(dy-.01);
-  ltx->SetNDC(true);
-  lines->Add(ltx);
-
-  y -= dy;
-  ltx = new TLatex(x, y, Form("Fit range: [%6.2f,%6.2f]", low, high));
-  ltx->SetTextColor(kGray+3);
-  ltx->SetTextSize(dy-.01);
-  ltx->SetNDC(true);
-  lines->Add(ltx);
-
-  for (Int_t i = 0; i < nPar; i++) { 
-    if (res->IsParameterFixed(i)) continue; 
-    y -= dy;
-    Double_t pv  = res->Parameter(i);
-    Double_t pe  = res->ParError(i);
-    Double_t rel = (pv == 0 ? 100 : pe / pv);
-    ltx = new TLatex(x, y, Form("#delta%s/%s: %7.3f", 
-                               res->ParName(i).c_str(),
-                               res->ParName(i).c_str(),
-                               /*pv, pe,*/ rel));
-    ltx->SetNDC(true);
-    ltx->SetTextColor(color);
-    ltx->SetTextSize(dy-.01);
-    lines->Add(ltx);
-  }
-  TList*   lf  = hist->GetListOfFunctions();
-  TObject* old = lf->FindObject(lines->GetName());
-  if (old) {
-    lf->Remove(old);
-    delete old;
-  }
-  lf->Add(lines);
-  hist->SetStats(false);
-}
-
 //__________________________________________________________________
 UShort_t
 AliFMDQAChecker::CheckRaw(AliRecoParam::EventSpecie_t specie, 
@@ -629,7 +614,7 @@ AliFMDQAChecker::CheckRaw(AliRecoParam::EventSpecie_t specie,
        sum     += n * roErrors->GetYaxis()->GetBinCenter(j);
        cnt     += n;
       }
-      Double_t mean = sum / cnt;
+      Double_t mean = (cnt <= 0 ? 0 : sum / cnt);
       Double_t x    = ((i-.5) * (1-0.1-0.1) / 3 + 0.1);
       
       ltx = new TLatex(x, kROErrorsLabelY, Form("Mean: %6.3f", mean));
@@ -657,11 +642,17 @@ AliFMDQAChecker::CheckRaw(AliRecoParam::EventSpecie_t specie,
     }
   }
   else if (name.Contains("eloss",TString::kIgnoreCase)) { 
-    // Try to fit a function to the histogram 
-    if (hist->GetEntries() < 1000) return ret;
+    // If we' asked to not fit the data, return immediately
+    if (fNoFits) return ret;
+    // Do not fit cosmic or calibration data 
     if (specie == AliRecoParam::kCosmic || 
        specie == AliRecoParam::kCalib) return ret;
+    // Do not fit `expert' histograms 
+    if (hist->TestBit(AliQAv1::GetExpertBit())) return ret;
+    // Do not fit histograms with too little data 
+    if (hist->GetEntries() < fELossMinEntries) return ret;
 
+    // Try to fit a function to the histogram 
     Double_t xMin  = hist->GetXaxis()->GetXmin();
     Double_t xMax  = hist->GetXaxis()->GetXmax();
 
@@ -678,22 +669,47 @@ AliFMDQAChecker::CheckRaw(AliRecoParam::EventSpecie_t specie,
     func->SetLineColor(kGreen+4);
     // func->SetLineStyle(2);
     Double_t high = xMax; // xMaxY+fELossNRMS*rms;
+    if (fELossNRMS > 0) high = xMaxY+fELossNRMS*rms;
+    
+    // Check we don't have an empty fit range 
+    if (low >= high) return ret;
 
-    TFitResultPtr res  = hist->Fit(func, "QS", "", low, high);
+    // Check that we have enough counts in the fit range 
+    Int_t bLow  = hist->FindBin(low);
+    Int_t bHigh = hist->FindBin(high);
+    if (bLow >= bHigh || hist->Integral(bLow, bHigh) < fELossMinEntries)
+      return ret;
 
-    Int_t    color = func->GetLineColor();
-    UShort_t qual  = CheckFit(hist, res, low, high, color);
+    // Set our fit function 
+    TString fitOpt("QS");
+    TFitResultPtr res   = hist->Fit(func, fitOpt, "", low, high);
+    Int_t         color = func->GetLineColor();
+    UShort_t      qual  = CheckFit(hist, res, low, high, color);
 
     // Make sure we save the function in the full range of the histogram
     func = hist->GetFunction("landauGaus");
-    func->SetRange(xMin, xMax);
+    if (fELossNRMS <= 0) func->SetRange(xMin, xMax);
     // func->SetParent(hist);
     func->Save(xMin, xMax, 0, 0, 0, 0);
     func->SetLineColor(color);
 
+    fitOpt.Append("+");
+    res = hist->Fit("pol2", fitOpt, "", fELossMinSharing, low-0.05);
+    func = hist->GetFunction("pol2");
+    Double_t   s     = Chi2Scale(hist,fELossMinEntries*100);
+    Double_t   chi2  = (!res.Get() ? 0 : res->Chi2());
+    Int_t      nu    = (!res.Get() ? 1 : res->Ndf());
+    Double_t   red   = s * (nu == 0 ? fELossFkupChi2Nu : chi2 / nu);
+    if (AliDebugLevel()) 
+      printf("FIT: %s, 2, %d, %f, %f\n", hist->GetName(),
+            Int_t(hist->GetEntries()), red, s * red);
+    red *= s;
+    if (red > fELossFkupChi2Nu) func->SetLineColor(kRed);
+    else                        func->SetLineColor(kGreen+4);
+
     // Now check if this histogram should be cleared or not 
     if (fELossMaxEntries > 0 && hist->GetEntries() > fELossMaxEntries)
-      hist->SetBit(BIT(23));
+      hist->SetBit(AliFMDQADataMakerRec::kResetBit);
     if (qual > 0) { 
       func->SetLineWidth(3);
       func->SetLineStyle(1);
@@ -710,6 +726,9 @@ UShort_t
 AliFMDQAChecker::CheckSim(AliRecoParam::EventSpecie_t /* specie*/, 
                          TH1*                        hist) const
 {
+  // 
+  // Check simulated hits 
+  // 
   return BasicCheck(hist);
 }
 //__________________________________________________________________
@@ -717,9 +736,46 @@ UShort_t
 AliFMDQAChecker::CheckRec(AliRecoParam::EventSpecie_t /* specie*/, 
                          TH1*                        hist) const
 {
+  // 
+  // Check reconstructed data 
+  // 
   return BasicCheck(hist);
 }
 
+//__________________________________________________________________
+void AliFMDQAChecker::AddStatusPave(TH1* hist, Int_t qual, 
+                                   Double_t xl, Double_t yl, 
+                                   Double_t xh, Double_t yh) const
+{
+  //
+  // Add a status pave to a plot
+  // 
+  if (xh < 0) xh = gStyle->GetStatX();
+  if (xl < 0) xl = xh - gStyle->GetStatW(); 
+  if (yh < 0) yh = gStyle->GetStatY();
+  if (yl < 0) yl = xl - gStyle->GetStatH(); 
+  
+  TPaveText* text = new TPaveText(xl, yl, xh, yh, "brNDC");
+  Int_t   bg  = kGreen-10;
+  Int_t   fg  = kBlack;
+  TString msg = "OK";
+  if      (qual >= kWhatTheFk) { bg = kRed+1; fg = kWhite; msg = "Argh!"; }
+  else if (qual >= kBad)       { bg = kRed-3; fg = kWhite; msg = "Bad"; }
+  else if (qual >= kProblem)   { bg = kOrange-4; msg = "Warning"; }
+  text->AddText(msg);
+  text->SetTextFont(62);
+  text->SetTextColor(fg);
+  text->SetFillColor(bg);
+
+  TList*   ll  = hist->GetListOfFunctions();
+  TObject* old = ll->FindObject(text->GetName());
+  if (old) { 
+    ll->Remove(old);
+    delete old;
+  }
+  ll->Add(text);
+}
+
 //__________________________________________________________________
 void AliFMDQAChecker::Check(Double_t*                   rv, 
                            AliQAv1::ALITASK_t          what, 
@@ -756,14 +812,42 @@ void AliFMDQAChecker::Check(Double_t*                   rv,
     
     if(!list[specie]) continue;
     
-    TH1* hist  = 0;
-    Int_t nHist = list[specie]->GetEntriesFast();
-    UShort_t ret = 0;
+    TH1*     hist  = 0;
+    Int_t    nHist = list[specie]->GetEntriesFast();
+
+    // Find the status histogram if any 
+    TH2*  status  = 0;
+    Int_t istatus = AliFMDQADataMakerRec::GetHalfringIndex(4, 'i', 0, 0);
+    if (istatus < nHist) 
+      status = dynamic_cast<TH2*>(list[specie]->At(istatus));
+      
+    UShort_t ret   = 0;
     for(Int_t i= 0; i< nHist; i++) {
       if (!(hist = static_cast<TH1*>(list[specie]->At(i)))) continue;
+      if (hist == status) continue;
+      
       Int_t qual = CheckOne(what, AliRecoParam::ConvertIndex(specie), hist);
       hist->SetUniqueID(Quality2Bit(qual));
+      hist->SetStats(0);
+      AddStatusPave(hist, qual);
       ret += qual;
+
+      if (!status) continue;
+
+      // Parse out the detector and ring, calculate the bin, and fill
+      // status histogram.
+      TString nme(hist->GetName());
+      Char_t cD   = nme[nme.Length()-2];
+      Char_t cR   = nme[nme.Length()-1];
+      Int_t  xbin = 0;
+      switch (cD) { 
+      case '1': xbin = 1; break;
+      case '2': xbin = 2 + ((cR == 'i' || cR == 'I') ? 0 : 1); break;
+      case '3': xbin = 4 + ((cR == 'i' || cR == 'I') ? 0 : 1); break;
+      }
+      if (xbin == 0) continue;
+      status->Fill(xbin, qual);
+                  
     } // for (int i ...)
     rv[specie] = ret;
     // if      (ret > kWhatTheFk) rv[specie] = fLowTestValue[AliQAv1::kFATAL];
@@ -772,6 +856,19 @@ void AliFMDQAChecker::Check(Double_t*                   rv,
     // else                       rv[specie] = fUpTestValue[AliQAv1::kINFO]; 
     AliDebugF(3, "Combined sum is %d -> %f", ret, rv[specie]);
 
+    if (status) { 
+      Int_t nProblem = 0;
+      Int_t nBad     = 0;
+      for (Int_t i = 1; i < status->GetXaxis()->GetNbins(); i++) { 
+       nProblem += status->GetBinContent(i, 3);
+       nBad     += status->GetBinContent(i, 4);
+      }
+      Int_t qual = 0;
+      if (nProblem > fMaxNProblem) qual++;
+      if (nBad     > fMaxNBad)     qual += 2;
+      status->SetUniqueID(Quality2Bit(qual));
+      AddStatusPave(status, qual);
+    }
     // if (count != 0) rv[specie] /= count;
   }
   // return rv;
@@ -818,6 +915,22 @@ namespace {
     max = tmax;
   }
 }
+
+namespace { 
+  Int_t GetHalfringPad(TH1* h) {
+    TString nme(h->GetName());
+    Char_t cD   = nme[nme.Length()-2];
+    Char_t cR   = nme[nme.Length()-1];
+    Int_t  xbin = 0;
+    switch (cD) { 
+    case '1': xbin = 1; break;
+    case '2': xbin = ((cR == 'i' || cR == 'I') ? 2 : 5); break;
+    case '3': xbin = ((cR == 'i' || cR == 'I') ? 3 : 6); break;
+    }
+    return xbin;
+  }
+}
+
 //____________________________________________________________________________ 
 void 
 AliFMDQAChecker::MakeImage(TObjArray** list, 
@@ -855,7 +968,8 @@ AliFMDQAChecker::MakeImage(TObjArray** list,
       if (hist && hist->TestBit(AliQAv1::GetImageBit())) {
         nImages++; 
        TString name(hist->GetName());
-       if (name.Contains("readouterrors", TString::kIgnoreCase)) continue;
+       if (name.Contains("readouterrors", TString::kIgnoreCase) || 
+           name.Contains("status", TString::kIgnoreCase)) continue;
 
        // Double_t hMax = hist->GetMaximum(); 
        // hist->GetBinContent(hist->GetMaximumBin());
@@ -940,25 +1054,54 @@ AliFMDQAChecker::MakeImage(TObjArray** list,
     topText->SetTextColor(kBlue+3);
     topText->SetNDC();
     topText->Draw();
-                                
+
+    // Find the status histogram if any 
+    TH2*  status  = 0;
+    Int_t istatus = AliFMDQADataMakerRec::GetHalfringIndex(4, 'i', 0, 0);
+    if (istatus < list[specie]->GetEntriesFast()) 
+      status = dynamic_cast<TH2*>(list[specie]->At(istatus));
+
     // Divide canvas 
-    Int_t nx = int(nImages + .5) / 2;
-    Int_t ny = 2;
     // if (fDoScale) 
-    fImage[specie]->Divide(nx, ny, 0, 0);
+    TVirtualPad* plots = fImage[specie];
+    TVirtualPad* stat  = 0;
+    if (status) {
+      // AliWarning("Drawing plots sub-pad");
+      TPad* pM = new TPad("plots", "Plots Pad", 0, .2, 1., .9, 0, 0);
+      fImage[specie]->cd();
+      pM->Draw();
+      plots = pM;
+      // AliWarning("Drawing status sub-pad");
+      TPad* pS = new TPad("status", "Status Pad", 0, 0, 1., .2, 0, 0);
+      fImage[specie]->cd();
+      pS->Draw();
+      pS->SetLogz();
+      stat = pS;
+      // status->DrawCopy("colz");
+    }
+    // AliWarningF("fImage[specie]=%p, plots=%p", fImage[specie], plots);
+    // plots->cd();
+    Int_t nx = 3;
+    Int_t ny = (nImages + .5) / nx;
+    plots->Divide(nx, ny, 0, 0);
     // else fImage[specie]->Divide(nx, ny);
     
     
     // Loop over histograms 
     TH1*  hist  = 0;
     Int_t nHist = list[specie]->GetEntriesFast();
-    Int_t j     = 0;
     for (Int_t i = 0; i < nHist; i++) { 
       hist = static_cast<TH1*>(list[specie]->At(i));
       if (!hist || !hist->TestBit(AliQAv1::GetImageBit())) continue;
+      if (hist == status) continue;
+      TString name(hist->GetName());
+      Bool_t isROE = name.Contains("readouterrors", TString::kIgnoreCase);
 
       // Go to sub-pad 
-      TVirtualPad* pad = fImage[specie]->cd(++j);
+      TVirtualPad* pad = 0;
+      if      (isROE) pad = plots->cd(4);
+      else            pad = plots->cd(GetHalfringPad(hist));
+      
       pad->SetRightMargin(0.01);
       if (!fDoScale) { 
        pad->SetLeftMargin(0.10);
@@ -973,8 +1116,7 @@ AliFMDQAChecker::MakeImage(TObjArray** list,
 
       // Figure out special cases 
       TString opt("");
-      TString name(hist->GetName());
-      if (name.Contains("readouterrors", TString::kIgnoreCase)) {
+      if (isROE) {
        pad->SetRightMargin(0.15);
        pad->SetBottomMargin(0.10);
        // pad->SetTopMargin(0.02);
@@ -996,22 +1138,10 @@ AliFMDQAChecker::MakeImage(TObjArray** list,
       hist->DrawCopy(opt);
       
       // Special cases 
-      if (name.Contains("readouterrors", TString::kIgnoreCase)) {
-#if 0
-       for (Int_t kk = 1; kk <= 3; kk++) {
-         TH1* proj = static_cast<TH2*>(hist)->ProjectionY("",kk,kk);
-         Double_t m = proj->GetMean(); 
-         TLatex* l = new TLatex(kk, 30, Form("Mean: %f", m));
-         l->SetTextAngle(90);
-         l->SetTextColor(m > 10 ? kRed+1 : m > .7 ? kOrange+2 :kGreen+2);
-         l->Draw();
-       }
-#endif
-      }
-      else {
+      if (!name.Contains("readouterrors", TString::kIgnoreCase)) {
        gStyle->SetOptTitle(0);
        TPad* insert = new TPad("insert", "Zoom", 
-                               .4,.4, .99, .95, 0, 0, 0);
+                               .5,.5, .99, .95, 0, 0, 0);
        insert->SetTopMargin(0.01);
        insert->SetRightMargin(0.01);
        insert->SetFillColor(0);
@@ -1035,13 +1165,16 @@ AliFMDQAChecker::MakeImage(TObjArray** list,
       RestoreLog(hist->GetYaxis(), logOpts & 0x2);
       RestoreLog(hist->GetZaxis(), logOpts & 0x4);
     }
+    if (status && stat) {
+      stat->cd();
+      status->DrawCopy("BOX TEXT");
+    }
     // Print to a post-script file 
     fImage[specie]->Print(outName, "ps");
-#if 0
-    fImage[specie]->Print(Form("%s_%d.png", 
-                              AliRecoParam::GetEventSpecieName(specie), 
-                              AliQAChecker::Instance()->GetRunNumber()));
-#endif
+    if (AliDebugLevel() > 0) 
+      fImage[specie]->Print(Form("%s_%d.png", 
+                                AliRecoParam::GetEventSpecieName(specie), 
+                                AliQAChecker::Instance()->GetRunNumber()));
   }
 }