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 **************************************************************************/
16 /* $Id: AliEMCALCalibTimeDep.cxx $ */
18 //_________________________________________________________________________
20 ///////////////////////////////////////////////////////////////////////////////
22 // class for EMCAL time-dep calibration //
24 ///////////////////////////////////////////////////////////////////////////////
27 #include <TGraphSmooth.h>
29 #include "AliCDBEntry.h"
30 #include "AliCDBManager.h"
31 #include "AliEMCALSensorTempArray.h"
32 #include "AliCaloCalibSignal.h"
33 #include "AliEMCALBiasAPD.h"
34 #include "AliEMCALCalibMapAPD.h"
35 #include "AliEMCALCalibAbs.h"
36 #include "AliEMCALCalibTimeDepCorrection.h"
37 #include "AliEMCALCalibTimeDep.h"
39 /* first a bunch of constants.. */
40 const double fkSecToHour = 1.0/3600.0; // conversion factor from seconds to hours
42 // some global variables for APD handling; values from Catania studies, best fit
43 // TempCoeff = p0+p1*M (M=gain), where p0 and and p1 are functions of the dark current
44 const double fkTempCoeffP0Const = -0.903; //
45 const double fkTempCoeffP0Factor = -1.381e7; //
46 const double fkTempCoeffP1Const = -0.023; //
47 const double fkTempCoeffP1Factor = -4.966e5; //
49 const double fkErrorCode = -999; // to indicate that something went wrong
53 ClassImp(AliEMCALCalibTimeDep)
55 //________________________________________________________________
56 AliEMCALCalibTimeDep::AliEMCALCalibTimeDep() :
64 fTemperatureResolution(0.1), // 0.1 deg C is default
65 fTimeBinsPerHour(2), // 2 30-min bins per hour is default
71 fCalibTimeDepCorrection(NULL)
76 //________________________________________________________________
77 AliEMCALCalibTimeDep::AliEMCALCalibTimeDep(const AliEMCALCalibTimeDep& calibt) :
79 fRun(calibt.GetRunNumber()),
80 fStartTime(calibt.GetStartTime()),
81 fEndTime(calibt.GetEndTime()),
82 fMinTemp(calibt.GetMinTemp()),
83 fMaxTemp(calibt.GetMaxTemp()),
84 fMinTime(calibt.GetMinTime()),
85 fMaxTime(calibt.GetMaxTime()),
86 fTemperatureResolution(calibt.GetTemperatureResolution()),
87 fTimeBinsPerHour(calibt.GetTimeBinsPerHour()),
88 fTempArray(calibt.GetTempArray()),
89 fCalibSignal(calibt.GetCalibSignal()),
90 fBiasAPD(calibt.GetBiasAPD()),
91 fCalibMapAPD(calibt.GetCalibMapAPD()),
92 fCalibAbs(calibt.GetCalibAbs()),
93 fCalibTimeDepCorrection(calibt.GetCalibTimeDepCorrection())
99 //________________________________________________________________
100 AliEMCALCalibTimeDep &AliEMCALCalibTimeDep::operator =(const AliEMCALCalibTimeDep& calibt)
102 // assignment operator; use copy ctor
103 if (&calibt == this) return *this;
105 new (this) AliEMCALCalibTimeDep(calibt);
109 //________________________________________________________________
110 AliEMCALCalibTimeDep::~AliEMCALCalibTimeDep()
115 //________________________________________________________________
116 void AliEMCALCalibTimeDep::Reset()
118 // clear variables to default
126 fTemperatureResolution = 0.1; // 0.1 deg C is default
127 fTimeBinsPerHour = 2; // 2 30-min bins per hour is default
133 fCalibTimeDepCorrection = NULL;
137 //________________________________________________________________
138 void AliEMCALCalibTimeDep::PrintInfo() const
141 cout << endl << " AliEMCALCalibTimeDep::PrintInfo() " << endl;
142 // basic variables, all 'publicly available' also
143 cout << " VARIABLE DUMP: " << endl
144 << " GetStartTime() " << GetStartTime() << endl
145 << " GetEndTime() " << GetEndTime() << endl
146 << " GetMinTemp() " << GetMinTemp() << endl
147 << " GetMaxTemp() " << GetMaxTemp() << endl;
149 cout << " RUN INFO: " << endl
150 << " length (in hours) " << GetLengthOfRunInHours() << endl
151 << " range of temperature measurements (in hours) " << GetRangeOfTempMeasureInHours()
152 << " (in deg. C) " << GetRangeOfTempMeasureInDegrees()
158 //________________________________________________________________
159 Double_t AliEMCALCalibTimeDep::GetLengthOfRunInHours() const
161 return (fEndTime - fStartTime)*fkSecToHour;
164 //________________________________________________________________
165 Double_t AliEMCALCalibTimeDep::GetLengthOfRunInBins() const
167 return (fEndTime - fStartTime)*fkSecToHour*fTimeBinsPerHour;
170 //________________________________________________________________
171 Double_t AliEMCALCalibTimeDep::GetRangeOfTempMeasureInHours() const
173 return (fMaxTime - fMinTime)*fkSecToHour;
176 //________________________________________________________________
177 Double_t AliEMCALCalibTimeDep::GetRangeOfTempMeasureInDegrees() const
179 return (fMaxTemp - fMinTemp);
182 //________________________________________________________________
183 void AliEMCALCalibTimeDep::Initialize(Int_t run,
184 UInt_t startTime, UInt_t endTime)
186 Reset(); // start fresh
189 fStartTime = startTime;
192 // collect the needed information
193 GetTemperatureInfo(); // temperature readings during the run
194 ScanTemperatureInfo(); // see what the boundaries are (Min/Max Time/Temp)
199 //________________________________________________________________
200 Double_t AliEMCALCalibTimeDep::GetTemperature(UInt_t timeStamp) const
201 {// return estimate for all SuperModules and sensors, that had data
203 // first convert from seconds to hours..
204 Double_t timeHour = (timeStamp - fStartTime) * fkSecToHour;
206 Double_t average = 0;
209 for (int i=0; i<fTempArray->NumSensors(); i++) {
211 AliEMCALSensorTemp *st = fTempArray->GetSensor(i);
213 // check if we had valid data for the time that is being asked for
214 if ( timeStamp>=st->GetStartTime() && timeStamp<=st->GetEndTime() ) {
215 AliSplineFit *f = st->GetFit();
216 if (f) { // ok, looks like we have valid data/info
217 // let's check what the expected value at the time appears to be
218 Double_t val = f->Eval(timeHour);
223 } // loop over fTempArray
225 if (n>0) { // some valid data was found
229 else { // no good data
235 //________________________________________________________________
236 Double_t AliEMCALCalibTimeDep::GetTemperatureSM(int imod, UInt_t timeStamp) const
237 {// return estimate for this one SuperModule, if it had data
239 // first convert from seconds to hours..
240 Double_t timeHour = (timeStamp - fStartTime) * fkSecToHour;
242 Double_t average = 0;
245 for (int i=0; i<fTempArray->NumSensors(); i++) {
247 AliEMCALSensorTemp *st = fTempArray->GetSensor(i);
248 int module = st->GetSector()*2 + st->GetSide();
249 if ( module == imod ) { // right module
250 // check if we had valid data for the time that is being asked for
251 if ( timeStamp>=st->GetStartTime() && timeStamp<=st->GetEndTime() ) {
252 AliSplineFit *f = st->GetFit();
253 if (f) { // ok, looks like we have valid data/info
254 // let's check what the expected value at the time appears to be
255 Double_t val = f->Eval(timeHour);
256 cout << " i " << i << " val " << val << endl;
263 } // loop over fTempArray
265 if (n>0) { // some valid data was found
269 else { // no good data
275 //________________________________________________________________
276 Double_t AliEMCALCalibTimeDep::GetTemperatureSMSensor(int imod, int isens, UInt_t timeStamp) const
277 {// return estimate for this one SuperModule and sensor, if it had data
279 // first convert from seconds to hours..
280 Double_t timeHour = (timeStamp - fStartTime) * fkSecToHour;
282 for (int i=0; i<fTempArray->NumSensors(); i++) {
284 AliEMCALSensorTemp *st = fTempArray->GetSensor(i);
285 int module = st->GetSector()*2 + st->GetSide();
286 if ( module == imod && st->GetNum()==isens ) { // right module, and sensor
287 // check if we had valid data for the time that is being asked for
288 if ( timeStamp>=st->GetStartTime() && timeStamp<=st->GetEndTime() ) {
289 AliSplineFit *f = st->GetFit();
290 if (f) { // ok, looks like we have valid data/info
291 // let's check what the expected value at the time appears to be
292 Double_t val = f->Eval(timeHour);
294 return val; // no point to move further in for loop, we have found the sensor we were looking for
299 } // loop over fTempArray
301 // if we made it all here, it means that we didn't find the sensor we were looking for
307 //________________________________________________________________
308 Int_t AliEMCALCalibTimeDep::CalcCorrection()
309 { // OK, this is where the real action takes place - the heart of this class..
310 /* The philosophy is as follows:
311 0. Init corrections to 1.0 values
312 1: if we have LED info for the tower, use it
313 2. if not 1, we rely on LED info averaged over strip
314 3. if not 2 either, we try to use temperature info + APD bias and calibration info
318 // how many SuperModules do we have?
319 Int_t nSM = fCalibAbs->GetNSuperModule();
320 // how many time-bins should we have for this run?
321 Int_t nBins = (Int_t) GetLengthOfRunInBins(); // round-down (from double to int)
322 // set up a reasonable default (correction = 1.0)
323 fCalibTimeDepCorrection->InitCorrection(nSM, nBins, 1.0);
325 // 1+2: try with LED corrections
326 Int_t nRemaining = CalcLEDCorrection(nSM, nBins);
328 // 3: try with Temperature, if needed
330 nRemaining = CalcTemperatureCorrection(nSM, nBins);
337 //________________________________________________________________
338 Double_t AliEMCALCalibTimeDep::GetTempCoeff(Double_t IDark, Double_t M) const
339 { // estimate the Temperature Coefficient, based on the dark current (IDark)
340 // and the gain (M), based on Catania parameterizations
342 Double_t P0 = fkTempCoeffP0Const + fkTempCoeffP0Factor * IDark;
343 Double_t P1 = fkTempCoeffP1Const + fkTempCoeffP1Factor * IDark;
345 Double_t TC = P0 + P1*M;
350 /* Next come the methods that do the work in picking up all the needed info..*/
351 //________________________________________________________________
352 void AliEMCALCalibTimeDep::GetTemperatureInfo()
354 // pick up Preprocessor output, based on fRun (most recent version)
355 AliCDBEntry* entry = AliCDBManager::Instance()->Get("EMCAL/Calib/Temperature", fRun);
357 fTempArray = (AliEMCALSensorTempArray *) entry->GetObject();
361 AliInfo( Form("NumSensors %d - IdDCS: first %d last %d",
362 fTempArray->NumSensors(),
363 fTempArray->GetFirstIdDCS(), fTempArray->GetLastIdDCS() ) );
366 AliWarning( Form("AliEMCALSensorTempArray not found!") );
372 //________________________________________________________________
373 Int_t AliEMCALCalibTimeDep::ScanTemperatureInfo()
374 {// assign max/min time and temperature values
376 fMinTemp = 999; // init to some large value (999 deg C)
378 fMinTime = 2147483647; // init to a large value in the far future (0x7fffffff), year 2038 times..
381 Int_t n = 0; // number of valid readings
383 for (int i=0; i<fTempArray->NumSensors(); i++) {
385 AliEMCALSensorTemp *st = fTempArray->GetSensor(i);
388 if (fMinTime > st->GetStartTime()) { fMinTime = st->GetStartTime(); }
389 if (fMaxTime < st->GetEndTime()) { fMaxTime = st->GetEndTime(); }
391 // check temperature ranges
392 TGraph *g = st->GetGraph();
393 if (g) { // ok, looks like we have valid data/info
394 // let's check what the expected value at the time appears to be
395 if (fMinTemp > g->GetMinimum()) { fMinTemp = g->GetMinimum(); }
396 if (fMaxTemp < g->GetMaximum()) { fMaxTemp = g->GetMaximum(); }
399 } // loop over fTempArray
401 if (n>0) { // some valid data was found
404 else { // no good data
405 return (Int_t) fkErrorCode;
410 //________________________________________________________________
411 void AliEMCALCalibTimeDep::GetCalibSignalInfo()
413 // pick up Preprocessor output, based on fRun (most recent version)
414 AliCDBEntry* entry = AliCDBManager::Instance()->Get("EMCAL/Calib/LED", fRun);
416 fCalibSignal = (AliCaloCalibSignal *) entry->GetObject();
420 AliInfo( Form("CalibSignal: NEvents %d NAcceptedEvents %d Entries %d AvgEntries LEDRefEntries %d LEDRefAvgEntries %d",
421 fCalibSignal->GetNEvents(), fCalibSignal->GetNAcceptedEvents(),
422 fCalibSignal->GetTreeAmpVsTime()->GetEntries(),
423 fCalibSignal->GetTreeAvgAmpVsTime()->GetEntries(),
424 fCalibSignal->GetTreeLEDAmpVsTime()->GetEntries(),
425 fCalibSignal->GetTreeLEDAvgAmpVsTime()->GetEntries() ) );
428 AliWarning( Form("AliCaloCalibSignal not found!") );
434 //________________________________________________________________
435 void AliEMCALCalibTimeDep::GetBiasAPDInfo()
437 // pick up Preprocessor output, based on fRun (most recent version)
438 AliCDBEntry* entry = AliCDBManager::Instance()->Get("EMCAL/Calib/BiasAPD", fRun);
440 fBiasAPD = (AliEMCALBiasAPD *) entry->GetObject();
444 AliInfo( Form("BiasAPD: NSuperModule %d ", fBiasAPD->GetNSuperModule() ) );
447 AliWarning( Form("AliEMCALBiasAPD not found!") );
453 //________________________________________________________________
454 void AliEMCALCalibTimeDep::GetCalibMapAPDInfo()
456 // pick up Preprocessor output, based on fRun (most recent version)
457 AliCDBEntry* entry = AliCDBManager::Instance()->Get("EMCAL/Calib/MapAPD", fRun);
459 fCalibMapAPD = (AliEMCALCalibMapAPD *) entry->GetObject();
463 AliInfo( Form("CalibMapAPD: NSuperModule %d ", fCalibMapAPD->GetNSuperModule() ) );
466 AliWarning( Form("AliEMCALCalibMapAPD not found!") );
472 //________________________________________________________________
473 void AliEMCALCalibTimeDep::GetCalibAbsInfo()
475 // pick up Preprocessor output, based on fRun (most recent version)
476 AliCDBEntry* entry = AliCDBManager::Instance()->Get("EMCAL/Calib/MapAPD", fRun);
478 fCalibAbs = (AliEMCALCalibAbs *) entry->GetObject();
482 AliInfo( Form("CalibAbs: NSuperModule %d ", fCalibAbs->GetNSuperModule() ) );
485 AliWarning( Form("AliEMCALCalibAbs not found!") );
491 //________________________________________________________________
492 Int_t AliEMCALCalibTimeDep::CalcLEDCorrection(Int_t nSM, Int_t nBins)
493 {// Construct normalized ratios R(t)=LED(t)/LEDRef(t), for current time T and calibration time t0
494 // The correction factor we keep is c(T) = R(t0)/R(T)
495 // T info from fCalibSignal, t0 info from fCalibAbs
497 // NOTE: for now we don't use the RMS info either from fCalibSignal or fCalibAbs
498 // but one could upgrade this in the future
499 Int_t nRemaining = 0; // we count the towers for which we could not get valid data
501 // sanity check; same SuperModule indices for corrections as for regular calibrations
502 AliEMCALCalibAbs::AliEMCALSuperModuleCalibAbs * CalibAbsData = fCalibAbs->GetSuperModuleData();
503 AliEMCALCalibTimeDepCorrection::AliEMCALSuperModuleCalibTimeDepCorrection * CalibTimeDepCorrectionData = fCalibTimeDepCorrection->GetSuperModuleData();
505 for (int i = 0; i < nSM; i++) {
506 int iSMAbs = CalibAbsData[i].fSuperModuleNum;
507 int iSMCorr = CalibTimeDepCorrectionData[i].fSuperModuleNum;
508 if (iSMAbs != iSMCorr) {
509 AliWarning( Form("AliEMCALCalibTimeDep - SuperModule index mismatch: %d != %d", iSMAbs, iSMCorr) );
510 nRemaining = nSM * AliEMCALGeoParams::fgkEMCALCols * AliEMCALGeoParams::fgkEMCALRows * nBins;
521 // The fCalibSignal info is stored in TTrees
522 // Note that the time-bins for the TTree's may not exactly match with our correction time bins
523 int timeDiff = fCalibSignal->GetStartTime() - fStartTime; // in seconds
524 // fCalibSignal time info in seconds: Hour/fkSecToHour
525 // corrected for startTime difference: Hour/fkSecToHour + timeDiff
526 // converted into a time-bin we use: (Hour + timeDiff*fkSecToHour) * fTimeBinsPerHour
528 // values for R(T), size of TArray = nBins
529 // the [2] dimension below is for the low or high gain
530 TArrayF ampT[AliEMCALGeoParams::fgkEMCALModules][AliEMCALGeoParams::fgkEMCALCols][AliEMCALGeoParams::fgkEMCALRows][2];
531 TArrayF nT[AliEMCALGeoParams::fgkEMCALModules][AliEMCALGeoParams::fgkEMCALCols][AliEMCALGeoParams::fgkEMCALRows][2];
532 TArrayF ampLEDRefT[AliEMCALGeoParams::fgkEMCALModules][AliEMCALGeoParams::fgkEMCALLEDRefs][2];
533 TArrayF nLEDRefT[AliEMCALGeoParams::fgkEMCALModules][AliEMCALGeoParams::fgkEMCALLEDRefs][2];
535 // set up TArray's first
536 for (iSM = 0; iSM < AliEMCALGeoParams::fgkEMCALModules; iSM++) {
537 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
538 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
539 for (iGain = 0; iGain < 2; iGain++) {
541 ampT[iSM][iCol][iRow][iGain].Set(nBins);
542 nT[iSM][iCol][iRow][iGain].Set(nBins);
544 for (int j = 0; j < nBins; j++) {
545 ampT[iSM][iCol][iRow][iGain].AddAt(0, j);
546 nT[iSM][iCol][iRow][iGain].AddAt(0, j);
551 for (iStrip = 0; iStrip < AliEMCALGeoParams::fgkEMCALLEDRefs; iStrip++) {
552 for (iGain = 0; iGain < 2; iGain++) {
554 ampLEDRefT[iSM][iStrip][iGain].Set(nBins);
555 nLEDRefT[iSM][iStrip][iGain].Set(nBins);
557 for (int j = 0; j < nBins; j++) {
558 ampLEDRefT[iSM][iStrip][iGain].AddAt(0, j);
559 nLEDRefT[iSM][iStrip][iGain].AddAt(0, j);
565 // OK, now loop over the TTrees and fill the arrays needed for R(T)
566 TTree *TAvg = fCalibSignal->GetTreeAvgAmpVsTime();
567 TTree *TLEDRefAvg = fCalibSignal->GetTreeAvgAmpVsTime();
569 int ChannelNum; // for regular towers
570 int RefNum; // for LED
574 TAvg->SetBranchAddress("fChannelNum", &ChannelNum);
575 TAvg->SetBranchAddress("fHour", &Hour);
576 TAvg->SetBranchAddress("fAvgAmp",&AvgAmp);
579 // counters for how many values were seen per SuperModule
580 int nCount[AliEMCALGeoParams::fgkEMCALModules] = {0};
581 int nCountLEDRef[AliEMCALGeoParams::fgkEMCALModules] = {0};
583 for (int ient=0; ient<TAvg->GetEntries(); ient++) {
584 TAvg->GetEntry(ient);
585 // figure out where this info comes from
586 fCalibSignal->DecodeChannelNum(ChannelNum, &iSM, &iCol, &iRow, &iGain);
587 iBin = (int) ( (Hour + timeDiff*fkSecToHour) * fTimeBinsPerHour ); // CHECK!!!
588 // add value in the arrays
589 ampT[iSM][iCol][iRow][iGain].AddAt( ampT[iSM][iCol][iRow][iGain].At(iBin)+AvgAmp, iBin );
590 nT[iSM][iCol][iRow][iGain].AddAt( nT[iSM][iCol][iRow][iGain].At(iBin)+1, iBin );
594 TLEDRefAvg->SetBranchAddress("fRefNum", &RefNum);
595 TLEDRefAvg->SetBranchAddress("fHour", &Hour);
596 TLEDRefAvg->SetBranchAddress("fAvgAmp",&AvgAmp);
598 for (int ient=0; ient<TLEDRefAvg->GetEntries(); ient++) {
599 TLEDRefAvg->GetEntry(ient);
600 // figure out where this info comes from
601 fCalibSignal->DecodeRefNum(RefNum, &iSM, &iStrip, &iGain);
602 iBin = (int) ( (Hour + timeDiff*fkSecToHour) * fTimeBinsPerHour ); // CHECK!!!
603 // add value in the arrays
604 ampLEDRefT[iSM][iStrip][iGain].AddAt( ampLEDRefT[iSM][iStrip][iGain].At(iBin)+AvgAmp, iBin );
605 nLEDRefT[iSM][iStrip][iGain].AddAt( nLEDRefT[iSM][iStrip][iGain].At(iBin)+1, iBin );
609 // Normalize TArray values, and calculate average also
610 Float_t norm = 0; // extra var, for readability
612 for (iSM = 0; iSM < AliEMCALGeoParams::fgkEMCALModules; iSM++) {
613 if (nCount[iSM]>0 && nCountLEDRef[iSM]>0) { // avoid SuperModules with no data..
614 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
615 // iStrip = AliEMCALGeoParams::GetStripModule(iSM, iCol);
616 iStrip = (iSM%2==0) ? iCol/2 : AliEMCALGeoParams::fgkEMCALLEDRefs - 1 - iCol/2; //TMP, FIXME
617 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
618 for (iGain = 0; iGain < 2; iGain++) {
620 for (int j = 0; j < nBins; j++) {
621 if (nT[iSM][iCol][iRow][iGain].At(j) > 0) {
622 norm = ampT[iSM][iCol][iRow][iGain].At(j) / nT[iSM][iCol][iRow][iGain].At(j);
623 ampT[iSM][iCol][iRow][iGain].AddAt(norm, j); // AddAt = SetAt
629 for (iStrip = 0; iStrip < AliEMCALGeoParams::fgkEMCALLEDRefs; iStrip++) {
630 for (iGain = 0; iGain < 2; iGain++) {
631 for (int j = 0; j < nBins; j++) {
632 if (nLEDRefT[iSM][iStrip][iGain].At(j) > 0) {
633 norm = ampLEDRefT[iSM][iStrip][iGain].At(j) / nLEDRefT[iSM][iStrip][iGain].At(j);
634 ampLEDRefT[iSM][iStrip][iGain].AddAt(norm, j); // AddAt = SetAt
643 // Calculate correction values, and store them
644 // set fkErrorCode values for those that could not be set
648 Float_t correction = 0; // c(T) = R(t0)/R(T)
649 Int_t refGain = 0; // typically use low gain for LED reference amplitude (high gain typically well beyond saturation)
651 for (int i = 0; i < nSM; i++) {
652 iSM = CalibAbsData[i].fSuperModuleNum;
653 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
654 // iStrip = AliEMCALGeoParams::GetStripModule(iSM, iCol);
655 iStrip = (iSM%2==0) ? iCol/2 : AliEMCALGeoParams::fgkEMCALLEDRefs - 1 - iCol/2; //TMP, FIXME
656 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
659 AliEMCALCalibAbs::AliEMCALCalibAbsVal &v = CalibAbsData[i].fAPDVal[iCol][iRow];
660 iGain = v.fHighLow; // gain value used for abs. calibration
661 refGain = CalibAbsData[i].fLEDRefHighLow[iStrip]; // LED reference gain value used for abs. calibration
663 // valid amplitude values should be larger than 0
664 if (v.fLEDAmp>0 && CalibAbsData[i].fLEDRefAmp[iStrip]>0) {
665 Rt0 = v.fLEDAmp / CalibAbsData[i].fLEDRefAmp[iStrip];
672 for (int j = 0; j < nBins; j++) {
674 // calculate R(T) also; first try with individual tower:
675 // same gain as for abs. calibration is the default
676 if (ampT[iSM][iCol][iRow][iGain].At(j)>0 && ampLEDRefT[iSM][iStrip][refGain].At(j)>0) {
677 // looks like valid data with the right gain combination
678 RT = ampT[iSM][iCol][iRow][iGain].At(j) / ampLEDRefT[iSM][iStrip][refGain].At(j);
680 // if data appears to be saturated, and we are in high gain, then try with low gain instead
681 if ( (ampT[iSM][iCol][iRow][iGain].At(j)>AliEMCALGeoParams::fgkOverflowCut && iGain==1) ||
682 (ampLEDRefT[iSM][iStrip][refGain].At(j)>AliEMCALGeoParams::fgkOverflowCut && refGain==1) ) { // presumably the gains should then both be changed.. can look into possibly only changing one in the future
683 RT = ampT[iSM][iCol][iRow][0].At(j) / ampLEDRefT[iSM][iStrip][0].At(j);
684 RT *= v.fHighLowRatio/CalibAbsData[i].fLEDRefHighLowRatio[iStrip]; // compensate for using different gain than in the absolute calibration
691 // Calc. correction factor
696 correction = fkErrorCode;
701 CalibTimeDepCorrectionData[i].fCorrection[iCol][iRow].AddAt(correction, j);
703 fTimeDepCorrection->SetCorrection(i, iCol, iRow, j, correction);
710 nRemaining = CalcLEDCorrectionStripBasis(nSM, nBins);
714 //________________________________________________________________
715 Int_t AliEMCALCalibTimeDep::CalcLEDCorrectionStripBasis(Int_t nSM, Int_t nBins)
716 { // use averages for each strip if no good values exist for some single tower
718 // go over fTimeDepCorrection info
719 Int_t nRemaining = 0; // we count the towers for which we could not get valid data
721 AliEMCALCalibTimeDepCorrection::AliEMCALSuperModuleCalibTimeDepCorrection * CalibTimeDepCorrectionData = fCalibTimeDepCorrection->GetSuperModuleData();
723 // for calculating StripAverage info
725 Float_t StripAverage = 0;
735 for (int i = 0; i < nSM; i++) {
736 iSM = CalibTimeDepCorrectionData[i].fSuperModuleNum;
737 for (int j = 0; j < nBins; j++) {
742 for (iStrip = 0; iStrip < AliEMCALGeoParams::fgkEMCALLEDRefs; iStrip++) {
744 if ((iSM%2)==1) { // C side
745 firstCol = (AliEMCALGeoParams::fgkEMCALLEDRefs-1 - iStrip)*2;
747 lastCol = firstCol+1;
749 for (iCol = firstCol; iCol <= lastCol; iCol++) {
750 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
751 val = CalibTimeDepCorrectionData[i].fCorrection[iCol][iRow].At(j);
752 if (val>0) { // valid value; error code is negative
759 // calc average over strip
761 StripAverage /= nValidTower;
762 for (iCol = firstCol; iCol <= lastCol; iCol++) {
763 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
764 val = CalibTimeDepCorrectionData[i].fCorrection[iCol][iRow].At(j);
765 if (val<0) { // invalid value; error code is negative
766 CalibTimeDepCorrectionData[i].fCorrection[iCol][iRow].AddAt(val, j);
771 else { // could not fill in unvalid entries
772 nRemaining += 2*AliEMCALGeoParams::fgkEMCALRows;
782 //________________________________________________________________
783 Int_t AliEMCALCalibTimeDep::CalcTemperatureCorrection(Int_t nSM, Int_t nBins)
784 { // OK, so we didn't have valid LED data that allowed us to do the correction only
786 // So, instead we'll rely on the temperature info and try to do the correction
787 // based on that instead.
788 // For this, we'll need the info from 3 classes (+temperature array), and output the values in a 4th class
789 Int_t nRemaining = 0;
792 AliEMCALBiasAPD::AliEMCALSuperModuleBiasAPD * BiasAPDData = fBiasAPD->GetSuperModuleData();
793 AliEMCALCalibMapAPD::AliEMCALSuperModuleCalibMapAPD * CalibMapAPDData = fCalibMapAPD->GetSuperModuleData();
794 AliEMCALCalibAbs::AliEMCALSuperModuleCalibAbs * CalibAbsData = fCalibAbs->GetSuperModuleData();
795 // correction container
796 AliEMCALCalibTimeDepCorrection::AliEMCALSuperModuleCalibTimeDepCorrection * CalibTimeDepCorrectionData = fCalibTimeDepCorrection->GetSuperModuleData();
802 Double_t TempCoeff[AliEMCALGeoParams::fgkEMCALCols][AliEMCALGeoParams::fgkEMCALRows];
803 memset(TempCoeff, 0, sizeof(TempCoeff));
805 Double_t correction = 0;
806 Double_t secondsPerBin = (1/fkSecToHour)*(1/fTimeBinsPerHour);
808 for (int i = 0; i < nSM; i++) {
809 iSM = CalibTimeDepCorrectionData[i].fSuperModuleNum;
811 // first calculate the M=Gain values, and TemperatureCoeff, for all towers in this SuperModule, from BiasAPD and CalibMapAPD info
812 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
813 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
814 AliEMCALCalibMapAPD::AliEMCALCalibMapAPDVal &mapAPD = CalibMapAPDData[i].fAPDVal[iCol][iRow];
815 MGain = fCalibMapAPD->GetGain(mapAPD.fPar[0], mapAPD.fPar[1], mapAPD.fPar[2],
816 BiasAPDData[i].fVoltage[iCol][iRow]);
817 TempCoeff[iCol][iRow] = GetTempCoeff(mapAPD.fDarkCurrent, MGain);
821 // figure out what the reference temperature is, from fCalibAbs
822 Double_t ReferenceTemperature = 0;
824 for (int iSensor = 0; iSensor<AliEMCALGeoParams::fgkEMCALTempSensors ; iSensor++) {
825 if (CalibAbsData[i].fTemperature[iSensor]>0) { // hopefully OK value
826 ReferenceTemperature += CalibAbsData[i].fTemperature[iSensor];
832 ReferenceTemperature /= nVal; // valid values exist, we can look into corrections
834 for (int j = 0; j < nBins; j++) {
836 // what is the timestamp in the middle of this bin? (0.5 is for middle of bin)
837 UInt_t timeStamp = fStartTime + (UInt_t)((j+0.5)*secondsPerBin);
838 // get the temperature at this time; use average over whole SM for now (TO BE CHECKED LATER - if we can do better with finer grained info)
839 Double_t SMTemperature = GetTemperatureSM(iSM, timeStamp);
841 Double_t TemperatureDiff = ReferenceTemperature - SMTemperature; // old vs new
842 // if the new temperature is higher than the old/reference one, then the gain has gone down
843 if (fabs(TemperatureDiff)>fTemperatureResolution) {
844 // significant enough difference that we need to consider it
846 // loop over all towers; effect of temperature change will depend on gain for this tower
847 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
848 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
850 correction = TemperatureDiff * TempCoeff[iCol][iRow];
851 CalibTimeDepCorrectionData[i].fCorrection[iCol][iRow].AddAt(correction, j);
855 } // if noteworthy temperature change
856 else { // just set correction values to 1.0
858 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
859 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
860 CalibTimeDepCorrectionData[i].fCorrection[iCol][iRow].AddAt(correction, j);
866 } // if reference temperature exist
867 else { // could not do the needed check.. signal that in the return code
868 nRemaining += AliEMCALGeoParams::fgkEMCALCols * AliEMCALGeoParams::fgkEMCALRows * nBins;