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