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