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