]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONReconstructor.cxx
Coverity fix
[u/mrichter/AliRoot.git] / MUON / AliMUONReconstructor.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 /* $Id$ */
16
17 //-----------------------------------------------------------------------------
18 /// \class AliMUONReconstructor
19 ///
20 /// Implementation of AliReconstructor for MUON subsystem.
21 ///
22 /// The clustering mode and the associated parameters can be changed through the
23 /// AliMUONRecoParam object set in the reconstruction macro or read from the CDB
24 /// (see methods in AliMUONRecoParam.h file for details)
25 ///
26 /// Valid modes are :
27 ///
28 /// SIMPLEFIT : use the AliMUONClusterFinderSimpleFit clusterizer
29 ///
30 /// SIMPLEFITV3 : SIMPLEFIT with preclustering=PRECLUSTERV3
31 ///
32 /// MLEM : use AliMUONClusterFinderMLEM and AliMUONPreClusterFinder for preclustering (default)
33 /// MLEMV2 : MLEM with preclustering=PRECLUSTERV2
34 /// MLEMV3 : MLEM with preclustering=PRECLUSTERV3
35 ///
36 /// PRECLUSTER : use only AliMUONPreClusterFinder. Only for debug as
37 /// the produced clusters do not have a position, hence the tracking will not
38 /// work
39 /// PRECLUSTERV2 : another version of the preclustering
40 /// PRECLUSTERV3 : yet another version of the preclustering
41 ///
42 /// COG : use AliMUONClusterFinderCOG clusterizer. Not really a production
43 /// option either, as center-of-gravity is generally not a good estimate
44 /// of the cluster position...
45 ///
46 /// PEAKCOG : COG cluster finder around local maxima
47 /// PEAKFIT : fit around local maxima with up to 3 peaks, COG otherwise
48 ///
49 /// NOCLUSTERING : bypass completely the clustering stage
50 ///
51 /// ------
52 ///
53 /// The behavior of the MUON reconstruction can also be changed, besides
54 /// the usual methods found in AliReconstruction (e.g. to disable tracking)
55 /// by using AliReconstruction::SetOption("MUON",options)
56 /// where options should be a space separated string.
57 ///
58 /// Valid options are :
59 ///
60 /// SAVEDIGITS : if you want to save in the TreeD the *calibrated* digits
61 ///     that are used for the clustering
62 ///
63 /// DIGITSTOREV1 : use the V1 implementation of the digitstore 
64 /// DIGITSTOREV2R : use the V2R implementation of the digitstore 
65 ///
66 /// NOLOCALRECONSTRUCTION : for debug, to disable local reconstruction (and hence
67 /// "recover" old behavior)
68 ///
69 /// TRIGGERDISABLE : disable the treatment of MUON trigger
70 ///
71 /// ENABLEERRORLOGGING : enable error logging (this activates also warnings in RawStreamTracker)
72 ///
73 /// \author Laurent Aphecetche, Subatech
74 //-----------------------------------------------------------------------------
75
76 #include "AliMUONReconstructor.h"
77
78 #include "AliMUONCalibrationData.h"
79 #include "AliMUONClusterFinderCOG.h"
80 #include "AliMUONClusterFinderMLEM.h"
81 #include "AliMUONClusterFinderSimpleFit.h"
82 #include "AliMUONClusterFinderPeakCOG.h"
83 #include "AliMUONClusterFinderPeakFit.h"
84 #include "AliMUONClusterStoreV1.h"
85 #include "AliMUONClusterStoreV2.h"
86 #include "AliMUONConstants.h"
87 #include "AliMUONDigitCalibrator.h"
88 #include "AliMUONDigitMaker.h"
89 #include "AliMUONDigitStoreV1.h"
90 #include "AliMUONDigitStoreV2R.h"
91 #include "AliMUONGeometryTransformer.h"
92 #include "AliMUONPadStatusMaker.h"
93 #include "AliMUONPreClusterFinder.h"
94 #include "AliMUONPreClusterFinderV2.h"
95 #include "AliMUONPreClusterFinderV3.h"
96 #include "AliMUONSimpleClusterServer.h"
97 #include "AliMUONTracker.h"
98 #include "AliMUONTriggerCircuit.h"
99 #include "AliMUONTriggerStoreV1.h"
100 #include "AliMUONVClusterFinder.h"
101 #include "AliMUONVClusterServer.h"
102 #include "AliMUONVTrackStore.h"
103 #include "AliMUONTriggerElectronics.h"
104 #include "AliMUONTriggerUtilities.h"
105
106 #include "AliMpArea.h"
107 #include "AliMpCDB.h"
108 #include "AliMpConstants.h"
109 #include "AliMpDDLStore.h"
110 #include "AliMpSegmentation.h"
111
112 #include "AliRawReader.h"
113 #include "AliCDBManager.h"
114 #include "AliCodeTimer.h"
115 #include "AliLog.h"
116 #include "AliRunInfo.h"
117
118 #include <Riostream.h>
119 #include <TObjArray.h>
120 #include <TClonesArray.h>
121 #include <TString.h>
122 #include <TTree.h>
123
124 /// \cond CLASSIMP
125 ClassImp(AliMUONReconstructor)
126 /// \endcond 
127
128 //_____________________________________________________________________________
129 AliMUONReconstructor::AliMUONReconstructor() : 
130 AliReconstructor(),
131 fDigitMaker(0x0),
132 fTransformer(new AliMUONGeometryTransformer()),
133 fDigitStore(0x0),
134 fTriggerCircuit(0x0),
135 fCalibrationData(0x0),
136 fDigitCalibrator(0x0),
137 fTriggerStore(0x0),
138 fTrackStore(0x0),
139 fClusterStore(0x0),
140 fTriggerProcessor(0x0),
141 fTriggerUtilities(0x0),
142 fClusterServers(),
143 fTrackers()
144 {
145   /// normal ctor
146
147   AliDebug(1,"");
148   
149   // Unload mapping objects
150   // if they have been loaded from the obsolete OCDB mapping objects
151
152   if ( AliMpDDLStore::Instance(false) ) {
153     AliCDBManager::Instance()->UnloadFromCache("MUON/Calib/DDLStore");
154     delete AliMpDDLStore::Instance();
155   }  
156
157   if ( AliMpSegmentation::Instance(false) ) { 
158     AliCDBManager::Instance()->UnloadFromCache("MUON/Calib/Mapping");
159     delete AliMpSegmentation::Instance();
160   }  
161
162   // Load mapping
163   if ( ! AliMpCDB::LoadDDLStore() ) {
164     AliFatal("Could not access mapping from OCDB !");
165   }
166   
167   // Load geometry data
168   fTransformer->LoadGeometryData();
169  
170   fClusterServers.SetOwner(kTRUE);
171   fTrackers.SetOwner(kTRUE);
172 }
173
174 //_____________________________________________________________________________
175 AliMUONReconstructor::~AliMUONReconstructor()
176 {
177   /// dtor
178
179   AliDebug(1,"");
180
181   delete fDigitCalibrator;
182
183   delete fDigitMaker;
184   delete fDigitStore;
185   delete fTransformer;
186   delete fTriggerCircuit;
187   delete fTriggerStore;
188   delete fTrackStore;
189   delete fClusterStore;
190   delete fTriggerProcessor;
191   delete fTriggerUtilities;
192
193   delete AliMpSegmentation::Instance(false);
194   delete AliMpDDLStore::Instance(false);  
195
196   delete fCalibrationData;  
197 }
198
199 //_____________________________________________________________________________
200 void
201 AliMUONReconstructor::Calibrate(AliMUONVDigitStore& digitStore) const
202 {
203   /// Calibrate the digitStore
204   if (!fDigitCalibrator)
205   {
206     CreateCalibrator();
207   }
208   AliCodeTimerAuto(Form("%s::Calibrate(AliMUONVDigitStore*)",fDigitCalibrator->ClassName()),0)
209   fDigitCalibrator->Calibrate(digitStore);      
210 }
211
212 //_____________________________________________________________________________
213 void
214 AliMUONReconstructor::ConvertDigits(AliRawReader* rawReader, 
215                                     AliMUONVDigitStore* digitStore,
216                                     AliMUONVTriggerStore* triggerStore) const
217 {
218   /// Convert raw data into digit and trigger stores
219   CreateDigitMaker();
220
221   // Skip reconstruction if event is Calibration
222   if ( GetRecoParam()->GetEventSpecie() == AliRecoParam::kCalib ) {
223     digitStore->Clear(); // Remove possible digits from previous event
224     triggerStore->Clear(); // Remove possible triggers from previous event
225     AliInfo("Calibration event: do not convert digits");
226     return;
227   }
228   
229   AliCodeTimerStart(Form("%s::Raw2Digits(AliRawReader*,AliMUONVDigitStore*,AliMUONVTriggerStore*)",
230                     fDigitMaker->ClassName()))
231   fDigitMaker->Raw2Digits(rawReader,digitStore,triggerStore);
232   AliCodeTimerStop(Form("%s::Raw2Digits(AliRawReader*,AliMUONVDigitStore*,AliMUONVTriggerStore*)",
233                          fDigitMaker->ClassName()))
234   Calibrate(*digitStore);
235 }
236
237 //_____________________________________________________________________________
238 void 
239 AliMUONReconstructor::ConvertDigits(AliRawReader* rawReader, TTree* digitsTree) const
240 {
241    /// convert raw data into a digit tree
242   AliCodeTimerAuto("",0)
243
244   Bool_t alone = ( TriggerStore() == 0 );
245   
246   Bool_t ok = DigitStore()->Connect(*digitsTree,alone);
247   if ( TriggerStore() ) 
248   {
249     ok = ok && TriggerStore()->Connect(*digitsTree,kFALSE);
250   }
251   
252   if (!ok)
253   {
254     AliError("Could not make branches on TreeD");
255   }
256   else
257   {
258     ConvertDigits(rawReader,DigitStore(),TriggerStore());
259     AliCodeTimerStart("Fill digits")
260     digitsTree->Fill();
261     AliCodeTimerStop("Fill digits")
262     DigitStore()->Clear();
263   }
264 }
265
266 //_____________________________________________________________________________
267 void
268 AliMUONReconstructor::CreateDigitMaker() const
269 {
270   /// Create (and create if necessary) the digit maker
271   if (fDigitMaker) return;
272
273   AliCodeTimerAuto("",0)
274
275   TString option = GetOption();
276   
277   Bool_t enableErrorLogging = kFALSE;
278
279   if (option.Contains("ENABLEERRORLOGGING"))
280   {
281     enableErrorLogging = kTRUE;
282   }
283
284   fDigitMaker = new AliMUONDigitMaker(enableErrorLogging);
285   option.ToUpper();
286
287   // Always make trigger digits
288   // (needed when calculating trigger chamber efficiency)
289   fDigitMaker->SetMakeTriggerDigits(kTRUE);
290
291   if ( GetRecoParam()->TryRecover() )
292   {
293     fDigitMaker->SetTryRecover(kTRUE);
294   }
295   else
296   {
297     fDigitMaker->SetTryRecover(kFALSE);    
298   }
299 }
300
301 //_____________________________________________________________________________
302 void 
303 AliMUONReconstructor::CreateTriggerCircuit() const
304 {
305   /// Return (and create if necessary) the trigger circuit object
306   if (fTriggerCircuit) return;
307
308   AliCodeTimerAuto("",0)
309
310   fTriggerCircuit = new AliMUONTriggerCircuit(fTransformer);
311
312 }
313
314 //_____________________________________________________________________________
315 void 
316 AliMUONReconstructor::CreateTriggerUtilities() const
317 {
318   /// Return (and create if necessary) the trigger utilities object
319   if ( fTriggerUtilities ) return;
320   
321   AliCodeTimerAuto("",0)
322   
323   if ( ! fCalibrationData ) CreateCalibrationData();
324   
325   fTriggerUtilities = new AliMUONTriggerUtilities(fCalibrationData);
326 }
327
328 //_____________________________________________________________________________
329 AliTracker* 
330 AliMUONReconstructor::CreateTracker() const
331 {
332   /// Create the MUONTracker object
333   
334   CreateTriggerCircuit();
335   CreateTriggerUtilities();
336   
337   const AliMUONRecoParam* rp = GetRecoParam();
338   
339   Int_t es = rp->GetEventSpecie();
340   
341   AliTracker* tracker = static_cast<AliTracker*>(fTrackers.At(es));
342   
343   if (!tracker ) 
344   {
345     if ( ! rp->CombineClusterTrackReco() )
346     {
347       tracker = new AliMUONTracker(rp,
348                                    0x0,
349                                    *DigitStore(),
350                                    fTransformer,
351                                    fTriggerCircuit,
352                                    fTriggerUtilities);
353
354       AliInfo(Form("Created tracker %p for recoparam of type %s es=%d",
355                    tracker,
356                    AliRecoParam::GetEventSpecieName(AliRecoParam::Convert(rp->GetEventSpecie())),es));
357     }
358     else
359     {
360       
361       tracker = new AliMUONTracker(rp,
362                                    CreateClusterServer(*rp),
363                                    *DigitStore(),
364                                    fTransformer,
365                                    fTriggerCircuit,
366                                    fTriggerUtilities);
367
368       AliInfo(Form("Created (combined) tracker %p for recoparam of type %s es=%d",
369                    tracker,
370                    AliRecoParam::GetEventSpecieName(AliRecoParam::Convert(rp->GetEventSpecie())),es));      
371     }
372     
373     fTrackers.AddAtAndExpand(tracker,es);
374   }
375   
376   
377   return tracker;
378 }
379
380 //_____________________________________________________________________________
381 AliMUONVClusterFinder*
382 AliMUONReconstructor::CreateClusterFinder(const char* clusterFinderType)
383 {
384   /// Create a given cluster finder instance
385   
386   AliCodeTimerAutoGeneral("",0)
387
388   AliMUONVClusterFinder* clusterFinder(0x0);
389   
390   TString opt(clusterFinderType);
391   opt.ToUpper();
392   
393   if ( strstr(opt,"PRECLUSTERV2") )
394   {
395     clusterFinder = new AliMUONPreClusterFinderV2;
396   }    
397   else if ( strstr(opt,"PRECLUSTERV3") )
398   {
399     clusterFinder = new AliMUONPreClusterFinderV3;
400   }  
401   else if ( strstr(opt,"PRECLUSTER") )
402   {
403     clusterFinder = new AliMUONPreClusterFinder;
404   }  
405   else if ( strstr(opt,"PEAKCOG") )
406   {
407     clusterFinder = new AliMUONClusterFinderPeakCOG(kFALSE,new AliMUONPreClusterFinder);
408   }
409   else if ( strstr(opt,"PEAKFIT") )
410   {
411     clusterFinder = new AliMUONClusterFinderPeakFit(kFALSE,new AliMUONPreClusterFinder);
412   }
413   else if ( strstr(opt,"COG") )
414   {
415     clusterFinder = new AliMUONClusterFinderCOG(new AliMUONPreClusterFinder);
416   }  
417   else if ( strstr(opt,"SIMPLEFITV3") )
418   {
419     clusterFinder = new AliMUONClusterFinderSimpleFit(new AliMUONClusterFinderCOG(new AliMUONPreClusterFinderV3));
420   }
421   else if ( strstr(opt,"SIMPLEFIT") )
422   {
423     clusterFinder = new AliMUONClusterFinderSimpleFit(new AliMUONClusterFinderCOG(new AliMUONPreClusterFinder));
424   }
425   else if ( strstr(opt,"MLEM:DRAW") )
426   {
427     clusterFinder = new AliMUONClusterFinderMLEM(kTRUE,new AliMUONPreClusterFinder);
428   }
429   else if ( strstr(opt,"MLEMV3") )
430   {
431     clusterFinder = new AliMUONClusterFinderMLEM(kFALSE,new AliMUONPreClusterFinderV3);
432   } 
433   else if ( strstr(opt,"MLEMV2") )
434   {
435     clusterFinder = new AliMUONClusterFinderMLEM(kFALSE,new AliMUONPreClusterFinderV2);
436   } 
437   else if ( strstr(opt,"MLEM") )
438   {
439     clusterFinder = new AliMUONClusterFinderMLEM(kFALSE,new AliMUONPreClusterFinder);
440   } 
441   else
442   {
443     AliErrorClass(Form("clustering mode \"%s\" does not exist",opt.Data()));
444     return 0x0;
445   }
446   
447   return clusterFinder;
448 }
449
450 //_____________________________________________________________________________
451 AliMUONVClusterServer*
452 AliMUONReconstructor::CreateClusterServer(const AliMUONRecoParam& rp) const
453 {
454   /// Create cluster server
455   
456   AliCodeTimerAuto("",0);
457   
458   AliMUONVClusterServer* clusterServer = static_cast<AliMUONVClusterServer*>(fClusterServers.At(rp.GetEventSpecie()));
459   
460   if (!clusterServer )
461   {
462     AliMUONVClusterFinder* clusterFinder = CreateClusterFinder(rp.GetClusteringMode());
463     
464     if ( !clusterFinder ) return 0x0;
465     
466     clusterServer = new AliMUONSimpleClusterServer(clusterFinder,*fTransformer);
467
468     AliInfo(Form("Created AliMUONSimpleClusterServer (%p) for specie %d with clustering = %s (following requesting clustering mode %s)",
469                  clusterServer,rp.GetEventSpecie(),clusterFinder->ClassName(),rp.GetClusteringMode()));
470     
471     fClusterServers.AddAtAndExpand(clusterServer,rp.GetEventSpecie());
472   }
473   
474   return clusterServer;
475 }
476
477 //_____________________________________________________________________________
478 void
479 AliMUONReconstructor::CreateCalibrationData() const
480 {
481   /// Create the calibrator
482   
483   AliCodeTimerAuto("",0);
484   
485   Int_t runNumber = AliCDBManager::Instance()->GetRun();
486
487   fCalibrationData = new AliMUONCalibrationData(runNumber);
488   if ( !fCalibrationData->IsValid() )
489   {
490     AliError("Could not retrieve calibrations !");
491     delete fCalibrationData;
492     fCalibrationData = 0x0;
493     return;
494   }    
495   
496   // It is now time to check whether we have everything to proceed.
497   // What we need depends on whether both tracker and trigger
498   // are in the readout chain, and what specific "bad channel policy"
499   // we use
500   
501   Bool_t kTracker(kFALSE);
502   Bool_t kTrigger(kFALSE);
503   
504   const AliRunInfo* runInfo = GetRunInfo();
505   if (!runInfo)
506   {
507     AliError("Could not get runinfo ?");
508   }
509   else
510   {
511     TString detectors(runInfo->GetActiveDetectors());
512     if (detectors.Contains("MUONTRK")) kTracker=kTRUE;
513     if (detectors.Contains("MUONTRG")) kTrigger=kTRUE;
514   }
515    
516   AliInfo(Form("Run with MUON TRIGGER : %s and MUON TRACKER : %s",
517                kTrigger ? "YES":"NO" , 
518                kTracker ? "YES":"NO"));
519   
520   if ( kTracker ) 
521   {
522     // Check that we get all the calibrations we'll need
523     if ( !fCalibrationData->Pedestals() ||
524         !fCalibrationData->Gains() )
525     {
526       AliFatal(Form("Could not access all required calibration data (PED %p GAIN %p)",
527                     fCalibrationData->Pedestals(),fCalibrationData->Gains()));      
528     }
529     
530     if ( !fCalibrationData->HV() ) 
531     {
532       // Special treatment of HV. We only break if the values
533       // are not there *AND* we cut on them.
534       UInt_t mask = GetRecoParam()->PadGoodnessMask();
535       TString smask(AliMUONPadStatusMaker::AsCondition(mask));
536       if ( smask.Contains("HV") )
537       {
538         AliFatal("Could not access all required calibration data (HV)");      
539       }
540     } 
541   }
542 }
543
544 //_____________________________________________________________________________
545 void
546 AliMUONReconstructor::CreateCalibrator() const
547 {
548   /// Create the calibrator
549
550   AliCodeTimerAuto("",0);
551
552   if ( ! fCalibrationData )
553     CreateCalibrationData();
554
555   AliInfo("Calibration will occur.");
556
557   TString opt(GetOption());
558   opt.ToUpper();
559   
560   if ( strstr(opt,"NOSTATUSMAP") )
561   {
562     AliWarning("NOSTATUSMAP is obsolete");
563   }
564
565   fDigitCalibrator = new AliMUONDigitCalibrator(*fCalibrationData,GetRecoParam());
566 }
567
568 //_____________________________________________________________________________
569 void
570 AliMUONReconstructor::ResponseRemovingChambers(AliMUONVTriggerStore* triggerStore) const
571 {
572   /// Update trigger information with informatins obtained after
573   /// re-calculation of trigger response
574   AliCodeTimerAuto("",0);
575
576   if ( ! fCalibrationData )
577     CreateCalibrationData();
578
579   if ( ! fTriggerProcessor )
580     fTriggerProcessor = new AliMUONTriggerElectronics(fCalibrationData);
581
582   fTriggerProcessor->ResponseRemovingChambers(*triggerStore);
583 }
584
585 //_____________________________________________________________________________
586 AliMUONVDigitStore*
587 AliMUONReconstructor::DigitStore() const
588 {
589   /// Return (and create if necessary) the digit container
590   if (!fDigitStore) 
591   {
592     TString sopt(GetOption());
593     sopt.ToUpper();
594     
595     AliInfo(Form("Options=%s",sopt.Data()));
596     
597     if ( sopt.Contains("DIGITSTOREV1") )
598     {
599       fDigitStore = AliMUONVDigitStore::Create("AliMUONDigitStoreV1");
600     }
601     else if ( sopt.Contains("DIGITSTOREV2R") ) 
602     {
603       fDigitStore = AliMUONVDigitStore::Create("AliMUONDigitStoreV2R");
604     }
605     else if ( sopt.Contains("DIGITSTOREV2S") ) 
606     {
607       fDigitStore = AliMUONVDigitStore::Create("AliMUONDigitStoreV2S");
608     }
609     
610     if (!fDigitStore) fDigitStore = AliMUONVDigitStore::Create("AliMUONDigitStoreV2R");
611     
612     AliInfo(Form("Will use %s to store digits during reconstruction",fDigitStore->ClassName()));
613   }
614   return fDigitStore;
615 }
616
617 //_____________________________________________________________________________
618 void
619 AliMUONReconstructor::FillTreeR(AliMUONVTriggerStore* triggerStore,
620                                 TTree& clustersTree) const
621 {
622   /// Write the trigger and cluster information into TreeR
623
624   AliCodeTimerAuto("",0)
625
626   Bool_t ok(kFALSE);
627   Bool_t alone(kTRUE); // is trigger the only info in TreeR ?
628   
629    const AliMUONRecoParam* rp = GetRecoParam();
630   
631   if ( ! rp->CombineClusterTrackReco() )
632   {
633     alone = kFALSE; // we'll get both tracker and trigger information in TreeR
634   }
635   
636   if ( triggerStore ) 
637   {
638     ResponseRemovingChambers(triggerStore);
639     ok = triggerStore->Connect(clustersTree,alone);
640     if (!ok)
641     {
642       AliError("Could not create triggerStore branches in TreeR");
643     }
644   }
645
646   if ( !alone )
647   {
648     if (!fClusterStore)
649     {
650       fClusterStore = new AliMUONClusterStoreV2;
651     }
652     
653     AliMUONVClusterServer* clusterServer = CreateClusterServer(*rp);
654     
655     TIter next(DigitStore()->CreateIterator());
656     clusterServer->UseDigits(next,DigitStore());
657
658     AliMpArea area;
659     
660     AliDebug(1,Form("Doing full clusterization in local reconstruction using %s ",clusterServer->ClassName()));
661     
662     for ( Int_t i = 0; i < AliMpConstants::NofTrackingChambers(); ++i ) 
663     {
664       if (rp->UseChamber(i))
665       {
666         if ( ( i == 6 || i == 7 )  && rp->BypassSt4() ) continue;
667         if ( ( i == 8 || i == 9 )  && rp->BypassSt5() ) continue;
668         
669         clusterServer->Clusterize(i,*fClusterStore,area,rp);
670       }
671     }
672     
673     Bool_t cok = fClusterStore->Connect(clustersTree,alone);
674     
675     if (!cok) AliError("Could not connect clusterStore to clusterTree");
676     
677     AliDebug(1,Form("Number of clusters found = %d",fClusterStore->GetSize()));
678     
679     StdoutToAliDebug(1,fClusterStore->Print());
680   }
681          
682   if (ok) // at least one type of branches created successfully
683   {
684     clustersTree.Fill();
685   }
686   
687   if (fClusterStore) fClusterStore->Clear();
688 }
689
690 //_____________________________________________________________________________
691 const AliMUONRecoParam* AliMUONReconstructor::GetRecoParam()
692
693   /// Get the recoparam from reconstruction
694   return dynamic_cast<const AliMUONRecoParam*>(AliReconstructor::GetRecoParam(AliReconstruction::GetDetIndex("MUON"))); 
695 }
696
697
698 //_____________________________________________________________________________
699 Bool_t 
700 AliMUONReconstructor::HasDigitConversion() const
701 {
702   /// We *do* have digit conversion, but we might advertise it only 
703   /// if we want to save the digits.
704   
705   TString opt(GetOption());
706   opt.ToUpper();
707   if ( opt.Contains("SAVEDIGITS" ) && !opt.Contains("NOLOCALRECONSTRUCTION") )
708   {
709     return kTRUE;
710   }
711   else
712   {
713     return kFALSE;
714   }
715 }
716
717 //_____________________________________________________________________________
718 void 
719 AliMUONReconstructor::Reconstruct(AliRawReader* rawReader, TTree* clustersTree) const
720 {
721   /// This method is called by AliReconstruction if HasLocalReconstruction()==kTRUE AND
722   /// HasDigitConversion()==kFALSE
723   
724   if ( !clustersTree ) 
725   {
726     AliError("clustersTree is 0x0 !");
727     return;
728   }
729   
730   ConvertDigits(rawReader,DigitStore(),TriggerStore());
731
732   FillTreeR(TriggerStore(),*clustersTree);
733 }
734
735 //_____________________________________________________________________________
736 void 
737 AliMUONReconstructor::Reconstruct(TTree* digitsTree, TTree* clustersTree) const
738 {
739   /// This method is called by AliReconstruction if HasLocalReconstruction()==kTRUE
740   /// AND HasDigitConversion()==kTRUE
741   
742   AliCodeTimerAuto("",0)
743   
744   AliDebug(1,"");
745   
746   if (!digitsTree || !clustersTree) 
747   {
748     AliError(Form("Tree is null : digitsTree=%p clustersTree=%p",
749                   digitsTree,clustersTree));
750     return;
751   }
752
753   if (!fDigitStore)
754   {
755     fDigitStore = AliMUONVDigitStore::Create(*digitsTree);
756     if (!fDigitStore)
757     {
758       AliError(Form("Could not get DigitStore from %s",digitsTree->GetName()));
759     }
760     else
761     {
762       AliInfo(Form("Created %s from %s",fDigitStore->ClassName(),digitsTree->GetName()));
763     }
764   }
765   if (!fTriggerStore)
766   {
767     fTriggerStore = AliMUONVTriggerStore::Create(*digitsTree);
768     if (!fTriggerStore)
769     {
770       AliError(Form("Could not get TriggerStore from %s",digitsTree->GetName()));
771     }
772     else
773     {
774       AliInfo(Form("Created %s from %s",fTriggerStore->ClassName(),digitsTree->GetName()));
775     }
776   }
777   
778   if (!fTriggerStore && !fDigitStore)
779   {
780     AliError("No store at all. Nothing to do.");
781     return;
782   }
783   
784   // insure we start with empty stores
785   if ( fDigitStore ) 
786   {
787     fDigitStore->Clear(); 
788     Bool_t alone = ( fTriggerStore ? kFALSE : kTRUE );
789     Bool_t ok = fDigitStore->Connect(*digitsTree,alone);
790     if (!ok)
791     {
792       AliError("Could not connect digitStore to digitsTree");
793       return;
794     }
795   }
796   if ( fTriggerStore ) 
797   {
798     fTriggerStore->Clear();
799     Bool_t alone = ( fDigitStore ? kFALSE : kTRUE );
800     Bool_t ok = fTriggerStore->Connect(*digitsTree,alone);
801     if (!ok)
802     {
803       AliError("Could not connect triggerStore to digitsTree");
804       return;
805     }
806   }
807   
808   digitsTree->GetEvent(0);
809   
810   if ( fDigitStore ) 
811   {
812     // Insure we got calibrated digits (if we reconstruct from pure simulated,
813     // i.e. w/o going through raw data, this will be the case)
814     TIter next(fDigitStore->CreateIterator());
815     AliMUONVDigit* digit = static_cast<AliMUONVDigit*>(next());
816     if (digit && !digit->IsCalibrated())
817     {
818       Calibrate(*fDigitStore);
819     }
820   }
821     
822   FillTreeR(fTriggerStore,*clustersTree);
823 }
824
825 //_____________________________________________________________________________
826 AliMUONVTriggerStore*
827 AliMUONReconstructor::TriggerStore() const
828 {
829   /// Return (and create if necessary and allowed) the trigger container
830   TString sopt(GetOption());
831   sopt.ToUpper();
832   
833   if (sopt.Contains("TRIGGERDISABLE"))
834   {
835     delete fTriggerStore;
836     fTriggerStore = 0x0;
837   }
838   else
839   {
840     if (!fTriggerStore)
841     {
842       fTriggerStore = new AliMUONTriggerStoreV1;
843     }
844   }
845   return fTriggerStore;
846 }