1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
22 This update should solve two problems mainly:
23 * The vs event histograms have been limited to a fixed size for the
24 DQM. The 500k seemed to be a big size but is no longer so, so we
25 need to dynamically expand the range. The non-trivial point is that
26 we also have to do it for the copy owned by AliTPCQADataMakerRec.
27 * The amoreGui now remembers the x-range of the first visualization so
28 the trick of setting the relevant event range as the histogram is
29 filled no longer works.
31 The fix is a bit crude but avoids creating a new histogram. Instead
32 the range is expanded (max events and events per bin is doubled) but
33 the number of bins is kept constant! In this way we can change just
34 double the max of the X-axis of the hist and rebin the data. The
35 same can easily be done for the copy owned by AliTPCQADataMakerRec.
38 If we change the number of bins we could crash the whole system
39 because ROOT does not create space for extra bins! (but we do not do
40 this). In that way it is a crude solution.
41 The rebinning in the code only works for an even number of bins.
43 In addition to the above a bug in the reading of the config file was
44 also found and corrected. fAdcMax was set instead of fEventsPerBin.
46 Finally cout was changes to AliInfo.
50 The code has been heavily modified so that now the RAW data is
51 "expanded" for each sector and stored in a big signal array. Then a
52 simple version of the code in AliTPCclustererMI is used to identify
53 the local maxima and these are then used for QA. This gives a better
54 estimate of the charge (both max and total) and also limits the
59 In Update the RAW signals >= 3 ADC channels are stored in the arrays.
62 Float_t** fAllBins 2d array [row][bin(pad, time)] ADC signal
63 Int_t** fAllSigBins 2d array [row][signal#] bin(with signal)
64 Int_t* fAllNSigBins; 1d array [row] Nsignals
66 This is done sector by sector.
68 When data from a new sector is encountered, the method
69 FindLocalMaxima is called on the data from the previous sector, and
70 the calibration/data objects are updated with the "cluster"
71 info. Finally the arrays are cleared.
73 The requirements for a local maxima is:
74 Charge in bin is >= 5 ADC channels.
75 Charge in bin is larger than all the 8 neighboring bins.
76 At least one of the two pad neighbors has a signal.
77 At least one of the two time neighbors has a signal.
79 Before accessing the data it is expected that the Analyse method is
80 called. This normalizes some of the data objects to per event or per
82 If more data is passed to the class after Analyse has been called
83 the normalization is reversed and Analyse has to be called again.
92 #include <TDirectory.h>
98 #include "AliRawReader.h"
99 #include "AliRawReaderRoot.h"
100 #include "AliRawReaderDate.h"
101 #include "AliTPCRawStream.h"
102 #include "AliTPCRawStreamV3.h"
103 #include "AliTPCCalROC.h"
104 #include "AliTPCROC.h"
105 #include "AliMathBase.h"
106 #include "TTreeStream.h"
110 #include "AliTPCCalPad.h"
111 #include "AliTPCPreprocessorOnline.h"
114 #include "AliTPCdataQA.h"
117 ClassImp(AliTPCdataQA)
119 AliTPCdataQA::AliTPCdataQA() : /*FOLD00*/
137 fHistQVsTimeSideA(0),
138 fHistQVsTimeSideC(0),
139 fHistQMaxVsTimeSideA(0),
140 fHistQMaxVsTimeSideC(0),
141 fHistOccupancyVsEvent(0),
142 fHistNclustersVsEvent(0),
145 fMaxEvents(500000), // Max events for event histograms
146 fEventsPerBin(1000), // Events per bin for event histograms
147 fSignalCounter(0), // Signal counter
148 fClusterCounter(0), // Cluster counter
157 // default constructor
161 //_____________________________________________________________________
162 AliTPCdataQA::AliTPCdataQA(AliRecoParam::EventSpecie_t es) :
180 fHistQVsTimeSideA(0),
181 fHistQVsTimeSideC(0),
182 fHistQMaxVsTimeSideA(0),
183 fHistQMaxVsTimeSideC(0),
184 fHistOccupancyVsEvent(0),
185 fHistNclustersVsEvent(0),
199 // ctor creating the histogram
200 char * name = Form("TPCRAW_%s", AliRecoParam::GetEventSpecieName(es)) ;
201 TH1F(name, name,100,0,100) ;
204 //_____________________________________________________________________
205 AliTPCdataQA::AliTPCdataQA(const AliTPCdataQA &ped) : /*FOLD00*/
207 fFirstTimeBin(ped.GetFirstTimeBin()),
208 fLastTimeBin(ped.GetLastTimeBin()),
209 fAdcMin(ped.GetAdcMin()),
210 fAdcMax(ped.GetAdcMax()),
224 fHistQVsTimeSideA(0),
225 fHistQVsTimeSideC(0),
226 fHistQMaxVsTimeSideA(0),
227 fHistQMaxVsTimeSideC(0),
228 fHistOccupancyVsEvent(0),
229 fHistNclustersVsEvent(0),
230 fEventCounter(ped.GetEventCounter()),
231 fIsAnalysed(ped.GetIsAnalysed()),
232 fMaxEvents(ped.GetMaxEvents()),
233 fEventsPerBin(ped.GetEventsPerBin()),
234 fSignalCounter(ped.GetSignalCounter()),
235 fClusterCounter(ped.GetClusterCounter()),
246 if(ped.GetNLocalMaxima())
247 fNLocalMaxima = new AliTPCCalPad(*ped.GetNLocalMaxima());
248 if(ped.GetMaxCharge())
249 fMaxCharge = new AliTPCCalPad(*ped.GetMaxCharge());
250 if(ped.GetMeanCharge())
251 fMeanCharge = new AliTPCCalPad(*ped.GetMeanCharge());
252 if(ped.GetNoThreshold())
253 fNoThreshold = new AliTPCCalPad(*ped.GetNoThreshold());
254 if(ped.GetNTimeBins())
255 fNTimeBins = new AliTPCCalPad(*ped.GetNTimeBins());
257 fNPads = new AliTPCCalPad(*ped.GetNPads());
258 if(ped.GetTimePosition())
259 fTimePosition = new AliTPCCalPad(*ped.GetTimePosition());
260 if(ped.GetOverThreshold10())
261 fOverThreshold10 = new AliTPCCalPad(*ped.GetOverThreshold10());
262 if(ped.GetOverThreshold20())
263 fOverThreshold20 = new AliTPCCalPad(*ped.GetOverThreshold20());
264 if(ped.GetOverThreshold30())
265 fOverThreshold30 = new AliTPCCalPad(*ped.GetOverThreshold30());
266 if(ped.GetHistQVsTimeSideA()) {
267 fHistQVsTimeSideA = new TProfile(*ped.GetHistQVsTimeSideA());
268 fHistQVsTimeSideA->SetDirectory(0);
270 if(ped.GetHistQVsTimeSideC()) {
271 fHistQVsTimeSideC = new TProfile(*ped.GetHistQVsTimeSideC());
272 fHistQVsTimeSideC->SetDirectory(0);
274 if(ped.GetHistQMaxVsTimeSideA()) {
275 fHistQMaxVsTimeSideA = new TProfile(*ped.GetHistQMaxVsTimeSideA());
276 fHistQMaxVsTimeSideA->SetDirectory(0);
278 if(ped.GetHistQMaxVsTimeSideC()) {
279 fHistQMaxVsTimeSideC = new TProfile(*ped.GetHistQMaxVsTimeSideC());
280 fHistQMaxVsTimeSideC->SetDirectory(0);
282 if(ped.GetHistOccupancyVsEventConst()) {
283 fHistOccupancyVsEvent = new TH1F(*ped.GetHistOccupancyVsEventConst());
284 fHistOccupancyVsEvent->SetDirectory(0);
286 if(ped.GetHistNclustersVsEventConst()) {
287 fHistNclustersVsEvent = new TH1F(*ped.GetHistNclustersVsEventConst());
288 fHistNclustersVsEvent->SetDirectory(0);
292 //_____________________________________________________________________
293 AliTPCdataQA::AliTPCdataQA(const TMap *config) : /*FOLD00*/
294 TH1F("TPCRAW","TPCRAW",100,0,100),
312 fHistQVsTimeSideA(0),
313 fHistQVsTimeSideC(0),
314 fHistQMaxVsTimeSideA(0),
315 fHistQMaxVsTimeSideC(0),
316 fHistOccupancyVsEvent(0),
317 fHistNclustersVsEvent(0),
332 // default constructor
334 if (config->GetValue("FirstTimeBin")) fFirstTimeBin = ((TObjString*)config->GetValue("FirstTimeBin"))->GetString().Atoi();
335 if (config->GetValue("LastTimeBin")) fLastTimeBin = ((TObjString*)config->GetValue("LastTimeBin"))->GetString().Atoi();
336 if (config->GetValue("AdcMin")) fAdcMin = ((TObjString*)config->GetValue("AdcMin"))->GetString().Atoi();
337 if (config->GetValue("AdcMax")) fAdcMax = ((TObjString*)config->GetValue("AdcMax"))->GetString().Atoi();
338 if (config->GetValue("MaxEvents")) fMaxEvents = ((TObjString*)config->GetValue("MaxEvents"))->GetString().Atoi();
339 if (config->GetValue("EventsPerBin")) fEventsPerBin = ((TObjString*)config->GetValue("EventsPerBin"))->GetString().Atoi();
342 //_____________________________________________________________________
343 AliTPCdataQA& AliTPCdataQA::operator = (const AliTPCdataQA &source)
346 // assignment operator
348 if (&source == this) return *this;
349 new (this) AliTPCdataQA(source);
355 //_____________________________________________________________________
356 AliTPCdataQA::~AliTPCdataQA() /*FOLD00*/
362 // do not delete fMapping, because we do not own it.
363 // do not delete fMapping, because we do not own it.
364 // do not delete fNoise and fPedestal, because we do not own them.
366 delete fNLocalMaxima;
372 delete fTimePosition;
373 delete fOverThreshold10;
374 delete fOverThreshold20;
375 delete fOverThreshold30;
376 delete fHistQVsTimeSideA;
377 delete fHistQVsTimeSideC;
378 delete fHistQMaxVsTimeSideA;
379 delete fHistQMaxVsTimeSideC;
380 delete fHistOccupancyVsEvent;
381 delete fHistNclustersVsEvent;
383 for (Int_t iRow = 0; iRow < fRowsMax; iRow++) {
384 delete [] fAllBins[iRow];
385 delete [] fAllSigBins[iRow];
388 delete [] fAllSigBins;
389 delete [] fAllNSigBins;
392 //_____________________________________________________________________
393 TH1F* AliTPCdataQA::GetHistOccupancyVsEvent()
396 // Create Occupancy vs event histogram
397 // (we create this histogram differently then the other histograms
398 // because this we want to be able to access and copy
399 // from AliTPCQAMakerRec before it normally would be created)
401 if(!fHistOccupancyVsEvent) {
403 Int_t nBins = fMaxEvents/fEventsPerBin;
404 fHistOccupancyVsEvent = new TH1F("hOccupancyVsEvent", "Occupancy vs event number (~time); Event number; Occupancy", nBins, 0, nBins*fEventsPerBin);
405 fHistOccupancyVsEvent->SetDirectory(0);
408 return fHistOccupancyVsEvent;
411 //_____________________________________________________________________
412 TH1F* AliTPCdataQA::GetHistNclustersVsEvent()
415 // Create Nclusters vs event histogram
416 // (we create this histogram differently then the other histograms
417 // because this we want to be able to access and copy
418 // from AliTPCQAMakerRec before it normally would be created)
420 if(!fHistNclustersVsEvent) {
422 Int_t nBins = fMaxEvents/fEventsPerBin;
423 fHistNclustersVsEvent = new TH1F("hNclustersVsEvent", "Nclusters vs event number (~time); Event number; Nclusters per event", nBins, 0, nBins*fEventsPerBin);
424 fHistNclustersVsEvent->SetDirectory(0);
427 return fHistNclustersVsEvent;
430 //_____________________________________________________________________
431 void AliTPCdataQA::UpdateEventHistograms()
433 // Update histograms that display occupancy and
434 // number of clusters as a function of number of
436 if (!fHistOccupancyVsEvent)
437 GetHistOccupancyVsEvent();
438 if (!fHistNclustersVsEvent)
439 GetHistNclustersVsEvent();
441 if(fEventCounter > fMaxEvents) {
443 // we have to expand the histogram to handle the larger number of
444 // events. The way it is done now is to double the range and the
445 // number of events per bin (so the number of histogram bins stays
450 // Change histogram limits
451 const Int_t nBins = fHistOccupancyVsEvent->GetXaxis()->GetNbins();
452 fHistOccupancyVsEvent->GetXaxis()->Set(nBins, fHistOccupancyVsEvent->GetXaxis()->GetNbins(), fMaxEvents);
453 fHistNclustersVsEvent->GetXaxis()->Set(nBins, fHistNclustersVsEvent->GetXaxis()->GetNbins(), fMaxEvents);
455 // Rebin the histogram
456 for(Int_t bin = 1; bin <= nBins; bin+=2) {
458 Int_t newBin = TMath::Nint(Float_t(bin+1)/2.0);
459 Float_t newContent = (fHistOccupancyVsEvent->GetBinContent(bin)+
460 fHistOccupancyVsEvent->GetBinContent(bin+1))/2.0;
461 fHistOccupancyVsEvent->SetBinContent(newBin, newContent);
463 newContent = (fHistNclustersVsEvent->GetBinContent(bin)+
464 fHistNclustersVsEvent->GetBinContent(bin+1))/2.0;
465 fHistNclustersVsEvent->SetBinContent(newBin, newContent);
468 // Set the remaining bins to 0
469 Int_t lastHalf = nBins/2 +1;
470 for(Int_t bin = lastHalf; bin <= nBins; bin++) {
472 fHistOccupancyVsEvent->SetBinContent(bin, 0);
473 fHistNclustersVsEvent->SetBinContent(bin, 0);
476 // In this case we should nut update but wait untill the new
477 // number of events per bin is reached!
481 const Int_t bin = TMath::Nint(Float_t(fEventCounter)/fEventsPerBin);
483 Float_t averageOccupancy =
484 Float_t(fSignalCounter)/fEventsPerBin/(fLastTimeBin - fFirstTimeBin +1.0)
485 / 570132.0; // 570,132 is number of pads
486 fHistOccupancyVsEvent->SetBinContent(bin, averageOccupancy);
489 Float_t averageNclusters =
490 Float_t(fClusterCounter)/fEventsPerBin;
491 fHistNclustersVsEvent->SetBinContent(bin, averageNclusters);
495 //_____________________________________________________________________
496 Bool_t AliTPCdataQA::ProcessEvent(AliTPCRawStreamV3 *const rawStreamV3)
499 // Event Processing loop - AliTPCRawStreamV3
501 Bool_t withInput = kFALSE;
503 Int_t lastSector = -1;
505 while ( rawStreamV3->NextDDL() ){
507 while ( rawStreamV3->NextChannel() ){
509 Int_t iSector = rawStreamV3->GetSector(); // current sector
510 Int_t iRow = rawStreamV3->GetRow(); // current row
511 Int_t iPad = rawStreamV3->GetPad(); // current pad
512 if (iRow<0 || iPad<0) continue;
513 // Call local maxima finder if the data is in a new sector
514 if(iSector != lastSector) {
517 FindLocalMaxima(lastSector);
520 lastSector = iSector;
524 while ( rawStreamV3->NextBunch() ){
526 Int_t startTbin = (Int_t)rawStreamV3->GetStartTimeBin();
527 Int_t bunchlength = (Int_t)rawStreamV3->GetBunchLength();
528 const UShort_t *sig = rawStreamV3->GetSignals();
530 for (Int_t iTimeBin = 0; iTimeBin<bunchlength; iTimeBin++){
531 Float_t signal=(Float_t)sig[iTimeBin];
532 nSignals += Update(iSector,iRow,iPad,startTbin--,signal);
539 if (lastSector>=0&&nSignals>0)
540 FindLocalMaxima(lastSector);
545 //_____________________________________________________________________
546 Bool_t AliTPCdataQA::ProcessEvent(AliRawReader *const rawReader)
549 // Event processing loop - AliRawReader
551 AliTPCRawStreamV3 rawStreamV3(rawReader, (AliAltroMapping**)fMapping);
552 Bool_t res=ProcessEvent(&rawStreamV3);
554 fEventCounter++; // only increment event counter if there is TPC data
556 if(fEventCounter%fEventsPerBin==0)
557 UpdateEventHistograms();
562 //_____________________________________________________________________
563 Bool_t AliTPCdataQA::ProcessEvent(AliTPCRawStream *const rawStream)
566 // Event Processing loop - AliTPCRawStream
569 Bool_t withInput = kFALSE;
571 Int_t lastSector = -1;
573 while (rawStream->Next()) {
575 Int_t iSector = rawStream->GetSector(); // current ROC
576 Int_t iRow = rawStream->GetRow(); // current row
577 Int_t iPad = rawStream->GetPad(); // current pad
578 Int_t iTimeBin = rawStream->GetTime(); // current time bin
579 Float_t signal = rawStream->GetSignal(); // current ADC signal
581 // Call local maxima finder if the data is in a new sector
582 if(iSector != lastSector) {
585 FindLocalMaxima(lastSector);
588 lastSector = iSector;
592 // Sometimes iRow==-1 if there is problems to read the data
594 nSignals += Update(iSector,iRow,iPad,iTimeBin,signal);
599 if (lastSector>=0&&nSignals>0)
600 FindLocalMaxima(lastSector);
606 //_____________________________________________________________________
607 Bool_t AliTPCdataQA::ProcessEventOld(AliRawReader *const rawReader)
610 // Event processing loop - AliRawReader
613 // if fMapping is NULL the rawstream will crate its own mapping
614 AliTPCRawStream rawStream(rawReader, (AliAltroMapping**)fMapping);
615 rawReader->Select("TPC");
616 Bool_t res = ProcessEvent(&rawStream);
619 fEventCounter++; // only increment event counter if there is TPC data
620 // otherwise Analyse (called in QA) fails
625 //_____________________________________________________________________
626 Bool_t AliTPCdataQA::ProcessEvent(eventHeaderStruct *const event)
629 // process date event
632 AliRawReaderDate rawReader((void*)event);
633 Bool_t result=ProcessEvent(&rawReader);
639 //_____________________________________________________________________
640 void AliTPCdataQA::DumpToFile(const Char_t *filename, const Char_t *dir, Bool_t append) /*FOLD00*/
643 // Write class to file
654 TDirectory *backup = gDirectory;
655 TFile f(filename,option.Data());
657 if ( !sDir.IsNull() ){
658 f.mkdir(sDir.Data());
664 if ( backup ) backup->cd();
668 //_____________________________________________________________________
669 Int_t AliTPCdataQA::Update(const Int_t iSector, /*FOLD00*/
672 const Int_t iTimeBin,
676 // Signal filling method
680 // Define the calibration objects the first time Update is called
681 // NB! This has to be done first even if the data is rejected by the time
682 // cut to make sure that the objects are available in Analyse
684 if (!fNLocalMaxima) fNLocalMaxima = new AliTPCCalPad("NLocalMaxima","NLocalMaxima");
685 if (!fMaxCharge) fMaxCharge = new AliTPCCalPad("MaxCharge","MaxCharge");
686 if (!fMeanCharge) fMeanCharge = new AliTPCCalPad("MeanCharge","MeanCharge");
687 if (!fNoThreshold) fNoThreshold = new AliTPCCalPad("NoThreshold","NoThreshold");
688 if (!fNTimeBins) fNTimeBins = new AliTPCCalPad("NTimeBins","NTimeBins");
689 if (!fNPads) fNPads = new AliTPCCalPad("NPads","NPads");
690 if (!fTimePosition) fTimePosition = new AliTPCCalPad("TimePosition","TimePosition");
691 if (!fOverThreshold10) fOverThreshold10 = new AliTPCCalPad("OverThreshold10","OverThreshold10");
692 if (!fOverThreshold20) fOverThreshold20 = new AliTPCCalPad("OverThreshold20","OverThreshold20");
693 if (!fOverThreshold30) fOverThreshold30 = new AliTPCCalPad("OverThreshold30","OverThreshold30");
694 if (!fHistQVsTimeSideA) {
695 fHistQVsTimeSideA = new TProfile("hQVsTimeSideA", "Q vs time (side A); Time [Timebin]; Q [ADC ch]", 100, 0, 1000);
696 fHistQVsTimeSideA->SetDirectory(0);
698 if (!fHistQVsTimeSideC) {
699 fHistQVsTimeSideC = new TProfile("hQVsTimeSideC", "Q vs time (side C); Time [Timebin]; Q [ADC ch]", 100, 0, 1000);
700 fHistQVsTimeSideC->SetDirectory(0);
702 if (!fHistQMaxVsTimeSideA) {
703 fHistQMaxVsTimeSideA = new TProfile("hQMaxVsTimeSideA", "Q_{MAX} vs time (side A); Time [Timebin]; Q_{MAX} [ADC ch]", 100, 0, 1000);
704 fHistQMaxVsTimeSideA->SetDirectory(0);
706 if (!fHistQMaxVsTimeSideC) {
707 fHistQMaxVsTimeSideC = new TProfile("hQMaxVsTimeSideC", "Q_{MAX} vs time (side C); Time [Timebin]; Q_{MAX} [ADC ch]", 100, 0, 1000);
708 fHistQMaxVsTimeSideC->SetDirectory(0);
711 // Make the arrays for expanding the data
717 // If Analyse has been previously called we need now to denormalize the data
718 // as more data is coming
720 if(fIsAnalysed == kTRUE) {
722 const Int_t nTimeBins = fLastTimeBin - fFirstTimeBin +1;
723 const Float_t denormalization = Float_t(fEventCounter * nTimeBins);
724 fNoThreshold->Multiply(denormalization);
726 fMeanCharge->Multiply(fNLocalMaxima);
727 fMaxCharge->Multiply(fNLocalMaxima);
728 fNTimeBins->Multiply(fNLocalMaxima);
729 fNPads->Multiply(fNLocalMaxima);
730 fTimePosition->Multiply(fNLocalMaxima);
731 fIsAnalysed = kFALSE;
737 if (iTimeBin<fFirstTimeBin) return 0;
738 if (iTimeBin>fLastTimeBin) return 0;
740 // if pedestal calibrations are loaded subtract pedestals
743 Float_t ped = fPedestal->GetCalROC(iSector)->GetValue(iRow, iPad);
744 // Don't use data from pads where pedestals are abnormally small or large
750 // In fNoThreshold we fill all data to estimate the ZS volume
751 Float_t count = fNoThreshold->GetCalROC(iSector)->GetValue(iRow, iPad);
752 fNoThreshold->GetCalROC(iSector)->SetValue(iRow, iPad,count+1);
754 // Require at least 3 ADC channels
758 // if noise calibrations are loaded require at least 3*sigmaNoise
761 Float_t noise = fNoise->GetCalROC(iSector)->GetValue(iRow, iPad);
763 if(signal < noise*3.0)
768 // This signal is ok and we store it in the cluster map
771 SetExpandDigit(iRow, iPad, iTimeBin, signal);
775 return 1; // signal was accepted
778 //_____________________________________________________________________
779 void AliTPCdataQA::FindLocalMaxima(const Int_t iSector)
782 // This method is called after the data from each sector has been
783 // exapanded into an array
784 // Loop over the signals and identify local maxima and fill the
785 // calibration objects with the information
788 Int_t nLocalMaxima = 0;
789 const Int_t maxTimeBin = fTimeBinsMax+4; // Used to step between neighboring pads
790 // Because we have tha pad-time data in a
793 for (Int_t iRow = 0; iRow < fRowsMax; iRow++) {
795 Float_t* allBins = fAllBins[iRow];
796 Int_t* sigBins = fAllSigBins[iRow];
797 const Int_t nSigBins = fAllNSigBins[iRow];
799 for (Int_t iSig = 0; iSig < nSigBins; iSig++) {
801 Int_t bin = sigBins[iSig];
802 Float_t *b = &allBins[bin];
805 // Now we check if this is a local maximum
810 // First check that the charge is bigger than the threshold
814 // Require at least one neighboring pad with signal
815 if (b[-maxTimeBin]+b[maxTimeBin]<=0) continue;
817 // Require at least one neighboring time bin with signal
818 if (b[-1]+b[1]<=0) continue;
821 // Check that this is a local maximum
822 // Note that the checking is done so that if 2 charges has the same
823 // qMax then only 1 cluster is generated
824 // (that is why there is BOTH > and >=)
826 if (b[-maxTimeBin] >= qMax) continue;
827 if (b[-1 ] >= qMax) continue;
828 if (b[+maxTimeBin] > qMax) continue;
829 if (b[+1 ] > qMax) continue;
830 if (b[-maxTimeBin-1] >= qMax) continue;
831 if (b[+maxTimeBin-1] >= qMax) continue;
832 if (b[+maxTimeBin+1] > qMax) continue;
833 if (b[-maxTimeBin+1] >= qMax) continue;
836 // Now we accept the local maximum and fill the calibration/data objects
840 Int_t iPad, iTimeBin;
841 GetPadAndTimeBin(bin, iPad, iTimeBin);
843 Float_t count = fNLocalMaxima->GetCalROC(iSector)->GetValue(iRow, iPad);
844 fNLocalMaxima->GetCalROC(iSector)->SetValue(iRow, iPad, count+1);
846 count = fTimePosition->GetCalROC(iSector)->GetValue(iRow, iPad);
847 fTimePosition->GetCalROC(iSector)->SetValue(iRow, iPad, count+iTimeBin);
849 Float_t charge = fMaxCharge->GetCalROC(iSector)->GetValue(iRow, iPad);
850 fMaxCharge->GetCalROC(iSector)->SetValue(iRow, iPad, charge + qMax);
853 count = fOverThreshold10->GetCalROC(iSector)->GetValue(iRow, iPad);
854 fOverThreshold10->GetCalROC(iSector)->SetValue(iRow, iPad, count+1);
857 count = fOverThreshold20->GetCalROC(iSector)->GetValue(iRow, iPad);
858 fOverThreshold20->GetCalROC(iSector)->SetValue(iRow, iPad, count+1);
861 count = fOverThreshold30->GetCalROC(iSector)->GetValue(iRow, iPad);
862 fOverThreshold30->GetCalROC(iSector)->SetValue(iRow, iPad, count+1);
866 // Calculate the total charge as the sum over the region:
874 // with qmax at the center C.
876 // The inner charge (i) we always add, but we only add the outer
877 // charge (o) if the neighboring inner bin (i) has a signal.
879 Int_t minP = 0, maxP = 0, minT = 0, maxT = 0;
881 for(Int_t i = -1; i<=1; i++) {
882 for(Int_t j = -1; j<=1; j++) {
887 Float_t charge1 = GetQ(b, i, j, maxTimeBin, minT, maxT, minP, maxP);
890 // see if the next neighbor is also above threshold
892 qTot += GetQ(b, 2*i, 2*j, maxTimeBin, minT, maxT, minP, maxP);
894 // we are in a diagonal corner
895 qTot += GetQ(b, i, 2*j, maxTimeBin, minT, maxT, minP, maxP);
896 qTot += GetQ(b, 2*i, j, maxTimeBin, minT, maxT, minP, maxP);
897 qTot += GetQ(b, 2*i, 2*j, maxTimeBin, minT, maxT, minP, maxP);
903 charge = fMeanCharge->GetCalROC(iSector)->GetValue(iRow, iPad);
904 fMeanCharge->GetCalROC(iSector)->SetValue(iRow, iPad, charge + qTot);
906 count = fNTimeBins->GetCalROC(iSector)->GetValue(iRow, iPad);
907 fNTimeBins->GetCalROC(iSector)->SetValue(iRow, iPad, count + maxT-minT+1);
909 count = fNPads->GetCalROC(iSector)->GetValue(iRow, iPad);
910 fNPads->GetCalROC(iSector)->SetValue(iRow, iPad, count + maxP-minP+1);
912 if((iSector%36)<18) { // A side
913 fHistQVsTimeSideA->Fill(iTimeBin, qTot);
914 fHistQMaxVsTimeSideA->Fill(iTimeBin, qMax);
916 fHistQVsTimeSideC->Fill(iTimeBin, qTot);
917 fHistQMaxVsTimeSideC->Fill(iTimeBin, qMax);
919 } // end loop over signals
920 } // end loop over rows
922 fClusterCounter += nLocalMaxima;
925 //_____________________________________________________________________
926 void AliTPCdataQA::Analyse()
929 // Calculate calibration constants
932 AliInfo("Analyse called");
934 if(fIsAnalysed == kTRUE) {
936 AliInfo("No new data since Analyse was called last time");
940 if(fEventCounter==0) {
942 AliInfo("EventCounter == 0, Cannot analyse");
946 Int_t nTimeBins = fLastTimeBin - fFirstTimeBin +1;
947 AliInfo(Form("EventCounter: %d , TimeBins: %d", fEventCounter, nTimeBins));
949 Float_t normalization = 1.0 / Float_t(fEventCounter * nTimeBins);
950 fNoThreshold->Multiply(normalization);
952 fMeanCharge->Divide(fNLocalMaxima);
953 fMaxCharge->Divide(fNLocalMaxima);
954 fNTimeBins->Divide(fNLocalMaxima);
955 fNPads->Divide(fNLocalMaxima);
956 fTimePosition->Divide(fNLocalMaxima);
962 //_____________________________________________________________________
963 void AliTPCdataQA::MakeTree(const char *fname) const {
965 // Export result to the tree -located in the file
966 // This file can be analyzed using AliTPCCalibViewer
968 AliTPCPreprocessorOnline preprocesor;
970 if (fNLocalMaxima) preprocesor.AddComponent(fNLocalMaxima);
971 if (fMaxCharge) preprocesor.AddComponent(fMaxCharge);
972 if (fMeanCharge) preprocesor.AddComponent(fMeanCharge);
973 if (fNoThreshold) preprocesor.AddComponent(fNoThreshold);
974 if (fNTimeBins) preprocesor.AddComponent(fNTimeBins);
975 if (fNPads) preprocesor.AddComponent(fNPads);
976 if (fTimePosition) preprocesor.AddComponent(fTimePosition);
977 if (fOverThreshold10) preprocesor.AddComponent(fOverThreshold10);
978 if (fOverThreshold20) preprocesor.AddComponent(fOverThreshold20);
979 if (fOverThreshold30) preprocesor.AddComponent(fOverThreshold30);
981 preprocesor.DumpToFile(fname);
985 //_____________________________________________________________________
986 void AliTPCdataQA::MakeArrays(){
988 // The arrays for expanding the raw data are defined and
989 // som parameters are intialised
991 AliTPCROC * roc = AliTPCROC::Instance();
993 // To make the array big enough for all sectors we take
994 // the dimensions from the outer row of an OROC (the last sector)
996 fRowsMax = roc->GetNRows(roc->GetNSector()-1);
997 fPadsMax = roc->GetNPads(roc->GetNSector()-1,fRowsMax-1);
998 fTimeBinsMax = fLastTimeBin - fFirstTimeBin +1;
1001 // Since we have added 2 pads (TimeBins) before and after the real pads (TimeBins)
1002 // to make sure that we can always query the exanded table even when the
1003 // max is on the edge
1007 fAllBins = new Float_t*[fRowsMax];
1008 fAllSigBins = new Int_t*[fRowsMax];
1009 fAllNSigBins = new Int_t[fRowsMax];
1011 for (Int_t iRow = 0; iRow < fRowsMax; iRow++) {
1013 Int_t maxBin = (fTimeBinsMax+4)*(fPadsMax+4);
1014 fAllBins[iRow] = new Float_t[maxBin];
1015 memset(fAllBins[iRow],0,sizeof(Float_t)*maxBin); // set all values to 0
1016 fAllSigBins[iRow] = new Int_t[maxBin];
1017 fAllNSigBins[iRow] = 0;
1022 //_____________________________________________________________________
1023 void AliTPCdataQA::CleanArrays(){
1028 for (Int_t iRow = 0; iRow < fRowsMax; iRow++) {
1030 // To speed up the performance by a factor 2 on cosmic data (and
1031 // presumably pp data as well) where the ocupancy is low, the
1032 // memset is only called if there is more than 1000 signals for a
1033 // row (of the order 1% occupancy)
1034 if(fAllNSigBins[iRow]<1000) {
1036 Float_t* allBins = fAllBins[iRow];
1037 Int_t* sigBins = fAllSigBins[iRow];
1038 const Int_t nSignals = fAllNSigBins[iRow];
1039 for(Int_t i = 0; i < nSignals; i++)
1040 allBins[sigBins[i]]=0;
1043 Int_t maxBin = (fTimeBinsMax+4)*(fPadsMax+4);
1044 memset(fAllBins[iRow],0,sizeof(Float_t)*maxBin);
1047 fAllNSigBins[iRow]=0;
1051 //_____________________________________________________________________
1052 void AliTPCdataQA::GetPadAndTimeBin(Int_t bin, Int_t& iPad, Int_t& iTimeBin){
1054 // Return pad and timebin for a given bin
1057 // Int_t bin = iPad*(fTimeBinsMax+4)+iTimeBin;
1058 iTimeBin = bin%(fTimeBinsMax+4);
1059 iPad = (bin-iTimeBin)/(fTimeBinsMax+4);
1063 iTimeBin += fFirstTimeBin;
1065 R__ASSERT(iPad>=0 && iPad<=fPadsMax);
1066 R__ASSERT(iTimeBin>=fFirstTimeBin && iTimeBin<=fLastTimeBin);
1069 //_____________________________________________________________________
1070 void AliTPCdataQA::SetExpandDigit(const Int_t iRow, Int_t iPad,
1071 Int_t iTimeBin, const Float_t signal)
1076 R__ASSERT(iRow>=0 && iRow<fRowsMax);
1077 R__ASSERT(iPad>=0 && iPad<=fPadsMax);
1078 R__ASSERT(iTimeBin>=fFirstTimeBin && iTimeBin<=fLastTimeBin);
1080 iTimeBin -= fFirstTimeBin;
1084 Int_t bin = iPad*(fTimeBinsMax+4)+iTimeBin;
1085 fAllBins[iRow][bin] = signal;
1086 fAllSigBins[iRow][fAllNSigBins[iRow]] = bin;
1087 fAllNSigBins[iRow]++;
1090 Float_t AliTPCdataQA::GetQ(const Float_t* adcArray, const Int_t time,
1091 const Int_t pad, const Int_t maxTimeBins,
1092 Int_t& timeMin, Int_t& timeMax,
1093 Int_t& padMin, Int_t& padMax) const
1096 // This methods return the charge in the bin time+pad*maxTimeBins
1097 // If the charge is above 0 it also updates the padMin, padMax, timeMin
1098 // and timeMax if necessary
1100 Float_t charge = adcArray[time + pad*maxTimeBins];
1102 timeMin = TMath::Min(time, timeMin); timeMax = TMath::Max(time, timeMax);
1103 padMin = TMath::Min(pad, padMin); padMax = TMath::Max(pad, padMax);
1108 //______________________________________________________________________________
1109 void AliTPCdataQA::Streamer(TBuffer &xRuub)
1111 // Automatic schema evolution was first used from revision 4
1113 // http://root.cern.ch/root/roottalk/roottalk02/3207.html
1115 UInt_t xRuus, xRuuc;
1116 if (xRuub.IsReading()) {
1117 Version_t xRuuv = xRuub.ReadVersion(&xRuus, &xRuuc);
1118 //we use the automatic algorithm for class version > 3
1120 AliTPCdataQA::Class()->ReadBuffer(xRuub, this, xRuuv, xRuus,
1124 TH1F::Streamer(xRuub);
1125 xRuub >> fFirstTimeBin;
1126 xRuub >> fLastTimeBin;
1129 xRuub >> fNLocalMaxima;
1130 xRuub >> fMaxCharge;
1131 xRuub >> fMeanCharge;
1132 xRuub >> fNoThreshold;
1133 xRuub >> fNTimeBins;
1135 xRuub >> fTimePosition;
1136 xRuub >> fEventCounter;
1137 xRuub >> fIsAnalysed;
1138 xRuub.CheckByteCount(xRuus, xRuuc, AliTPCdataQA::IsA());
1140 AliTPCdataQA::Class()->WriteBuffer(xRuub,this);