]> git.uio.no Git - u/mrichter/AliRoot.git/blame - EMCAL/AliEMCALCalibTimeDep.cxx
bug in loop, wrong varialble in increment
[u/mrichter/AliRoot.git] / EMCAL / AliEMCALCalibTimeDep.cxx
CommitLineData
a42992b7 1/**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 * *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
6 * *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
15
16/* $Id: AliEMCALCalibTimeDep.cxx $ */
17
18//_________________________________________________________________________
19///*-- Author:
20///////////////////////////////////////////////////////////////////////////////
21// //
0ce5c45d 22// class for EMCAL time-dep calibration
23// - supposed to run in preprocessor
24// we use input from the following sources:
25// AliEMCALBiasAPD (bias values), AliEMCALCalibMapAPD (APD calibration and location info),
26// AliCaloCalibSignal (LED DA), AliEMCALSensorTempArray (ELMB DCS)
27// AliEMCALCalibReference: LED amplitude and temperature info at reference time
28//
29// output/result is in AliEMCALCalibTimeDepCorrection
a42992b7 30// //
31///////////////////////////////////////////////////////////////////////////////
32
33#include <iostream>
34#include <TGraphSmooth.h>
35#include "AliLog.h"
36#include "AliCDBEntry.h"
37#include "AliCDBManager.h"
38#include "AliEMCALSensorTempArray.h"
d81e6423 39#include "AliCaloCalibSignal.h"
40#include "AliEMCALBiasAPD.h"
41#include "AliEMCALCalibMapAPD.h"
82d90a2f 42#include "AliEMCALCalibReference.h"
d81e6423 43#include "AliEMCALCalibTimeDepCorrection.h"
a42992b7 44#include "AliEMCALCalibTimeDep.h"
45
46/* first a bunch of constants.. */
0ce5c45d 47const double kSecToHour = 1.0/3600.0; // conversion factor from seconds to hours
a42992b7 48
d81e6423 49// some global variables for APD handling; values from Catania studies, best fit
50// TempCoeff = p0+p1*M (M=gain), where p0 and and p1 are functions of the dark current
0ce5c45d 51const double kTempCoeffP0Const = -0.903; //
52const double kTempCoeffP0Factor = -1.381e7; //
53const double kTempCoeffP1Const = -0.023; //
54const double kTempCoeffP1Factor = -4.966e5; //
d81e6423 55
0ce5c45d 56const double kErrorCode = -999; // to indicate that something went wrong
621ff010 57
a42992b7 58using namespace std;
59
60ClassImp(AliEMCALCalibTimeDep)
61
62//________________________________________________________________
63AliEMCALCalibTimeDep::AliEMCALCalibTimeDep() :
64 fRun(0),
65 fStartTime(0),
66 fEndTime(0),
67 fMinTemp(0),
68 fMaxTemp(0),
716fca62 69 fMinTempVariation(0),
70 fMaxTempVariation(0),
a42992b7 71 fMinTime(0),
72 fMaxTime(0),
d81e6423 73 fTemperatureResolution(0.1), // 0.1 deg C is default
74 fTimeBinsPerHour(2), // 2 30-min bins per hour is default
82d90a2f 75 fHighLowGainFactor(16), // factor ~16 between High gain and low gain
d81e6423 76 fTempArray(NULL),
77 fCalibSignal(NULL),
78 fBiasAPD(NULL),
79 fCalibMapAPD(NULL),
82d90a2f 80 fCalibReference(NULL),
716fca62 81 fCalibTimeDepCorrection(NULL),
82 fVerbosity(0)
a42992b7 83{
84 // Constructor
85}
86
87//________________________________________________________________
88AliEMCALCalibTimeDep::AliEMCALCalibTimeDep(const AliEMCALCalibTimeDep& calibt) :
621ff010 89 TObject(calibt),
a42992b7 90 fRun(calibt.GetRunNumber()),
91 fStartTime(calibt.GetStartTime()),
92 fEndTime(calibt.GetEndTime()),
93 fMinTemp(calibt.GetMinTemp()),
94 fMaxTemp(calibt.GetMaxTemp()),
716fca62 95 fMinTempVariation(calibt.GetMinTempVariation()),
96 fMaxTempVariation(calibt.GetMaxTempVariation()),
a42992b7 97 fMinTime(calibt.GetMinTime()),
98 fMaxTime(calibt.GetMaxTime()),
d81e6423 99 fTemperatureResolution(calibt.GetTemperatureResolution()),
100 fTimeBinsPerHour(calibt.GetTimeBinsPerHour()),
82d90a2f 101 fHighLowGainFactor(calibt.GetHighLowGainFactor()),
d81e6423 102 fTempArray(calibt.GetTempArray()),
103 fCalibSignal(calibt.GetCalibSignal()),
104 fBiasAPD(calibt.GetBiasAPD()),
105 fCalibMapAPD(calibt.GetCalibMapAPD()),
82d90a2f 106 fCalibReference(calibt.GetCalibReference()),
716fca62 107 fCalibTimeDepCorrection(calibt.GetCalibTimeDepCorrection()),
108 fVerbosity(calibt.GetVerbosity())
a42992b7 109{
110 // copy constructor
111}
112
113
114//________________________________________________________________
115AliEMCALCalibTimeDep &AliEMCALCalibTimeDep::operator =(const AliEMCALCalibTimeDep& calibt)
116{
117 // assignment operator; use copy ctor
118 if (&calibt == this) return *this;
119
120 new (this) AliEMCALCalibTimeDep(calibt);
121 return *this;
122}
123
124//________________________________________________________________
125AliEMCALCalibTimeDep::~AliEMCALCalibTimeDep()
126{
127 // Destructor
128}
129
130//________________________________________________________________
131void AliEMCALCalibTimeDep::Reset()
132{
133 // clear variables to default
134 fRun = 0;
135 fStartTime = 0;
136 fEndTime = 0;
137 fMinTemp = 0;
138 fMaxTemp = 0;
716fca62 139 fMinTempVariation = 0;
140 fMaxTempVariation = 0;
a42992b7 141 fMinTime = 0;
142 fMaxTime = 0;
d81e6423 143 fTemperatureResolution = 0.1; // 0.1 deg C is default
144 fTimeBinsPerHour = 2; // 2 30-min bins per hour is default
a42992b7 145 fTempArray = NULL;
d81e6423 146 fCalibSignal = NULL;
147 fBiasAPD = NULL;
148 fCalibMapAPD = NULL;
82d90a2f 149 fCalibReference = NULL;
d81e6423 150 fCalibTimeDepCorrection = NULL;
716fca62 151 fVerbosity = 0;
a42992b7 152 return;
153}
154
155//________________________________________________________________
621ff010 156void AliEMCALCalibTimeDep::PrintInfo() const
a42992b7 157{
158 // print some info
d81e6423 159 cout << endl << " AliEMCALCalibTimeDep::PrintInfo() " << endl;
a42992b7 160 // basic variables, all 'publicly available' also
161 cout << " VARIABLE DUMP: " << endl
162 << " GetStartTime() " << GetStartTime() << endl
163 << " GetEndTime() " << GetEndTime() << endl
716fca62 164 << " GetMinTime() " << GetMinTime() << endl
165 << " GetMaxTime() " << GetMaxTime() << endl
a42992b7 166 << " GetMinTemp() " << GetMinTemp() << endl
716fca62 167 << " GetMaxTemp() " << GetMaxTemp() << endl
168 << " GetMinTempVariation() " << GetMinTempVariation() << endl
169 << " GetMaxTempVariation() " << GetMaxTempVariation() << endl;
a42992b7 170 // run ranges
171 cout << " RUN INFO: " << endl
716fca62 172 << " runnumber " << GetRunNumber() << endl
a42992b7 173 << " length (in hours) " << GetLengthOfRunInHours() << endl
174 << " range of temperature measurements (in hours) " << GetRangeOfTempMeasureInHours()
175 << " (in deg. C) " << GetRangeOfTempMeasureInDegrees()
176 << endl;
a42992b7 177
178 return;
179}
d81e6423 180
a42992b7 181//________________________________________________________________
d81e6423 182Double_t AliEMCALCalibTimeDep::GetLengthOfRunInHours() const
a42992b7 183{
0ce5c45d 184 return (fEndTime - fStartTime)*kSecToHour;
a42992b7 185}
d81e6423 186
187//________________________________________________________________
188Double_t AliEMCALCalibTimeDep::GetLengthOfRunInBins() const
189{
0ce5c45d 190 return (fEndTime - fStartTime)*kSecToHour*fTimeBinsPerHour;
d81e6423 191}
192
a42992b7 193//________________________________________________________________
d81e6423 194Double_t AliEMCALCalibTimeDep::GetRangeOfTempMeasureInHours() const
a42992b7 195{
0ce5c45d 196 return (fMaxTime - fMinTime)*kSecToHour;
a42992b7 197}
d81e6423 198
a42992b7 199//________________________________________________________________
d81e6423 200Double_t AliEMCALCalibTimeDep::GetRangeOfTempMeasureInDegrees() const
a42992b7 201{
202 return (fMaxTemp - fMinTemp);
203}
204
205//________________________________________________________________
206void AliEMCALCalibTimeDep::Initialize(Int_t run,
207 UInt_t startTime, UInt_t endTime)
0ce5c45d 208{ // setup, and get temperature info
a42992b7 209 Reset(); // start fresh
210
211 fRun = run;
212 fStartTime = startTime;
213 fEndTime = endTime;
214
215 // collect the needed information
216 GetTemperatureInfo(); // temperature readings during the run
d81e6423 217 ScanTemperatureInfo(); // see what the boundaries are (Min/Max Time/Temp)
a42992b7 218
219 return;
220}
221
222//________________________________________________________________
d81e6423 223Double_t AliEMCALCalibTimeDep::GetTemperature(UInt_t timeStamp) const
a42992b7 224{// return estimate for all SuperModules and sensors, that had data
225
226 // first convert from seconds to hours..
0ce5c45d 227 Double_t timeHour = (timeStamp - fStartTime) * kSecToHour;
621ff010 228
d81e6423 229 Double_t average = 0;
621ff010 230 int n = 0;
231
232 for (int i=0; i<fTempArray->NumSensors(); i++) {
233
234 AliEMCALSensorTemp *st = fTempArray->GetSensor(i);
235
236 // check if we had valid data for the time that is being asked for
237 if ( timeStamp>=st->GetStartTime() && timeStamp<=st->GetEndTime() ) {
238 AliSplineFit *f = st->GetFit();
239 if (f) { // ok, looks like we have valid data/info
240 // let's check what the expected value at the time appears to be
d81e6423 241 Double_t val = f->Eval(timeHour);
621ff010 242 average += val;
243 n++;
244 }
245 } // time
246 } // loop over fTempArray
247
248 if (n>0) { // some valid data was found
249 average /= n;
250 return average;
251 }
252 else { // no good data
0ce5c45d 253 return kErrorCode;
621ff010 254 }
a42992b7 255
a42992b7 256}
257
258//________________________________________________________________
d81e6423 259Double_t AliEMCALCalibTimeDep::GetTemperatureSM(int imod, UInt_t timeStamp) const
a42992b7 260{// return estimate for this one SuperModule, if it had data
261
262 // first convert from seconds to hours..
0ce5c45d 263 Double_t timeHour = (timeStamp - fStartTime) * kSecToHour;
621ff010 264
d81e6423 265 Double_t average = 0;
621ff010 266 int n = 0;
267
268 for (int i=0; i<fTempArray->NumSensors(); i++) {
269
270 AliEMCALSensorTemp *st = fTempArray->GetSensor(i);
271 int module = st->GetSector()*2 + st->GetSide();
272 if ( module == imod ) { // right module
273 // check if we had valid data for the time that is being asked for
274 if ( timeStamp>=st->GetStartTime() && timeStamp<=st->GetEndTime() ) {
275 AliSplineFit *f = st->GetFit();
276 if (f) { // ok, looks like we have valid data/info
277 // let's check what the expected value at the time appears to be
d81e6423 278 Double_t val = f->Eval(timeHour);
716fca62 279 if ( fVerbosity > 0 ) {
280 cout << " sensor i " << i << " val " << val << endl;
281 }
621ff010 282 average += val;
283 n++;
284 }
285 } // time
286 }
287
288 } // loop over fTempArray
289
290 if (n>0) { // some valid data was found
291 average /= n;
292 return average;
293 }
294 else { // no good data
0ce5c45d 295 return kErrorCode;
621ff010 296 }
a42992b7 297
a42992b7 298}
299
300//________________________________________________________________
d81e6423 301Double_t AliEMCALCalibTimeDep::GetTemperatureSMSensor(int imod, int isens, UInt_t timeStamp) const
a42992b7 302{// return estimate for this one SuperModule and sensor, if it had data
621ff010 303
a42992b7 304 // first convert from seconds to hours..
0ce5c45d 305 Double_t timeHour = (timeStamp - fStartTime) * kSecToHour;
621ff010 306
307 for (int i=0; i<fTempArray->NumSensors(); i++) {
308
309 AliEMCALSensorTemp *st = fTempArray->GetSensor(i);
310 int module = st->GetSector()*2 + st->GetSide();
311 if ( module == imod && st->GetNum()==isens ) { // right module, and sensor
312 // check if we had valid data for the time that is being asked for
313 if ( timeStamp>=st->GetStartTime() && timeStamp<=st->GetEndTime() ) {
314 AliSplineFit *f = st->GetFit();
315 if (f) { // ok, looks like we have valid data/info
316 // let's check what the expected value at the time appears to be
d81e6423 317 Double_t val = f->Eval(timeHour);
621ff010 318
319 return val; // no point to move further in for loop, we have found the sensor we were looking for
320 }
321 } // time
322 }
323
324 } // loop over fTempArray
a42992b7 325
621ff010 326 // if we made it all here, it means that we didn't find the sensor we were looking for
327 // i.e. no good data
0ce5c45d 328 return kErrorCode;
621ff010 329
a42992b7 330}
331
332//________________________________________________________________
d81e6423 333Int_t AliEMCALCalibTimeDep::CalcCorrection()
334{ // OK, this is where the real action takes place - the heart of this class..
335 /* The philosophy is as follows:
716fca62 336 0. Init corrections to 1.0 values, and see how many correction bins we need
337 1. Check how large temperature variations we have through the run - do we really need all the correction bias (otherwise adjust to single bin)
338 2. try to use temperature info + APD bias and calibration info, to estimate correction.
339 For now (from Dec 2009), we do not use LED info, since we are not taking LED triggers during the run.
d81e6423 340 */
341
342 // 0: Init
343 // how many SuperModules do we have?
82d90a2f 344 Int_t nSM = fCalibReference->GetNSuperModule();
d81e6423 345 // how many time-bins should we have for this run?
346 Int_t nBins = (Int_t) GetLengthOfRunInBins(); // round-down (from double to int)
220ed45a 347 Int_t binSize = (Int_t) (3600/fTimeBinsPerHour); // in seconds
716fca62 348
349 // 1: get info on how much individual sensors might have changed during
350 // the run (compare max-min for each sensor separately)
351 if (fMaxTempVariation < fTemperatureResolution) {
352 nBins = 1; // just one bin needed..
353 binSize = fEndTime - fStartTime;
354 }
355
d81e6423 356 // set up a reasonable default (correction = 1.0)
716fca62 357 fCalibTimeDepCorrection = new AliEMCALCalibTimeDepCorrection(nSM);
d81e6423 358 fCalibTimeDepCorrection->InitCorrection(nSM, nBins, 1.0);
220ed45a 359 fCalibTimeDepCorrection->SetStartTime(fStartTime);
360 fCalibTimeDepCorrection->SetNTimeBins(nBins);
361 fCalibTimeDepCorrection->SetTimeBinSize(binSize);
d81e6423 362
716fca62 363 // 2: try with Temperature correction
364 Int_t nRemaining = CalcTemperatureCorrection(nSM, nBins, binSize);
d81e6423 365
366 return nRemaining;
a42992b7 367}
368
d81e6423 369
370//________________________________________________________________
371Double_t AliEMCALCalibTimeDep::GetTempCoeff(Double_t IDark, Double_t M) const
372{ // estimate the Temperature Coefficient, based on the dark current (IDark)
373 // and the gain (M), based on Catania parameterizations
374
0ce5c45d 375 Double_t dP0 = kTempCoeffP0Const + kTempCoeffP0Factor * IDark;
376 Double_t dP1 = kTempCoeffP1Const + kTempCoeffP1Factor * IDark;
d81e6423 377
0ce5c45d 378 Double_t dTC = dP0 + dP1*M;
d81e6423 379
0ce5c45d 380 return dTC;
d81e6423 381}
382
383/* Next come the methods that do the work in picking up all the needed info..*/
a42992b7 384//________________________________________________________________
385void AliEMCALCalibTimeDep::GetTemperatureInfo()
386{
387 // pick up Preprocessor output, based on fRun (most recent version)
388 AliCDBEntry* entry = AliCDBManager::Instance()->Get("EMCAL/Calib/Temperature", fRun);
389 if (entry) {
390 fTempArray = (AliEMCALSensorTempArray *) entry->GetObject();
391 }
392
621ff010 393 if (fTempArray) {
a42992b7 394 AliInfo( Form("NumSensors %d - IdDCS: first %d last %d",
395 fTempArray->NumSensors(),
396 fTempArray->GetFirstIdDCS(), fTempArray->GetLastIdDCS() ) );
621ff010 397 }
398 else {
399 AliWarning( Form("AliEMCALSensorTempArray not found!") );
a42992b7 400 }
401
402 return;
403}
d81e6423 404
405//________________________________________________________________
406Int_t AliEMCALCalibTimeDep::ScanTemperatureInfo()
407{// assign max/min time and temperature values
408
409 fMinTemp = 999; // init to some large value (999 deg C)
410 fMaxTemp = 0;
716fca62 411 fMinTempVariation = 999; // init to some large value (999 deg C)
412 fMaxTempVariation = 0;
d81e6423 413 fMinTime = 2147483647; // init to a large value in the far future (0x7fffffff), year 2038 times..
414 fMaxTime = 0;
415
416 Int_t n = 0; // number of valid readings
417
418 for (int i=0; i<fTempArray->NumSensors(); i++) {
419
420 AliEMCALSensorTemp *st = fTempArray->GetSensor(i);
716fca62 421 if ( st->GetStartTime() == 0 ) { // no valid data
422 continue;
423 }
d81e6423 424
425 // check time ranges
426 if (fMinTime > st->GetStartTime()) { fMinTime = st->GetStartTime(); }
427 if (fMaxTime < st->GetEndTime()) { fMaxTime = st->GetEndTime(); }
716fca62 428
d81e6423 429 // check temperature ranges
716fca62 430 AliSplineFit *f = st->GetFit();
431
432 if (f) { // ok, looks like we have valid data/info
433 int np = f->GetKnots();
434 Double_t *y0 = f->GetY0();
435 // min and max values within the single sensor
436 Double_t min = 999;
437 Double_t max = 0;
438 for (int ip=0; ip<np; ip++) {
439 if (min > y0[ip]) { min = y0[ip]; }
440 if (max < y0[ip]) { max = y0[ip]; }
441 }
442 if (fMinTemp > min) { fMinTemp = min; }
443 if (fMaxTemp < max) { fMaxTemp = max; }
444 Double_t variation = max - min;
445 if (fMinTempVariation > variation) { fMinTempVariation = variation; }
446 if (fMaxTempVariation < variation) { fMaxTempVariation = variation; }
447
d81e6423 448 n++;
449 }
450 } // loop over fTempArray
451
452 if (n>0) { // some valid data was found
453 return n;
454 }
455 else { // no good data
0ce5c45d 456 return (Int_t) kErrorCode;
d81e6423 457 }
458
459}
460
461//________________________________________________________________
462void AliEMCALCalibTimeDep::GetCalibSignalInfo()
463{
464 // pick up Preprocessor output, based on fRun (most recent version)
465 AliCDBEntry* entry = AliCDBManager::Instance()->Get("EMCAL/Calib/LED", fRun);
466 if (entry) {
467 fCalibSignal = (AliCaloCalibSignal *) entry->GetObject();
468 }
469
470 if (fCalibSignal) {
29b7e56e 471 AliInfo( Form("CalibSignal: NEvents %d NAcceptedEvents %d Entries %lld AvgEntries LEDRefEntries %lld LEDRefEntries %lld, LEDRefAvgEntries %lld",
d81e6423 472 fCalibSignal->GetNEvents(), fCalibSignal->GetNAcceptedEvents(),
473 fCalibSignal->GetTreeAmpVsTime()->GetEntries(),
474 fCalibSignal->GetTreeAvgAmpVsTime()->GetEntries(),
29b7e56e 475 fCalibSignal->GetTreeLEDAmpVsTime()->GetEntries(),
d81e6423 476 fCalibSignal->GetTreeLEDAvgAmpVsTime()->GetEntries() ) );
477 }
478 else {
479 AliWarning( Form("AliCaloCalibSignal not found!") );
480 }
481
482 return;
483}
484
485//________________________________________________________________
486void AliEMCALCalibTimeDep::GetBiasAPDInfo()
487{
488 // pick up Preprocessor output, based on fRun (most recent version)
489 AliCDBEntry* entry = AliCDBManager::Instance()->Get("EMCAL/Calib/BiasAPD", fRun);
490 if (entry) {
2f17a269 491 fBiasAPD = (AliEMCALBiasAPD *) entry->GetObject();
d81e6423 492 }
493
494 if (fBiasAPD) {
495 AliInfo( Form("BiasAPD: NSuperModule %d ", fBiasAPD->GetNSuperModule() ) );
496 }
497 else {
498 AliWarning( Form("AliEMCALBiasAPD not found!") );
499 }
500
501 return;
502}
503
504//________________________________________________________________
505void AliEMCALCalibTimeDep::GetCalibMapAPDInfo()
506{
507 // pick up Preprocessor output, based on fRun (most recent version)
508 AliCDBEntry* entry = AliCDBManager::Instance()->Get("EMCAL/Calib/MapAPD", fRun);
61917ab3 509 // stored object should be a TTree; read the info
d81e6423 510 if (entry) {
2f17a269 511 fCalibMapAPD = (AliEMCALCalibMapAPD *) entry->GetObject();
d81e6423 512 }
513
514 if (fCalibMapAPD) {
515 AliInfo( Form("CalibMapAPD: NSuperModule %d ", fCalibMapAPD->GetNSuperModule() ) );
516 }
517 else {
518 AliWarning( Form("AliEMCALCalibMapAPD not found!") );
519 }
520
521 return;
522}
523
524//________________________________________________________________
82d90a2f 525void AliEMCALCalibTimeDep::GetCalibReferenceInfo()
d81e6423 526{
527 // pick up Preprocessor output, based on fRun (most recent version)
716fca62 528 AliCDBEntry* entry = AliCDBManager::Instance()->Get("EMCAL/Calib/Reference", fRun);
d81e6423 529 if (entry) {
82d90a2f 530 fCalibReference = (AliEMCALCalibReference *) entry->GetObject();
d81e6423 531 }
532
82d90a2f 533 if (fCalibReference) {
534 AliInfo( Form("CalibReference: NSuperModule %d ", fCalibReference->GetNSuperModule() ) );
d81e6423 535 }
536 else {
82d90a2f 537 AliWarning( Form("AliEMCALCalibReference not found!") );
d81e6423 538 }
539
540 return;
541}
542
543//________________________________________________________________
544Int_t AliEMCALCalibTimeDep::CalcLEDCorrection(Int_t nSM, Int_t nBins)
545{// Construct normalized ratios R(t)=LED(t)/LEDRef(t), for current time T and calibration time t0
546 // The correction factor we keep is c(T) = R(t0)/R(T)
82d90a2f 547 // T info from fCalibSignal, t0 info from fCalibReference
d81e6423 548
82d90a2f 549 // NOTE: for now we don't use the RMS info either from fCalibSignal or fCalibReference
d81e6423 550 // but one could upgrade this in the future
551 Int_t nRemaining = 0; // we count the towers for which we could not get valid data
552
553 // sanity check; same SuperModule indices for corrections as for regular calibrations
d81e6423 554 for (int i = 0; i < nSM; i++) {
0ce5c45d 555 AliEMCALSuperModuleCalibReference * dataCalibReference = fCalibReference->GetSuperModuleCalibReferenceNum(i);
556 AliEMCALSuperModuleCalibTimeDepCorrection * dataCalibTimeDepCorrection = fCalibTimeDepCorrection->GetSuperModuleCalibTimeDepCorrectionNum(i);
2f17a269 557
0ce5c45d 558 int iSMRef = dataCalibReference->GetSuperModuleNum();
559 int iSMCorr = dataCalibTimeDepCorrection->GetSuperModuleNum();
82d90a2f 560 if (iSMRef != iSMCorr) {
561 AliWarning( Form("AliEMCALCalibTimeDep - SuperModule index mismatch: %d != %d", iSMRef, iSMCorr) );
d81e6423 562 nRemaining = nSM * AliEMCALGeoParams::fgkEMCALCols * AliEMCALGeoParams::fgkEMCALRows * nBins;
563 return nRemaining;
564 }
565 }
566
567 int iSM = 0;
568 int iCol = 0;
569 int iRow = 0;
570 int iStrip = 0;
571 int iGain = 0;
572
573 // The fCalibSignal info is stored in TTrees
574 // Note that the time-bins for the TTree's may not exactly match with our correction time bins
575 int timeDiff = fCalibSignal->GetStartTime() - fStartTime; // in seconds
0ce5c45d 576 // fCalibSignal time info in seconds: Hour/kSecToHour
577 // corrected for startTime difference: Hour/kSecToHour + timeDiff
578 // converted into a time-bin we use: (Hour + timeDiff*kSecToHour) * fTimeBinsPerHour
d81e6423 579
580 // values for R(T), size of TArray = nBins
581 // the [2] dimension below is for the low or high gain
582 TArrayF ampT[AliEMCALGeoParams::fgkEMCALModules][AliEMCALGeoParams::fgkEMCALCols][AliEMCALGeoParams::fgkEMCALRows][2];
583 TArrayF nT[AliEMCALGeoParams::fgkEMCALModules][AliEMCALGeoParams::fgkEMCALCols][AliEMCALGeoParams::fgkEMCALRows][2];
584 TArrayF ampLEDRefT[AliEMCALGeoParams::fgkEMCALModules][AliEMCALGeoParams::fgkEMCALLEDRefs][2];
585 TArrayF nLEDRefT[AliEMCALGeoParams::fgkEMCALModules][AliEMCALGeoParams::fgkEMCALLEDRefs][2];
586
587 // set up TArray's first
588 for (iSM = 0; iSM < AliEMCALGeoParams::fgkEMCALModules; iSM++) {
589 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
590 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
591 for (iGain = 0; iGain < 2; iGain++) {
592 // length of arrays
593 ampT[iSM][iCol][iRow][iGain].Set(nBins);
594 nT[iSM][iCol][iRow][iGain].Set(nBins);
595 // content of arrys
596 for (int j = 0; j < nBins; j++) {
597 ampT[iSM][iCol][iRow][iGain].AddAt(0, j);
598 nT[iSM][iCol][iRow][iGain].AddAt(0, j);
599 }
600 }
601 }
602 }//iCol
603 for (iStrip = 0; iStrip < AliEMCALGeoParams::fgkEMCALLEDRefs; iStrip++) {
604 for (iGain = 0; iGain < 2; iGain++) {
605 // length of arrays
606 ampLEDRefT[iSM][iStrip][iGain].Set(nBins);
607 nLEDRefT[iSM][iStrip][iGain].Set(nBins);
608 // content of arrys
609 for (int j = 0; j < nBins; j++) {
610 ampLEDRefT[iSM][iStrip][iGain].AddAt(0, j);
611 nLEDRefT[iSM][iStrip][iGain].AddAt(0, j);
612 }
613 }
614 }//iStrip
615 }
616
617 // OK, now loop over the TTrees and fill the arrays needed for R(T)
0ce5c45d 618 TTree *treeAvg = fCalibSignal->GetTreeAvgAmpVsTime();
619 TTree *treeLEDRefAvg = fCalibSignal->GetTreeAvgAmpVsTime();
d81e6423 620
18831b6c 621 int iChannelNum = 0; // for regular towers
622 int iRefNum = 0; // for LED
623 double dHour = 0;
624 double dAvgAmp = 0;
d81e6423 625
0ce5c45d 626 treeAvg->SetBranchAddress("fChannelNum", &iChannelNum);
627 treeAvg->SetBranchAddress("fHour", &dHour);
628 treeAvg->SetBranchAddress("fAvgAmp",&dAvgAmp);
d81e6423 629
630 int iBin = 0;
631 // counters for how many values were seen per SuperModule
632 int nCount[AliEMCALGeoParams::fgkEMCALModules] = {0};
633 int nCountLEDRef[AliEMCALGeoParams::fgkEMCALModules] = {0};
634
0ce5c45d 635 for (int ient=0; ient<treeAvg->GetEntries(); ient++) {
636 treeAvg->GetEntry(ient);
d81e6423 637 // figure out where this info comes from
0ce5c45d 638 fCalibSignal->DecodeChannelNum(iChannelNum, &iSM, &iCol, &iRow, &iGain);
639 iBin = (int) ( (dHour + timeDiff*kSecToHour) * fTimeBinsPerHour ); // CHECK!!!
d81e6423 640 // add value in the arrays
0ce5c45d 641 ampT[iSM][iCol][iRow][iGain].AddAt( ampT[iSM][iCol][iRow][iGain].At(iBin)+dAvgAmp, iBin );
d81e6423 642 nT[iSM][iCol][iRow][iGain].AddAt( nT[iSM][iCol][iRow][iGain].At(iBin)+1, iBin );
643 nCount[iSM]++;
644 }
645
0ce5c45d 646 treeLEDRefAvg->SetBranchAddress("fRefNum", &iRefNum);
647 treeLEDRefAvg->SetBranchAddress("fHour", &dHour);
648 treeLEDRefAvg->SetBranchAddress("fAvgAmp",&dAvgAmp);
d81e6423 649
0ce5c45d 650 for (int ient=0; ient<treeLEDRefAvg->GetEntries(); ient++) {
651 treeLEDRefAvg->GetEntry(ient);
d81e6423 652 // figure out where this info comes from
0ce5c45d 653 fCalibSignal->DecodeRefNum(iRefNum, &iSM, &iStrip, &iGain);
654 iBin = (int) ( (dHour + timeDiff*kSecToHour) * fTimeBinsPerHour ); // CHECK!!!
d81e6423 655 // add value in the arrays
0ce5c45d 656 ampLEDRefT[iSM][iStrip][iGain].AddAt( ampLEDRefT[iSM][iStrip][iGain].At(iBin)+dAvgAmp, iBin );
d81e6423 657 nLEDRefT[iSM][iStrip][iGain].AddAt( nLEDRefT[iSM][iStrip][iGain].At(iBin)+1, iBin );
658 nCountLEDRef[iSM]++;
659 }
660
661 // Normalize TArray values, and calculate average also
662 Float_t norm = 0; // extra var, for readability
663
664 for (iSM = 0; iSM < AliEMCALGeoParams::fgkEMCALModules; iSM++) {
665 if (nCount[iSM]>0 && nCountLEDRef[iSM]>0) { // avoid SuperModules with no data..
666 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
667 // iStrip = AliEMCALGeoParams::GetStripModule(iSM, iCol);
668 iStrip = (iSM%2==0) ? iCol/2 : AliEMCALGeoParams::fgkEMCALLEDRefs - 1 - iCol/2; //TMP, FIXME
669 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
670 for (iGain = 0; iGain < 2; iGain++) {
671 // content of arrys
672 for (int j = 0; j < nBins; j++) {
673 if (nT[iSM][iCol][iRow][iGain].At(j) > 0) {
674 norm = ampT[iSM][iCol][iRow][iGain].At(j) / nT[iSM][iCol][iRow][iGain].At(j);
675 ampT[iSM][iCol][iRow][iGain].AddAt(norm, j); // AddAt = SetAt
676 }
677 }
678 }
679 }
680 }//iCol
681 for (iStrip = 0; iStrip < AliEMCALGeoParams::fgkEMCALLEDRefs; iStrip++) {
682 for (iGain = 0; iGain < 2; iGain++) {
683 for (int j = 0; j < nBins; j++) {
684 if (nLEDRefT[iSM][iStrip][iGain].At(j) > 0) {
685 norm = ampLEDRefT[iSM][iStrip][iGain].At(j) / nLEDRefT[iSM][iStrip][iGain].At(j);
686 ampLEDRefT[iSM][iStrip][iGain].AddAt(norm, j); // AddAt = SetAt
687 }
688 }
689 }
690 }//iStrip
691 }
692 } // iSM
693
694
695 // Calculate correction values, and store them
0ce5c45d 696 // set kErrorCode values for those that could not be set
d81e6423 697
0ce5c45d 698 Float_t ratiot0 = 0;
699 Float_t ratioT = 0;
d81e6423 700 Float_t correction = 0; // c(T) = R(t0)/R(T)
701 Int_t refGain = 0; // typically use low gain for LED reference amplitude (high gain typically well beyond saturation)
702
703 for (int i = 0; i < nSM; i++) {
0ce5c45d 704 AliEMCALSuperModuleCalibReference * dataCalibReference = fCalibReference->GetSuperModuleCalibReferenceNum(i);
705 AliEMCALSuperModuleCalibTimeDepCorrection * dataCalibTimeDepCorrection = fCalibTimeDepCorrection->GetSuperModuleCalibTimeDepCorrectionNum(i);
706 iSM = dataCalibReference->GetSuperModuleNum();
2f17a269 707
d81e6423 708 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
709 // iStrip = AliEMCALGeoParams::GetStripModule(iSM, iCol);
710 iStrip = (iSM%2==0) ? iCol/2 : AliEMCALGeoParams::fgkEMCALLEDRefs - 1 - iCol/2; //TMP, FIXME
0ce5c45d 711 refGain = dataCalibReference->GetLEDRefHighLow(iStrip); // LED reference gain value used for reference calibration
82d90a2f 712
d81e6423 713 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
714
715 // Calc. R(t0):
0ce5c45d 716 AliEMCALCalibReferenceVal * refVal = dataCalibReference->GetAPDVal(iCol, iRow);
82d90a2f 717 iGain = refVal->GetHighLow(); // gain value used for reference calibration
d81e6423 718 // valid amplitude values should be larger than 0
0ce5c45d 719 if (refVal->GetLEDAmp()>0 && dataCalibReference->GetLEDRefAmp(iStrip)>0) {
720 ratiot0 = refVal->GetLEDAmp() / dataCalibReference->GetLEDRefAmp(iStrip);
d81e6423 721 }
722 else {
0ce5c45d 723 ratiot0 = kErrorCode;
d81e6423 724 }
725
82d90a2f 726 // Calc. R(T)
d81e6423 727 for (int j = 0; j < nBins; j++) {
728
729 // calculate R(T) also; first try with individual tower:
82d90a2f 730 // same gain as for reference calibration is the default
d81e6423 731 if (ampT[iSM][iCol][iRow][iGain].At(j)>0 && ampLEDRefT[iSM][iStrip][refGain].At(j)>0) {
732 // looks like valid data with the right gain combination
0ce5c45d 733 ratioT = ampT[iSM][iCol][iRow][iGain].At(j) / ampLEDRefT[iSM][iStrip][refGain].At(j);
d81e6423 734
735 // if data appears to be saturated, and we are in high gain, then try with low gain instead
82d90a2f 736 int newGain = iGain;
737 int newRefGain = refGain;
738 if ( ampT[iSM][iCol][iRow][iGain].At(j)>AliEMCALGeoParams::fgkOverflowCut && iGain==1 ) {
739 newGain = 0;
740 }
741 if ( ampLEDRefT[iSM][iStrip][refGain].At(j)>AliEMCALGeoParams::fgkOverflowCut && refGain==1 ) {
742 newRefGain = 0;
743 }
744
745 if (newGain!=iGain || newRefGain!=refGain) {
746 // compensate for using different gain than in the reference calibration
747 // we may need to have a custom H/L ratio value for each tower
748 // later, but for now just use a common value, as the rest of the code does..
0ce5c45d 749 ratioT = ampT[iSM][iCol][iRow][newGain].At(j) / ampLEDRefT[iSM][iStrip][newRefGain].At(j);
82d90a2f 750
751 if (newGain<iGain) {
0ce5c45d 752 ratioT *= fHighLowGainFactor;
82d90a2f 753 }
754 else if (newRefGain<refGain) {
0ce5c45d 755 ratioT /= fHighLowGainFactor;
82d90a2f 756 }
d81e6423 757 }
758 }
759 else {
0ce5c45d 760 ratioT = kErrorCode;
d81e6423 761 }
762
763 // Calc. correction factor
0ce5c45d 764 if (ratiot0>0 && ratioT>0) {
765 correction = ratiot0/ratioT;
d81e6423 766 }
767 else {
0ce5c45d 768 correction = kErrorCode;
d81e6423 769 nRemaining++;
770 }
771
772 // Store the value
0ce5c45d 773 dataCalibTimeDepCorrection->GetCorrection(iCol,iRow)->AddAt(correction, j);
d81e6423 774 /* Check that
775 fTimeDepCorrection->SetCorrection(i, iCol, iRow, j, correction);
776 also works OK */
777 } // nBins
778 }
779 }
780 }
781
782 nRemaining = CalcLEDCorrectionStripBasis(nSM, nBins);
783 return nRemaining;
784}
785
786//________________________________________________________________
787Int_t AliEMCALCalibTimeDep::CalcLEDCorrectionStripBasis(Int_t nSM, Int_t nBins)
788{ // use averages for each strip if no good values exist for some single tower
789
790 // go over fTimeDepCorrection info
791 Int_t nRemaining = 0; // we count the towers for which we could not get valid data
792
d81e6423 793 // for calculating StripAverage info
794 int nValidTower = 0;
0ce5c45d 795 Float_t stripAverage = 0;
d81e6423 796 Float_t val = 0;
797
798 int iSM = 0;
799 int iCol = 0;
800 int iRow = 0;
801 int iStrip = 0;
802 int firstCol = 0;
803 int lastCol = 0;
804
805 for (int i = 0; i < nSM; i++) {
0ce5c45d 806 AliEMCALSuperModuleCalibTimeDepCorrection * dataCalibTimeDepCorrection = fCalibTimeDepCorrection->GetSuperModuleCalibTimeDepCorrectionNum(i);
807 iSM = dataCalibTimeDepCorrection->GetSuperModuleNum();
2f17a269 808
d81e6423 809 for (int j = 0; j < nBins; j++) {
810
811 nValidTower = 0;
0ce5c45d 812 stripAverage = 0;
d81e6423 813
814 for (iStrip = 0; iStrip < AliEMCALGeoParams::fgkEMCALLEDRefs; iStrip++) {
815 firstCol = iStrip*2;
816 if ((iSM%2)==1) { // C side
817 firstCol = (AliEMCALGeoParams::fgkEMCALLEDRefs-1 - iStrip)*2;
818 }
819 lastCol = firstCol+1;
820
821 for (iCol = firstCol; iCol <= lastCol; iCol++) {
822 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
0ce5c45d 823 val = dataCalibTimeDepCorrection->GetCorrection(iCol,iRow)->At(j);
d81e6423 824 if (val>0) { // valid value; error code is negative
0ce5c45d 825 stripAverage += val;
d81e6423 826 nValidTower++;
827 }
828 }
829 }
830
831 // calc average over strip
832 if (nValidTower>0) {
0ce5c45d 833 stripAverage /= nValidTower;
d81e6423 834 for (iCol = firstCol; iCol <= lastCol; iCol++) {
835 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
0ce5c45d 836 val = dataCalibTimeDepCorrection->GetCorrection(iCol,iRow)->At(j);
d81e6423 837 if (val<0) { // invalid value; error code is negative
0ce5c45d 838 dataCalibTimeDepCorrection->GetCorrection(iCol,iRow)->AddAt(val, j);
d81e6423 839 }
840 }
841 }
842 }
843 else { // could not fill in unvalid entries
844 nRemaining += 2*AliEMCALGeoParams::fgkEMCALRows;
845 }
846
847 } // iStrip
848 } // j, bins
849 } // iSM
850
851 return nRemaining;
852}
853
854//________________________________________________________________
716fca62 855Int_t AliEMCALCalibTimeDep::CalcTemperatureCorrection(Int_t nSM, Int_t nBins, Int_t binSize)
d81e6423 856{ // OK, so we didn't have valid LED data that allowed us to do the correction only
857 // with that info.
858 // So, instead we'll rely on the temperature info and try to do the correction
859 // based on that instead.
860 // For this, we'll need the info from 3 classes (+temperature array), and output the values in a 4th class
861 Int_t nRemaining = 0;
862
d81e6423 863 int iSM = 0;
864 int iCol = 0;
865 int iRow = 0;
866
0ce5c45d 867 Double_t dTempCoeff[AliEMCALGeoParams::fgkEMCALCols][AliEMCALGeoParams::fgkEMCALRows];
868 memset(dTempCoeff, 0, sizeof(dTempCoeff));
869 Float_t gainM = 0;
d81e6423 870 Double_t correction = 0;
716fca62 871 Double_t secondsPerBin = (Double_t) binSize;
d81e6423 872
873 for (int i = 0; i < nSM; i++) {
716fca62 874 AliEMCALSuperModuleCalibTimeDepCorrection * dataCalibTimeDepCorrection = fCalibTimeDepCorrection->GetSuperModuleCalibTimeDepCorrectionNum(i);
0ce5c45d 875 iSM = dataCalibTimeDepCorrection->GetSuperModuleNum();
2f17a269 876
0ce5c45d 877 AliEMCALSuperModuleCalibReference * dataCalibReference = fCalibReference->GetSuperModuleCalibReferenceNum(iSM);
878 AliEMCALSuperModuleCalibMapAPD * dataCalibMapAPD = fCalibMapAPD->GetSuperModuleCalibMapAPDNum(iSM);
716fca62 879 AliEMCALSuperModuleBiasAPD * dataBiasAPD = fBiasAPD->GetSuperModuleBiasAPDNum(iSM);
880
d81e6423 881 // first calculate the M=Gain values, and TemperatureCoeff, for all towers in this SuperModule, from BiasAPD and CalibMapAPD info
882 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
883 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
0ce5c45d 884 AliEMCALCalibMapAPDVal * mapAPD = dataCalibMapAPD->GetAPDVal(iCol, iRow);
885 gainM = fCalibMapAPD->GetGain(mapAPD->GetPar(0), mapAPD->GetPar(1), mapAPD->GetPar(2),
886 dataBiasAPD->GetVoltage(iCol, iRow));
887 dTempCoeff[iCol][iRow] = GetTempCoeff(mapAPD->GetDarkCurrent(), gainM);
716fca62 888 if (fVerbosity > 1) {
889 cout << " iSM " << iSM << " iCol " << iCol << " iRow " << iRow
890 << " par0 " << mapAPD->GetPar(0)
891 << " par1 " << mapAPD->GetPar(1)
892 << " par2 " << mapAPD->GetPar(2)
893 << " bias " << dataBiasAPD->GetVoltage(iCol, iRow)
894 << " gainM " << gainM << " dTempCoeff " << dTempCoeff[iCol][iRow] << endl;
895 }
d81e6423 896 }
897 }
898
82d90a2f 899 // figure out what the reference temperature is, from fCalibReference
0ce5c45d 900 Double_t referenceTemperature = 0;
d81e6423 901 int nVal = 0;
902 for (int iSensor = 0; iSensor<AliEMCALGeoParams::fgkEMCALTempSensors ; iSensor++) {
0ce5c45d 903 if (dataCalibReference->GetTemperature(iSensor)>0) { // hopefully OK value
904 referenceTemperature += dataCalibReference->GetTemperature(iSensor);
d81e6423 905 nVal++;
906 }
907 }
908
909 if (nVal>0) {
0ce5c45d 910 referenceTemperature /= nVal; // valid values exist, we can look into corrections
d81e6423 911
912 for (int j = 0; j < nBins; j++) {
d81e6423 913 // what is the timestamp in the middle of this bin? (0.5 is for middle of bin)
914 UInt_t timeStamp = fStartTime + (UInt_t)((j+0.5)*secondsPerBin);
915 // 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)
0ce5c45d 916 Double_t dSMTemperature = GetTemperatureSM(iSM, timeStamp);
d81e6423 917
716fca62 918 Double_t temperatureDiff = dSMTemperature - referenceTemperature ; // new - old
919 if (fVerbosity > 0) {
920 cout << " referenceTemperature " << referenceTemperature
921 << " dSMTemperature " << dSMTemperature
922 << " temperatureDiff " << temperatureDiff
923 << endl;
924 }
d81e6423 925 // if the new temperature is higher than the old/reference one, then the gain has gone down
716fca62 926 // if the new temperature is lower than the old/reference one, then the gain has gone up
927 // dTempCoeff is a negative number describing how many % (hence 0.01 factor below) the gain
928 // changes with a positive degree change.
929 // i.e. the product temperatureDiff * dTempCoeff increase when the gain goes up
930 // The correction we want to keep is what we should multiply our ADC value with as a function
931 // of time, i.e. the inverse of the gain change..
0ce5c45d 932 if (fabs(temperatureDiff)>fTemperatureResolution) {
d81e6423 933 // significant enough difference that we need to consider it
934
935 // loop over all towers; effect of temperature change will depend on gain for this tower
936 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
937 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
938
716fca62 939 // the correction should be inverse of modification in gain: (see discussion above)
940 // modification in gain: 1.0 + (temperatureDiff * dTempCoeff[iCol][iRow])*0.01;
941 // 1/(1+x) ~= 1 - x for small x, i.e. we arrive at:
942 correction = 1.0 - (temperatureDiff * dTempCoeff[iCol][iRow])*0.01;
0ce5c45d 943 dataCalibTimeDepCorrection->GetCorrection(iCol,iRow)->AddAt(correction, j);
716fca62 944 if (fVerbosity > 1) {
945 cout << " iSM " << iSM
946 << " iCol " << iCol
947 << " iRow " << iRow
948 << " j " << j
949 << " correction " << correction
950 << endl;
951 }
d81e6423 952 }
953 }
954
955 } // if noteworthy temperature change
956 else { // just set correction values to 1.0
957 correction = 1;
958 for (iCol = 0; iCol < AliEMCALGeoParams::fgkEMCALCols; iCol++) {
959 for (iRow = 0; iRow < AliEMCALGeoParams::fgkEMCALRows; iRow++) {
0ce5c45d 960 dataCalibTimeDepCorrection->GetCorrection(iCol,iRow)->AddAt(correction, j);
d81e6423 961 }
962 }
963 } // else
964 } // j, Bins
965
966 } // if reference temperature exist
967 else { // could not do the needed check.. signal that in the return code
968 nRemaining += AliEMCALGeoParams::fgkEMCALCols * AliEMCALGeoParams::fgkEMCALRows * nBins;
969 }
970 } // iSM
971
972 return nRemaining;
973}
974