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