Modifications to get a much more explicit report on token lost readout errors for...
[u/mrichter/AliRoot.git] / MUON / AliMUONTrackerQAChecker.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 // $Id$
17
18 #include "AliMUONTrackerQAChecker.h"
19
20 /// \class AliMUONTrackerQAChecker
21 ///
22 /// Implementation of AliQACheckerBase for MCH and MTR
23 ///
24 /// For the moment we only implement the checking of raw data QA for the tracker
25 /// by looking at the occupancy at the bus patch level.
26 ///
27 /// \author Laurent Aphecetche, Subatech
28
29 #include "AliCDBManager.h"
30 #include "AliCodeTimer.h"
31 #include "AliLog.h"
32 #include "AliMUONQAIndices.h"
33 #include "AliMUONRecoParam.h"
34 #include "AliMpBusPatch.h"
35 #include "AliMpDDLStore.h"
36 #include "AliQAv1.h"
37 #include "AliQAv1.h"
38 #include "Riostream.h"
39 #include "TAxis.h"
40 #include "TDirectory.h"
41 #include "TH1.h"
42 #include "TLine.h"
43 #include "TMath.h"
44 #include "TPaveText.h"
45 #include "TGaxis.h"
46 #include "TVirtualPad.h"
47
48 /// \cond CLASSIMP
49 ClassImp(AliMUONTrackerQAChecker)
50 /// \endcond
51
52 namespace {
53   
54   //___________________________________________________________________________  
55   int trim(Int_t n, 
56            Double_t* x,
57            Double_t alpha,
58            Double_t& tmean,
59            Double_t& tvar,
60            Double_t& min,
61            Double_t& max)
62   {
63     //
64     // Calculates the trimmed (tmean) mean
65     // of a sample (x) and estimates the variance (tvar)
66     // of that mean.
67     //
68     
69     // First check input parameters
70     
71     // number of observations
72     if ( n < 2 )
73     {
74       return -1;
75     }
76     
77     if ( alpha < 0 || alpha >= 0.5 )
78       // proportion of observations
79       // to be trimmed at each end of the sorted sample
80     {
81       return -2;
82     }
83     
84     // Input parameters are good. Let's move on.
85     
86     // Insure we use a sample sorted into ascending order.
87     
88     Int_t* indices = new Int_t[n];
89     
90     TMath::Sort(n,x,indices,kFALSE);
91     
92     Double_t* sx = new Double_t[n];
93     
94     for ( Int_t i = 0; i < n; ++i )
95     {
96       sx[i] = x[indices[i]];
97     }
98     delete[] indices;
99     
100     
101     // Number of observations trimmed at each end.
102     
103     Int_t k = TMath::FloorNint(alpha * n);
104     
105     double sum = 0.0;
106     
107     for ( Int_t i = k; i < n - k ; ++i )
108     {
109       sum += sx[i];
110     }
111     
112     tmean = sum / ( n - 2 * k );
113     
114     double t2 = 0.0;
115     
116     for ( Int_t i = k; i < n - k; ++i )
117     {
118       t2 += (sx[i] - tmean) * (sx[i] - tmean);
119     }
120     
121     tvar = (
122             t2 +
123             k * (sx[k] - tmean) * (sx[k] - tmean) +
124             k * (sx[n - k - 1] - tmean) * (sx[n - k - 1] - tmean)
125             ) / (n * n);
126     
127     // get the min and max for the non-rejected values
128     min = DBL_MAX;
129     max = 0.0;
130     
131     for ( Int_t i = k; i < n-k; ++i ) 
132     {
133       min = TMath::Min(min,sx[i]);
134       max = TMath::Max(max,sx[i]);
135     }
136     
137     delete[] sx;
138     
139     return 0;
140   }
141   
142   //___________________________________________________________________________  
143   void SetPaveColor(TPaveText& text, AliMUONVQAChecker::ECheckCode code)
144   {
145     const Int_t INFOCOLOR(3);  // green = INFO
146     const Int_t WARNINGCOLOR(5); // yellow = WARNING
147     const Int_t ERRORCOLOR(6); // pink = ERROR
148     const Int_t FATALCOLOR(2); // red = FATAL
149     
150     if ( code == AliMUONVQAChecker::kInfo ) text.SetFillColor(INFOCOLOR);
151     else if ( code == AliMUONVQAChecker::kWarning ) text.SetFillColor(WARNINGCOLOR);
152     else if ( code ==  AliMUONVQAChecker::kFatal) text.SetFillColor(FATALCOLOR);
153     else text.SetFillColor(ERRORCOLOR);
154   }
155   
156 }
157
158 //__________________________________________________________________
159 AliMUONTrackerQAChecker::AliMUONTrackerQAChecker() : AliMUONVQAChecker()
160 {
161         /// ctor
162 }          
163
164 //__________________________________________________________________
165 AliMUONTrackerQAChecker::~AliMUONTrackerQAChecker() 
166 {
167         /// dtor
168 }
169
170 //__________________________________________________________________
171 AliMUONTrackerQAChecker::AliMUONTrackerQAChecker(const AliMUONTrackerQAChecker& qac) : 
172     AliMUONVQAChecker(qac) 
173 {
174         /// copy ctor 
175 }   
176
177 //______________________________________________________________________________
178 AliMUONVQAChecker::ECheckCode*
179 AliMUONTrackerQAChecker::CheckRecPoints(TObjArray ** list, const AliMUONRecoParam* /*recoParam*/)
180 {
181   /// Check rec points
182   /// Very binary check for the moment. 
183   
184   AliCodeTimerAuto("",0);
185   
186   AliMUONVQAChecker::ECheckCode * rv = new AliMUONVQAChecker::ECheckCode[AliRecoParam::kNSpecies] ; 
187   for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) 
188     rv[specie] =  AliMUONVQAChecker::kInfo; 
189   
190   
191   for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) 
192   {
193     TH1* h = AliQAv1::GetData(list,AliMUONQAIndices::kTrackerNumberOfClustersPerDE,AliRecoParam::ConvertIndex(specie));
194
195     if ( !h ) rv[specie] = AliMUONVQAChecker::kWarning; // only a warning if histo not found, in order not to kill anything because QA failed...
196   
197     else if ( h->GetMean() == 0.0 ) rv[specie] =  MarkHisto(*h,AliMUONVQAChecker::kFatal);
198   }
199   return rv;
200 }
201
202 //______________________________________________________________________________
203 AliMUONVQAChecker::ECheckCode 
204 AliMUONTrackerQAChecker::MarkHisto(TH1& histo, AliMUONVQAChecker::ECheckCode value) const
205 {
206   /// Mark histo as originator of some QA error/warning
207   
208   if ( value != AliMUONVQAChecker::kInfo )
209   {
210     histo.SetBit(AliQAv1::GetQABit());
211   }
212   
213   return value;
214 }
215
216 //______________________________________________________________________________
217 AliMUONVQAChecker::ECheckCode*
218 AliMUONTrackerQAChecker::CheckESD(TObjArray ** list, const AliMUONRecoParam* /*recoParam*/)
219 {
220   /// Check ESD
221   
222   AliCodeTimerAuto("",0);
223   
224   AliMUONVQAChecker::ECheckCode * rv = new AliMUONVQAChecker::ECheckCode[AliRecoParam::kNSpecies] ; 
225   for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) 
226     rv[specie] = AliMUONVQAChecker::kInfo; 
227   
228   for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) {
229     
230     TH1* h = AliQAv1::GetData(list,AliMUONQAIndices::kESDnTracks,AliRecoParam::ConvertIndex(specie));
231   
232     if (!h) rv[specie] = AliMUONVQAChecker::kWarning;
233   
234     else if ( h->GetMean() == 0.0 ) rv[specie] =  MarkHisto(*h,AliMUONVQAChecker::kFatal); // no track -> fatal
235   
236     h = AliQAv1::GetData(list,AliMUONQAIndices::kESDMatchTrig,AliRecoParam::ConvertIndex(specie));
237   
238     if (!h) rv[specie] = AliMUONVQAChecker::kWarning;
239   
240     else if (h->GetMean() == 0.0 ) rv[specie] = MarkHisto(*h,AliMUONVQAChecker::kError); // no trigger matching -> error
241   }
242   return rv;
243 }
244
245 //______________________________________________________________________________
246 AliMUONVQAChecker::ECheckCode*
247 AliMUONTrackerQAChecker::CheckRaws(TObjArray ** list, const AliMUONRecoParam* recoParam)
248 {
249   /// Check raws
250
251   AliCodeTimerAuto("",0);
252   
253   if (!recoParam) return 0x0;
254   
255   AliMUONVQAChecker::ECheckCode * rv = new AliMUONVQAChecker::ECheckCode[AliRecoParam::kNSpecies] ; 
256
257   for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) 
258   {
259     rv[specie] = AliMUONVQAChecker::kInfo; 
260   }
261   
262   for (Int_t specie = 0 ; specie < AliRecoParam::kNSpecies ; specie++) 
263   {
264     TH1* hbp = AliQAv1::GetData(list,AliMUONQAIndices::kTrackerBusPatchOccupancy,AliRecoParam::ConvertIndex(specie));    
265
266     TH1* hnpads = AliQAv1::GetData(list,AliMUONQAIndices::kTrackerBusPatchNofPads,AliRecoParam::ConvertIndex(specie));
267
268     TH1* hbpconfig = AliQAv1::GetData(list,AliMUONQAIndices::kTrackerBusPatchConfig,AliRecoParam::ConvertIndex(specie));
269
270     TH1* hnevents = AliQAv1::GetData(list,AliMUONQAIndices::kTrackerNofRawEventSeen,AliRecoParam::ConvertIndex(specie));
271
272     TH1* hddl = AliQAv1::GetData(list,AliMUONQAIndices::kTrackerDDLOccupancy,AliRecoParam::ConvertIndex(specie));
273
274     TH1* hroe = AliQAv1::GetData(list,AliMUONQAIndices::kTrackerReadoutErrors,AliRecoParam::ConvertIndex(specie));
275
276     TH1* hbuspatchtokenerrors = AliQAv1::GetData(list,AliMUONQAIndices::kTrackerBusPatchTokenLostErrors,AliRecoParam::ConvertIndex(specie));
277     
278     if ( !hbp || !hnpads || !hnevents || !hddl || !hroe || ! hbuspatchtokenerrors ) 
279     {
280       continue;
281     }
282     
283     Int_t nevents = TMath::Nint(hnevents->GetBinContent(1));
284         
285     rv[specie] = BeautifyHistograms(*hddl,*hbp,*hroe,hbpconfig,*hnpads,*hbuspatchtokenerrors,nevents,*recoParam);    
286   }
287   
288   return rv;
289 }
290
291 //____________________________________________________________________________ 
292 AliMUONVQAChecker::ECheckCode
293 AliMUONTrackerQAChecker::BeautifyHistograms(TH1& hddl,
294                                             TH1& hbp, 
295                                             TH1& hroe,
296                                             const TH1* hbuspatchconfig, 
297                                             const TH1& hnpads, 
298                                             const TH1& hbuspatchtokenerrors,
299                                             Int_t nevents,
300                                             const AliMUONRecoParam& recoParam)
301 {
302   /// Put labels, limits and so on on the TrackerBusPatchOccupancy and TrackerReadoutErrors histograms
303   /// hbuspatchconfig and hbp must have the same bin definitions
304   
305   if ( hbuspatchconfig )
306   {
307     if ( hbp.GetNbinsX() != hbuspatchconfig->GetNbinsX() ||
308         hbp.GetXaxis()->GetXmin() != hbuspatchconfig->GetXaxis()->GetXmin() ||
309         hbp.GetXaxis()->GetXmax() != hbuspatchconfig->GetXaxis()->GetXmax() )
310     {
311       AliError("hbp and hbuspatchconfig histograms are not compatible !");
312       return AliMUONVQAChecker::kFatal;
313     }
314   }
315   
316   hbp.SetXTitle("Absolute Bus Patch Id");
317   hbp.SetYTitle("Occupancy (percent)");
318   hbp.SetStats(kFALSE);
319   
320   Double_t xmin = hbp.GetXaxis()->GetXmin();
321   Double_t xmax = hbp.GetXaxis()->GetXmax();
322   
323   Double_t occMax(0.1); // 0.1% y-limit for the plot
324   Double_t maxToleratedOccupancy(recoParam.BuspatchOccupancyHighLimit()*100.0); 
325   Double_t minToleratedOccupancy(recoParam.BuspatchOccupancyLowLimit()*100.0);   
326   TLine* line1 = new TLine(xmin,maxToleratedOccupancy,xmax,maxToleratedOccupancy);
327   line1->SetLineColor(1);
328   line1->SetLineWidth(1);
329
330   TLine* line2 = new TLine(xmin,minToleratedOccupancy,xmax,minToleratedOccupancy);
331   line2->SetLineColor(1);
332   line2->SetLineWidth(1);
333   
334   hbp.GetListOfFunctions()->Add(line1);
335   hbp.GetListOfFunctions()->Add(line2);
336     
337   TIter next(AliMpDDLStore::Instance()->CreateBusPatchIterator());
338   AliMpBusPatch* bp(0x0);
339
340   Int_t nMissingPads(0);
341   Int_t nPads(0);
342   Int_t nBusPatches(0);
343   Int_t nMissingBusPatches(0);
344   
345   while ( ( bp = static_cast<AliMpBusPatch*>(next())) )
346   {
347     Int_t bin = hbp.FindBin(bp->GetId());
348     Int_t n = TMath::Nint(hnpads.GetBinContent(bin));
349     
350     ++nBusPatches;
351     
352     nPads += n;
353     
354     if ( hbp.GetBinContent(bin) <= 0 ) 
355     {
356       nMissingPads += n;
357       ++nMissingBusPatches;
358     }
359   }
360   
361   next.Reset();
362   
363   Int_t ok(-1);
364   Int_t n(0);
365   Int_t nBusPatchesAboveLimit(0);
366   Int_t nBusPatchesBelowLimit(0);
367   Double_t alpha(0.1); // trim 10% of data
368   Double_t tmean(0.0),tvar(0.0);
369   Double_t ymin(0.0),ymax(0.0);
370   AliMUONVQAChecker::ECheckCode rv(AliMUONVQAChecker::kFatal); // default value = serious problem
371   
372   if ( nBusPatches ) 
373   {
374     Double_t* x = new Double_t[nBusPatches];
375     
376     while ( ( bp = static_cast<AliMpBusPatch*>(next())) )
377     {
378       Int_t bin = hbp.FindBin(bp->GetId());
379       if ( hbp.GetBinContent(bin) > 0 )
380       {
381         x[n] = hbp.GetBinContent(bin);
382         ++n;
383       }
384       if ( hbp.GetBinContent(bin) > maxToleratedOccupancy )
385       {
386         ++nBusPatchesAboveLimit;
387       }
388       if ( hbp.GetBinContent(bin) < minToleratedOccupancy )
389       {
390         // check whether this buspatch has a reason to be absent (only valid
391         // if we got the config, otherwise we cannot do the test)
392         if ( hbuspatchconfig && hbuspatchconfig->GetBinContent(bin) > 0 )
393         {
394           // should be there, so it's an error
395           ++nBusPatchesBelowLimit;
396         }
397       }
398     }
399     
400     // computed the truncated mean of the occupancy values, in order to get a 
401     // reasonable y-range for the histogram (without giant peaks to the roof 
402     // for misbehaving buspatches).
403     ok = trim(n,x,alpha,tmean,tvar,ymin,ymax);
404     
405     delete[] x;
406   }
407   
408   if ( ok < 0 ) 
409   {
410     ymax = occMax;
411   }
412   else
413   {
414     ymax = TMath::Max(ymax,occMax);
415   }
416   
417   hbp.SetMaximum(ymax*1.4);
418   
419   TPaveText* text = new TPaveText(0.30,0.50,0.99,0.99,"NDC");
420   
421   text->AddText(Form("MCH RUN %d - %d events",AliCDBManager::Instance()->GetRun(),nevents));
422   
423   if ( ok < 0 ) 
424   {
425     text->AddText("Could not compute truncated mean. Not enough events ?");
426     text->AddText(Form("nBusPatches=%d n=%d",nBusPatches,n));
427   }
428   else if (!nPads || !nBusPatches)
429   {
430     text->AddText(Form("Could not get the total number of pads (%d) or total number of buspatches (%d). ERROR !!!",
431                        nPads,nBusPatches));
432   }
433   else
434   {
435     Float_t missingPadFraction = nMissingPads*100.0/nPads;
436     Float_t missingBusPatchFraction = nMissingBusPatches*100.0/nBusPatches;
437     Float_t aboveLimitFraction = nBusPatchesAboveLimit*100.0/nBusPatches;
438     Float_t belowLimitFraction = nBusPatchesBelowLimit*100.0/nBusPatches;
439     
440     text->AddText(Form("%5.2f %% of missing buspatches (%d out of %d)",missingBusPatchFraction,nMissingBusPatches,nBusPatches));
441     text->AddText(Form("%5.2f %% of missing pads (%d out of %d)",missingPadFraction,nMissingPads,nPads));
442     text->AddText(Form("%5.2f %% bus patches above the %5.2f %% limit",aboveLimitFraction,maxToleratedOccupancy));
443     text->AddText(Form("%5.2f %% bus patches below the %e %% limit",belowLimitFraction,minToleratedOccupancy));
444     text->AddText(Form("Bus patch mean occupancy (truncated at %2d %%) is %7.2f %%",(Int_t)(alpha*100),tmean));
445     
446     if ( missingPadFraction >= 100.0 ) 
447     {
448       rv = AliMUONVQAChecker::kFatal;       
449     }
450     
451     else if ( missingPadFraction > recoParam.MissingPadFractionLimit()*100.0 || 
452              aboveLimitFraction > recoParam.FractionOfBuspatchOutsideOccupancyLimit()*100.0 || 
453              belowLimitFraction > recoParam.FractionOfBuspatchOutsideOccupancyLimit()*100.0 ) 
454     {
455       rv = AliMUONVQAChecker::kError;
456     }
457     else
458     {
459       rv = AliMUONVQAChecker::kInfo;
460     }
461   }
462   
463   hbp.GetListOfFunctions()->Add(text);
464   
465   
466   SetPaveColor(*text,rv);
467
468   /// Make as well a version for DDL occupancy, that'll be used by the shifter
469   
470   hddl.GetListOfFunctions()->Add(text->Clone());
471   
472   Bool_t aboveOnePercent(kFALSE);
473   Bool_t aboveTwoPercent(kFALSE);
474   
475   for ( Int_t i = 1; i <= hddl.GetXaxis()->GetNbins(); ++i )
476   {
477     Double_t b = hddl.GetBinContent(i);
478     if ( b > 1.0 ) aboveOnePercent = kTRUE;
479     if ( b > 2.0 ) aboveTwoPercent = kTRUE;
480     
481   }
482   
483   hddl.SetMaximum(2);
484   hddl.SetFillStyle(0);
485   if ( aboveOnePercent ) 
486   {
487     hddl.SetFillStyle(1001);
488     hddl.SetFillColor(kOrange);    
489   }
490   if ( aboveTwoPercent ) 
491   {
492     hddl.SetFillStyle(1001);
493     hddl.SetFillColor(kRed);
494   }
495   hddl.SetLineWidth(3);
496   hddl.SetStats(kFALSE);
497   
498   /// Finally make another pavetext for readout errors, in particular TokenLost ones !
499   
500   Double_t tokenLost = hroe.GetBinContent(hroe.FindBin(1.0*AliMUONQAIndices::kTrackerRawNofTokenLostErrors));
501   
502   AliInfo(Form("tokenLost=%e",tokenLost));
503   
504   if ( tokenLost > 0 )
505   {
506     TPaveText* errText = new TPaveText(0.30,0.50,0.9,0.9,"NDC");
507     
508     errText->AddText(Form("MCH RUN %d - %d events",AliCDBManager::Instance()->GetRun(),nevents));
509     errText->AddText("There are some token lost errors !");
510     errText->AddText("PLEASE CHECK THE BUSY TIME FOR MUON !");
511     errText->AddText("If above 5 ms please have the MUON expert");
512     errText->AddText("check the following bus patches :");
513     
514     for ( Int_t i = 1; i <= hbuspatchtokenerrors.GetNbinsX(); ++i ) 
515     {
516       if ( hbuspatchtokenerrors.GetBinContent(i) > 0 ) 
517       {
518         errText->AddText(Form("BP %4d",i));
519       }
520     }
521     
522     hroe.GetListOfFunctions()->Add(errText);
523
524     rv = AliMUONVQAChecker::kFatal;
525     
526     SetPaveColor(*errText,rv);
527   }
528   
529   return rv;
530 }