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 **************************************************************************/
15 /* $Id: AliCaloCalibSignal.cxx $ */
17 //________________________________________________________________________
19 // A help class for monitoring and calibration tools: MOOD, AMORE etc.,
20 // It can be created and used a la (ctor):
22 //Create the object for making the histograms
23 fSignals = new AliCaloCalibSignal( fDetType );
24 // AliCaloCalibSignal knows how many modules we have for PHOS or EMCAL
25 fNumModules = fSignals->GetModules();
28 // fSignals->ProcessEvent(fCaloRawStream,fRawEventHeaderBase);
30 // fSignals->GetXXX..()
32 //________________________________________________________________________
37 #include "AliRawReader.h"
38 #include "AliRawEventHeaderBase.h"
39 #include "AliCaloRawStreamV3.h"
42 #include "AliCaloCalibSignal.h"
44 ClassImp(AliCaloCalibSignal)
48 // variables for TTree filling; not sure if they should be static or not
49 static int fChannelNum; // for regular towers
50 static int fRefNum; // for LED
52 static double fAvgAmp;
55 // ctor; initialize everything in order to avoid compiler warnings
56 // put some reasonable defaults
57 AliCaloCalibSignal::AliCaloCalibSignal(kDetType detectorType) :
69 fReqFractionAboveAmpCutVal(0.8),
70 fReqFractionAboveAmp(kTRUE),
78 fTreeAvgAmpVsTime(NULL),
79 fTreeLEDAmpVsTime(NULL),
80 fTreeLEDAvgAmpVsTime(NULL)
82 //Default constructor. First we set the detector-type related constants.
83 if (detectorType == kPhos) {
84 fColumns = fgkPhosCols;
86 fLEDRefs = fgkPhosLEDRefs;
87 fModules = fgkPhosModules;
91 //We'll just trust the enum to keep everything in line, so that if detectorType
92 //isn't kPhos then it is kEmCal. Note, however, that this is not necessarily the
93 //case, if someone intentionally gives another number
94 fColumns = AliEMCALGeoParams::fgkEMCALCols;
95 fRows = AliEMCALGeoParams::fgkEMCALRows;
96 fLEDRefs = AliEMCALGeoParams::fgkEMCALLEDRefs;
97 fModules = AliEMCALGeoParams::fgkEMCALModules;
98 fCaloString = "EMCAL";
101 fDetType = detectorType;
103 ResetInfo(); // trees and counters
107 //_____________________________________________________________________
108 AliCaloCalibSignal::~AliCaloCalibSignal()
113 //_____________________________________________________________________
114 void AliCaloCalibSignal::DeleteTrees()
116 // delete what was created in the ctor (TTrees)
117 if (fTreeAmpVsTime) delete fTreeAmpVsTime;
118 if (fTreeAvgAmpVsTime) delete fTreeAvgAmpVsTime;
119 if (fTreeLEDAmpVsTime) delete fTreeLEDAmpVsTime;
120 if (fTreeLEDAvgAmpVsTime) delete fTreeLEDAvgAmpVsTime;
121 // and reset pointers
122 fTreeAmpVsTime = NULL;
123 fTreeAvgAmpVsTime = NULL;
124 fTreeLEDAmpVsTime = NULL;
125 fTreeLEDAvgAmpVsTime = NULL;
131 //_____________________________________________________________________
132 AliCaloCalibSignal::AliCaloCalibSignal(const AliCaloCalibSignal &sig) :
134 fDetType(sig.GetDetectorType()),
135 fColumns(sig.GetColumns()),
136 fRows(sig.GetRows()),
137 fLEDRefs(sig.GetLEDRefs()),
138 fModules(sig.GetModules()),
139 fCaloString(sig.GetCaloString()),
140 fMapping(NULL), //! note that we are not copying the map info
141 fRunNumber(sig.GetRunNumber()),
142 fStartTime(sig.GetStartTime()),
143 fAmpCut(sig.GetAmpCut()),
144 fReqFractionAboveAmpCutVal(sig.GetReqFractionAboveAmpCutVal()),
145 fReqFractionAboveAmp(sig.GetReqFractionAboveAmp()),
146 fHour(sig.GetHour()),
147 fLatestHour(sig.GetLatestHour()),
148 fUseAverage(sig.GetUseAverage()),
149 fSecInAverage(sig.GetSecInAverage()),
150 fNEvents(sig.GetNEvents()),
151 fNAcceptedEvents(sig.GetNAcceptedEvents()),
152 fTreeAmpVsTime(NULL),
153 fTreeAvgAmpVsTime(NULL),
154 fTreeLEDAmpVsTime(NULL),
155 fTreeLEDAvgAmpVsTime(NULL)
157 // also the TTree contents
161 // assignment operator; use copy ctor to make life easy..
162 //_____________________________________________________________________
163 AliCaloCalibSignal& AliCaloCalibSignal::operator = (const AliCaloCalibSignal &source)
165 // assignment operator; use copy ctor
166 if (&source == this) return *this;
168 new (this) AliCaloCalibSignal(source);
172 //_____________________________________________________________________
173 void AliCaloCalibSignal::CreateTrees()
176 // first, regular version
177 fTreeAmpVsTime = new TTree("fTreeAmpVsTime","Amplitude vs. Time Tree Variables");
179 fTreeAmpVsTime->Branch("fChannelNum", &fChannelNum, "fChannelNum/I");
180 fTreeAmpVsTime->Branch("fHour", &fHour, "fHour/D");
181 fTreeAmpVsTime->Branch("fAmp", &fAmp, "fAmp/D");
183 // then, average version
184 fTreeAvgAmpVsTime = new TTree("fTreeAvgAmpVsTime","Average Amplitude vs. Time Tree Variables");
186 fTreeAvgAmpVsTime->Branch("fChannelNum", &fChannelNum, "fChannelNum/I");
187 fTreeAvgAmpVsTime->Branch("fHour", &fHour, "fHour/D");
188 fTreeAvgAmpVsTime->Branch("fAvgAmp", &fAvgAmp, "fAvgAmp/D");
189 fTreeAvgAmpVsTime->Branch("fRMS", &fRMS, "fRMS/D");
191 // then same for LED..
192 fTreeLEDAmpVsTime = new TTree("fTreeLEDAmpVsTime","LED Amplitude vs. Time Tree Variables");
193 fTreeLEDAmpVsTime->Branch("fRefNum", &fRefNum, "fRefNum/I");
194 fTreeLEDAmpVsTime->Branch("fHour", &fHour, "fHour/D");
195 fTreeLEDAmpVsTime->Branch("fAmp", &fAmp, "fAmp/D");
197 fTreeLEDAvgAmpVsTime = new TTree("fTreeLEDAvgAmpVsTime","Average LED Amplitude vs. Time Tree Variables");
198 fTreeLEDAvgAmpVsTime->Branch("fRefNum", &fRefNum, "fRefNum/I");
199 fTreeLEDAvgAmpVsTime->Branch("fHour", &fHour, "fHour/D");
200 fTreeLEDAvgAmpVsTime->Branch("fAvgAmp", &fAvgAmp, "fAvgAmp/D");
201 fTreeLEDAvgAmpVsTime->Branch("fRMS", &fRMS, "fRMS/D");
206 //_____________________________________________________________________
207 void AliCaloCalibSignal::ResetInfo()
209 Zero(); // set all counters to 0
210 DeleteTrees(); // delete previous stuff
211 CreateTrees(); // and create some new ones
215 //_____________________________________________________________________
216 void AliCaloCalibSignal::Zero()
218 // set all counters to 0; not cuts etc. though
222 fNAcceptedEvents = 0;
224 // Set the number of points for each tower: Amp vs. Time
225 memset(fNHighGain, 0, sizeof(fNHighGain));
226 memset(fNLowGain, 0, sizeof(fNLowGain));
228 memset(fNRef, 0, sizeof(fNRef));
233 //_____________________________________________________________________
234 Bool_t AliCaloCalibSignal::CheckFractionAboveAmp(int *AmpVal, int nTotChan)
239 for (int i = 0; i<fModules; i++) {
240 for (int j = 0; j<fColumns; j++) {
241 for (int k = 0; k<fRows; k++) {
242 TowerNum = GetTowerNum(i,j,k);
243 if (AmpVal[TowerNum] > fAmpCut) {
250 double fraction = (1.0*nAbove) / nTotChan;
252 if (fraction > fReqFractionAboveAmpCutVal) {
258 //_____________________________________________________________________
259 Bool_t AliCaloCalibSignal::AddInfo(const AliCaloCalibSignal *sig)
261 // note/FIXME: we are not yet adding correctly the info for fN{HighGain,LowGain,Ref} here - but consider this a feature for now (20080905): we'll do Analyze() unless entries were found for a tower in this original object.
263 // add info from sig's TTrees to ours..
264 TTree *sigAmp = sig->GetTreeAmpVsTime();
265 TTree *sigAvgAmp = sig->GetTreeAvgAmpVsTime();
267 // we could try some merging via TList or what also as a more elegant approach
268 // but I wanted with the stupid/simple and hopefully safe approach of looping
269 // over what we want to add..
271 // associate variables for sigAmp and sigAvgAmp:
272 sigAmp->SetBranchAddress("fChannelNum",&fChannelNum);
273 sigAmp->SetBranchAddress("fHour",&fHour);
274 sigAmp->SetBranchAddress("fAmp",&fAmp);
276 // loop over the trees.. note that since we use the same variables we should not need
277 // to do any assignments between the getting and filling
278 for (int i=0; i<sigAmp->GetEntries(); i++) {
280 fTreeAmpVsTime->Fill();
283 sigAvgAmp->SetBranchAddress("fChannelNum",&fChannelNum);
284 sigAvgAmp->SetBranchAddress("fHour",&fHour);
285 sigAvgAmp->SetBranchAddress("fAvgAmp",&fAvgAmp);
286 sigAvgAmp->SetBranchAddress("fRMS",&fRMS);
288 for (int i=0; i<sigAvgAmp->GetEntries(); i++) {
289 sigAvgAmp->GetEntry(i);
290 fTreeAvgAmpVsTime->Fill();
294 TTree *sigLEDAmp = sig->GetTreeLEDAmpVsTime();
295 TTree *sigLEDAvgAmp = sig->GetTreeLEDAvgAmpVsTime();
297 // associate variables for sigAmp and sigAvgAmp:
298 sigLEDAmp->SetBranchAddress("fRefNum",&fRefNum);
299 sigLEDAmp->SetBranchAddress("fHour",&fHour);
300 sigLEDAmp->SetBranchAddress("fAmp",&fAmp);
302 // loop over the trees.. note that since we use the same variables we should not need
303 // to do any assignments between the getting and filling
304 for (int i=0; i<sigLEDAmp->GetEntries(); i++) {
305 sigLEDAmp->GetEntry(i);
306 fTreeLEDAmpVsTime->Fill();
309 sigLEDAvgAmp->SetBranchAddress("fRefNum",&fRefNum);
310 sigLEDAvgAmp->SetBranchAddress("fHour",&fHour);
311 sigLEDAvgAmp->SetBranchAddress("fAvgAmp",&fAvgAmp);
312 sigLEDAvgAmp->SetBranchAddress("fRMS",&fRMS);
314 for (int i=0; i<sigLEDAvgAmp->GetEntries(); i++) {
315 sigLEDAvgAmp->GetEntry(i);
316 fTreeLEDAvgAmpVsTime->Fill();
320 return kTRUE;//We hopefully succesfully added info from the supplied object
323 //_____________________________________________________________________
324 Bool_t AliCaloCalibSignal::ProcessEvent(AliRawReader *rawReader)
326 // if fMapping is NULL the rawstream will crate its own mapping
327 AliCaloRawStreamV3 rawStream(rawReader, fCaloString, (AliAltroMapping**)fMapping);
329 return ProcessEvent( &rawStream, (AliRawEventHeaderBase*)rawReader->GetEventHeader() );
332 //_____________________________________________________________________
333 Bool_t AliCaloCalibSignal::ProcessEvent(AliCaloRawStreamV3 *in, AliRawEventHeaderBase *aliHeader)
335 // Method to process=analyze one event in the data stream
336 if (!in) return kFALSE; //Return right away if there's a null pointer
338 fNEvents++; // one more event
340 // use maximum numbers to set array sizes
341 int AmpValHighGain[fgkMaxTowers];
342 int AmpValLowGain[fgkMaxTowers];
343 memset(AmpValHighGain, 0, sizeof(AmpValHighGain));
344 memset(AmpValLowGain, 0, sizeof(AmpValLowGain));
346 // also for LED reference
347 int LEDAmpVal[fgkMaxRefs * 2]; // factor 2 is for the two gain values
348 memset(LEDAmpVal, 0, sizeof(LEDAmpVal));
350 int sample; // temporary value
351 int gain = 0; // high or low gain
353 // Number of Low and High gain channels for this event:
357 int TowerNum = 0; // array index for regular towers
358 int RefNum = 0; // array index for LED references
360 // loop first to get the fraction of channels with amplitudes above cut
362 while (in->NextDDL()) {
363 while (in->NextChannel()) {
366 int max = AliEMCALGeoParams::fgkSampleMin, min = AliEMCALGeoParams::fgkSampleMax; // min and max sample values
368 while (in->NextBunch()) {
369 const UShort_t *sig = in->GetSignals();
370 for (Int_t i = 0; i < in->GetBunchLength(); i++) {
373 // check if it's a min or max value
374 if (sample < min) min = sample;
375 if (sample > max) max = sample;
377 } // loop over samples in bunch
378 } // loop over bunches
380 gain = -1; // init to not valid value
381 //If we're here then we're done with this tower
382 if ( in->IsLowGain() ) {
385 else if ( in->IsHighGain() ) {
388 else if ( in->IsLEDMonData() ) {
389 gain = in->GetRow(); // gain coded in (in RCU/Altro mapping) as Row info for LED refs..
392 // it should be enough to check the SuperModule info for each DDL really, but let's keep it here for now
393 int arrayPos = in->GetModule(); //The modules are numbered starting from 0
395 if (arrayPos < 0 || arrayPos >= fModules) {
396 printf("AliCaloCalibSignal::ProcessEvent = Oh no: arrayPos = %i.\n", arrayPos);
400 if ( in->IsHighGain() || in->IsLowGain() ) { // regular tower
401 // get tower number for AmpVal array
402 TowerNum = GetTowerNum(arrayPos, in->GetColumn(), in->GetRow());
405 // fill amplitude into the array
406 AmpValLowGain[TowerNum] = max - min;
409 else if (gain==1) {//fill the high gain ones
410 // fill amplitude into the array
411 AmpValHighGain[TowerNum] = max - min;
415 else if ( in->IsLEDMonData() ) { // LED ref.;
416 // strip # is coded is 'column' in the channel maps
417 RefNum = GetRefNum(arrayPos, in->GetColumn(), gain);
418 LEDAmpVal[RefNum] = max - min;
421 } // end while over channel
423 }//end while over DDL's, of input stream
425 in->Reset(); // just in case the next customer forgets to check if the stream was reset..
427 // now check if it was a led event, only use high gain (that should be sufficient)
428 if (fReqFractionAboveAmp) {
431 ok = CheckFractionAboveAmp(AmpValHighGain, nHighChan);
433 if (!ok) return false; // skip event
436 fNAcceptedEvents++; // one more event accepted
438 if (fStartTime == 0) { // if start-timestamp wasn't set,we'll pick it up from the first event we encounter
439 fStartTime = aliHeader->Get("Timestamp");
442 fHour = (aliHeader->Get("Timestamp")-fStartTime)/(double)fgkNumSecInHr;
443 if (fLatestHour < fHour) {
447 // it is a led event, now fill TTree
448 for(int i=0; i<fModules; i++){
449 for(int j=0; j<fColumns; j++){
450 for(int k=0; k<fRows; k++){
452 TowerNum = GetTowerNum(i, j, k);
454 if(AmpValHighGain[TowerNum]) {
455 fAmp = AmpValHighGain[TowerNum];
456 fChannelNum = GetChannelNum(i,j,k,1);
457 fTreeAmpVsTime->Fill();//fChannelNum,fHour,AmpValHighGain[TowerNum]);
458 fNHighGain[TowerNum]++;
460 if(AmpValLowGain[TowerNum]) {
461 fAmp = AmpValLowGain[TowerNum];
462 fChannelNum = GetChannelNum(i,j,k,0);
463 fTreeAmpVsTime->Fill();//fChannelNum,fHour,AmpValLowGain[TowerNum]);
464 fNLowGain[TowerNum]++;
470 for(int j=0; j<fLEDRefs; j++){
471 for (gain=0; gain<2; gain++) {
472 fRefNum = GetRefNum(i, j, gain);
473 if (LEDAmpVal[fRefNum]) {
474 fAmp = LEDAmpVal[fRefNum];
475 fTreeLEDAmpVsTime->Fill();//fRefNum,fHour,fAmp);
486 //_____________________________________________________________________
487 Bool_t AliCaloCalibSignal::Save(TString fileName)
489 //Saves all the TTrees to the designated file
491 TFile destFile(fileName, "recreate");
493 if (destFile.IsZombie()) {
500 fTreeAmpVsTime->Write();
501 fTreeLEDAmpVsTime->Write();
503 Analyze(); // get the latest and greatest averages
504 fTreeAvgAmpVsTime->Write();
505 fTreeLEDAvgAmpVsTime->Write();
513 //_____________________________________________________________________
514 Bool_t AliCaloCalibSignal::Analyze()
516 // Fill the tree holding the average values
517 if (!fUseAverage) { return kFALSE; }
519 // Reset the average TTree if Analyze has already been called earlier,
520 // meaning that the TTree could have been partially filled
521 if (fTreeAvgAmpVsTime->GetEntries() > 0) {
522 fTreeAvgAmpVsTime->Reset();
525 //0: setup variables for the TProfile plots that we'll use to do the averages
529 if (fSecInAverage > 0) {
530 numProfBins = (int)( (fLatestHour*fgkNumSecInHr)/fSecInAverage + 1 ); // round-off
532 numProfBins += 2; // add extra buffer : first and last
533 double binSize = 1.0*fSecInAverage / fgkNumSecInHr;
535 timeMax = timeMin + numProfBins*binSize;
537 //1: set up TProfiles for the towers that had data
538 TProfile * profile[fgkMaxTowers*2]; // *2 is since we include both high and low gains
539 memset(profile, 0, sizeof(profile));
541 char name[200]; // for profile id and title
544 for (int i = 0; i<fModules; i++) {
545 for (int ic=0; ic<fColumns; ic++){
546 for (int ir=0; ir<fRows; ir++) {
548 TowerNum = GetTowerNum(i, ic, ir);
550 if (fNHighGain[TowerNum] > 0) {
551 fChannelNum = GetChannelNum(i, ic, ir, 1);
552 sprintf(name, "profileChan%d", fChannelNum);
553 profile[fChannelNum] = new TProfile(name, name, numProfBins, timeMin, timeMax, "s");
557 if (fNLowGain[TowerNum] > 0) {
558 fChannelNum = GetChannelNum(i, ic, ir, 0);
559 sprintf(name, "profileChan%d", fChannelNum);
560 profile[fChannelNum] = new TProfile(name, name, numProfBins, timeMin, timeMax, "s");
567 //2: fill profiles by looping over tree
568 // Set addresses for tree-readback also
569 fTreeAmpVsTime->SetBranchAddress("fChannelNum", &fChannelNum);
570 fTreeAmpVsTime->SetBranchAddress("fHour", &fHour);
571 fTreeAmpVsTime->SetBranchAddress("fAmp", &fAmp);
573 for (int ient=0; ient<fTreeAmpVsTime->GetEntries(); ient++) {
574 fTreeAmpVsTime->GetEntry(ient);
575 if (profile[fChannelNum]) {
576 // profile should always have been created above, for active channels
577 profile[fChannelNum]->Fill(fHour, fAmp);
581 // re-associating the branch addresses here seems to be needed for OK 'average' storage
582 fTreeAvgAmpVsTime->SetBranchAddress("fChannelNum", &fChannelNum);
583 fTreeAvgAmpVsTime->SetBranchAddress("fHour", &fHour);
584 fTreeAvgAmpVsTime->SetBranchAddress("fAvgAmp", &fAvgAmp);
585 fTreeAvgAmpVsTime->SetBranchAddress("fRMS", &fRMS);
587 //3: fill avg tree by looping over the profiles
588 for (fChannelNum = 0; fChannelNum<(fgkMaxTowers*2); fChannelNum++) {
589 if (profile[fChannelNum]) { // profile was created
590 if (profile[fChannelNum]->GetEntries() > 0) { // profile had some entries
591 for(int it=0; it<numProfBins; it++) {
592 if (profile[fChannelNum]->GetBinEntries(it+1) > 0) {
593 fAvgAmp = profile[fChannelNum]->GetBinContent(it+1);
594 fHour = profile[fChannelNum]->GetBinCenter(it+1);
595 fRMS = profile[fChannelNum]->GetBinError(it+1);
596 fTreeAvgAmpVsTime->Fill();
597 } // some entries for this bin
599 } // some entries for this profile
601 } // loop over all possible channels
604 // and finally, go through same exercise for LED also..
606 //1: set up TProfiles for the towers that had data
607 TProfile * profileLED[fgkMaxRefs*2]; // *2 is since we include both high and low gains
608 memset(profileLED, 0, sizeof(profileLED));
610 for (int i = 0; i<fModules; i++) {
611 for(int j=0; j<fLEDRefs; j++){
612 for (int gain=0; gain<2; gain++) {
613 fRefNum = GetRefNum(i, j, gain);
614 if (fNRef[fRefNum] > 0) {
615 sprintf(name, "profileLEDRef%d", fRefNum);
616 profileLED[fRefNum] = new TProfile(name, name, numProfBins, timeMin, timeMax, "s");
622 //2: fill profiles by looping over tree
623 // Set addresses for tree-readback also
624 fTreeLEDAmpVsTime->SetBranchAddress("fRefNum", &fRefNum);
625 fTreeLEDAmpVsTime->SetBranchAddress("fHour", &fHour);
626 fTreeLEDAmpVsTime->SetBranchAddress("fAmp", &fAmp);
628 for (int ient=0; ient<fTreeLEDAmpVsTime->GetEntries(); ient++) {
629 fTreeLEDAmpVsTime->GetEntry(ient);
630 if (profileLED[fRefNum]) {
631 // profile should always have been created above, for active channels
632 profileLED[fRefNum]->Fill(fHour, fAmp);
636 // re-associating the branch addresses here seems to be needed for OK 'average' storage
637 fTreeLEDAvgAmpVsTime->SetBranchAddress("fRefNum", &fRefNum);
638 fTreeLEDAvgAmpVsTime->SetBranchAddress("fHour", &fHour);
639 fTreeLEDAvgAmpVsTime->SetBranchAddress("fAvgAmp", &fAvgAmp);
640 fTreeLEDAvgAmpVsTime->SetBranchAddress("fRMS", &fRMS);
642 //3: fill avg tree by looping over the profiles
643 for (fRefNum = 0; fRefNum<(fgkMaxRefs*2); fRefNum++) {
644 if (profileLED[fRefNum]) { // profile was created
645 if (profileLED[fRefNum]->GetEntries() > 0) { // profile had some entries
646 for(int it=0; it<numProfBins; it++) {
647 if (profileLED[fRefNum]->GetBinEntries(it+1) > 0) {
648 fAvgAmp = profileLED[fRefNum]->GetBinContent(it+1);
649 fHour = profileLED[fRefNum]->GetBinCenter(it+1);
650 fRMS = profileLED[fRefNum]->GetBinError(it+1);
651 fTreeLEDAvgAmpVsTime->Fill();
652 } // some entries for this bin
654 } // some entries for this profile
656 } // loop over all possible channels