]>
Commit | Line | Data |
---|---|---|
d99769c3 | 1 | /************************************************************************** |
66cdf5b3 | 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 | **************************************************************************/ | |
d99769c3 | 15 | |
16 | // $Id$ | |
17 | ||
18 | #include "AliMUONDigitCalibrator.h" | |
19 | ||
861d6ce8 | 20 | #include "AliLog.h" |
d99769c3 | 21 | #include "AliMUONCalibrationData.h" |
fe6ed686 | 22 | #include "AliMUONLogger.h" |
d1c20d08 | 23 | #include "AliMUONPadStatusMaker.h" |
24 | #include "AliMUONPadStatusMapMaker.h" | |
de487b6e | 25 | #include "AliMUONRecoParam.h" |
c795d086 | 26 | #include "AliMUONVCalibParam.h" |
861d6ce8 | 27 | #include "AliMUONVDigit.h" |
28 | #include "AliMUONVDigitStore.h" | |
29 | #include "AliMUONVStore.h" | |
30 | #include "AliMpBusPatch.h" | |
de98fdc9 | 31 | #include "AliMpConstants.h" |
ab167304 | 32 | #include "AliMpCDB.h" |
de98fdc9 | 33 | #include "AliMpDDLStore.h" |
861d6ce8 | 34 | #include "AliMpDEIterator.h" |
35 | #include "AliMpDetElement.h" | |
ab167304 | 36 | #include "AliMpManuStore.h" |
d99769c3 | 37 | |
3d1463c8 | 38 | //----------------------------------------------------------------------------- |
7945aae7 | 39 | /// \class AliMUONDigitCalibrator |
1171bb0a | 40 | /// Class used to calibrate digits (either real or simulated ones). |
41 | /// | |
42 | /// The calibration consists of subtracting the pedestal | |
43 | /// and multiplying by a gain, so that | |
44 | /// Signal = (ADC-pedestal)*gain | |
45 | /// | |
46 | /// Please note also that for the moment, if a digit lies on a dead channel | |
47 | /// we remove this digit from the list of digits. | |
48 | /// FIXME: this has to be revisited. By using the AliMUONDigit::fFlags we | |
49 | /// should in principle flag a digit as bad w/o removing it, but this | |
50 | /// then requires some changes in the cluster finder to deal with this extra | |
51 | /// information correctly (e.g. to set a quality for the cluster if it contains | |
52 | /// bad digits). | |
53 | /// | |
7945aae7 | 54 | /// \author Laurent Aphecetche |
3d1463c8 | 55 | //----------------------------------------------------------------------------- |
7945aae7 | 56 | |
1171bb0a | 57 | |
7945aae7 | 58 | /// \cond CLASSIMP |
d99769c3 | 59 | ClassImp(AliMUONDigitCalibrator) |
7945aae7 | 60 | /// \endcond |
d99769c3 | 61 | |
de98fdc9 | 62 | const Int_t AliMUONDigitCalibrator::fgkNoGain(0); |
63 | const Int_t AliMUONDigitCalibrator::fgkGainConstantCapa(1); | |
64 | const Int_t AliMUONDigitCalibrator::fgkGain(2); | |
66cdf5b3 | 65 | const Int_t AliMUONDigitCalibrator::fgkInjectionGain(3); |
de98fdc9 | 66 | |
d99769c3 | 67 | //_____________________________________________________________________________ |
de98fdc9 | 68 | AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib, |
ab167304 | 69 | const AliMUONRecoParam* recoParams, |
de98fdc9 | 70 | const char* calibMode) |
42825ed9 | 71 | : TObject(), |
3b6f7dce | 72 | fLogger(new AliMUONLogger(20000)), |
49e396d9 | 73 | fStatusMaker(0x0), |
74 | fStatusMapMaker(0x0), | |
75 | fPedestals(0x0), | |
de98fdc9 | 76 | fGains(0x0), |
77 | fApplyGains(0), | |
de487b6e | 78 | fCapacitances(0x0), |
79 | fNumberOfBadPads(0), | |
170f4046 | 80 | fNumberOfPads(0), |
81 | fChargeSigmaCut(0) | |
d99769c3 | 82 | { |
42825ed9 | 83 | /// ctor |
de98fdc9 | 84 | |
de487b6e | 85 | Ctor(calibMode,calib,recoParams); |
86 | } | |
87 | ||
88 | //_____________________________________________________________________________ | |
89 | AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib, | |
90 | const char* calibMode) | |
91 | : TObject(), | |
92 | fLogger(new AliMUONLogger(20000)), | |
93 | fStatusMaker(0x0), | |
94 | fStatusMapMaker(0x0), | |
95 | fPedestals(0x0), | |
96 | fGains(0x0), | |
97 | fApplyGains(0), | |
98 | fCapacitances(0x0), | |
99 | fNumberOfBadPads(0), | |
170f4046 | 100 | fNumberOfPads(0), |
101 | fChargeSigmaCut(0) | |
de487b6e | 102 | { |
103 | /// ctor | |
104 | ||
105 | Ctor(calibMode,calib,0x0); | |
106 | } | |
107 | ||
108 | //_____________________________________________________________________________ | |
109 | void | |
110 | AliMUONDigitCalibrator::Ctor(const char* calibMode, | |
111 | const AliMUONCalibrationData& calib, | |
112 | const AliMUONRecoParam* recoParams) | |
113 | { | |
114 | /// designated ctor | |
115 | ||
de98fdc9 | 116 | TString cMode(calibMode); |
117 | cMode.ToUpper(); | |
118 | ||
119 | if ( cMode == "NOGAIN" ) | |
120 | { | |
121 | fApplyGains = fgkNoGain; | |
122 | AliInfo("Will NOT apply gain correction"); | |
123 | } | |
3b6f7dce | 124 | else if ( cMode == "GAINCONSTANTCAPA" ) |
de98fdc9 | 125 | { |
126 | fApplyGains = fgkGainConstantCapa; | |
127 | AliInfo("Will apply gain correction, but with constant capacitance"); | |
128 | } | |
129 | else if ( cMode == "GAIN" ) | |
130 | { | |
131 | fApplyGains = fgkGain; | |
132 | AliInfo("Will apply gain correction, with measured capacitances"); | |
133 | } | |
66cdf5b3 | 134 | else if ( cMode == "INJECTIONGAIN") |
135 | { | |
136 | fApplyGains = fgkInjectionGain; | |
137 | AliInfo("Will apply injection gain correction, with EMELEC factory gains"); | |
138 | } | |
de98fdc9 | 139 | else |
140 | { | |
141 | AliError(Form("Invalid calib mode = %s. Will use NOGAIN instead",calibMode)); | |
142 | fApplyGains = fgkNoGain; | |
143 | } | |
66cdf5b3 | 144 | |
ab167304 | 145 | // Load mapping manu store |
146 | if ( ! AliMpCDB::LoadManuStore() ) { | |
147 | AliFatal("Could not access manu store from OCDB !"); | |
148 | } | |
66cdf5b3 | 149 | |
49e396d9 | 150 | fStatusMaker = new AliMUONPadStatusMaker(calib); |
151 | ||
170f4046 | 152 | // Set default values, as loose as reasonable |
66cdf5b3 | 153 | |
170f4046 | 154 | fChargeSigmaCut = 3.0; |
155 | ||
156 | Int_t mask(0x8080); // reject pads where ped *or* hv are missing | |
de487b6e | 157 | |
de487b6e | 158 | if ( recoParams ) |
159 | { | |
170f4046 | 160 | // if we have reco params, we use limits and cuts from there : |
161 | ||
de487b6e | 162 | fStatusMaker->SetHVSt12Limits(recoParams->HVSt12LowLimit(),recoParams->HVSt12HighLimit()); |
163 | fStatusMaker->SetHVSt345Limits(recoParams->HVSt345LowLimit(),recoParams->HVSt345HighLimit()); | |
164 | fStatusMaker->SetPedMeanLimits(recoParams->PedMeanLowLimit(),recoParams->PedMeanHighLimit()); | |
165 | fStatusMaker->SetPedSigmaLimits(recoParams->PedSigmaLowLimit(),recoParams->PedSigmaHighLimit()); | |
166 | fStatusMaker->SetGainA1Limits(recoParams->GainA1LowLimit(),recoParams->GainA1HighLimit()); | |
167 | fStatusMaker->SetGainA2Limits(recoParams->GainA2LowLimit(),recoParams->GainA2HighLimit()); | |
168 | fStatusMaker->SetGainThresLimits(recoParams->GainThresLowLimit(),recoParams->GainThresHighLimit()); | |
170f4046 | 169 | |
170 | mask = recoParams->PadGoodnessMask(); | |
de487b6e | 171 | //WARNING : getting this mask wrong is a very effective way of getting |
172 | //no digits at all out of this class ;-) | |
170f4046 | 173 | |
174 | fChargeSigmaCut = recoParams->ChargeSigmaCut(); | |
de487b6e | 175 | } |
49e396d9 | 176 | |
177 | Bool_t deferredInitialization = kTRUE; | |
178 | ||
179 | fStatusMapMaker = new AliMUONPadStatusMapMaker(*fStatusMaker,mask,deferredInitialization); | |
180 | ||
181 | fPedestals = calib.Pedestals(); | |
66cdf5b3 | 182 | |
de98fdc9 | 183 | fGains = calib.Gains(); // we get gains whatever the calibMode is, in order |
184 | // to get the saturation value... | |
66cdf5b3 | 185 | |
de98fdc9 | 186 | if ( fApplyGains == fgkGain ) |
187 | { | |
188 | fCapacitances = calib.Capacitances(); | |
189 | } | |
d99769c3 | 190 | } |
191 | ||
192 | //_____________________________________________________________________________ | |
193 | AliMUONDigitCalibrator::~AliMUONDigitCalibrator() | |
194 | { | |
d1c20d08 | 195 | /// dtor. |
49e396d9 | 196 | delete fStatusMaker; |
197 | delete fStatusMapMaker; | |
fe6ed686 | 198 | |
199 | AliInfo("Summary of messages:"); | |
200 | fLogger->Print(); | |
66cdf5b3 | 201 | |
de487b6e | 202 | AliInfo(Form("We have seen %g pads, and rejected %g (%7.2f %%)", |
203 | fNumberOfPads,fNumberOfBadPads, | |
204 | ( fNumberOfPads > 0 ) ? fNumberOfBadPads*100.0/fNumberOfPads : 0 )); | |
205 | ||
fe6ed686 | 206 | delete fLogger; |
d99769c3 | 207 | } |
208 | ||
209 | //_____________________________________________________________________________ | |
210 | void | |
42825ed9 | 211 | AliMUONDigitCalibrator::Calibrate(AliMUONVDigitStore& digitStore) |
d99769c3 | 212 | { |
42825ed9 | 213 | /// Calibrate the digits contained in digitStore |
214 | TIter next(digitStore.CreateTrackerIterator()); | |
215 | AliMUONVDigit* digit; | |
66cdf5b3 | 216 | |
0045b488 | 217 | fStatusMapMaker->RefreshRejectProbabilities(); // this will do something only for simulations |
218 | // (and only for those simulations where the reject list contain probabilities which are | |
219 | // different from zero or one) | |
861d6ce8 | 220 | |
221 | AliDebug(1,Form("# of digits = %d",digitStore.GetSize())); | |
c795d086 | 222 | |
42825ed9 | 223 | while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) ) |
d99769c3 | 224 | { |
de487b6e | 225 | if ( digit->IsCalibrated() ) |
226 | { | |
227 | fLogger->Log("ERROR : trying to calibrate a digit twice"); | |
228 | return; | |
229 | } | |
230 | ||
231 | digit->Calibrated(kTRUE); | |
232 | ||
de487b6e | 233 | Float_t charge(0.0); |
234 | Int_t statusMap; | |
235 | Bool_t isSaturated(kFALSE); | |
66cdf5b3 | 236 | |
8bf22fd6 | 237 | ++fNumberOfPads; |
66cdf5b3 | 238 | |
de487b6e | 239 | Bool_t ok = IsValidDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(),&statusMap); |
66cdf5b3 | 240 | |
de487b6e | 241 | digit->SetStatusMap(statusMap); |
242 | ||
243 | if (ok) | |
244 | { | |
de487b6e | 245 | charge = CalibrateDigit(digit->DetElemId(),digit->ManuId(),digit->ManuChannel(), |
0045b488 | 246 | digit->ADC(),fChargeSigmaCut,&isSaturated); |
de487b6e | 247 | } |
248 | else | |
249 | { | |
0045b488 | 250 | AliDebug(3,Form("Rejecting the pad DE %4d MANU %4d CH %2d ADC %6d STATUSMAP %x STATUS %s", |
251 | digit->DetElemId(),digit->ManuId(),digit->ManuChannel(), | |
252 | digit->ADC(),statusMap, | |
253 | fStatusMaker->AsString(fStatusMaker->PadStatus(digit->DetElemId(),digit->ManuId(),digit->ManuChannel())).Data())); | |
66cdf5b3 | 254 | |
de487b6e | 255 | ++fNumberOfBadPads; |
0045b488 | 256 | |
de487b6e | 257 | } |
258 | ||
259 | digit->SetCharge(charge); | |
260 | digit->Saturated(isSaturated); | |
42825ed9 | 261 | } |
262 | } | |
263 | ||
264 | //_____________________________________________________________________________ | |
de487b6e | 265 | Float_t |
266 | AliMUONDigitCalibrator::CalibrateDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel, | |
267 | Float_t adc, Float_t nsigmas, | |
268 | Bool_t* isSaturated) const | |
269 | ||
42825ed9 | 270 | { |
271 | /// Calibrate one digit | |
272 | ||
cf27231a | 273 | |
de487b6e | 274 | AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*> |
275 | (fPedestals->FindObject(detElemId,manuId)); | |
49e396d9 | 276 | |
de487b6e | 277 | if (!pedestal) |
42825ed9 | 278 | { |
de487b6e | 279 | // no pedestal -> no charge |
280 | fLogger->Log(Form("Got a null pedestal object for DE,manu=%d,%d",detElemId,manuId)); | |
281 | return 0.0; | |
42825ed9 | 282 | } |
de487b6e | 283 | |
284 | ||
285 | AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*> | |
286 | (fGains->FindObject(detElemId,manuId)); | |
287 | ||
288 | if (!gain) | |
42825ed9 | 289 | { |
de487b6e | 290 | if ( fApplyGains != fgkNoGain ) |
d99769c3 | 291 | { |
de487b6e | 292 | // no gain -> no charge |
293 | fLogger->Log(Form("Got a null gain object for DE,manu=%d,%d", | |
294 | detElemId,manuId)); | |
295 | return 0.0; | |
42825ed9 | 296 | } |
de487b6e | 297 | } |
298 | ||
299 | Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0); | |
de487b6e | 300 | |
66cdf5b3 | 301 | // Gain (mV/fC) = 1/(a0*capa) with a0~1.25 and capa~0.2 |
302 | Float_t charge(0); | |
303 | Float_t capa(0.2); // capa = 0.2 and a0 = 1.25 | |
304 | Float_t a0(1.25); // is equivalent to gain = 4 mV/fC | |
305 | Float_t a1(0); | |
306 | Float_t adc2mv(0.61); // 1 ADC channel = 0.61 mV | |
307 | Float_t injGain(4); // By default the gain is set to 4 mV/fC | |
308 | ||
309 | if ( fApplyGains == fgkGain || fApplyGains == fgkInjectionGain ) | |
de487b6e | 310 | { |
ab167304 | 311 | Int_t serialNumber |
66cdf5b3 | 312 | = AliMpManuStore::Instance()->GetManuSerial(detElemId, manuId); |
3b6f7dce | 313 | |
de487b6e | 314 | AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>(fCapacitances->FindObject(serialNumber)); |
315 | ||
316 | if ( param ) | |
42825ed9 | 317 | { |
66cdf5b3 | 318 | capa = param->ValueAsFloat(manuChannel,0); |
319 | injGain = param->ValueAsFloat(manuChannel,1); | |
42825ed9 | 320 | } |
de487b6e | 321 | else |
de98fdc9 | 322 | { |
66cdf5b3 | 323 | // If capa not found in the OCDB we use default value |
324 | fLogger->Log(Form("No capa (injGain) found for serialNumber=%d",serialNumber)); | |
325 | return 0.0; | |
de98fdc9 | 326 | } |
de487b6e | 327 | } |
328 | ||
329 | if ( padc > nsigmas*pedestal->ValueAsFloat(manuChannel,1) ) | |
330 | { | |
66cdf5b3 | 331 | if ( fApplyGains == fgkGain || fApplyGains == fgkGainConstantCapa ) |
de98fdc9 | 332 | { |
66cdf5b3 | 333 | a0 = gain->ValueAsFloat(manuChannel,0); |
334 | a1 = gain->ValueAsFloat(manuChannel,1); | |
de487b6e | 335 | Int_t thres = gain->ValueAsInt(manuChannel,2); |
336 | if ( padc < thres ) | |
3b6f7dce | 337 | { |
de487b6e | 338 | charge = a0*padc; |
3b6f7dce | 339 | } |
340 | else | |
341 | { | |
de487b6e | 342 | charge = a0*thres + a0*(padc-thres) + a1*(padc-thres)*(padc-thres); |
3b6f7dce | 343 | } |
66cdf5b3 | 344 | charge *= capa*adc2mv; |
de98fdc9 | 345 | } |
66cdf5b3 | 346 | else if ( fApplyGains == fgkInjectionGain ) |
42825ed9 | 347 | { |
66cdf5b3 | 348 | |
349 | charge = padc*adc2mv/injGain; | |
42825ed9 | 350 | } |
66cdf5b3 | 351 | else |
352 | { | |
353 | charge = a0*padc*capa*adc2mv; | |
354 | } | |
de487b6e | 355 | } |
356 | ||
de487b6e | 357 | if ( isSaturated ) |
358 | { | |
3b6f7dce | 359 | Int_t saturation(3000); |
66cdf5b3 | 360 | |
6b191dea | 361 | if ( gain && ( fApplyGains != fgkNoGain ) ) |
3b6f7dce | 362 | { |
363 | saturation = gain->ValueAsInt(manuChannel,4); | |
364 | } | |
66cdf5b3 | 365 | |
de98fdc9 | 366 | if ( padc >= saturation ) |
42825ed9 | 367 | { |
de487b6e | 368 | *isSaturated = kTRUE; |
369 | } | |
370 | else | |
371 | { | |
ada26c2d | 372 | *isSaturated = kFALSE; |
d99769c3 | 373 | } |
374 | } | |
de487b6e | 375 | |
376 | return charge; | |
d99769c3 | 377 | } |
de487b6e | 378 | |
379 | //_____________________________________________________________________________ | |
380 | Bool_t | |
381 | AliMUONDigitCalibrator::IsValidDigit(Int_t detElemId, Int_t manuId, Int_t manuChannel, | |
382 | Int_t* statusMap) const | |
383 | ||
384 | { | |
385 | /// Check if a given pad is ok or not. | |
386 | ||
387 | // First a protection against bad input parameters | |
388 | AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(detElemId); | |
389 | if (!de) return kFALSE; // not existing DE | |
390 | if (!de->IsExistingChannel(manuId,manuChannel)) | |
391 | { | |
392 | // non-existing (might happen when we get parity errors in read-out | |
393 | // that spoils the manuId | |
394 | return kFALSE; | |
395 | } | |
396 | if (!de->IsConnectedChannel(manuId,manuChannel)) | |
397 | { | |
398 | // existing (in read-out), but not connected channel | |
399 | return kFALSE; | |
400 | } | |
401 | ||
402 | // ok, now we have a valid channel number, so let's see if that pad | |
403 | // behaves or not ;-) | |
404 | ||
405 | Int_t sm = fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel); | |
406 | ||
407 | if (statusMap) *statusMap = sm; | |
408 | ||
409 | if ( ( sm & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 ) | |
410 | { | |
411 | // pad itself is bad (not testing its neighbours at this stage) | |
412 | return kFALSE; | |
413 | } | |
414 | ||
415 | return kTRUE; | |
416 | } | |
417 | ||
418 | //_____________________________________________________________________________ | |
419 | Int_t | |
420 | AliMUONDigitCalibrator::PadStatus(Int_t detElemId, Int_t manuId, Int_t manuChannel) const | |
421 | { | |
422 | /// Return the status of the given pad | |
423 | return fStatusMaker->PadStatus(detElemId,manuId,manuChannel); | |
424 | } | |
425 | ||
426 | //_____________________________________________________________________________ | |
427 | Int_t | |
428 | AliMUONDigitCalibrator::StatusMap(Int_t detElemId, Int_t manuId, Int_t manuChannel) const | |
429 | { | |
430 | /// Return the status map of the given pad | |
431 | return fStatusMapMaker->StatusMap(detElemId,manuId,manuChannel); | |
432 | ||
433 | } | |
434 |