- Disentangle masks effect from trigger chamber efficiency estimation.
[u/mrichter/AliRoot.git] / MUON / AliMUONDigitizerV3.cxx
CommitLineData
92aeef15 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
9edefa04 18
92aeef15 19#include "AliMUONDigitizerV3.h"
20
4ce497c4 21#include "AliMUON.h"
92aeef15 22#include "AliMUONCalibrationData.h"
92aeef15 23#include "AliMUONConstants.h"
92aeef15 24#include "AliMUONDigit.h"
ad26d4f6 25#include "AliMUONLogger.h"
4f8a3d8b 26#include "AliMUONTriggerElectronics.h"
40e382ae 27#include "AliMUONTriggerStoreV1.h"
05314992 28#include "AliMUONVCalibParam.h"
40e382ae 29#include "AliMUONVDigitStore.h"
331a617a 30#include "AliMUONGeometryTransformer.h" //ADDED for trigger noise
d5315275 31#include "AliMUONTriggerChamberEfficiency.h"
32#include "AliMUONTriggerUtilities.h"
331a617a 33
88544f7e 34#include "AliMpCDB.h"
331a617a 35#include "AliMpSegmentation.h"
40e382ae 36#include "AliMpCathodType.h"
37#include "AliMpConstants.h"
4ce497c4 38#include "AliMpDEIterator.h"
92aeef15 39#include "AliMpDEManager.h"
4ce497c4 40#include "AliMpPad.h"
40e382ae 41#include "AliMpStationType.h"
4ce497c4 42#include "AliMpVSegmentation.h"
d5315275 43#include "AliMpDDLStore.h"
331a617a 44
45#include "AliCDBManager.h"
46#include "AliCodeTimer.h"
47#include "AliLog.h"
92aeef15 48#include "AliRun.h"
49#include "AliRunDigitizer.h"
c93255fe 50#include "AliLoader.h"
92aeef15 51#include "AliRunLoader.h"
331a617a 52
866c3232 53#include <Riostream.h>
54#include <TF1.h>
40e382ae 55#include <TFile.h>
866c3232 56#include <TMath.h>
57#include <TRandom.h>
58#include <TString.h>
40e382ae 59#include <TSystem.h>
c93255fe 60#include <TTree.h>
40e382ae 61
3d1463c8 62//-----------------------------------------------------------------------------
9265505b 63/// \class AliMUONDigitizerV3
4ce497c4 64/// The digitizer is performing the transformation to go from SDigits (digits
65/// w/o any electronic noise) to Digits (w/ electronic noise, and decalibration)
66///
67/// The decalibration is performed by doing the reverse operation of the
68/// calibration, that is we do (Signal+pedestal)/gain -> ADC
69///
70/// Note also that the digitizer takes care of merging sdigits that belongs
71/// to the same pad, either because we're merging several input sdigit files
72/// or with a single file because the sdigitizer does not merge sdigits itself
73/// (for performance reason mainly, and because anyway we know we have to do it
74/// here, at the digitization level).
75///
c4ee792d 76/// \author Laurent Aphecetche
3d1463c8 77//-----------------------------------------------------------------------------
4ce497c4 78
79namespace
80{
81 AliMUON* muon()
82 {
83 return static_cast<AliMUON*>(gAlice->GetModule("MUON"));
84 }
8c0b5e70 85
86 //ADDED for trigger noise
87 const AliMUONGeometryTransformer* GetTransformer()
88 {
89 return muon()->GetGeometryTransformer();
90 }
4ce497c4 91}
92
5c083cba 93Double_t AliMUONDigitizerV3::fgNSigmas = 4.0;
4ce497c4 94
9265505b 95/// \cond CLASSIMP
92aeef15 96ClassImp(AliMUONDigitizerV3)
9265505b 97/// \endcond
92aeef15 98
99//_____________________________________________________________________________
100AliMUONDigitizerV3::AliMUONDigitizerV3(AliRunDigitizer* manager,
8c0b5e70 101 Int_t generateNoisyDigits)
92aeef15 102: AliDigitizer(manager),
92aeef15 103fIsInitialized(kFALSE),
92aeef15 104fCalibrationData(0x0),
105fTriggerProcessor(0x0),
8c0b5e70 106fNoiseFunctionTrig(0x0),
ec9acc85 107fGenerateNoisyDigits(generateNoisyDigits),
108fLogger(new AliMUONLogger(1000)),
40e382ae 109fTriggerStore(new AliMUONTriggerStoreV1),
110fDigitStore(0x0),
9ec6a948 111fOutputDigitStore(0x0),
d5315275 112fInputDigitStores(0x0),
113fTriggerEfficiency(0x0),
114fTriggerUtilities(0x0),
115fEfficiencyResponse(2*AliMUONConstants::NTriggerCh()*AliMUONConstants::NTriggerCircuit())
92aeef15 116{
9265505b 117 /// Ctor.
118
92aeef15 119 AliDebug(1,Form("AliRunDigitizer=%p",fManager));
ec9acc85 120
92aeef15 121}
122
123//_____________________________________________________________________________
124AliMUONDigitizerV3::~AliMUONDigitizerV3()
125{
9265505b 126 /// Dtor. Note we're the owner of some pointers.
127
92aeef15 128 AliDebug(1,"dtor");
4ce497c4 129
92c23b09 130 // delete fCalibrationData;
92aeef15 131 delete fTriggerProcessor;
8c0b5e70 132 delete fNoiseFunctionTrig;
40e382ae 133 delete fTriggerStore;
134 delete fDigitStore;
135 delete fOutputDigitStore;
ca8c8223 136 delete fInputDigitStores;
d5315275 137 delete fTriggerUtilities;
9ec6a948 138
ad26d4f6 139 AliInfo("Summary of messages");
140 fLogger->Print();
4ce497c4 141
ad26d4f6 142 delete fLogger;
92aeef15 143}
144
145//_____________________________________________________________________________
146void
40e382ae 147AliMUONDigitizerV3::ApplyResponseToTrackerDigit(AliMUONVDigit& digit, Bool_t addNoise)
92aeef15 148{
9265505b 149 /// For tracking digits, starting from an ideal digit's charge, we :
150 ///
cf27231a 151 /// - "divide" by a gain (thus decalibrating the digit)
9265505b 152 /// - add a pedestal (thus decalibrating the digit)
b74ca120 153 /// - add some electronics noise (thus leading to a realistic adc), if requested to do so
9265505b 154 /// - sets the signal to zero if below 3*sigma of the noise
59b91539 155
5d950f54 156 Float_t charge = digit.IsChargeInFC() ? digit.Charge()*AliMUONConstants::FC2ADC() : digit.Charge();
cf27231a 157
158 // We set the charge to 0, as the only relevant piece of information
159 // after Digitization is the ADC value.
160 digit.SetCharge(0);
b74ca120 161
4ce497c4 162 Int_t detElemId = digit.DetElemId();
92aeef15 163 Int_t manuId = digit.ManuId();
92aeef15 164
4ce497c4 165 AliMUONVCalibParam* pedestal = fCalibrationData->Pedestals(detElemId,manuId);
92aeef15 166 if (!pedestal)
ad26d4f6 167 {
168 fLogger->Log(Form("%s:%d:Could not get pedestal for DE=%4d manuId=%4d. Disabling.",
169 __FILE__,__LINE__,
170 detElemId,manuId));
ad26d4f6 171 digit.SetADC(0);
172 return;
173 }
59b91539 174
627ba19f 175 Int_t manuChannel = digit.ManuChannel();
176
177 if ( pedestal->ValueAsFloat(manuChannel,0) == AliMUONVCalibParam::InvalidFloatValue() ||
178 pedestal->ValueAsFloat(manuChannel,1) == AliMUONVCalibParam::InvalidFloatValue() )
179 {
180 // protection against invalid pedestal value
181 digit.SetADC(0);
182 return;
183 }
184
4ce497c4 185 AliMUONVCalibParam* gain = fCalibrationData->Gains(detElemId,manuId);
92aeef15 186 if (!gain)
ad26d4f6 187 {
188 fLogger->Log(Form("%s:%d:Could not get gain for DE=%4d manuId=%4d. Disabling.",
189 __FILE__,__LINE__,
190 detElemId,manuId));
ad26d4f6 191 digit.SetADC(0);
192 return;
193 }
cf27231a 194
ec9acc85 195 Int_t adc = DecalibrateTrackerDigit(*pedestal,*gain,manuChannel,charge,addNoise,
196 digit.IsNoiseOnly());
59b91539 197
92aeef15 198 digit.SetADC(adc);
199}
200
d5315275 201
202//_____________________________________________________________________________
203void
204AliMUONDigitizerV3::ApplyResponseToTriggerDigit(AliMUONVDigit& digit)
205{
206 /// For trigger digits, starting from an ideal digit, we :
207 ///
208 /// - apply efficiency (on demand)
209 /// - apply trigger masks
210
211 Int_t detElemId = digit.DetElemId();
212 Int_t localCircuit = digit.ManuId();
213 Int_t strip = digit.ManuChannel();
214 Int_t cathode = digit.Cathode();
215 Int_t trigCh = detElemId/100 - 11;
216
217 Int_t arrayIndex = GetArrayIndex(cathode, trigCh, localCircuit);
218
219 // Trigger chamber efficiency
220 if ( fTriggerEfficiency ) {
221 if ( fEfficiencyResponse[arrayIndex] < 0 ) {
222 Bool_t isTrig[2] = {kTRUE, kTRUE};
223 fTriggerEfficiency->IsTriggered(detElemId, localCircuit, isTrig[0], isTrig[1]);
224 Int_t arrayIndexBend = GetArrayIndex(0, trigCh, localCircuit);
225 Int_t arrayIndexNonBend = GetArrayIndex(1, trigCh, localCircuit);
226 fEfficiencyResponse[arrayIndexBend] = isTrig[0];
227 fEfficiencyResponse[arrayIndexNonBend] = isTrig[1];
228 }
229 AliDebug(1,Form("ch %i cath %i board %i strip %i efficiency %i\n", trigCh, cathode, localCircuit, strip, fEfficiencyResponse[arrayIndex]));
230 if ( fEfficiencyResponse[arrayIndex] == 0 ) {
231 digit.SetCharge(0);
232 digit.SetADC(0);
233 //AliDebug(1,Form("ch %i cath %i board %i strip %i NOT efficient\n", trigCh, cathode, localCircuit, strip));
234 return;
235 }
236 }
237
238 // Masked channels
239 Bool_t isMasked = fTriggerUtilities->IsMasked(digit);
240 AliDebug(1,Form("ch %i cath %i board %i strip %i mask %i\n", trigCh, cathode, localCircuit, strip, !isMasked));
241 if ( isMasked ) {
242 digit.SetCharge(0);
243 digit.SetADC(0);
244 //AliDebug(1,Form("ch %i cath %i board %i strip %i masked\n", trigCh, cathode, localCircuit, strip));
245 return;
246 }
247}
248
249
250
92aeef15 251//_____________________________________________________________________________
252void
40e382ae 253AliMUONDigitizerV3::ApplyResponse(const AliMUONVDigitStore& store,
254 AliMUONVDigitStore& filteredStore)
92aeef15 255{
9265505b 256 /// Loop over all chamber digits, and apply the response to them
257 /// Note that this method may remove digits.
258
40e382ae 259 filteredStore.Clear();
260
4ce497c4 261 const Bool_t kAddNoise = kTRUE;
262
40e382ae 263 TIter next(store.CreateIterator());
264 AliMUONVDigit* digit;
265
d5315275 266 if ( fTriggerEfficiency ) fEfficiencyResponse.Reset(-1);
267
40e382ae 268 while ( ( digit = static_cast<AliMUONVDigit*>(next()) ) )
4ce497c4 269 {
40e382ae 270 AliMp::StationType stationType = AliMpDEManager::GetStationType(digit->DetElemId());
271
272 if ( stationType != AliMp::kStationTrigger )
92aeef15 273 {
ac6411cf 274 Bool_t addNoise = kAddNoise;
275 if (digit->IsConverted()) addNoise = kFALSE; // No need to add extra noise to a converted real digit
276 ApplyResponseToTrackerDigit(*digit,addNoise);
92aeef15 277 }
d5315275 278 else {
279 ApplyResponseToTriggerDigit(*digit);
280 }
7d7d22a6 281
cf27231a 282 if ( digit->ADC() > 0 || digit->Charge() > 0 )
40e382ae 283 {
284 filteredStore.Add(*digit,AliMUONVDigitStore::kIgnore);
92aeef15 285 }
92aeef15 286 }
40e382ae 287}
92aeef15 288
289//_____________________________________________________________________________
b74ca120 290Int_t
291AliMUONDigitizerV3::DecalibrateTrackerDigit(const AliMUONVCalibParam& pedestals,
292 const AliMUONVCalibParam& gains,
293 Int_t channel,
294 Float_t charge,
ec9acc85 295 Bool_t addNoise,
296 Bool_t noiseOnly)
b74ca120 297{
298 /// Decalibrate (i.e. go from charge to adc) a tracker digit, given its
299 /// pedestal and gain parameters.
300 /// Must insure before calling that channel is valid (i.e. between 0 and
301 /// pedestals or gains->GetSize()-1, but also corresponding to a valid channel
302 /// otherwise results are not predictible...)
303
304 static const Int_t kMaxADC = (1<<12)-1; // We code the charge on a 12 bits ADC.
305
306 Float_t pedestalMean = pedestals.ValueAsFloat(channel,0);
307 Float_t pedestalSigma = pedestals.ValueAsFloat(channel,1);
308
ec9acc85 309 AliDebugClass(1,Form("DE %04d MANU %04d CH %02d PEDMEAN %7.2f PEDSIGMA %7.2f",
5d950f54 310 pedestals.ID0(),pedestals.ID1(),channel,pedestalMean,pedestalSigma));
ec9acc85 311
b74ca120 312 Float_t a0 = gains.ValueAsFloat(channel,0);
313 Float_t a1 = gains.ValueAsFloat(channel,1);
314 Int_t thres = gains.ValueAsInt(channel,2);
315 Int_t qual = gains.ValueAsInt(channel,3);
5d950f54 316
b74ca120 317 if ( qual <= 0 ) return 0;
318
319 Float_t chargeThres = a0*thres;
320
321 Float_t padc(0); // (adc - ped) value
322
323 if ( charge <= chargeThres || TMath::Abs(a1) < 1E-12 )
324 {
325 // linear part only
326
327 if ( TMath::Abs(a0) > 1E-12 )
328 {
329 padc = charge/a0;
330 }
331 }
332 else
333 {
334 // linear + parabolic part
335 Double_t qt = chargeThres - charge;
336 Double_t delta = a0*a0-4*a1*qt;
337 if ( delta < 0 )
338 {
339 AliErrorClass(Form("delta=%e DE %d Manu %d Channel %d "
340 " charge %e a0 %e a1 %e thres %d ped %e pedsig %e",
341 delta,pedestals.ID0(),pedestals.ID1(),
342 channel, charge, a0, a1, thres, pedestalMean,
343 pedestalSigma));
344 }
345 else
346 {
347 delta = TMath::Sqrt(delta);
348
349 padc = ( ( -a0 + delta ) > 0 ? ( -a0 + delta ) : ( -a0 - delta ) );
350
351 padc /= 2*a1;
352
353 if ( padc < 0 )
354 {
355 if ( TMath::Abs(padc) > 1E-3)
356 {
357 // this is more than a precision problem : let's signal it !
358 AliErrorClass(Form("padc=%e DE %d Manu %d Channel %d "
359 " charge %e a0 %e a1 %e thres %d ped %e pedsig %e delta %e",
360 padc,pedestals.ID0(),pedestals.ID1(),
361 channel, charge, a0, a1, thres, pedestalMean,
362 pedestalSigma,delta));
363 }
364
365 // ok. consider we're just at thres, let it be zero.
366 padc = 0;
367 }
368
369 padc += thres;
370
371 }
372 }
373
374 Int_t adc(0);
375
ec9acc85 376 Float_t adcNoise = 0.0;
b74ca120 377
ec9acc85 378 if ( addNoise )
379 {
380 if ( noiseOnly )
381 {
382 adcNoise = NoiseFunction()->GetRandom()*pedestalSigma;
383 }
384 else
385 {
386 adcNoise = gRandom->Gaus(0.0,pedestalSigma);
387 }
388 }
b74ca120 389
ec9acc85 390 adc = TMath::Nint(padc + pedestalMean + adcNoise + 0.5);
391
5c083cba 392 if ( adc < TMath::Nint(pedestalMean + fgNSigmas*pedestalSigma + 0.5) )
ec9acc85 393 {
d537c8e4 394 // this is an error only in specific cases
395 if ( !addNoise || (addNoise && noiseOnly) )
396 {
397 AliErrorClass(Form(" DE %04d Manu %04d Channel %02d "
398 " a0 %7.2f a1 %7.2f thres %04d ped %7.2f pedsig %7.2f adcNoise %7.2f "
399 " charge=%7.2f padc=%7.2f adc=%04d ZS=%04d fgNSigmas=%e addNoise %d noiseOnly %d ",
400 pedestals.ID0(),pedestals.ID1(),channel,
401 a0, a1, thres, pedestalMean, pedestalSigma, adcNoise,
402 charge, padc, adc,
403 TMath::Nint(pedestalMean + fgNSigmas*pedestalSigma + 0.5),
404 fgNSigmas,addNoise,noiseOnly));
405 }
406
ec9acc85 407 adc = 0;
b74ca120 408 }
409
410 // be sure we stick to 12 bits.
411 if ( adc > kMaxADC )
412 {
413 adc = kMaxADC;
414 }
415
416 return adc;
417}
418
419//_____________________________________________________________________________
92aeef15 420void
ca8c8223 421AliMUONDigitizerV3::CreateInputDigitStores()
9ec6a948 422{
ca8c8223 423 /// Create input digit stores
424 ///
9ec6a948 425
ca8c8223 426 if (fInputDigitStores)
427 {
428 AliFatal("Should be called only once !");
429 }
430
431 fInputDigitStores = new TObjArray;
432
433 fInputDigitStores->SetOwner(kTRUE);
9ec6a948 434
435 for ( Int_t iFile = 0; iFile < fManager->GetNinputs(); ++iFile )
436 {
437 AliLoader* inputLoader = GetLoader(fManager->GetInputFolderName(iFile));
438
439 inputLoader->LoadSDigits("READ");
440
441 TTree* iTreeS = inputLoader->TreeS();
442 if (!iTreeS)
443 {
444 AliFatal(Form("Could not get access to input file #%d",iFile));
445 }
446
ca8c8223 447 fInputDigitStores->AddAt(AliMUONVDigitStore::Create(*iTreeS),iFile);
9ec6a948 448 }
449}
450
451//_____________________________________________________________________________
452void
92aeef15 453AliMUONDigitizerV3::Exec(Option_t*)
454{
9265505b 455 /// Main method.
456 /// We first loop over input files, and merge the sdigits we found there.
457 /// Second, we digitize all the resulting sdigits
458 /// Then we generate noise-only digits (for tracker only)
459 /// And we finally generate the trigger outputs.
4ce497c4 460
99c136e1 461 AliCodeTimerAuto("",0)
b74ca120 462
92aeef15 463 if ( fManager->GetNinputs() == 0 )
464 {
465 AliWarning("No input set. Nothing to do.");
466 return;
467 }
468
469 if ( !fIsInitialized )
470 {
471 AliError("Not initialized. Cannot perform the work. Sorry");
472 return;
473 }
474
475 Int_t nInputFiles = fManager->GetNinputs();
476
40e382ae 477 AliLoader* outputLoader = GetLoader(fManager->GetOutputFolderName());
478
479 outputLoader->MakeDigitsContainer();
480
481 TTree* oTreeD = outputLoader->TreeD();
482
483 if (!oTreeD)
92aeef15 484 {
40e382ae 485 AliFatal("Cannot create output TreeD");
92aeef15 486 }
40e382ae 487
92aeef15 488 // Loop over all the input files, and merge the sdigits found in those
489 // files.
40e382ae 490
92aeef15 491 for ( Int_t iFile = 0; iFile < nInputFiles; ++iFile )
5d950f54 492 {
40e382ae 493 AliLoader* inputLoader = GetLoader(fManager->GetInputFolderName(iFile));
494
495 inputLoader->LoadSDigits("READ");
496
497 TTree* iTreeS = inputLoader->TreeS();
498 if (!iTreeS)
92aeef15 499 {
500 AliFatal(Form("Could not get access to input file #%d",iFile));
501 }
9ec6a948 502
ca8c8223 503 if (!fInputDigitStores)
9ec6a948 504 {
ca8c8223 505 CreateInputDigitStores();
9ec6a948 506 }
40e382ae 507
ca8c8223 508 AliMUONVDigitStore* dstore = static_cast<AliMUONVDigitStore*>(fInputDigitStores->At(iFile));
509
510 dstore->Connect(*iTreeS);
40e382ae 511
ca8c8223 512 iTreeS->GetEvent(0);
513
514 MergeWithSDigits(fDigitStore,*dstore,fManager->GetMask(iFile));
05314992 515
40e382ae 516 inputLoader->UnloadSDigits();
05314992 517
ca8c8223 518 dstore->Clear();
92aeef15 519 }
5d950f54 520
92aeef15 521
522 // At this point, we do have digit arrays (one per chamber) which contains
523 // the merging of all the sdigits of the input file(s).
524 // We now massage them to apply the detector response, i.e. this
525 // is here that we do the "digitization" work.
526
40e382ae 527 if (!fOutputDigitStore)
528 {
529 fOutputDigitStore = fDigitStore->Create();
530 }
531
8c0b5e70 532 if ( fGenerateNoisyDigits>=2 )
533 {
534 // Generate noise-only digits for trigger.
535 GenerateNoisyDigitsForTrigger(*fDigitStore);
536 }
40e382ae 537 ApplyResponse(*fDigitStore,*fOutputDigitStore);
5d950f54 538
4ce497c4 539 if ( fGenerateNoisyDigits )
540 {
541 // Generate noise-only digits for tracker.
40e382ae 542 GenerateNoisyDigits(*fOutputDigitStore);
4ce497c4 543 }
544
92aeef15 545 // We generate the global and local trigger decisions.
40e382ae 546 fTriggerProcessor->Digits2Trigger(*fOutputDigitStore,*fTriggerStore);
547
548 // Prepare output tree
549 Bool_t okD = fOutputDigitStore->Connect(*oTreeD,kFALSE);
550 Bool_t okT = fTriggerStore->Connect(*oTreeD,kFALSE);
551 if (!okD || !okT)
552 {
553 AliError(Form("Could not make branch : Digit %d Trigger %d",okD,okT));
554 return;
555 }
92aeef15 556
557 // Fill the output treeD
40e382ae 558 oTreeD->Fill();
92aeef15 559
560 // Write to the output tree(D).
561 // Please note that as GlobalTrigger, LocalTrigger and Digits are in the same
562 // tree (=TreeD) in different branches, this WriteDigits in fact writes all of
563 // the 3 branches.
40e382ae 564 outputLoader->WriteDigits("OVERWRITE");
92aeef15 565
40e382ae 566 outputLoader->UnloadDigits();
4ce497c4 567
40e382ae 568 // Finally, we clean up after ourselves.
569 fTriggerStore->Clear();
570 fDigitStore->Clear();
571 fOutputDigitStore->Clear();
92aeef15 572}
573
4ce497c4 574
575//_____________________________________________________________________________
4ce497c4 576void
40e382ae 577AliMUONDigitizerV3::GenerateNoisyDigits(AliMUONVDigitStore& digitStore)
4ce497c4 578{
9265505b 579 /// According to a given probability, generate digits that
580 /// have a signal above the noise cut (ped+n*sigma_ped), i.e. digits
581 /// that are "only noise".
4ce497c4 582
99c136e1 583 AliCodeTimerAuto("",0)
b74ca120 584
4ce497c4 585 for ( Int_t i = 0; i < AliMUONConstants::NTrackingCh(); ++i )
586 {
587 AliMpDEIterator it;
588
589 it.First(i);
590
591 while ( !it.IsDone() )
592 {
593 for ( Int_t cathode = 0; cathode < 2; ++cathode )
594 {
40e382ae 595 GenerateNoisyDigitsForOneCathode(digitStore,it.CurrentDEId(),cathode);
4ce497c4 596 }
597 it.Next();
598 }
599 }
4ce497c4 600}
601
602//_____________________________________________________________________________
603void
40e382ae 604AliMUONDigitizerV3::GenerateNoisyDigitsForOneCathode(AliMUONVDigitStore& digitStore,
605 Int_t detElemId, Int_t cathode)
4ce497c4 606{
9265505b 607 /// Generate noise-only digits for one cathode of one detection element.
608 /// Called by GenerateNoisyDigits()
4ce497c4 609
9265505b 610 const AliMpVSegmentation* seg
866c3232 611 = AliMpSegmentation::Instance()->GetMpSegmentation(detElemId,AliMp::GetCathodType(cathode));
4ce497c4 612 Int_t nofPads = seg->NofPads();
613
614 Int_t maxIx = seg->MaxPadIndexX();
615 Int_t maxIy = seg->MaxPadIndexY();
616
5c083cba 617 static const Double_t kProbToBeOutsideNsigmas = TMath::Erfc(fgNSigmas/TMath::Sqrt(2.0)) / 2. ;
4ce497c4 618
84aac932 619 Int_t nofNoisyPads = TMath::Nint(kProbToBeOutsideNsigmas*nofPads);
4ce497c4 620 if ( !nofNoisyPads ) return;
621
622 nofNoisyPads =
623 TMath::Nint(gRandom->Gaus(nofNoisyPads,
624 nofNoisyPads/TMath::Sqrt(nofNoisyPads)));
625
626 AliDebug(3,Form("DE %d cath %d nofNoisyPads %d",detElemId,cathode,nofNoisyPads));
627
40e382ae 628 for ( Int_t i = 0; i < nofNoisyPads; ++i )
4ce497c4 629 {
630 Int_t ix(-1);
631 Int_t iy(-1);
40e382ae 632 AliMpPad pad;
633
4ce497c4 634 do {
635 ix = gRandom->Integer(maxIx+1);
636 iy = gRandom->Integer(maxIy+1);
168e9c4d 637 pad = seg->PadByIndices(ix,iy,kFALSE);
40e382ae 638 } while ( !pad.IsValid() );
639
168e9c4d 640 Int_t manuId = pad.GetManuId();
641 Int_t manuChannel = pad.GetManuChannel();
40e382ae 642
4ce497c4 643 AliMUONVCalibParam* pedestals = fCalibrationData->Pedestals(detElemId,manuId);
644
ad26d4f6 645 if (!pedestals)
646 {
647 // no pedestal available for this channel, simply give up
40e382ae 648 continue;
ad26d4f6 649 }
650
40e382ae 651 AliMUONVDigit* d = digitStore.CreateDigit(detElemId,manuId,manuChannel,cathode);
652
653 d->SetPadXY(ix,iy);
654
ec9acc85 655 d->SetCharge(0.0); // charge is zero, the ApplyResponseToTrackerDigit will add the noise
40e382ae 656 d->NoiseOnly(kTRUE);
ec9acc85 657 ApplyResponseToTrackerDigit(*d,kTRUE);
cf27231a 658 if ( d->ADC() > 0 )
4ce497c4 659 {
40e382ae 660 Bool_t ok = digitStore.Add(*d,AliMUONVDigitStore::kDeny);
661 // this can happen (that we randomly chose a digit that is
662 // already there). We simply ignore this, but log the occurence
663 // to cross-check that it's not too frequent.
664 if (!ok)
665 {
666 fLogger->Log("Collision while adding noiseOnly digit");
667 }
668 else
669 {
670 fLogger->Log("Added noiseOnly digit");
671 }
4ce497c4 672 }
40e382ae 673 delete d;
4ce497c4 674 }
675}
676
8c0b5e70 677
678//_____________________________________________________________________________
679void
680AliMUONDigitizerV3::GenerateNoisyDigitsForTrigger(AliMUONVDigitStore& digitStore)
681{
682 /// Generate noise-only digits for one cathode of one detection element.
683 /// Called by GenerateNoisyDigits()
684
685 if ( !fNoiseFunctionTrig )
686 {
687 fNoiseFunctionTrig = new TF1("AliMUONDigitizerV3::fNoiseFunctionTrig","landau",
688 50.,270.);
689
690 fNoiseFunctionTrig->SetParameters(3.91070e+02, 9.85026, 9.35881e-02);
691 }
692
693 AliMpPad pad[2];
694 AliMUONVDigit *d[2]={0x0};
695
696 for ( Int_t chamberId = AliMUONConstants::NTrackingCh(); chamberId < AliMUONConstants::NCh(); ++chamberId )
697 {
698
699 Int_t nofNoisyPads = 50;
700
701 Float_t r=-1, fi = 0., gx, gy, x, y, z, xg01, yg01, zg, xg02, yg02;
702 AliMpDEIterator it;
703
704 AliDebug(3,Form("Chamber %d nofNoisyPads %d",chamberId,nofNoisyPads));
705
706 for ( Int_t i = 0; i < nofNoisyPads; ++i )
707 {
708 //printf("Generating noise %i\n",i);
709 Int_t ix(-1);
710 Int_t iy(-1);
711 Bool_t isOk = kFALSE;
712 Int_t detElemId = -1;
713 do {
714 //r = gRandom->Landau(9.85026, 9.35881e-02);
715 r = fNoiseFunctionTrig->GetRandom();
716 fi = 2. * TMath::Pi() * gRandom->Rndm();
717 //printf("r = %f\tfi = %f\n", r, fi);
718 gx = r * TMath::Cos(fi);
719 gy = r * TMath::Sin(fi);
720
721 for ( it.First(chamberId); ! it.IsDone(); it.Next() ){
722 Int_t currDetElemId = it.CurrentDEId();
723 const AliMpVSegmentation* seg
724 = AliMpSegmentation::Instance()->GetMpSegmentation(currDetElemId,AliMp::GetCathodType(0));
725 if (!seg) continue;
6e97fbb8 726 Float_t deltax = seg->GetDimensionX();
727 Float_t deltay = seg->GetDimensionY();
8c0b5e70 728 GetTransformer()->Local2Global(currDetElemId, -deltax, -deltay, 0, xg01, yg01, zg);
729 GetTransformer()->Local2Global(currDetElemId, deltax, deltay, 0, xg02, yg02, zg);
730 Float_t xg1 = xg01, xg2 = xg02, yg1 = yg01, yg2 = yg02;
731 if(xg01>xg02){
732 xg1 = xg02;
733 xg2 = xg01;
734 }
735 if(yg01>yg02){
736 yg1 = yg02;
737 yg2 = yg01;
738 }
739 if(gx>=xg1 && gx<=xg2 && gy>=yg1 && gy<=yg2){
740 detElemId = currDetElemId;
741 GetTransformer()->Global2Local(detElemId, gx, gy, 0, x, y, z);
6e97fbb8 742 pad[0] = seg->PadByPosition(x,y,kFALSE);
8c0b5e70 743 if(!pad[0].IsValid()) continue;
744 isOk = kTRUE;
745 break;
746 }
747 } // loop on slats
748 } while ( !isOk );
749
750 const AliMpVSegmentation* seg1
751 = AliMpSegmentation::Instance()->GetMpSegmentation(detElemId,AliMp::GetCathodType(1));
6e97fbb8 752 pad[1] = seg1->PadByPosition(x,y,kFALSE);
8c0b5e70 753
754 for ( Int_t cathode = 0; cathode < 2; ++cathode ){
168e9c4d 755 Int_t manuId = pad[cathode].GetLocalBoardId(0);
756 Int_t manuChannel = pad[cathode].GetLocalBoardChannel(0);
8c0b5e70 757 d[cathode] = digitStore.CreateDigit(detElemId,manuId,manuChannel,cathode);
168e9c4d 758 ix = pad[cathode].GetIx();
759 iy = pad[cathode].GetIy();
8c0b5e70 760 d[cathode]->SetPadXY(ix,iy);
761 //d[cathode].SetSignal(1);
762 //d[cathode].SetPhysicsSignal(0);
763 d[cathode]->SetCharge(1);
764 d[cathode]->NoiseOnly(kTRUE);
765 AliDebug(3,Form("Adding a pure noise digit :"));
766
767 Bool_t ok = digitStore.Add(*d[cathode],AliMUONVDigitStore::kDeny);
768 if (!ok)
769 {
770 fLogger->Log("Collision while adding TriggerNoise digit");
771 }
772 else
773 {
774 fLogger->Log("Added triggerNoise digit");
775 }
776 } //loop on cathodes
777 } // loop on noisy pads
778 } // loop on chambers
779}
780
781
4ce497c4 782//_____________________________________________________________________________
40e382ae 783AliLoader*
784AliMUONDigitizerV3::GetLoader(const TString& folderName)
92aeef15 785{
40e382ae 786 /// Get a MUON loader
9265505b 787
ad26d4f6 788 AliDebug(2,Form("Getting access to folder %s",folderName.Data()));
40e382ae 789 AliLoader* loader = AliRunLoader::GetDetectorLoader("MUON",folderName.Data());
92aeef15 790 if (!loader)
791 {
792 AliError(Form("Could not get MuonLoader from folder %s",folderName.Data()));
793 return 0x0;
794 }
40e382ae 795 return loader;
92aeef15 796}
797
798//_____________________________________________________________________________
799Bool_t
800AliMUONDigitizerV3::Init()
801{
9265505b 802 /// Initialization of the TTask :
40e382ae 803 /// a) create the calibrationData, according to run number
804 /// b) create the trigger processing task
9265505b 805
ad26d4f6 806 AliDebug(2,"");
92aeef15 807
808 if ( fIsInitialized )
809 {
810 AliError("Object already initialized.");
811 return kFALSE;
812 }
813
814 if (!fManager)
815 {
816 AliError("fManager is null !");
817 return kFALSE;
818 }
819
331a617a 820 // Load mapping
821 if ( ! AliMpCDB::LoadDDLStore() ) {
88544f7e 822 AliFatal("Could not access mapping from OCDB !");
823 }
824
92c23b09 825 if (!fCalibrationData)
826 AliFatal("Calibration data object not defined");
827
ad26d4f6 828 if ( !fCalibrationData->Pedestals() )
829 {
830 AliFatal("Could not access pedestals from OCDB !");
831 }
832 if ( !fCalibrationData->Gains() )
833 {
834 AliFatal("Could not access gains from OCDB !");
835 }
92c23b09 836
837
838 AliInfo("Using trigger configuration from CDB");
839
40e382ae 840 fTriggerProcessor = new AliMUONTriggerElectronics(fCalibrationData);
4ce497c4 841
ad26d4f6 842 AliDebug(1, Form("Will %s generate noise-only digits for tracker",
843 (fGenerateNoisyDigits ? "":"NOT")));
d5315275 844
845 fTriggerUtilities = new AliMUONTriggerUtilities(fCalibrationData);
846
847 if ( muon()->GetTriggerEffCells() ) {
848 // Apply trigger efficiency
849 AliDebug(1, "Will apply trigger efficiency");
850 fTriggerEfficiency = new AliMUONTriggerChamberEfficiency(fCalibrationData->TriggerEfficiency());
851 }
ad26d4f6 852
92aeef15 853 fIsInitialized = kTRUE;
854 return kTRUE;
855}
856
d5315275 857
858//_____________________________________________________________________________
859Int_t AliMUONDigitizerV3::GetArrayIndex(Int_t cathode, Int_t trigCh, Int_t localCircuit)
860{
861 /// Get index of array with trigger status map or efficiency
862 return
863 AliMUONConstants::NTriggerCircuit() * AliMUONConstants::NTriggerCh() * cathode +
864 AliMUONConstants::NTriggerCircuit() * trigCh + localCircuit-1;
865}
866
867
92aeef15 868//_____________________________________________________________________________
92aeef15 869void
40e382ae 870AliMUONDigitizerV3::MergeWithSDigits(AliMUONVDigitStore*& outputStore,
871 const AliMUONVDigitStore& input,
872 Int_t mask)
92aeef15 873{
9265505b 874 /// Merge the sdigits in inputData with the digits already present in outputData
92aeef15 875
40e382ae 876 if ( !outputStore ) outputStore = input.Create();
877
878 TIter next(input.CreateIterator());
879 AliMUONVDigit* sdigit;
880
881 while ( ( sdigit = static_cast<AliMUONVDigit*>(next()) ) )
882 {
883 // Update the track references using the mask.
884 // FIXME: this is dirty, for backward compatibility only.
885 // Should re-design all this way of keeping track of MC information...
886 if ( mask ) sdigit->PatchTracks(mask);
887 // Then add or update the digit to the output.
888 AliMUONVDigit* added = outputStore->Add(*sdigit,AliMUONVDigitStore::kMerge);
889 if (!added)
92aeef15 890 {
40e382ae 891 AliError("Could not add digit in merge mode");
92aeef15 892 }
92aeef15 893 }
894}
ec9acc85 895
896//_____________________________________________________________________________
897TF1*
898AliMUONDigitizerV3::NoiseFunction()
899{
900 /// Return noise function
901 static TF1* f = 0x0;
902 if (!f)
903 {
5c083cba 904 f = new TF1("AliMUONDigitizerV3::NoiseFunction","gaus",fgNSigmas,fgNSigmas*10);
ec9acc85 905 f->SetParameters(1,0,1);
906 }
907 return f;
908}
909