Fix to allow new initialization of AliReconstruction (C.H.Christinsen)
[u/mrichter/AliRoot.git] / FMD / AliFMDQAChecker.cxx
index 5a6b7c2..6e499ab 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>
@@ -89,7 +91,7 @@ namespace {
     l->Add(m);
   }
   
-  const Double_t kROErrorsLabelY    = 30.;
+  const Double_t kROErrorsLabelY    = .30;
   
   const Int_t    kConvolutionSteps  = 100;
   const Double_t kConvolutionNSigma = 5;
@@ -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);
@@ -254,9 +256,14 @@ AliFMDQAChecker::AliFMDQAChecker()
     fELossBadChi2Nu(10), 
     fELossFkupChi2Nu(100), 
     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)
 {
 }          
 
@@ -271,11 +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("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();
 
@@ -334,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);
   }
 }
@@ -403,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, 
@@ -410,41 +464,66 @@ 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*    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, 
+    //             fELossFkupChi2Nu);
+    // res->Print();
+    chi2Check++;
+    if (red > fELossFkupChi2Nu) { 
+      chi2Check++;
+      chi2Lim = fELossFkupChi2Nu;
+    }
+  }
+  ret += chi2Check;
+
   if (fShowFitResults) { 
     lines = new TObjArray(nPar+3);
     lines->SetName("lines");
     lines->SetOwner(true);
-    
-    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);
-    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;
-    ltx = new TLatex(x1, y1, Form("[thresholds: %6.2f, %6.2f]", 
-                               fELossBadChi2Nu, fELossFkupChi2Nu));
+
+    // y1 -= dy;
+    ltx = new TLatex(x1, y1, Form("Fit range: [%6.2f,%6.2f]", low, high));
     ltx->SetTextColor(kGray+3);
     ltx->SetTextSize(dy-.01);
-    ltx->SetNDC(true);
     ltx->SetTextAlign(31);
-    lines->Add(ltx);    
+    ltx->SetNDC(true);
+    lines->Add(ltx);
 
     y1 -= dy;
-    ltx = new TLatex(x1, y1, Form("Fit range: [%6.2f,%6.2f]", low, high));
+    ltx = new TLatex(x1, y1, Form("Entries: %d (%d)", 
+                                 Int_t(hist->GetEffectiveEntries()),
+                                 fELossMaxEntries));
     ltx->SetTextColor(kGray+3);
     ltx->SetTextSize(dy-.01);
     ltx->SetTextAlign(31);
@@ -452,8 +531,10 @@ AliFMDQAChecker::CheckFit(TH1* hist, const TFitResultPtr& res,
     lines->Add(ltx);
 
     y1 -= dy;
-    ltx = new TLatex(x1, y1, Form("Entries: %d", 
-                                  Int_t(hist->GetEffectiveEntries())));
+    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);
@@ -461,126 +542,47 @@ AliFMDQAChecker::CheckFit(TH1* hist, const TFitResultPtr& res,
     lines->Add(ltx);
   }
   
-  if (red > fELossBadChi2Nu) { // || res->Prob() < .01) { 
-    AliWarningF("Fit gave chi^2/nu=%f/%d=%f>%f (%f)", 
-               res->Chi2(), res->Ndf(), red, fELossBadChi2Nu, 
-               fELossFkupChi2Nu);
-    if (lRed) lRed->SetTextColor(kOrange+2);
-    res->Print();
-    ret++;
-    if (red > fELossFkupChi2Nu) { 
-      if (lRed) lRed->SetTextColor(kRed+2);
-      ret++;
-    }
-  }
   // Now check the relative error on the fit parameters 
   Int_t parsOk = 0;
   for (Int_t i = 0; i < nPar; i++) { 
     if (res->IsParameterFixed(i)) continue; 
+    Double_t thr = fELossGoodParError;
     Double_t pv  = res->Parameter(i);
     Double_t pe  = res->ParError(i);
     Double_t rel = (pv == 0 ? 100 : pe / pv);
+    Bool_t   ok  = (i == 3) || (rel < thr);
     if (lines) {
       y -= dy;
-      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);
+      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 
-    Double_t thr = fELossGoodParError;
-    if (rel < thr) parsOk++;
-    else if (ltx) ltx->SetLineColor(kOrange+2);
+    if (ok) parsOk++;
   }
   if (parsOk > 0) 
     ret = TMath::Max(ret-(parsOk-1),0);
   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
-{
-  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*/, 
+AliFMDQAChecker::CheckRaw(AliRecoParam::EventSpecie_t specie, 
                          TH1*                        hist) const
 {
   Int_t ret = BasicCheck(hist);
@@ -590,7 +592,7 @@ AliFMDQAChecker::CheckRaw(AliRecoParam::EventSpecie_t /* specie*/,
     TH2*  roErrors = static_cast<TH2*>(hist);
     Int_t nY       = roErrors->GetNbinsY();
 
-    TLatex* ltx = new TLatex(.15, .8, Form("Thresholds: %5.2f,%5.2f",
+    TLatex* ltx = new TLatex(.15, .9, Form("Thresholds: %5.2f,%5.2f",
                                           fROErrorsBad, fROErrorsFkup));
     ltx->SetName("thresholds");
     ltx->SetTextColor(kGray+3);
@@ -612,10 +614,12 @@ AliFMDQAChecker::CheckRaw(AliRecoParam::EventSpecie_t /* specie*/,
        sum     += n * roErrors->GetYaxis()->GetBinCenter(j);
        cnt     += n;
       }
-      Double_t mean = sum / cnt;
-
-      ltx = new TLatex(i, kROErrorsLabelY, Form("Mean: %6.3f", mean));
+      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));
       ltx->SetName(Form("FMD%d", i));
+      ltx->SetNDC();
       ltx->SetTextAngle(90);
       ltx->SetTextColor(kGreen+4);
       old = ll->FindObject(ltx->GetName());
@@ -638,9 +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();
 
@@ -657,19 +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(AliFMDQADataMakerRec::kResetBit);
     if (qual > 0) { 
       func->SetLineWidth(3);
       func->SetLineStyle(1);
@@ -686,6 +726,9 @@ UShort_t
 AliFMDQAChecker::CheckSim(AliRecoParam::EventSpecie_t /* specie*/, 
                          TH1*                        hist) const
 {
+  // 
+  // Check simulated hits 
+  // 
   return BasicCheck(hist);
 }
 //__________________________________________________________________
@@ -693,10 +736,47 @@ 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, 
                            TObjArray**                 list, 
@@ -732,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];
@@ -748,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;
@@ -794,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, 
@@ -831,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());
@@ -916,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);
@@ -949,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);
@@ -972,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);
@@ -1011,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()));
   }
 }