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 The code has been heavily modified so that now the RAW data is
23 "expanded" for each sector and stored in a big signal array. Then a
24 simple version of the code in AliTPCclustererMI is used to identify
25 the local maxima and these are then used for QA. This gives a better
26 estimate of the charge (both max and total) and also limits the
31 In Update the RAW signals >= 3 ADC channels are stored in the arrays.
34 Float_t** fAllBins 2d array [row][bin(pad, time)] ADC signal
35 Int_t** fAllSigBins 2d array [row][signal#] bin(with signal)
36 Int_t* fAllNSigBins; 1d array [row] Nsignals
38 This is done sector by sector.
40 When data from a new sector is encountered, the method
41 FindLocalMaxima is called on the data from the previous sector, and
42 the calibration/data objects are updated with the "cluster"
43 info. Finally the arrays are cleared.
45 The requirements for a local maxima is:
46 Charge in bin is >= 5 ADC channels.
47 Charge in bin is larger than all the 8 neighboring bins.
48 At least one of the two pad neighbors has a signal.
49 At least one of the two time neighbors has a signal.
51 Before accessing the data it is expected that the Analyse method is
52 called. This normalizes some of the data objects to per event or per
54 If more data is passed to the class after Analyse has been called
55 the normalization is reversed and Analyse has to be called again.
71 #include <TDirectory.h>
75 #include "AliRawReader.h"
76 #include "AliRawReaderRoot.h"
77 #include "AliRawReaderDate.h"
78 #include "AliTPCRawStream.h"
79 #include "AliTPCCalROC.h"
80 #include "AliTPCROC.h"
81 #include "AliMathBase.h"
82 #include "TTreeStream.h"
83 #include "AliTPCRawStreamFast.h"
87 #include "AliTPCCalPad.h"
88 #include "AliTPCPreprocessorOnline.h"
91 #include "AliTPCdataQA.h"
93 ClassImp(AliTPCdataQA)
95 AliTPCdataQA::AliTPCdataQA() : /*FOLD00*/
96 TH1F("TPCRAW","TPCRAW",100,0,100),
124 // default constructor
129 //_____________________________________________________________________
130 AliTPCdataQA::AliTPCdataQA(const AliTPCdataQA &ped) : /*FOLD00*/
132 fFirstTimeBin(ped.GetFirstTimeBin()),
133 fLastTimeBin(ped.GetLastTimeBin()),
134 fAdcMin(ped.GetAdcMin()),
135 fAdcMax(ped.GetAdcMax()),
149 fEventCounter(ped.GetEventCounter()),
150 fIsAnalysed(ped.GetIsAnalysed()),
161 if(ped.GetNLocalMaxima())
162 fNLocalMaxima = new AliTPCCalPad(*ped.GetNLocalMaxima());
163 if(ped.GetMaxCharge())
164 fMaxCharge = new AliTPCCalPad(*ped.GetMaxCharge());
165 if(ped.GetMeanCharge())
166 fMeanCharge = new AliTPCCalPad(*ped.GetMeanCharge());
167 if(ped.GetNoThreshold())
168 fNoThreshold = new AliTPCCalPad(*ped.GetNoThreshold());
169 if(ped.GetNTimeBins())
170 fNTimeBins = new AliTPCCalPad(*ped.GetNTimeBins());
172 fNPads = new AliTPCCalPad(*ped.GetNPads());
173 if(ped.GetTimePosition())
174 fTimePosition = new AliTPCCalPad(*ped.GetTimePosition());
175 if(ped.GetOverThreshold10())
176 fOverThreshold10 = new AliTPCCalPad(*ped.GetOverThreshold10());
177 if(ped.GetOverThreshold20())
178 fOverThreshold20 = new AliTPCCalPad(*ped.GetOverThreshold20());
179 if(ped.GetOverThreshold30())
180 fOverThreshold30 = new AliTPCCalPad(*ped.GetOverThreshold30());
184 //_____________________________________________________________________
185 AliTPCdataQA& AliTPCdataQA::operator = (const AliTPCdataQA &source)
188 // assignment operator
190 if (&source == this) return *this;
191 new (this) AliTPCdataQA(source);
197 //_____________________________________________________________________
198 AliTPCdataQA::~AliTPCdataQA() /*FOLD00*/
204 // do not delete fMapping, because we do not own it.
205 // do not delete fMapping, because we do not own it.
206 // do not delete fNoise and fPedestal, because we do not own them.
208 delete fNLocalMaxima;
214 delete fTimePosition;
215 delete fOverThreshold10;
216 delete fOverThreshold20;
217 delete fOverThreshold30;
219 for (Int_t iRow = 0; iRow < fRowsMax; iRow++) {
220 delete [] fAllBins[iRow];
221 delete [] fAllSigBins[iRow];
224 delete [] fAllSigBins;
225 delete [] fAllNSigBins;
228 //_____________________________________________________________________
229 Bool_t AliTPCdataQA::ProcessEventFast(AliTPCRawStreamFast *rawStreamFast)
232 // Event Processing loop - AliTPCRawStream
234 Bool_t withInput = kFALSE;
236 Int_t lastSector = -1;
238 while ( rawStreamFast->NextDDL() ){
239 while ( rawStreamFast->NextChannel() ){
241 Int_t iSector = rawStreamFast->GetSector(); // current sector
242 Int_t iRow = rawStreamFast->GetRow(); // current row
243 Int_t iPad = rawStreamFast->GetPad(); // current pad
244 // Call local maxima finder if the data is in a new sector
245 if(iSector != lastSector) {
248 FindLocalMaxima(lastSector);
251 lastSector = iSector;
255 while ( rawStreamFast->NextBunch() ){
256 Int_t startTbin = (Int_t)rawStreamFast->GetStartTimeBin();
257 Int_t endTbin = (Int_t)rawStreamFast->GetEndTimeBin();
259 for (Int_t iTimeBin = startTbin; iTimeBin < endTbin; iTimeBin++){
260 Float_t signal = rawStreamFast->GetSignals()[iTimeBin-startTbin];
261 nSignals += Update(iSector,iRow,iPad,iTimeBin+1,signal);
270 //_____________________________________________________________________
271 Bool_t AliTPCdataQA::ProcessEventFast(AliRawReader *rawReader)
274 // Event processing loop - AliRawReader
276 AliTPCRawStreamFast *rawStreamFast = new AliTPCRawStreamFast(rawReader, (AliAltroMapping**)fMapping);
277 Bool_t res=ProcessEventFast(rawStreamFast);
279 fEventCounter++; // only increment event counter if there is TPC data
280 // otherwise Analyse (called in QA) fails
282 delete rawStreamFast;
286 //_____________________________________________________________________
287 Bool_t AliTPCdataQA::ProcessEvent(AliTPCRawStream *rawStream)
290 // Event Processing loop - AliTPCRawStream
293 Bool_t withInput = kFALSE;
295 Int_t lastSector = -1;
297 while (rawStream->Next()) {
299 Int_t iSector = rawStream->GetSector(); // current ROC
300 Int_t iRow = rawStream->GetRow(); // current row
301 Int_t iPad = rawStream->GetPad(); // current pad
302 Int_t iTimeBin = rawStream->GetTime(); // current time bin
303 Float_t signal = rawStream->GetSignal(); // current ADC signal
305 // Call local maxima finder if the data is in a new sector
306 if(iSector != lastSector) {
309 FindLocalMaxima(lastSector);
312 lastSector = iSector;
316 // Sometimes iRow==-1 if there is problems to read the data
318 nSignals += Update(iSector,iRow,iPad,iTimeBin,signal);
327 //_____________________________________________________________________
328 Bool_t AliTPCdataQA::ProcessEvent(AliRawReader *rawReader)
331 // Event processing loop - AliRawReader
334 // if fMapping is NULL the rawstream will crate its own mapping
335 AliTPCRawStream rawStream(rawReader, (AliAltroMapping**)fMapping);
336 rawReader->Select("TPC");
337 Bool_t res = ProcessEvent(&rawStream);
340 fEventCounter++; // only increment event counter if there is TPC data
341 // otherwise Analyse (called in QA) fails
346 //_____________________________________________________________________
347 Bool_t AliTPCdataQA::ProcessEvent(eventHeaderStruct *event)
350 // process date event
353 AliRawReader *rawReader = new AliRawReaderDate((void*)event);
354 Bool_t result=ProcessEvent(rawReader);
361 //_____________________________________________________________________
362 void AliTPCdataQA::DumpToFile(const Char_t *filename, const Char_t *dir, Bool_t append) /*FOLD00*/
365 // Write class to file
376 TDirectory *backup = gDirectory;
377 TFile f(filename,option.Data());
379 if ( !sDir.IsNull() ){
380 f.mkdir(sDir.Data());
386 if ( backup ) backup->cd();
390 //_____________________________________________________________________
391 Int_t AliTPCdataQA::Update(const Int_t iSector, /*FOLD00*/
394 const Int_t iTimeBin,
398 // Signal filling method
402 // Define the calibration objects the first time Update is called
403 // NB! This has to be done first even if the data is rejected by the time
404 // cut to make sure that the objects are available in Analyse
406 if (!fNLocalMaxima) fNLocalMaxima = new AliTPCCalPad("NLocalMaxima","NLocalMaxima");
407 if (!fMaxCharge) fMaxCharge = new AliTPCCalPad("MaxCharge","MaxCharge");
408 if (!fMeanCharge) fMeanCharge = new AliTPCCalPad("MeanCharge","MeanCharge");
409 if (!fNoThreshold) fNoThreshold = new AliTPCCalPad("NoThreshold","NoThreshold");
410 if (!fNTimeBins) fNTimeBins = new AliTPCCalPad("NTimeBins","NTimeBins");
411 if (!fNPads) fNPads = new AliTPCCalPad("NPads","NPads");
412 if (!fTimePosition) fTimePosition = new AliTPCCalPad("TimePosition","TimePosition");
413 if (!fOverThreshold10) fOverThreshold10 = new AliTPCCalPad("OverThreshold10","OverThreshold10");
414 if (!fOverThreshold20) fOverThreshold20 = new AliTPCCalPad("OverThreshold20","OverThreshold20");
415 if (!fOverThreshold30) fOverThreshold30 = new AliTPCCalPad("OverThreshold30","OverThreshold30");
416 // Make the arrays for expanding the data
422 // If Analyse has been previously called we need now to denormalize the data
423 // as more data is coming
425 if(fIsAnalysed == kTRUE) {
427 const Int_t nTimeBins = fLastTimeBin - fFirstTimeBin +1;
428 const Float_t denormalization = Float_t(fEventCounter * nTimeBins);
429 fNoThreshold->Multiply(denormalization);
431 fMeanCharge->Multiply(fNLocalMaxima);
432 fMaxCharge->Multiply(fNLocalMaxima);
433 fNTimeBins->Multiply(fNLocalMaxima);
434 fNPads->Multiply(fNLocalMaxima);
435 fTimePosition->Multiply(fNLocalMaxima);
436 fIsAnalysed = kFALSE;
442 if (iTimeBin<fFirstTimeBin) return 0;
443 if (iTimeBin>fLastTimeBin) return 0;
445 // if pedestal calibrations are loaded subtract pedestals
448 Float_t ped = fPedestal->GetCalROC(iSector)->GetValue(iRow, iPad);
449 // Don't use data from pads where pedestals are abnormally small or large
455 // In fNoThreshold we fill all data to estimate the ZS volume
456 Float_t count = fNoThreshold->GetCalROC(iSector)->GetValue(iRow, iPad);
457 fNoThreshold->GetCalROC(iSector)->SetValue(iRow, iPad,count+1);
459 // Require at least 3 ADC channels
463 // if noise calibrations are loaded require at least 3*sigmaNoise
466 Float_t noise = fNoise->GetCalROC(iSector)->GetValue(iRow, iPad);
468 if(signal < noise*3.0)
473 // This signal is ok and we store it in the cluster map
476 SetExpandDigit(iRow, iPad, iTimeBin, signal);
478 return 1; // signal was accepted
481 //_____________________________________________________________________
482 void AliTPCdataQA::FindLocalMaxima(const Int_t iSector)
485 // This method is called after the data from each sector has been
486 // exapanded into an array
487 // Loop over the signals and identify local maxima and fill the
488 // calibration objects with the information
491 Int_t nLocalMaxima = 0;
492 const Int_t maxTimeBin = fTimeBinsMax+4; // Used to step between neighboring pads
493 // Because we have tha pad-time data in a
496 for (Int_t iRow = 0; iRow < fRowsMax; iRow++) {
498 Float_t* allBins = fAllBins[iRow];
499 Int_t* sigBins = fAllSigBins[iRow];
500 const Int_t nSigBins = fAllNSigBins[iRow];
502 for (Int_t iSig = 0; iSig < nSigBins; iSig++) {
504 Int_t bin = sigBins[iSig];
505 Float_t *b = &allBins[bin];
508 // Now we check if this is a local maximum
513 // First check that the charge is bigger than the threshold
517 // Require at least one neighboring pad with signal
518 if (b[-maxTimeBin]+b[maxTimeBin]<=0) continue;
520 // Require at least one neighboring time bin with signal
521 if (b[-1]+b[1]<=0) continue;
524 // Check that this is a local maximum
525 // Note that the checking is done so that if 2 charges has the same
526 // qMax then only 1 cluster is generated
527 // (that is why there is BOTH > and >=)
529 if (b[-maxTimeBin] >= qMax) continue;
530 if (b[-1 ] >= qMax) continue;
531 if (b[+maxTimeBin] > qMax) continue;
532 if (b[+1 ] > qMax) continue;
533 if (b[-maxTimeBin-1] >= qMax) continue;
534 if (b[+maxTimeBin-1] >= qMax) continue;
535 if (b[+maxTimeBin+1] > qMax) continue;
536 if (b[-maxTimeBin+1] >= qMax) continue;
539 // Now we accept the local maximum and fill the calibration/data objects
543 Int_t iPad, iTimeBin;
544 GetPadAndTimeBin(bin, iPad, iTimeBin);
546 Float_t count = fNLocalMaxima->GetCalROC(iSector)->GetValue(iRow, iPad);
547 fNLocalMaxima->GetCalROC(iSector)->SetValue(iRow, iPad, count+1);
549 count = fTimePosition->GetCalROC(iSector)->GetValue(iRow, iPad);
550 fTimePosition->GetCalROC(iSector)->SetValue(iRow, iPad, count+iTimeBin);
552 Float_t charge = fMaxCharge->GetCalROC(iSector)->GetValue(iRow, iPad);
553 fMaxCharge->GetCalROC(iSector)->SetValue(iRow, iPad, charge + qMax);
556 count = fOverThreshold10->GetCalROC(iSector)->GetValue(iRow, iPad);
557 fOverThreshold10->GetCalROC(iSector)->SetValue(iRow, iPad, count+1);
560 count = fOverThreshold20->GetCalROC(iSector)->GetValue(iRow, iPad);
561 fOverThreshold20->GetCalROC(iSector)->SetValue(iRow, iPad, count+1);
564 count = fOverThreshold30->GetCalROC(iSector)->GetValue(iRow, iPad);
565 fOverThreshold30->GetCalROC(iSector)->SetValue(iRow, iPad, count+1);
569 // Calculate the total charge as the sum over the region:
577 // with qmax at the center C.
579 // The inner charge (i) we always add, but we only add the outer
580 // charge (o) if the neighboring inner bin (i) has a signal.
582 Int_t minP = 0, maxP = 0, minT = 0, maxT = 0;
584 for(Int_t i = -1; i<=1; i++) {
585 for(Int_t j = -1; j<=1; j++) {
590 Float_t charge = GetQ(b, i, j, maxTimeBin, minT, maxT, minP, maxP);
593 // see if the next neighbor is also above threshold
595 qTot += GetQ(b, 2*i, 2*j, maxTimeBin, minT, maxT, minP, maxP);
597 // we are in a diagonal corner
598 qTot += GetQ(b, i, 2*j, maxTimeBin, minT, maxT, minP, maxP);
599 qTot += GetQ(b, 2*i, j, maxTimeBin, minT, maxT, minP, maxP);
600 qTot += GetQ(b, 2*i, 2*j, maxTimeBin, minT, maxT, minP, maxP);
606 charge = fMeanCharge->GetCalROC(iSector)->GetValue(iRow, iPad);
607 fMeanCharge->GetCalROC(iSector)->SetValue(iRow, iPad, charge + qTot);
609 count = fNTimeBins->GetCalROC(iSector)->GetValue(iRow, iPad);
610 fNTimeBins->GetCalROC(iSector)->SetValue(iRow, iPad, count + maxT-minT+1);
612 count = fNPads->GetCalROC(iSector)->GetValue(iRow, iPad);
613 fNPads->GetCalROC(iSector)->SetValue(iRow, iPad, count + maxP-minP+1);
615 } // end loop over signals
616 } // end loop over rows
618 // cout << "Number of local maximas found: " << nLocalMaxima << endl;
621 //_____________________________________________________________________
622 void AliTPCdataQA::Analyse()
625 // Calculate calibration constants
628 cout << "Analyse called" << endl;
630 if(fIsAnalysed == kTRUE) {
632 cout << "No new data since Analyse was called last time" << endl;
636 if(fEventCounter==0) {
638 cout << "EventCounter == 0, Cannot analyse" << endl;
642 Int_t nTimeBins = fLastTimeBin - fFirstTimeBin +1;
643 cout << "EventCounter: " << fEventCounter << endl
644 << "TimeBins: " << nTimeBins << endl;
646 Float_t normalization = 1.0 / Float_t(fEventCounter * nTimeBins);
647 fNoThreshold->Multiply(normalization);
649 fMeanCharge->Divide(fNLocalMaxima);
650 fMaxCharge->Divide(fNLocalMaxima);
651 fNTimeBins->Divide(fNLocalMaxima);
652 fNPads->Divide(fNLocalMaxima);
653 fTimePosition->Divide(fNLocalMaxima);
659 //_____________________________________________________________________
660 void AliTPCdataQA::MakeTree(const char *fname){
662 // Export result to the tree -located in the file
663 // This file can be analyzed using AliTPCCalibViewer
665 AliTPCPreprocessorOnline preprocesor;
667 if (fNLocalMaxima) preprocesor.AddComponent(fNLocalMaxima);
668 if (fMaxCharge) preprocesor.AddComponent(fMaxCharge);
669 if (fMeanCharge) preprocesor.AddComponent(fMeanCharge);
670 if (fNoThreshold) preprocesor.AddComponent(fNoThreshold);
671 if (fNTimeBins) preprocesor.AddComponent(fNTimeBins);
672 if (fNPads) preprocesor.AddComponent(fNPads);
673 if (fTimePosition) preprocesor.AddComponent(fTimePosition);
674 if (fOverThreshold10) preprocesor.AddComponent(fOverThreshold10);
675 if (fOverThreshold20) preprocesor.AddComponent(fOverThreshold20);
676 if (fOverThreshold30) preprocesor.AddComponent(fOverThreshold30);
678 preprocesor.DumpToFile(fname);
682 //_____________________________________________________________________
683 void AliTPCdataQA::MakeArrays(){
685 // The arrays for expanding the raw data are defined and
686 // som parameters are intialised
688 AliTPCROC * roc = AliTPCROC::Instance();
690 // To make the array big enough for all sectors we take
691 // the dimensions from the outer row of an OROC (the last sector)
693 fRowsMax = roc->GetNRows(roc->GetNSector()-1);
694 fPadsMax = roc->GetNPads(roc->GetNSector()-1,fRowsMax-1);
695 fTimeBinsMax = fLastTimeBin - fFirstTimeBin +1;
698 // Since we have added 2 pads (TimeBins) before and after the real pads (TimeBins)
699 // to make sure that we can always query the exanded table even when the
700 // max is on the edge
704 fAllBins = new Float_t*[fRowsMax];
705 fAllSigBins = new Int_t*[fRowsMax];
706 fAllNSigBins = new Int_t[fRowsMax];
708 for (Int_t iRow = 0; iRow < fRowsMax; iRow++) {
710 Int_t maxBin = (fTimeBinsMax+4)*(fPadsMax+4);
711 fAllBins[iRow] = new Float_t[maxBin];
712 memset(fAllBins[iRow],0,sizeof(Float_t)*maxBin); // set all values to 0
713 fAllSigBins[iRow] = new Int_t[maxBin];
714 fAllNSigBins[iRow] = 0;
719 //_____________________________________________________________________
720 void AliTPCdataQA::CleanArrays(){
725 for (Int_t iRow = 0; iRow < fRowsMax; iRow++) {
727 Int_t maxBin = (fTimeBinsMax+4)*(fPadsMax+4);
728 memset(fAllBins[iRow],0,sizeof(Float_t)*maxBin);
729 fAllNSigBins[iRow]=0;
733 //_____________________________________________________________________
734 void AliTPCdataQA::GetPadAndTimeBin(Int_t bin, Int_t& iPad, Int_t& iTimeBin){
736 // Return pad and timebin for a given bin
739 // Int_t bin = iPad*(fTimeBinsMax+4)+iTimeBin;
740 iTimeBin = bin%(fTimeBinsMax+4);
741 iPad = (bin-iTimeBin)/(fTimeBinsMax+4);
745 iTimeBin += fFirstTimeBin;
747 R__ASSERT(iPad>=0 && iPad<=fPadsMax);
748 R__ASSERT(iTimeBin>=fFirstTimeBin && iTimeBin<=fLastTimeBin);
751 //_____________________________________________________________________
752 void AliTPCdataQA::SetExpandDigit(const Int_t iRow, Int_t iPad,
753 Int_t iTimeBin, const Float_t signal)
758 R__ASSERT(iRow>=0 && iRow<fRowsMax);
759 R__ASSERT(iPad>=0 && iPad<=fPadsMax);
760 R__ASSERT(iTimeBin>=fFirstTimeBin && iTimeBin<=fLastTimeBin);
762 iTimeBin -= fFirstTimeBin;
766 Int_t bin = iPad*(fTimeBinsMax+4)+iTimeBin;
767 fAllBins[iRow][bin] = signal;
768 fAllSigBins[iRow][fAllNSigBins[iRow]] = bin;
769 fAllNSigBins[iRow]++;
772 Float_t AliTPCdataQA::GetQ(const Float_t* adcArray, const Int_t time,
773 const Int_t pad, const Int_t maxTimeBins,
774 Int_t& timeMin, Int_t& timeMax,
775 Int_t& padMin, Int_t& padMax)
778 // This methods return the charge in the bin time+pad*maxTimeBins
779 // If the charge is above 0 it also updates the padMin, padMax, timeMin
780 // and timeMax if necessary
782 Float_t charge = adcArray[time + pad*maxTimeBins];
784 timeMin = TMath::Min(time, timeMin); timeMax = TMath::Max(time, timeMax);
785 padMin = TMath::Min(pad, padMin); padMax = TMath::Max(pad, padMax);