#include <TClass.h>
#include <TH1F.h>
#include <TF1.h>
#include <TH2.h>
#include <TH1I.h>
#include <TIterator.h>
#include <TKey.h>
#include <TFile.h>
#include <iostream>
#include <TCanvas.h>
#include <TStyle.h>
#include <TLatex.h>
#include <TFitResult.h>
#include <TParameter.h>
#include <TMacro.h>
#include <TPaveText.h>
#include <TVirtualFitter.h>
#include "AliLog.h"
#include "AliQAv1.h"
#include "AliQAChecker.h"
#include "AliFMDQAChecker.h"
#include "AliFMDQADataMakerRec.h"
#include "AliRecoParam.h"
#include <AliCDBManager.h>
#include <AliCDBEntry.h>
#include <AliCDBId.h>
#include <AliQAThresholds.h>
ClassImp(AliFMDQAChecker)
#if 0
;
#endif
namespace {
void addFitsMacro(TList* l) {
TMacro* m = new TMacro("fits");
m->AddLine("void fits() {");
m->AddLine(" if (!gPad) { Printf(\"No gPad\"); return; }");
m->AddLine(" TList* lp = gPad->GetListOfPrimitives();");
m->AddLine(" if (!lp) return;");
m->AddLine(" TObject* po = 0;");
m->AddLine(" TIter next(lp);");
m->AddLine(" while ((po = next())) {");
m->AddLine(" if (!po->IsA()->InheritsFrom(TH1::Class())) continue;");
m->AddLine(" TH1* htmp = dynamic_cast<TH1*>(po);");
m->AddLine(" TList* lf = htmp->GetListOfFunctions();");
m->AddLine(" TObject* pso = (lf ? lf->FindObject(\"stats\") : 0);");
m->AddLine(" if (!pso) continue;");
m->AddLine(" TPaveStats* ps = static_cast<TPaveStats*>(pso);");
m->AddLine(" ps->SetOptFit(111);");
m->AddLine(" UShort_t qual = htmp->GetUniqueID();");
m->AddLine(" ps->SetFillColor(qual >= 3 ? kRed-4 : qual >= 2 ? kOrange-4 : qual >= 1 ? kYellow-4 : kGreen-4);");
m->AddLine(" break;");
m->AddLine(" }");
m->AddLine("}");
TObject* old = l->FindObject(m->GetName());
if (old) l->Remove(old);
l->Add(m);
}
const Double_t kROErrorsLabelY = .30;
const Int_t kConvolutionSteps = 100;
const Double_t kConvolutionNSigma = 5;
const Double_t kMpShift = -0.22278298;
const Double_t kInvSq2Pi = 1. / TMath::Sqrt(2*TMath::Pi());
Double_t landau(Double_t x, Double_t delta, Double_t xi)
{
return TMath::Landau(x, delta - xi * kMpShift, xi);
}
Double_t landauGaus(Double_t x, Double_t delta, Double_t xi,
Double_t sigma, Double_t sigmaN)
{
Double_t deltap = delta - xi * kMpShift;
Double_t sigma2 = sigmaN*sigmaN + sigma*sigma;
Double_t sigma1 = sigmaN == 0 ? sigma : TMath::Sqrt(sigma2);
Double_t xlow = x - kConvolutionNSigma * sigma1;
Double_t xhigh = x + kConvolutionNSigma * sigma1;
Double_t step = (xhigh - xlow) / kConvolutionSteps;
Double_t sum = 0;
for (Int_t i = 0; i <= kConvolutionSteps/2; i++) {
Double_t x1 = xlow + (i - .5) * step;
Double_t x2 = xhigh - (i - .5) * step;
sum += TMath::Landau(x1, deltap, xi, kTRUE) * TMath::Gaus(x, x1, sigma1);
sum += TMath::Landau(x2, deltap, xi, kTRUE) * TMath::Gaus(x, x2, sigma1);
}
return step * sum * kInvSq2Pi / sigma1;
}
Double_t landauGaus1(Double_t* xp, Double_t* pp)
{
Double_t x = xp[0];
Double_t constant = pp[0];
Double_t delta = pp[1];
Double_t xi = pp[2];
Double_t sigma = pp[3];
Double_t sigmaN = pp[4];
return constant * landauGaus(x, delta, xi, sigma, sigmaN);
}
TF1* makeLandauGaus(const char* ,
Double_t c=1,
Double_t delta=.5, Double_t xi=0.07,
Double_t sigma=.1, Double_t sigmaN=-1,
Double_t xmin=0, Double_t xmax=15)
{
Int_t npar = 5;
TF1* func = new TF1("landauGaus",
&landauGaus1,xmin,xmax,npar);
func->SetLineColor(kBlack);
func->SetLineWidth(2);
func->SetNpx(500);
func->SetParNames("C","#Delta_{p}","#xi", "#sigma", "#sigma_{n}");
func->SetParameter(0, c);
func->SetParameter(1, delta);
func->SetParameter(2, xi);
func->SetParameter(3, sigma);
func->SetParameter(4, sigmaN);
func->SetParLimits(1, 0, xmax);
func->SetParLimits(2, 0, xmax);
func->SetParLimits(3, 0.01, 1);
if (sigmaN < 0) func->FixParameter(4, 0);
else func->SetParLimits(4, 0, xmax);
return func;
}
}
AliFMDQAChecker::AliFMDQAChecker()
: AliQACheckerBase("FMD","FMD Quality Assurance Checker") ,
fDoScale(false),
fDidExternal(false),
fShowFitResults(true),
fELossLowCut(0.2),
fELossNRMS(3),
fELossBadChi2Nu(10),
fELossFkupChi2Nu(100),
fELossMinEntries(1000),
fELossMaxEntries(-1),
fELossGoodParError(0.1),
fELossMinSharing(0.1),
fROErrorsBad(0.3),
fROErrorsFkup(0.5),
fMaxNProblem(10),
fMaxNBad(10),
fNoFits(false)
{
}
void
AliFMDQAChecker::ProcessExternalParams()
{
ProcessExternalParam("ELossLowCut", fELossLowCut);
ProcessExternalParam("ELossNRMS", fELossNRMS);
ProcessExternalParam("ELossBadChi2Nu", fELossBadChi2Nu);
ProcessExternalParam("ELossFkupChi2Nu", fELossFkupChi2Nu);
ProcessExternalParam("ELossGoodParError", fELossGoodParError);
ProcessExternalParam("ROErrorsBad", fROErrorsBad);
ProcessExternalParam("ROErrorsFkup", fROErrorsFkup);
ProcessExternalParam("ELossMinSharing", fELossMinSharing);
Double_t tmp = 0;
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();
fDidExternal = true;
}
void
AliFMDQAChecker::ProcessExternalParam(const char* name, Double_t& v)
{
TObject* o = fExternParamList->FindObject(name);
if (!o) return;
TParameter<double>* p = static_cast<TParameter<double>*>(o);
v = p->GetVal();
AliDebugF(3, "External parameter: %-20s=%lf", name, v);
}
void
AliFMDQAChecker::GetThresholds()
{
const char* path = "GRP/Calib/QAThresholds";
AliCDBManager* cdbMan = AliCDBManager::Instance();
AliCDBEntry* cdbEnt = cdbMan->Get(path);
if (!cdbEnt) {
AliWarningF("Failed to get CDB entry at %s", path);
return;
}
TObjArray* cdbObj = static_cast<TObjArray*>(cdbEnt->GetObject());
if (!cdbObj) {
AliWarningF("Failed to get CDB object at %s", path);
return;
}
TObject* fmdObj = cdbObj->FindObject("FMD");
if (!fmdObj) {
AliWarningF("Failed to get FMD object at from CDB %s", path);
return;
}
AliQAThresholds* qaThr = static_cast<AliQAThresholds*>(fmdObj);
Int_t nThr = qaThr->GetSize();
for (Int_t i = 0; i < nThr; i++) {
TObject* thr = qaThr->GetThreshold(i);
if (!thr) continue;
TParameter<double>* d = dynamic_cast<TParameter<double>*>(thr);
if (!d) {
AliWarningF("Parameter %s not of type double", thr->GetName());
continue;
}
Double_t val = d->GetVal();
TString name(thr->GetName());
if (name.EqualTo("ELossBadChi2Nu")) fELossBadChi2Nu = val;
else if (name.EqualTo("ELossFkupChi2Nu")) fELossFkupChi2Nu = val;
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);
}
}
AliQAv1::QABIT_t
AliFMDQAChecker::Quality2Bit(UShort_t value) const
{
AliQAv1::QABIT_t ret = AliQAv1::kINFO;
if (value >= kWhatTheFk) ret = AliQAv1::kFATAL;
else if (value >= kBad) ret = AliQAv1::kERROR;
else if (value >= kProblem) ret = AliQAv1::kWARNING;
return ret;
}
void
AliFMDQAChecker::SetQA(AliQAv1::ALITASK_t index, Double_t* values) const
{
AliQAv1 * qa = AliQAv1::Instance(index) ;
for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) {
if (!qa->IsEventSpecieSet(AliRecoParam::ConvertIndex(specie)))
continue ;
if (!values) {
qa->Set(AliQAv1::kFATAL, specie) ;
continue;
}
UShort_t value = values[specie];
AliQAv1::QABIT_t ret = Quality2Bit(value);
qa->Set(ret, AliRecoParam::ConvertIndex(specie));
AliDebugF(3, "Quality of %s: %d -> %d",
AliRecoParam::GetEventSpecieName(specie), value, ret);
}
}
UShort_t
AliFMDQAChecker::BasicCheck(TH1* hist) const
{
if (hist->GetEntries() <= 0) return kOK;
return (hist->GetMean() > 0 ? kOK : kProblem);
}
UShort_t
AliFMDQAChecker::CheckOne(AliQAv1::ALITASK_t what,
AliRecoParam::EventSpecie_t specie,
TH1* hist) const
{
if(what == AliQAv1::kESD) return CheckESD(specie, hist);
if(what == AliQAv1::kRAW) return CheckRaw(specie, hist);
if(what == AliQAv1::kSIM) return CheckSim(specie, hist);
if(what == AliQAv1::kREC) return CheckRec(specie, hist);
return 0;
}
UShort_t
AliFMDQAChecker::CheckESD(AliRecoParam::EventSpecie_t ,
TH1* hist) const
{
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,
Double_t low, Double_t high, Int_t& color) const
{
color = kGreen+4;
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* 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) {
chi2Check++;
if (red > fELossFkupChi2Nu) {
chi2Check++;
chi2Lim = fELossFkupChi2Nu;
}
}
ret += chi2Check;
if (fShowFitResults) {
lines = new TObjArray(nPar+3);
lines->SetName("lines");
lines->SetOwner(true);
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("Fit range: [%6.2f,%6.2f]", low, high));
ltx->SetTextColor(kGray+3);
ltx->SetTextSize(dy-.01);
ltx->SetTextAlign(31);
ltx->SetNDC(true);
lines->Add(ltx);
y1 -= dy;
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);
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);
}
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;
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;
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;
if (lines) {
TList* lf = hist->GetListOfFunctions();
TObject* old = lf->FindObject(lines->GetName());
if (old) {
lf->Remove(old);
delete old;
}
lf->Add(lines);
}
hist->SetStats(false);
return ret;
}
UShort_t
AliFMDQAChecker::CheckRaw(AliRecoParam::EventSpecie_t specie,
TH1* hist) const
{
Int_t ret = BasicCheck(hist);
TString name(hist->GetName());
if (name.Contains("readouterrors", TString::kIgnoreCase)) {
TH2* roErrors = static_cast<TH2*>(hist);
Int_t nY = roErrors->GetNbinsY();
TLatex* ltx = new TLatex(.15, .9, Form("Thresholds: %5.2f,%5.2f",
fROErrorsBad, fROErrorsFkup));
ltx->SetName("thresholds");
ltx->SetTextColor(kGray+3);
ltx->SetNDC();
TList* ll = hist->GetListOfFunctions();
TObject* old = ll->FindObject(ltx->GetName());
if (old) {
ll->Remove(old);
delete old;
}
ll->Add(ltx);
for (Int_t i = 1; i <= 3; i++) {
Double_t sum = 0;
Int_t cnt = 0;
for (Int_t j = 1; j <= nY; j++) {
Int_t n = roErrors->GetBinContent(i, j);
sum += n * roErrors->GetYaxis()->GetBinCenter(j);
cnt += n;
}
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());
if (old) {
ll->Remove(old);
delete old;
}
ll->Add(ltx);
if (mean > fROErrorsBad) {
AliWarningF("Mean of readout errors for FMD%d = %f > %f (%f)",
i, mean, fROErrorsBad, fROErrorsFkup);
ret++;
ltx->SetTextColor(kOrange+2);
if (mean > fROErrorsFkup) {
ret++;
ltx->SetTextColor(kRed+2);
}
}
}
}
else if (name.Contains("eloss",TString::kIgnoreCase)) {
if (fNoFits) return ret;
if (specie == AliRecoParam::kCosmic ||
specie == AliRecoParam::kCalib) return ret;
if (hist->TestBit(AliQAv1::GetExpertBit())) return ret;
if (hist->GetEntries() < fELossMinEntries) return ret;
Double_t xMin = hist->GetXaxis()->GetXmin();
Double_t xMax = hist->GetXaxis()->GetXmax();
hist->GetXaxis()->SetRangeUser(fELossLowCut, xMax);
Int_t bMaxY = hist->GetMaximumBin();
Double_t xMaxY = hist->GetXaxis()->GetBinCenter(bMaxY);
Double_t rms = hist->GetRMS();
Double_t low = hist->GetXaxis()->GetBinCenter(bMaxY-4);
hist->GetXaxis()->SetRangeUser(0.2, xMaxY+(fELossNRMS+1)*rms);
rms = hist->GetRMS();
hist->GetXaxis()->SetRange(0,-1);
TF1* func = makeLandauGaus(name);
func->SetParameter(1, xMaxY);
func->SetLineColor(kGreen+4);
Double_t high = xMax;
if (fELossNRMS > 0) high = xMaxY+fELossNRMS*rms;
if (low >= high) return ret;
Int_t bLow = hist->FindBin(low);
Int_t bHigh = hist->FindBin(high);
if (bLow >= bHigh || hist->Integral(bLow, bHigh) < fELossMinEntries)
return ret;
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);
func = hist->GetFunction("landauGaus");
if (fELossNRMS <= 0) func->SetRange(xMin, xMax);
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);
if (fELossMaxEntries > 0 && hist->GetEntries() > fELossMaxEntries)
hist->SetBit(AliFMDQADataMakerRec::kResetBit);
if (qual > 0) {
func->SetLineWidth(3);
func->SetLineStyle(1);
if (qual > 1)
func->SetLineWidth(4);
}
ret += qual;
}
return ret;
}
UShort_t
AliFMDQAChecker::CheckSim(AliRecoParam::EventSpecie_t ,
TH1* hist) const
{
return BasicCheck(hist);
}
UShort_t
AliFMDQAChecker::CheckRec(AliRecoParam::EventSpecie_t ,
TH1* hist) const
{
return BasicCheck(hist);
}
void AliFMDQAChecker::AddStatusPave(TH1* hist, Int_t qual,
Double_t xl, Double_t yl,
Double_t xh, Double_t yh) const
{
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,
const AliDetectorRecoParam* )
{
if (!fDidExternal) ProcessExternalParams();
for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) {
rv[specie] = 0.;
if (!AliQAv1::Instance()->IsEventSpecieSet(specie) )
continue ;
if(!list[specie]) continue;
TH1* hist = 0;
Int_t nHist = list[specie]->GetEntriesFast();
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;
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);
}
rv[specie] = ret;
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);
}
}
}
namespace {
Int_t CheckForLog(TAxis* axis,
TVirtualPad* pad,
Int_t xyz)
{
Int_t ret = 0;
TString t(axis->GetTitle());
if (!t.Contains("[log]", TString::kIgnoreCase)) return 0;
t.ReplaceAll("[log]", "");
switch (xyz) {
case 1: pad->SetLogx(); ret |= 0x1; break;
case 2: pad->SetLogy(); ret |= 0x2; break;
case 3: pad->SetLogz(); ret |= 0x4; break;
}
axis->SetTitle(t);
return ret;
}
void RestoreLog(TAxis* axis, Bool_t log)
{
if (!log) return;
TString t(axis->GetTitle());
t.Append("[log]");
axis->SetTitle(t);
}
}
namespace {
void FindMinMax(TH1* h, Double_t& min, Double_t& max)
{
Double_t tmin = 1e9;
Double_t tmax = 0;
for (Int_t i = 1; i <= h->GetNbinsX(); i++) {
Double_t c = h->GetBinContent(i);
if (c < 1e-8) continue;
tmin = TMath::Min(tmin, c);
tmax = TMath::Max(tmax, c);
}
min = tmin;
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,
AliQAv1::TASKINDEX_t task,
AliQAv1::MODE_t mode)
{
Int_t nImages = 0 ;
Double_t max = 0;
Double_t min = 10000;
for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) {
AliRecoParam::EventSpecie_t spe = AliRecoParam::ConvertIndex(specie);
if (!AliQAv1::Instance(AliQAv1::GetDetIndex(GetName()))
->IsEventSpecieSet(spe))
continue;
if(!list[specie] || list[specie]->GetEntriesFast() == 0) continue;
TH1* hist = 0;
Int_t nHist = list[specie]->GetEntriesFast();
for(Int_t i= 0; i< nHist; i++) {
hist = static_cast<TH1F*>(list[specie]->At(i));
if (hist && hist->TestBit(AliQAv1::GetImageBit())) {
nImages++;
TString name(hist->GetName());
if (name.Contains("readouterrors", TString::kIgnoreCase) ||
name.Contains("status", TString::kIgnoreCase)) continue;
Double_t hMax, hMin;
FindMinMax(hist, hMin, hMax);
max = TMath::Max(max, hMax);
min = TMath::Min(min, hMin);
}
}
break ;
}
min = TMath::Max(1e-1, min);
max = TMath::Max(1e5, max);
if (nImages == 0) {
AliDebug(AliQAv1::GetQADebugLevel(),
Form("No histogram will be plotted for %s %s\n", GetName(),
AliQAv1::GetTaskName(task).Data()));
return;
}
AliDebug(AliQAv1::GetQADebugLevel(),
Form("%d histograms will be plotted for %s %s\n",
nImages, GetName(), AliQAv1::GetTaskName(task).Data()));
gStyle->SetOptStat(0);
for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) {
if (!AliQAv1::Instance(AliQAv1::GetDetIndex(GetName()))
->IsEventSpecieSet(specie)) continue;
if(!list[specie] || list[specie]->GetEntries() <= 0 ||
nImages <= 0) continue;
const Char_t * title = Form("QA_%s_%s_%s", GetName(),
AliQAv1::GetTaskName(task).Data(),
AliRecoParam::GetEventSpecieName(specie));
if (!fImage[specie]) fImage[specie] = new TCanvas(title, title) ;
fImage[specie]->Clear() ;
fImage[specie]->SetTitle(title) ;
fImage[specie]->cd() ;
TPaveText someText(0.015, 0.015, 0.98, 0.98) ;
someText.AddText(title) ;
someText.SetFillColor(0);
someText.SetFillStyle(0);
someText.SetBorderSize(0);
someText.SetTextColor(kRed+1);
someText.Draw() ;
TString outName(Form("%s%s%d.%s", AliQAv1::GetImageFileName(),
AliQAv1::GetModeName(mode),
AliQAChecker::Instance()->GetRunNumber(),
AliQAv1::GetImageFileFormat()));
fImage[specie]->Print(outName, "ps") ;
fImage[specie]->Clear();
fImage[specie]->SetTopMargin(0.10);
fImage[specie]->SetBottomMargin(0.15);
fImage[specie]->SetLeftMargin(0.15);
fImage[specie]->SetRightMargin(0.05);
const char* topT = Form("Mode: %s, Task: %s, Specie: %s, Run: %d",
AliQAv1::GetModeName(mode),
AliQAv1::GetTaskName(task).Data(),
AliRecoParam::GetEventSpecieName(specie),
AliQAChecker::Instance()->GetRunNumber());
TLatex* topText = new TLatex(.5, .99, topT);
topText->SetTextAlign(23);
topText->SetTextSize(.038);
topText->SetTextFont(42);
topText->SetTextColor(kBlue+3);
topText->SetNDC();
topText->Draw();
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));
TVirtualPad* plots = fImage[specie];
TVirtualPad* stat = 0;
if (status) {
TPad* pM = new TPad("plots", "Plots Pad", 0, .2, 1., .9, 0, 0);
fImage[specie]->cd();
pM->Draw();
plots = pM;
TPad* pS = new TPad("status", "Status Pad", 0, 0, 1., .2, 0, 0);
fImage[specie]->cd();
pS->Draw();
pS->SetLogz();
stat = pS;
}
Int_t nx = 3;
Int_t ny = (nImages + .5) / nx;
plots->Divide(nx, ny, 0, 0);
TH1* hist = 0;
Int_t nHist = list[specie]->GetEntriesFast();
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);
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);
pad->SetBottomMargin(0.10);
}
Int_t logOpts = 0;
logOpts |= CheckForLog(hist->GetXaxis(), pad, 1);
logOpts |= CheckForLog(hist->GetYaxis(), pad, 2);
logOpts |= CheckForLog(hist->GetZaxis(), pad, 3);
TString opt("");
if (isROE) {
pad->SetRightMargin(0.15);
pad->SetBottomMargin(0.10);
opt="COLZ";
}
else {
pad->SetGridx();
pad->SetGridy();
if (fDoScale) {
hist->SetMinimum(min);
hist->SetMaximum(max);
}
else {
hist->SetMinimum();
hist->SetMaximum();
}
}
hist->DrawCopy(opt);
if (!name.Contains("readouterrors", TString::kIgnoreCase)) {
gStyle->SetOptTitle(0);
TPad* insert = new TPad("insert", "Zoom",
.5,.5, .99, .95, 0, 0, 0);
insert->SetTopMargin(0.01);
insert->SetRightMargin(0.01);
insert->SetFillColor(0);
insert->SetBorderSize(1);
insert->SetBorderMode(0);
insert->Draw();
insert->cd();
if (logOpts & 0x1) insert->SetLogx();
if (logOpts & 0x2) insert->SetLogy();
if (logOpts & 0x4) insert->SetLogz();
hist->GetXaxis()->SetRange(1, hist->GetNbinsX()/8);
TH1* copy = hist->DrawCopy(opt);
copy->GetXaxis()->SetNdivisions(408, false);
hist->GetXaxis()->SetRange(0, 0);
gStyle->SetOptTitle(1);
}
pad->cd();
RestoreLog(hist->GetXaxis(), logOpts & 0x1);
RestoreLog(hist->GetYaxis(), logOpts & 0x2);
RestoreLog(hist->GetZaxis(), logOpts & 0x4);
}
if (status && stat) {
stat->cd();
status->DrawCopy("BOX TEXT");
}
fImage[specie]->Print(outName, "ps");
if (AliDebugLevel() > 0)
fImage[specie]->Print(Form("%s_%d.png",
AliRecoParam::GetEventSpecieName(specie),
AliQAChecker::Instance()->GetRunNumber()));
}
}