]> git.uio.no Git - u/mrichter/AliRoot.git/blame - MUON/AliMUONDigitCalibrator.cxx
Create the magnetic field map in the reconstruction macros (Yuri)
[u/mrichter/AliRoot.git] / MUON / AliMUONDigitCalibrator.cxx
CommitLineData
d99769c3 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
861d6ce8 20#include "AliLog.h"
d99769c3 21#include "AliMUONCalibrationData.h"
fe6ed686 22#include "AliMUONLogger.h"
d1c20d08 23#include "AliMUONPadStatusMaker.h"
24#include "AliMUONPadStatusMapMaker.h"
c795d086 25#include "AliMUONVCalibParam.h"
861d6ce8 26#include "AliMUONVDigit.h"
27#include "AliMUONVDigitStore.h"
28#include "AliMUONVStore.h"
29#include "AliMpBusPatch.h"
de98fdc9 30#include "AliMpConstants.h"
de98fdc9 31#include "AliMpDDLStore.h"
861d6ce8 32#include "AliMpDEIterator.h"
33#include "AliMpDetElement.h"
d99769c3 34
3d1463c8 35//-----------------------------------------------------------------------------
7945aae7 36/// \class AliMUONDigitCalibrator
1171bb0a 37/// Class used to calibrate digits (either real or simulated ones).
38///
39/// The calibration consists of subtracting the pedestal
40/// and multiplying by a gain, so that
41/// Signal = (ADC-pedestal)*gain
42///
43/// Please note also that for the moment, if a digit lies on a dead channel
44/// we remove this digit from the list of digits.
45/// FIXME: this has to be revisited. By using the AliMUONDigit::fFlags we
46/// should in principle flag a digit as bad w/o removing it, but this
47/// then requires some changes in the cluster finder to deal with this extra
48/// information correctly (e.g. to set a quality for the cluster if it contains
49/// bad digits).
50///
7945aae7 51/// \author Laurent Aphecetche
3d1463c8 52//-----------------------------------------------------------------------------
7945aae7 53
1171bb0a 54
7945aae7 55/// \cond CLASSIMP
d99769c3 56ClassImp(AliMUONDigitCalibrator)
7945aae7 57/// \endcond
d99769c3 58
de98fdc9 59const Int_t AliMUONDigitCalibrator::fgkNoGain(0);
60const Int_t AliMUONDigitCalibrator::fgkGainConstantCapa(1);
61const Int_t AliMUONDigitCalibrator::fgkGain(2);
62
d99769c3 63//_____________________________________________________________________________
de98fdc9 64AliMUONDigitCalibrator::AliMUONDigitCalibrator(const AliMUONCalibrationData& calib,
65 const char* calibMode)
42825ed9 66: TObject(),
3b6f7dce 67fLogger(new AliMUONLogger(20000)),
49e396d9 68fStatusMaker(0x0),
69fStatusMapMaker(0x0),
70fPedestals(0x0),
de98fdc9 71fGains(0x0),
72fApplyGains(0),
861d6ce8 73fCapacitances(0x0),
74fNofChannelsPerDE(new TExMap)
d99769c3 75{
42825ed9 76 /// ctor
de98fdc9 77
78 TString cMode(calibMode);
79 cMode.ToUpper();
80
81 if ( cMode == "NOGAIN" )
82 {
83 fApplyGains = fgkNoGain;
84 AliInfo("Will NOT apply gain correction");
85 }
3b6f7dce 86 else if ( cMode == "GAINCONSTANTCAPA" )
de98fdc9 87 {
88 fApplyGains = fgkGainConstantCapa;
89 AliInfo("Will apply gain correction, but with constant capacitance");
90 }
91 else if ( cMode == "GAIN" )
92 {
93 fApplyGains = fgkGain;
94 AliInfo("Will apply gain correction, with measured capacitances");
95 }
96 else
97 {
98 AliError(Form("Invalid calib mode = %s. Will use NOGAIN instead",calibMode));
99 fApplyGains = fgkNoGain;
100 }
101
49e396d9 102 fStatusMaker = new AliMUONPadStatusMaker(calib);
103
104 // this is here that we decide on our "goodness" policy, i.e.
105 // what do we call an invalid pad (a pad maybe bad because its HV
106 // was too low, or its pedestals too high, etc..)
107 // FIXME: find a way not to hard-code the goodness policy (i.e. the limits)
108 // here...
109 fStatusMaker->SetHVSt12Limits(1300,1600);
110 fStatusMaker->SetHVSt345Limits(1500,2000);
111 fStatusMaker->SetPedMeanLimits(50,200);
112 fStatusMaker->SetPedSigmaLimits(0.1,3);
113
114 Int_t mask(0x8080);
115 //FIXME: kind of fake one for the moment, we consider dead only
116 // if ped and/or hv value missing.
117 //WARNING : getting this mask wrong is a very effective way of getting
118 //no digits at all out of this class ;-)
119
120 Bool_t deferredInitialization = kTRUE;
121
122 fStatusMapMaker = new AliMUONPadStatusMapMaker(*fStatusMaker,mask,deferredInitialization);
123
124 fPedestals = calib.Pedestals();
de98fdc9 125
126 fGains = calib.Gains(); // we get gains whatever the calibMode is, in order
127 // to get the saturation value...
128
129 if ( fApplyGains == fgkGain )
130 {
131 fCapacitances = calib.Capacitances();
132 }
861d6ce8 133
134 // FIXME: get the nof of channels per de directly within AliMpDetElement ?
135 // or use the AliMUONTrackerData class for that ?
136
137 AliMpDEIterator it;
138
139 it.First();
140
141 while ( !it.IsDone() )
142 {
143
144 AliMpDetElement* det = it.CurrentDE();
145 Int_t detElemId = det->GetId();
146 Int_t nchannels(0);
147
148 for ( Int_t i = 0; i < det->GetNofBusPatches(); ++i )
149 {
150 Int_t busPatchId = det->GetBusPatchId(i);
151 AliMpBusPatch* bp = AliMpDDLStore::Instance()->GetBusPatch(busPatchId);
152 for ( Int_t j = 0; j < bp->GetNofManus(); ++j )
153 {
154 Int_t manuId = bp->GetManuId(j);
155 nchannels += det->NofChannelsInManu(manuId);
156 }
157 }
158
159 it.Next();
160
161 fNofChannelsPerDE->Add((Long_t)detElemId,(Long_t)nchannels);
162 }
d99769c3 163}
164
165//_____________________________________________________________________________
166AliMUONDigitCalibrator::~AliMUONDigitCalibrator()
167{
d1c20d08 168 /// dtor.
49e396d9 169 delete fStatusMaker;
170 delete fStatusMapMaker;
fe6ed686 171
172 AliInfo("Summary of messages:");
173 fLogger->Print();
174
175 delete fLogger;
861d6ce8 176 delete fNofChannelsPerDE;
d99769c3 177}
178
179//_____________________________________________________________________________
180void
42825ed9 181AliMUONDigitCalibrator::Calibrate(AliMUONVDigitStore& digitStore)
d99769c3 182{
42825ed9 183 /// Calibrate the digits contained in digitStore
184 TIter next(digitStore.CreateTrackerIterator());
185 AliMUONVDigit* digit;
861d6ce8 186 Int_t detElemId(-1);
187 Double_t nsigmas(3.0);
188
189 AliDebug(1,Form("# of digits = %d",digitStore.GetSize()));
c795d086 190
42825ed9 191 while ( ( digit = static_cast<AliMUONVDigit*>(next() ) ) )
d99769c3 192 {
861d6ce8 193 if ( digit->DetElemId() != detElemId )
194 {
195 // Find out occupancy of that DE
196 detElemId = digit->DetElemId();
197 Double_t nchannels = fNofChannelsPerDE->GetValue(detElemId);
198 Double_t occ = digitStore.GetSize(detElemId)/nchannels;
199 if ( occ > 0.05 )
200 {
201 nsigmas = 10.0; // enlarge (a lot) sigma cut if occupancy is high
202 // (which probably means zero suppression was not exactly OK).
203 fLogger->Log(Form("Will use %5.0f*sigma cut for DE %04d "
204 "due to high occupancy",nsigmas,detElemId));
205 }
206 else
207 {
208 nsigmas = 3.0;
209 }
210 }
211
212 CalibrateDigit(*digit,nsigmas);
42825ed9 213 }
214}
215
216//_____________________________________________________________________________
217void
861d6ce8 218AliMUONDigitCalibrator::CalibrateDigit(AliMUONVDigit& digit, Double_t nsigmas)
42825ed9 219{
220 /// Calibrate one digit
221
cf27231a 222 if ( digit.IsCalibrated() )
223 {
224 fLogger->Log("ERROR : trying to calibrate a digit twice");
225 return;
226 }
227
49e396d9 228 Int_t statusMap = fStatusMapMaker->StatusMap(digit.DetElemId(),
229 digit.ManuId(),
230 digit.ManuChannel());
231
42825ed9 232 digit.SetStatusMap(statusMap);
233 digit.Calibrated(kTRUE);
49e396d9 234
42825ed9 235 if ( ( statusMap & AliMUONPadStatusMapMaker::SelfDeadMask() ) != 0 )
236 {
237 // pad itself is bad (not testing its neighbours at this stage)
238 digit.SetCharge(0);
239 fLogger->Log(Form("%s:%d:Channel detElemId %d manuId %d "
240 "manuChannel %d is bad %x",__FILE__,__LINE__,
241 digit.DetElemId(),digit.ManuId(),
242 digit.ManuChannel(),digit.StatusMap()));
243 }
244 else
245 {
246 // If the channel is good, go on with the calibration itself.
247
248 AliMUONVCalibParam* pedestal = static_cast<AliMUONVCalibParam*>
49e396d9 249 (fPedestals->FindObject(digit.DetElemId(),digit.ManuId()));
3b6f7dce 250
42825ed9 251 if (!pedestal)
d99769c3 252 {
3b6f7dce 253 // no pedestal -> no charge
254 digit.SetCharge(0);
c795d086 255
3b6f7dce 256 fLogger->Log(Form("Got a null pedestal object for DE,manu=%d,%d",
257 digit.DetElemId(),digit.ManuId()));
258 return;
42825ed9 259 }
3b6f7dce 260
261
de98fdc9 262 AliMUONVCalibParam* gain = static_cast<AliMUONVCalibParam*>
263 (fGains->FindObject(digit.DetElemId(),digit.ManuId()));
264
42825ed9 265 if (!gain)
266 {
3b6f7dce 267 if ( fApplyGains != fgkNoGain )
268 {
269 // no gain -> no charge
270 digit.SetCharge(0);
271
272 fLogger->Log(Form("Got a null gain object for DE,manu=%d,%d",
273 digit.DetElemId(),digit.ManuId()));
274 return;
275 }
42825ed9 276 }
3b6f7dce 277
42825ed9 278 Int_t manuChannel = digit.ManuChannel();
279 Float_t adc = digit.ADC();
280 Float_t padc = adc-pedestal->ValueAsFloat(manuChannel,0);
cf27231a 281 Float_t charge(0);
de98fdc9 282 Float_t capa(1.0);
283
284 if ( fApplyGains == fgkGainConstantCapa )
285 {
286 capa = 0.2; // pF
287 }
288 else if ( fApplyGains == fgkGain )
289 {
290 AliMpDetElement* de = AliMpDDLStore::Instance()->GetDetElement(digit.DetElemId());
291
292 Int_t serialNumber = de->GetManuSerialFromId(digit.ManuId());
293
294 AliMUONVCalibParam* param = static_cast<AliMUONVCalibParam*>(fCapacitances->FindObject(serialNumber));
295
3b6f7dce 296 if ( param )
297 {
298 capa = param->ValueAsFloat(digit.ManuChannel());
299 }
300 else
301 {
302 fLogger->Log(Form("No capa found for serialNumber=%d",serialNumber));
303 capa = 0.0;
304 }
de98fdc9 305 }
306
861d6ce8 307 if ( padc > nsigmas*pedestal->ValueAsFloat(manuChannel,1) )
42825ed9 308 {
de98fdc9 309 if ( fApplyGains != fgkNoGain )
cf27231a 310 {
de98fdc9 311 Float_t a0 = gain->ValueAsFloat(manuChannel,0);
312 Float_t a1 = gain->ValueAsFloat(manuChannel,1);
313 Int_t thres = gain->ValueAsInt(manuChannel,2);
314 if ( padc < thres )
315 {
316 charge = a0*padc;
317 }
318 else
319 {
320 charge = a0*thres + a0*(padc-thres) + a1*(padc-thres)*(padc-thres);
321 }
cf27231a 322 }
323 else
324 {
de98fdc9 325 charge = padc;
cf27231a 326 }
42825ed9 327 }
3b6f7dce 328
de98fdc9 329 charge *= capa;
42825ed9 330 digit.SetCharge(charge);
3b6f7dce 331
332 Int_t saturation(3000);
333
334 if ( gain )
335 {
336 saturation = gain->ValueAsInt(manuChannel,4);
337 }
338
de98fdc9 339 if ( padc >= saturation )
42825ed9 340 {
341 digit.Saturated(kTRUE);
d99769c3 342 }
343 }
344}