- Disentangle masks effect from trigger chamber efficiency estimation.
[u/mrichter/AliRoot.git] / MUON / AliMUONDigitizerV3.cxx
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
19 #include "AliMUONDigitizerV3.h"
20
21 #include "AliMUON.h"
22 #include "AliMUONCalibrationData.h"
23 #include "AliMUONConstants.h"
24 #include "AliMUONDigit.h"
25 #include "AliMUONLogger.h"
26 #include "AliMUONTriggerElectronics.h"
27 #include "AliMUONTriggerStoreV1.h"
28 #include "AliMUONVCalibParam.h"
29 #include "AliMUONVDigitStore.h"
30 #include "AliMUONGeometryTransformer.h" //ADDED for trigger noise
31 #include "AliMUONTriggerChamberEfficiency.h"
32 #include "AliMUONTriggerUtilities.h"
33
34 #include "AliMpCDB.h"
35 #include "AliMpSegmentation.h"
36 #include "AliMpCathodType.h"
37 #include "AliMpConstants.h"
38 #include "AliMpDEIterator.h"
39 #include "AliMpDEManager.h"
40 #include "AliMpPad.h"
41 #include "AliMpStationType.h"
42 #include "AliMpVSegmentation.h"
43 #include "AliMpDDLStore.h"
44
45 #include "AliCDBManager.h"
46 #include "AliCodeTimer.h"
47 #include "AliLog.h"
48 #include "AliRun.h"
49 #include "AliRunDigitizer.h"
50 #include "AliLoader.h"
51 #include "AliRunLoader.h"
52
53 #include <Riostream.h>
54 #include <TF1.h>
55 #include <TFile.h>
56 #include <TMath.h>
57 #include <TRandom.h>
58 #include <TString.h>
59 #include <TSystem.h>
60 #include <TTree.h>
61
62 //-----------------------------------------------------------------------------
63 /// \class AliMUONDigitizerV3
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 ///
76 /// \author Laurent Aphecetche
77 //-----------------------------------------------------------------------------
78
79 namespace
80 {
81   AliMUON* muon()
82   {
83     return static_cast<AliMUON*>(gAlice->GetModule("MUON"));
84   }
85
86   //ADDED for trigger noise
87   const AliMUONGeometryTransformer* GetTransformer()
88   {
89       return muon()->GetGeometryTransformer();
90   }
91 }
92
93 Double_t AliMUONDigitizerV3::fgNSigmas = 4.0;
94
95 /// \cond CLASSIMP
96 ClassImp(AliMUONDigitizerV3)
97 /// \endcond
98
99 //_____________________________________________________________________________
100 AliMUONDigitizerV3::AliMUONDigitizerV3(AliRunDigitizer* manager, 
101                                        Int_t generateNoisyDigits)
102 : AliDigitizer(manager),
103 fIsInitialized(kFALSE),
104 fCalibrationData(0x0),
105 fTriggerProcessor(0x0),
106 fNoiseFunctionTrig(0x0),
107 fGenerateNoisyDigits(generateNoisyDigits),
108 fLogger(new AliMUONLogger(1000)),
109 fTriggerStore(new AliMUONTriggerStoreV1),
110 fDigitStore(0x0),
111 fOutputDigitStore(0x0),
112 fInputDigitStores(0x0),
113 fTriggerEfficiency(0x0),
114 fTriggerUtilities(0x0),
115 fEfficiencyResponse(2*AliMUONConstants::NTriggerCh()*AliMUONConstants::NTriggerCircuit())
116 {
117   /// Ctor.
118
119   AliDebug(1,Form("AliRunDigitizer=%p",fManager));
120
121 }
122
123 //_____________________________________________________________________________
124 AliMUONDigitizerV3::~AliMUONDigitizerV3()
125 {
126   /// Dtor. Note we're the owner of some pointers.
127
128   AliDebug(1,"dtor");
129
130  // delete fCalibrationData;
131   delete fTriggerProcessor;
132   delete fNoiseFunctionTrig;
133   delete fTriggerStore;
134   delete fDigitStore;
135   delete fOutputDigitStore;
136   delete fInputDigitStores;
137   delete fTriggerUtilities;
138   
139   AliInfo("Summary of messages");
140   fLogger->Print();
141   
142   delete fLogger;
143 }
144
145 //_____________________________________________________________________________
146 void 
147 AliMUONDigitizerV3::ApplyResponseToTrackerDigit(AliMUONVDigit& digit, Bool_t addNoise)
148 {
149   /// For tracking digits, starting from an ideal digit's charge, we :
150   ///
151   /// - "divide" by a gain (thus decalibrating the digit)
152   /// - add a pedestal (thus decalibrating the digit)
153   /// - add some electronics noise (thus leading to a realistic adc), if requested to do so
154   /// - sets the signal to zero if below 3*sigma of the noise
155
156   Float_t charge = digit.IsChargeInFC() ? digit.Charge()*AliMUONConstants::FC2ADC() : digit.Charge();
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);
161     
162   Int_t detElemId = digit.DetElemId();
163   Int_t manuId = digit.ManuId();
164   
165   AliMUONVCalibParam* pedestal = fCalibrationData->Pedestals(detElemId,manuId);
166   if (!pedestal)
167   {
168     fLogger->Log(Form("%s:%d:Could not get pedestal for DE=%4d manuId=%4d. Disabling.",
169                       __FILE__,__LINE__,
170                       detElemId,manuId));
171     digit.SetADC(0);
172     return;    
173   }
174   
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       
185   AliMUONVCalibParam* gain = fCalibrationData->Gains(detElemId,manuId);
186   if (!gain)
187   {
188     fLogger->Log(Form("%s:%d:Could not get gain for DE=%4d manuId=%4d. Disabling.",
189                       __FILE__,__LINE__,
190                       detElemId,manuId));
191     digit.SetADC(0);
192     return;        
193   }    
194
195   Int_t adc = DecalibrateTrackerDigit(*pedestal,*gain,manuChannel,charge,addNoise,
196                                       digit.IsNoiseOnly());
197   
198   digit.SetADC(adc);
199 }
200
201
202 //_____________________________________________________________________________
203 void 
204 AliMUONDigitizerV3::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
251 //_____________________________________________________________________________
252 void
253 AliMUONDigitizerV3::ApplyResponse(const AliMUONVDigitStore& store,
254                                   AliMUONVDigitStore& filteredStore)
255 {
256   /// Loop over all chamber digits, and apply the response to them
257   /// Note that this method may remove digits.
258
259   filteredStore.Clear();
260   
261   const Bool_t kAddNoise = kTRUE;
262   
263   TIter next(store.CreateIterator());
264   AliMUONVDigit* digit;
265   
266   if ( fTriggerEfficiency ) fEfficiencyResponse.Reset(-1);
267   
268   while ( ( digit = static_cast<AliMUONVDigit*>(next()) ) )
269   {
270     AliMp::StationType stationType = AliMpDEManager::GetStationType(digit->DetElemId());
271     
272     if ( stationType != AliMp::kStationTrigger )
273     {
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);
277     }
278     else {
279       ApplyResponseToTriggerDigit(*digit);
280     }
281
282     if ( digit->ADC() > 0  || digit->Charge() > 0 )
283     {
284       filteredStore.Add(*digit,AliMUONVDigitStore::kIgnore);
285     }
286   }
287 }    
288
289 //_____________________________________________________________________________
290 Int_t 
291 AliMUONDigitizerV3::DecalibrateTrackerDigit(const AliMUONVCalibParam& pedestals,
292                                             const AliMUONVCalibParam& gains,
293                                             Int_t channel,
294                                             Float_t charge,
295                                             Bool_t addNoise,
296                                             Bool_t noiseOnly)
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   
309   AliDebugClass(1,Form("DE %04d MANU %04d CH %02d PEDMEAN %7.2f PEDSIGMA %7.2f",
310                        pedestals.ID0(),pedestals.ID1(),channel,pedestalMean,pedestalSigma));
311   
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);
316
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   
376   Float_t adcNoise = 0.0;
377     
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   }
389     
390   adc = TMath::Nint(padc + pedestalMean + adcNoise + 0.5);
391   
392   if ( adc < TMath::Nint(pedestalMean + fgNSigmas*pedestalSigma + 0.5) ) 
393   {
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     
407     adc = 0;
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 //_____________________________________________________________________________
420 void
421 AliMUONDigitizerV3::CreateInputDigitStores()
422 {
423   /// Create input digit stores
424   /// 
425   
426   if (fInputDigitStores)
427   {
428     AliFatal("Should be called only once !");
429   }
430   
431   fInputDigitStores = new TObjArray;
432   
433   fInputDigitStores->SetOwner(kTRUE);
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     
447     fInputDigitStores->AddAt(AliMUONVDigitStore::Create(*iTreeS),iFile);
448   }
449 }
450
451 //_____________________________________________________________________________
452 void
453 AliMUONDigitizerV3::Exec(Option_t*)
454 {
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.
460     
461   AliCodeTimerAuto("",0)
462   
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   
477   AliLoader* outputLoader = GetLoader(fManager->GetOutputFolderName());
478   
479   outputLoader->MakeDigitsContainer();
480   
481   TTree* oTreeD = outputLoader->TreeD();
482   
483   if (!oTreeD) 
484   {
485     AliFatal("Cannot create output TreeD");
486   }
487
488   // Loop over all the input files, and merge the sdigits found in those
489   // files.
490   
491   for ( Int_t iFile = 0; iFile < nInputFiles; ++iFile )
492   {  
493     AliLoader* inputLoader = GetLoader(fManager->GetInputFolderName(iFile));
494
495     inputLoader->LoadSDigits("READ");
496
497     TTree* iTreeS = inputLoader->TreeS();
498     if (!iTreeS)
499     {
500       AliFatal(Form("Could not get access to input file #%d",iFile));
501     }
502
503     if (!fInputDigitStores)
504     {
505       CreateInputDigitStores();      
506     }
507     
508     AliMUONVDigitStore* dstore = static_cast<AliMUONVDigitStore*>(fInputDigitStores->At(iFile));
509     
510     dstore->Connect(*iTreeS);
511     
512     iTreeS->GetEvent(0);
513
514     MergeWithSDigits(fDigitStore,*dstore,fManager->GetMask(iFile));
515
516     inputLoader->UnloadSDigits();
517     
518     dstore->Clear();
519   }
520
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   
527   if (!fOutputDigitStore)
528   {
529     fOutputDigitStore = fDigitStore->Create();
530   }
531   
532   if ( fGenerateNoisyDigits>=2 )
533   {
534     // Generate noise-only digits for trigger.
535     GenerateNoisyDigitsForTrigger(*fDigitStore);
536   }
537   ApplyResponse(*fDigitStore,*fOutputDigitStore);
538
539   if ( fGenerateNoisyDigits )
540   {
541     // Generate noise-only digits for tracker.
542     GenerateNoisyDigits(*fOutputDigitStore);
543   }
544   
545   // We generate the global and local trigger decisions.
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   }
556   
557   // Fill the output treeD
558   oTreeD->Fill();
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.
564   outputLoader->WriteDigits("OVERWRITE");  
565   
566   outputLoader->UnloadDigits();
567   
568   // Finally, we clean up after ourselves.
569   fTriggerStore->Clear();
570   fDigitStore->Clear();
571   fOutputDigitStore->Clear();
572 }
573
574
575 //_____________________________________________________________________________
576 void
577 AliMUONDigitizerV3::GenerateNoisyDigits(AliMUONVDigitStore& digitStore)
578 {
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".
582   
583   AliCodeTimerAuto("",0)
584   
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       {
595         GenerateNoisyDigitsForOneCathode(digitStore,it.CurrentDEId(),cathode);
596       }
597       it.Next();
598     }
599   }
600 }
601  
602 //_____________________________________________________________________________
603 void
604 AliMUONDigitizerV3::GenerateNoisyDigitsForOneCathode(AliMUONVDigitStore& digitStore,
605                                                      Int_t detElemId, Int_t cathode)
606 {
607   /// Generate noise-only digits for one cathode of one detection element.
608   /// Called by GenerateNoisyDigits()
609   
610   const AliMpVSegmentation* seg 
611     = AliMpSegmentation::Instance()->GetMpSegmentation(detElemId,AliMp::GetCathodType(cathode));
612   Int_t nofPads = seg->NofPads();
613   
614   Int_t maxIx = seg->MaxPadIndexX();
615   Int_t maxIy = seg->MaxPadIndexY();
616   
617   static const Double_t kProbToBeOutsideNsigmas = TMath::Erfc(fgNSigmas/TMath::Sqrt(2.0)) / 2. ;
618   
619   Int_t nofNoisyPads = TMath::Nint(kProbToBeOutsideNsigmas*nofPads);
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   
628   for ( Int_t i = 0; i < nofNoisyPads; ++i ) 
629   {
630     Int_t ix(-1);
631     Int_t iy(-1);
632     AliMpPad pad;
633     
634     do {
635       ix = gRandom->Integer(maxIx+1);
636       iy = gRandom->Integer(maxIy+1);
637       pad = seg->PadByIndices(ix,iy,kFALSE);
638     } while ( !pad.IsValid() );
639
640     Int_t manuId = pad.GetManuId();
641     Int_t manuChannel = pad.GetManuChannel();    
642
643     AliMUONVCalibParam* pedestals = fCalibrationData->Pedestals(detElemId,manuId);
644     
645     if (!pedestals) 
646     {
647       // no pedestal available for this channel, simply give up
648       continue;
649     }
650     
651     AliMUONVDigit* d = digitStore.CreateDigit(detElemId,manuId,manuChannel,cathode);
652     
653     d->SetPadXY(ix,iy);
654     
655     d->SetCharge(0.0); // charge is zero, the ApplyResponseToTrackerDigit will add the noise
656     d->NoiseOnly(kTRUE);
657     ApplyResponseToTrackerDigit(*d,kTRUE);
658     if ( d->ADC() > 0 )
659     {
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       }
672     }
673     delete d;
674   }
675 }
676
677
678 //_____________________________________________________________________________
679 void
680 AliMUONDigitizerV3::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;
726                 Float_t deltax = seg->GetDimensionX();
727                 Float_t deltay = seg->GetDimensionY();
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);
742                     pad[0] = seg->PadByPosition(x,y,kFALSE);
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));
752         pad[1] = seg1->PadByPosition(x,y,kFALSE);
753
754         for ( Int_t cathode = 0; cathode < 2; ++cathode ){
755           Int_t manuId = pad[cathode].GetLocalBoardId(0);
756           Int_t manuChannel = pad[cathode].GetLocalBoardChannel(0);    
757           d[cathode] = digitStore.CreateDigit(detElemId,manuId,manuChannel,cathode);
758           ix = pad[cathode].GetIx();
759           iy = pad[cathode].GetIy();
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
782 //_____________________________________________________________________________
783 AliLoader*
784 AliMUONDigitizerV3::GetLoader(const TString& folderName)
785 {
786   /// Get a MUON loader
787
788   AliDebug(2,Form("Getting access to folder %s",folderName.Data()));
789   AliLoader* loader = AliRunLoader::GetDetectorLoader("MUON",folderName.Data());
790   if (!loader)
791   {
792     AliError(Form("Could not get MuonLoader from folder %s",folderName.Data()));
793     return 0x0;
794   }
795   return loader;
796 }
797
798 //_____________________________________________________________________________
799 Bool_t
800 AliMUONDigitizerV3::Init()
801 {
802   /// Initialization of the TTask :
803   /// a) create the calibrationData, according to run number
804   /// b) create the trigger processing task
805
806   AliDebug(2,"");
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   
820   // Load mapping
821   if ( ! AliMpCDB::LoadDDLStore() ) {
822     AliFatal("Could not access mapping from OCDB !");
823   }
824   
825   if (!fCalibrationData)
826       AliFatal("Calibration data object not defined");
827
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   }
836   
837   
838    AliInfo("Using trigger configuration from CDB");
839   
840   fTriggerProcessor = new AliMUONTriggerElectronics(fCalibrationData);
841   
842   AliDebug(1, Form("Will %s generate noise-only digits for tracker",
843                      (fGenerateNoisyDigits ? "":"NOT")));
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   }
852
853   fIsInitialized = kTRUE;
854   return kTRUE;
855 }
856
857
858 //_____________________________________________________________________________
859 Int_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
868 //_____________________________________________________________________________
869 void 
870 AliMUONDigitizerV3::MergeWithSDigits(AliMUONVDigitStore*& outputStore,
871                                      const AliMUONVDigitStore& input,
872                                      Int_t mask)
873 {
874   /// Merge the sdigits in inputData with the digits already present in outputData
875   
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)
890     {
891       AliError("Could not add digit in merge mode");
892     }
893   }
894 }
895
896 //_____________________________________________________________________________
897 TF1*
898 AliMUONDigitizerV3::NoiseFunction()
899 {
900   /// Return noise function
901   static TF1* f = 0x0;
902   if (!f)
903   {
904     f = new TF1("AliMUONDigitizerV3::NoiseFunction","gaus",fgNSigmas,fgNSigmas*10);
905     f->SetParameters(1,0,1);
906   }
907   return f;
908 }
909