]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONDigitizerV3.cxx
Raw2SDigits method implemented
[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 "AliMUONData.h"
25 #include "AliMUONDataIterator.h"
26 #include "AliMUONDigit.h"
27 #include "AliMUONSegmentation.h"
28 #include "AliMUONTriggerEfficiencyCells.h"
29 #include "AliMUONTriggerElectronics.h"
30 #include "AliMUONVCalibParam.h"
31
32 #include "AliMpDEIterator.h"
33 #include "AliMpDEManager.h"
34 #include "AliMpIntPair.h"
35 #include "AliMpPad.h"
36 #include "AliMpStationType.h"
37 #include "AliMpSegmentation.h"
38 #include "AliMpVSegmentation.h"
39 #include "AliMpDEManager.h"
40 #include "AliMpCathodType.h"
41
42 #include "AliRun.h"
43 #include "AliRunDigitizer.h"
44 #include "AliRunLoader.h"
45 #include "AliLog.h"
46
47 #include <Riostream.h>
48 #include <TF1.h>
49 #include <TMath.h>
50 #include <TRandom.h>
51 #include <TString.h>
52 ///
53 /// \class AliMUONDigitizerV3
54 /// The digitizer is performing the transformation to go from SDigits (digits
55 /// w/o any electronic noise) to Digits (w/ electronic noise, and decalibration)
56 /// 
57 /// The decalibration is performed by doing the reverse operation of the
58 /// calibration, that is we do (Signal+pedestal)/gain -> ADC
59 ///
60 /// Note also that the digitizer takes care of merging sdigits that belongs
61 /// to the same pad, either because we're merging several input sdigit files
62 /// or with a single file because the sdigitizer does not merge sdigits itself
63 /// (for performance reason mainly, and because anyway we know we have to do it
64 /// here, at the digitization level).
65 ///
66
67 namespace
68 {
69   AliMUON* muon()
70   {
71     return static_cast<AliMUON*>(gAlice->GetModule("MUON"));
72   }
73 }
74
75 const Double_t AliMUONDigitizerV3::fgkNSigmas=3;
76
77 /// \cond CLASSIMP
78 ClassImp(AliMUONDigitizerV3)
79 /// \endcond
80
81 //_____________________________________________________________________________
82 AliMUONDigitizerV3::AliMUONDigitizerV3(AliRunDigitizer* manager, 
83                                        Bool_t generateNoisyDigits)
84 : AliDigitizer(manager),
85 fIsInitialized(kFALSE),
86 fOutputData(0x0),
87 fCalibrationData(0x0),
88 fTriggerProcessor(0x0),
89 fTriggerEfficiency(0x0),
90 fFindDigitIndexTimer(),
91 fGenerateNoisyDigitsTimer(),
92 fExecTimer(),
93 fNoiseFunction(0x0),
94 fGenerateNoisyDigits(generateNoisyDigits)
95 {
96   /// Ctor.
97
98   AliDebug(1,Form("AliRunDigitizer=%p",fManager));
99   fGenerateNoisyDigitsTimer.Start(kTRUE); fGenerateNoisyDigitsTimer.Stop();
100   fExecTimer.Start(kTRUE); fExecTimer.Stop();
101   fFindDigitIndexTimer.Start(kTRUE); fFindDigitIndexTimer.Stop();
102 }
103
104 //_____________________________________________________________________________
105 AliMUONDigitizerV3::~AliMUONDigitizerV3()
106 {
107   /// Dtor. Note we're the owner of some pointers.
108
109   AliDebug(1,"dtor");
110
111   delete fOutputData;
112   delete fCalibrationData;
113   delete fTriggerProcessor;
114   delete fNoiseFunction;
115   
116   AliDebug(1, Form("Execution time for FindDigitIndex() : R:%.2fs C:%.2fs",
117                fFindDigitIndexTimer.RealTime(),fFindDigitIndexTimer.CpuTime()));
118   if ( fGenerateNoisyDigits )
119   {
120     AliDebug(1, Form("Execution time for GenerateNoisyDigits() : R:%.2fs C:%.2fs",
121                  fGenerateNoisyDigitsTimer.RealTime(),
122                  fGenerateNoisyDigitsTimer.CpuTime()));
123   }
124   AliDebug(1, Form("Execution time for Exec() : R:%.2fs C:%.2fs",
125                fExecTimer.RealTime(),fExecTimer.CpuTime()));
126   
127 }
128
129 //_____________________________________________________________________________
130 void 
131 AliMUONDigitizerV3::ApplyResponseToTrackerDigit(AliMUONDigit& digit, Bool_t addNoise)
132 {
133   /// For tracking digits, starting from an ideal digit's charge, we :
134   ///
135   /// - add some noise (thus leading to a realistic charge), if requested to do so
136   /// - divide by a gain (thus decalibrating the digit)
137   /// - add a pedestal (thus decalibrating the digit)
138   /// - sets the signal to zero if below 3*sigma of the noise
139
140   static const Int_t kMaxADC = (1<<12)-1; // We code the charge on a 12 bits ADC.
141
142   Float_t signal = digit.Signal();
143
144   if ( !addNoise )
145     {
146       digit.SetADC(TMath::Nint(signal));
147       return;
148     }
149   
150   Int_t detElemId = digit.DetElemId();
151   
152   Int_t manuId = digit.ManuId();
153   Int_t manuChannel = digit.ManuChannel();
154   
155   AliMUONVCalibParam* pedestal = fCalibrationData->Pedestals(detElemId,manuId);
156   if (!pedestal)
157     {
158       AliFatal(Form("Could not get pedestal for DE=%d manuId=%d",
159                     detElemId,manuId));    
160     }
161   Float_t pedestalMean = pedestal->ValueAsFloat(manuChannel,0);
162   Float_t pedestalSigma = pedestal->ValueAsFloat(manuChannel,1);
163   
164   AliMUONVCalibParam* gain = fCalibrationData->Gains(detElemId,manuId);
165   if (!gain)
166     {
167       AliFatal(Form("Could not get gain for DE=%d manuId=%d",
168                     detElemId,manuId));    
169     }    
170   Float_t gainMean = gain->ValueAsFloat(manuChannel,0);
171
172   Float_t adcNoise = gRandom->Gaus(0.0,pedestalSigma);
173      
174   Int_t adc;
175
176   if ( gainMean < 1E-6 )
177     {
178       AliError(Form("Got a too small gain %e for DE=%d manuId=%d manuChannel=%d. "
179                     "Setting signal to 0.",
180                     gainMean,detElemId,manuId,manuChannel));
181       adc = 0;
182     }
183   else
184     {
185       adc = TMath::Nint( signal / gainMean + pedestalMean + adcNoise);///
186       
187       if ( adc <= pedestalMean + fgkNSigmas*pedestalSigma ) 
188         {
189           adc = 0;
190         }
191     }
192   
193   // be sure we stick to 12 bits.
194   if ( adc > kMaxADC )
195     {
196       adc = kMaxADC;
197     }
198   
199   digit.SetPhysicsSignal(TMath::Nint(signal));
200   digit.SetSignal(adc);
201   digit.SetADC(adc);
202 }
203
204 //_____________________________________________________________________________
205 void 
206 AliMUONDigitizerV3::ApplyResponseToTriggerDigit(AliMUONDigit& digit,
207                                                 AliMUONData* data)
208 {
209   /// \todo add comment
210
211   if ( !fTriggerEfficiency ) return;
212
213   AliMUONDigit* correspondingDigit = FindCorrespondingDigit(digit,data);
214
215   if(!correspondingDigit)return;//reject bad correspondences
216
217   Int_t detElemId = digit.DetElemId();
218
219   AliMpSegmentation* segmentation = AliMpSegmentation::Instance();
220   const AliMpVSegmentation* segment[2] = 
221   {
222     segmentation->GetMpSegmentation(detElemId,AliMp::GetCathodType(digit.Cathode())), 
223     segmentation->GetMpSegmentation(detElemId,AliMp::GetCathodType(correspondingDigit->Cathode()))
224   };
225
226   AliMpPad pad[2] = 
227   {
228     segment[0]->PadByIndices(AliMpIntPair(digit.PadX(),digit.PadY()),kTRUE), 
229     segment[1]->PadByIndices(AliMpIntPair(correspondingDigit->PadX(),correspondingDigit->PadY()),kTRUE)
230   };
231
232   Int_t p0(1);
233   if (digit.Cathode()==0)p0=0;
234
235   AliMpIntPair location = pad[p0].GetLocation(0);
236   Int_t nboard = location.GetFirst();
237
238   Bool_t isTrig[2];
239
240   fTriggerEfficiency->IsTriggered(detElemId, nboard-1, 
241                                   isTrig[0], isTrig[1]);
242
243   if (!isTrig[digit.Cathode()])
244   {
245           digit.SetSignal(0);
246   }
247   
248   if ( &digit != correspondingDigit )
249   {
250           if (!isTrig[correspondingDigit->Cathode()])
251     {
252       correspondingDigit->SetSignal(0);
253           }
254   }
255 }
256
257 //_____________________________________________________________________________
258 void
259 AliMUONDigitizerV3::ApplyResponse()
260 {
261   /// Loop over all chamber digits, and apply the response to them
262   /// Note that this method may remove digits.
263
264   const Bool_t kAddNoise = kTRUE;
265   
266   for ( Int_t ich = 0; ich < AliMUONConstants::NCh(); ++ich )
267   {
268     TClonesArray* digits = fOutputData->Digits(ich);
269     Int_t n = digits->GetEntriesFast();
270     Bool_t trackingChamber = ( ich < AliMUONConstants::NTrackingCh() );
271     for ( Int_t i = 0; i < n; ++i )
272     {
273       AliMUONDigit* d = static_cast<AliMUONDigit*>(digits->UncheckedAt(i));
274       if ( trackingChamber )
275       {
276         ApplyResponseToTrackerDigit(*d,kAddNoise);
277       }
278       else
279       {
280         ApplyResponseToTriggerDigit(*d,fOutputData);
281       }
282       if ( d->Signal() <= 0 )
283       {
284         digits->RemoveAt(i);
285       }
286     }
287     digits->Compress();
288   }    
289   
290 // The version below, using iterator, does not yet work (as the iterator
291 // assumes it is reading digits from the tree, while in this case it's
292 // writing...)
293 //
294 //  AliMUONDigit* digit(0x0);
295 //
296 //  // First loop on tracker digits
297 //  AliMUONDataIterator tracker(fOutputData,"D",AliMUONDataIterator::kTrackingChambers);
298 //  
299 //  while ( ( digit = static_cast<AliMUONDigit*>(tracker.Next()) ) )
300 //  {
301 //    ApplyResponseToTrackerDigit(*digit);
302 //    if ( digit->Signal() <= 0 )
303 //    {
304 //      tracker.Remove();
305 //    }    
306 //    
307 //  }
308 //
309 //  // Then loop on trigger digits
310 //  AliMUONDataIterator trigger(fOutputData,"D",AliMUONDataIterator::kTriggerChambers);
311 //  
312 //  while ( ( digit = static_cast<AliMUONDigit*>(trigger.Next()) ) )
313 //  {
314 //    ApplyResponseToTriggerDigit(*digit,fOutputData);
315 //    if ( digit->Signal() <= 0 )
316 //    {
317 //      trigger.Remove();
318 //    }    
319 //  }
320 }
321
322 //_____________________________________________________________________________
323 void
324 AliMUONDigitizerV3::AddOrUpdateDigit(TClonesArray& array, 
325                                      const AliMUONDigit& digit)
326 {
327   /// Add or update a digit, depending on whether there's already a digit
328   /// for the corresponding channel.
329
330   Int_t ix = FindDigitIndex(array,digit);
331   
332   if (ix>=0)
333   {
334     AliMUONDigit* d = static_cast<AliMUONDigit*>(array.UncheckedAt(ix));
335     Bool_t ok = MergeDigits(digit,*d);
336     if (!ok)
337     {
338       AliError("Digits are not mergeable !");
339     }
340   }
341   else
342   {
343     ix = array.GetLast() + 1;
344     new(array[ix]) AliMUONDigit(digit);
345   }
346   
347 }
348
349 //_____________________________________________________________________________
350 void
351 AliMUONDigitizerV3::Exec(Option_t*)
352 {
353   /// Main method.
354   /// We first loop over input files, and merge the sdigits we found there.
355   /// Second, we digitize all the resulting sdigits
356   /// Then we generate noise-only digits (for tracker only)
357   /// And we finally generate the trigger outputs.
358     
359   AliDebug(1, "Running digitizer.");
360   
361   if ( fManager->GetNinputs() == 0 )
362   {
363     AliWarning("No input set. Nothing to do.");
364     return;
365   }
366   
367   if ( !fIsInitialized )
368   {
369     AliError("Not initialized. Cannot perform the work. Sorry");
370     return;
371   }
372   
373   fExecTimer.Start(kFALSE);
374
375   Int_t nInputFiles = fManager->GetNinputs();
376   
377   if ( fOutputData->TreeD() == 0x0 )
378   {
379     AliDebug(1,"Calling MakeDigitsContainer");
380     fOutputData->GetLoader()->MakeDigitsContainer();
381   }
382   fOutputData->MakeBranch("D,GLT");
383   fOutputData->SetTreeAddress("D,GLT");
384   
385   // Loop over all the input files, and merge the sdigits found in those
386   // files.
387   for ( Int_t iFile = 0; iFile < nInputFiles; ++iFile )
388   {    
389     AliMUONData* inputData = GetDataAccess(fManager->GetInputFolderName(iFile));
390     if (!inputData)
391     {
392       AliFatal(Form("Could not get access to input file #%d",iFile));
393     }
394
395     inputData->GetLoader()->LoadSDigits("READ");
396     inputData->SetTreeAddress("S");
397     inputData->GetSDigits();
398
399     MergeWithSDigits(*fOutputData,*inputData,fManager->GetMask(iFile));
400     
401     inputData->ResetSDigits();
402     inputData->GetLoader()->UnloadSDigits();
403     delete inputData;
404   }
405   
406   // At this point, we do have digit arrays (one per chamber) which contains 
407   // the merging of all the sdigits of the input file(s).
408   // We now massage them to apply the detector response, i.e. this
409   // is here that we do the "digitization" work.
410   
411   ApplyResponse();
412   
413   if ( fGenerateNoisyDigits )
414   {
415     // Generate noise-only digits for tracker.
416     GenerateNoisyDigits();
417   }
418   
419   // We generate the global and local trigger decisions.
420   fTriggerProcessor->ExecuteTask();
421   
422   // Fill the output treeD
423   fOutputData->Fill("D,GLT");
424   
425   // Write to the output tree(D).
426   // Please note that as GlobalTrigger, LocalTrigger and Digits are in the same
427   // tree (=TreeD) in different branches, this WriteDigits in fact writes all of 
428   // the 3 branches.
429   fOutputData->GetLoader()->WriteDigits("OVERWRITE");
430   
431   // Finally, we clean up after ourselves.
432   fOutputData->ResetDigits();
433   fOutputData->ResetTrigger();
434   fOutputData->GetLoader()->UnloadDigits();
435   
436   fExecTimer.Stop();
437 }
438
439 //_____________________________________________________________________________
440 AliMUONDigit* 
441 AliMUONDigitizerV3::FindCorrespondingDigit(AliMUONDigit& digit,
442                                            AliMUONData* data) const
443 {                                                
444   /// \todo add comment
445
446   AliMUONDataIterator it(data,"D",AliMUONDataIterator::kTriggerChambers);
447   AliMUONDigit* cd;
448
449   for(;;){
450       cd = static_cast<AliMUONDigit*>(it.Next());
451       if(!cd)continue;
452       if (cd->DetElemId() == digit.DetElemId() &&
453           cd->PadX() == digit.PadX() &&
454           cd->PadY() == digit.PadY() && 
455           cd->Cathode() == digit.Cathode()){
456           break;
457       }
458   }
459   //The corresponding digit is searched only forward in the AliMUONData.
460   //In this way when the first digit of the couple is given, the second digit is found and the efficiency is applied to both. 
461   //Afterwards, when the second digit of the couple is given the first one is not found and hence efficiency is not applied again
462   
463   while ( ( cd = static_cast<AliMUONDigit*>(it.Next()) ) )
464   {
465     if(!cd)continue;//avoid problems when 1 digit is removed
466     if ( cd->DetElemId() == digit.DetElemId() &&
467          cd->Hit() == digit.Hit() &&
468          cd->Cathode() != digit.Cathode() )
469     {
470       return cd;
471     }
472   }
473   return 0x0;
474 }
475
476
477 //_____________________________________________________________________________
478 Int_t
479 AliMUONDigitizerV3::FindDigitIndex(TClonesArray& array, 
480                                    const AliMUONDigit& digit) const
481 {
482   /// Return the index of digit within array, if that digit is there, 
483   /// otherwise returns -1
484   ///
485   /// \todo FIXME: this is of course not the best implementation you can think of.
486   /// Reconsider the use of hit/digit map... ? (but be sure it's needed!)
487   
488   fFindDigitIndexTimer.Start(kFALSE);
489   
490   Int_t n = array.GetEntriesFast();
491   for ( Int_t i = 0; i < n; ++i )
492   {
493     AliMUONDigit* d = static_cast<AliMUONDigit*>(array.UncheckedAt(i));
494     if ( d->DetElemId() == digit.DetElemId() &&
495          d->PadX() == digit.PadX() &&
496          d->PadY() == digit.PadY() && 
497          d->Cathode() == digit.Cathode() )
498     {
499       fFindDigitIndexTimer.Stop();
500       return i;
501     }
502   }
503   fFindDigitIndexTimer.Stop();
504   return -1;
505 }
506
507 //_____________________________________________________________________________
508 void
509 AliMUONDigitizerV3::GenerateNoisyDigits()
510 {
511   /// According to a given probability, generate digits that
512   /// have a signal above the noise cut (ped+n*sigma_ped), i.e. digits
513   /// that are "only noise".
514   
515   if ( !fNoiseFunction )
516   {
517     fNoiseFunction = new TF1("AliMUONDigitizerV3::fNoiseFunction","gaus",
518                              fgkNSigmas,fgkNSigmas*10);
519     
520     fNoiseFunction->SetParameters(1,0,1);
521   }
522   
523   fGenerateNoisyDigitsTimer.Start(kFALSE);
524   
525   for ( Int_t i = 0; i < AliMUONConstants::NTrackingCh(); ++i )
526   {
527     AliMpDEIterator it;
528   
529     it.First(i);
530   
531     while ( !it.IsDone() )
532     {
533       for ( Int_t cathode = 0; cathode < 2; ++cathode )
534       {
535         GenerateNoisyDigitsForOneCathode(it.CurrentDEId(),cathode);
536       }
537       it.Next();
538     }
539   }
540   
541   fGenerateNoisyDigitsTimer.Stop();
542 }
543  
544 //_____________________________________________________________________________
545 void
546 AliMUONDigitizerV3::GenerateNoisyDigitsForOneCathode(Int_t detElemId, Int_t cathode)
547 {
548   /// Generate noise-only digits for one cathode of one detection element.
549   /// Called by GenerateNoisyDigits()
550   
551   Int_t chamberId = AliMpDEManager::GetChamberId(detElemId);
552   TClonesArray* digits = fOutputData->Digits(chamberId);
553   
554   const AliMpVSegmentation* seg 
555     = AliMpSegmentation::Instance()->GetMpSegmentation(detElemId,AliMp::GetCathodType(cathode));
556   Int_t nofPads = seg->NofPads();
557   
558   Int_t maxIx = seg->MaxPadIndexX();
559   Int_t maxIy = seg->MaxPadIndexY();
560   
561   static const Double_t kProbToBeOutsideNsigmas = TMath::Erfc(fgkNSigmas/TMath::Sqrt(2.0)) / 2. ;
562   
563   Int_t nofNoisyPads = TMath::Nint(kProbToBeOutsideNsigmas*nofPads);
564   if ( !nofNoisyPads ) return;
565   
566   nofNoisyPads = 
567     TMath::Nint(gRandom->Gaus(nofNoisyPads,
568                               nofNoisyPads/TMath::Sqrt(nofNoisyPads)));
569   
570   AliDebug(3,Form("DE %d cath %d nofNoisyPads %d",detElemId,cathode,nofNoisyPads));
571   
572   for ( Int_t i = 0; i < nofNoisyPads; ++i )
573   {
574     Int_t ix(-1);
575     Int_t iy(-1);
576     do {
577       ix = gRandom->Integer(maxIx+1);
578       iy = gRandom->Integer(maxIy+1);
579     } while ( !seg->HasPad(AliMpIntPair(ix,iy)) );
580     AliMUONDigit d;
581     d.SetDetElemId(detElemId);
582     d.SetCathode(cathode);
583     d.SetPadX(ix);
584     d.SetPadY(iy);
585     if ( FindDigitIndex(*digits,d) >= 0 )
586     {
587       // this digit is already there, and not noise-only, we simply skip it
588       continue;
589     }
590     AliMpPad pad = seg->PadByIndices(AliMpIntPair(ix,iy));
591     Int_t manuId = pad.GetLocation().GetFirst();
592     Int_t manuChannel = pad.GetLocation().GetSecond();
593     
594     d.SetElectronics(manuId,manuChannel);
595     
596     AliMUONVCalibParam* pedestals = fCalibrationData->Pedestals(detElemId,manuId);
597     
598     Float_t pedestalMean = pedestals->ValueAsFloat(manuChannel,0);
599     Float_t pedestalSigma = pedestals->ValueAsFloat(manuChannel,1);
600     
601     Double_t ped = fNoiseFunction->GetRandom()*pedestalSigma;
602
603     d.SetSignal(TMath::Nint(ped+pedestalMean+0.5));
604     d.SetPhysicsSignal(0);
605     d.NoiseOnly(kTRUE);
606     AliDebug(3,Form("Adding a pure noise digit :"));
607     StdoutToAliDebug(3,cout << "Before Response: " << endl; 
608                      d.Print(););
609     ApplyResponseToTrackerDigit(d,kFALSE);
610     if ( d.Signal() > 0 )
611     {
612       AddOrUpdateDigit(*digits,d);
613     }
614     else
615     {
616       AliError("Pure noise below threshold. This should not happen. Not adding "
617                "this digit.");
618     }
619     StdoutToAliDebug(3,cout << "After Response: " << endl; 
620                      d.Print(););
621   }
622 }
623
624 //_____________________________________________________________________________
625 AliMUONData* 
626 AliMUONDigitizerV3::GetDataAccess(const TString& folderName)
627 {
628   /// Create an AliMUONData to deal with data found in folderName.
629
630   AliDebug(1,Form("Getting access to folder %s",folderName.Data()));
631   AliRunLoader* runLoader = AliRunLoader::GetRunLoader(folderName);
632   if (!runLoader)
633   {
634     AliError(Form("Could not get RunLoader from folder %s",folderName.Data()));
635     return 0x0;
636   }
637   AliLoader* loader = static_cast<AliLoader*>(runLoader->GetLoader("MUONLoader"));
638   if (!loader)
639   {
640     AliError(Form("Could not get MuonLoader from folder %s",folderName.Data()));
641     return 0x0;
642   }
643   AliMUONData* data = new AliMUONData(loader,"MUON","MUONDataForDigitOutput");
644   AliDebug(1,Form("AliMUONData=%p loader=%p",data,loader));
645   return data;
646 }
647
648 //_____________________________________________________________________________
649 Bool_t
650 AliMUONDigitizerV3::Init()
651 {
652   /// Initialization of the TTask :
653   /// a) set the outputData pointer
654   /// b) create the calibrationData, according to run number
655   /// c) create the trigger processing task
656
657   AliDebug(1,"");
658   
659   if ( fIsInitialized )
660   {
661     AliError("Object already initialized.");
662     return kFALSE;
663   }
664   
665   if (!fManager)
666   {
667     AliError("fManager is null !");
668     return kFALSE;
669   }
670   
671   fOutputData = GetDataAccess(fManager->GetOutputFolderName());
672   if (!fOutputData)
673   {
674     AliError("Can not perform digitization. I'm sorry");
675     return kFALSE;
676   }
677   AliDebug(1,Form("fOutputData=%p",fOutputData));
678   
679   AliRunLoader* runLoader = fOutputData->GetLoader()->GetRunLoader();
680   AliRun* galice = runLoader->GetAliRun();  
681   Int_t runnumber = galice->GetRunNumber();
682   
683   fCalibrationData = new AliMUONCalibrationData(runnumber);
684   
685   fTriggerProcessor = new AliMUONTriggerElectronics(fOutputData,fCalibrationData);
686   
687   if ( muon()->GetTriggerEffCells() )
688   {
689     fTriggerEfficiency = fCalibrationData->TriggerEfficiency();
690     if ( fTriggerEfficiency )
691     {
692       AliDebug(1, "Will apply trigger efficiency");
693     }
694     else
695     {
696       AliError("I was requested to apply trigger efficiency, but I could "
697                "not get it !");
698     }
699   }
700   
701   if ( fGenerateNoisyDigits )
702   {
703     AliDebug(1, "Will generate noise-only digits for tracker");
704   }
705   
706   fIsInitialized = kTRUE;
707   return kTRUE;
708 }
709
710 //_____________________________________________________________________________
711 Bool_t
712 AliMUONDigitizerV3::MergeDigits(const AliMUONDigit& src, 
713                                 AliMUONDigit& srcAndDest)
714 {
715   /// Merge 2 digits (src and srcAndDest) into srcAndDest.
716
717   AliDebug(1,"Merging the following digits:");
718   StdoutToAliDebug(1,src.Print("tracks"););
719   StdoutToAliDebug(1,srcAndDest.Print("tracks"););
720   
721   Bool_t check = ( src.DetElemId() == srcAndDest.DetElemId() &&
722                    src.PadX() == srcAndDest.PadX() &&
723                    src.PadY() == srcAndDest.PadY() &&
724                    src.Cathode() == srcAndDest.Cathode() );
725   if (!check)
726   {
727     return kFALSE;
728   }
729   
730   srcAndDest.AddSignal(src.Signal());
731   srcAndDest.AddPhysicsSignal(src.Physics());
732   for ( Int_t i = 0; i < src.Ntracks(); ++i )
733   {
734     srcAndDest.AddTrack(src.Track(i),src.TrackCharge(i));
735   }
736   StdoutToAliDebug(1,cout << "result:"; srcAndDest.Print("tracks"););
737   return kTRUE;
738 }
739
740 //_____________________________________________________________________________
741 void 
742 AliMUONDigitizerV3::MergeWithSDigits(AliMUONData& outputData, 
743                                      const AliMUONData& inputData, Int_t mask)
744 {
745   /// Merge the sdigits in inputData with the digits already present in outputData
746
747   AliDebug(1,"");
748   
749         for ( Int_t ich = 0; ich < AliMUONConstants::NCh(); ++ich )
750         {
751     TClonesArray* iDigits = inputData.SDigits(ich); 
752     TClonesArray* oDigits = outputData.Digits(ich);
753     if (!iDigits)
754     {
755       AliError(Form("Could not get sdigits for ich=%d",ich));
756       return;
757     }
758     Int_t nSDigits = iDigits->GetEntriesFast();
759     for ( Int_t k = 0; k < nSDigits; ++k )
760                 {
761                         AliMUONDigit* sdigit = static_cast<AliMUONDigit*>(iDigits->UncheckedAt(k));
762       if (!sdigit)
763       {
764         AliError(Form("Could not get sdigit for ich=%d and k=%d",ich,k));
765       }
766       else
767       {
768         // Update the track references using the mask.
769         // FIXME: this is dirty, for backward compatibility only.
770         // Should re-design all this way of keeping track of MC information...
771         if ( mask ) sdigit->PatchTracks(mask);
772         // Then add or update the digit to the output.
773         AddOrUpdateDigit(*oDigits,*sdigit);
774       }
775     }   
776   }
777 }