minor coverity defect: added protection for self-assignment
[u/mrichter/AliRoot.git] / MUON / AliMUONMCDataInterface.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 /// \class AliMUONMCDataInterface
20 ///
21 /// Easy to use MC data accessor
22 ///
23 /// \author Laurent Aphecetche, Subatech
24 ///
25 // Moved parts of old AliMUONDataInterface interface to AliMUONMCDataInterface
26 //  Artur Szostak <artursz@iafrica.com> (University of Cape Town)
27 //-----------------------------------------------------------------------------
28
29 #include "AliMUONMCDataInterface.h"
30 #include "AliMUONVDigitStore.h"
31 #include "AliMUONVHitStore.h"
32 #include "AliMUONVTriggerStore.h"
33 #include "AliMUONHit.h"
34 #include "AliMUONVDigit.h"
35 #include "AliMUONLocalTrigger.h"
36 #include "AliMUONRegionalTrigger.h"
37 #include "AliMUONGlobalTrigger.h"
38
39 #include "AliMpEncodePair.h"
40 #include "AliMpDEManager.h"
41 #include "AliMpConstants.h"
42 #include "AliMpCDB.h"
43
44 #include "AliLog.h"
45 #include "AliLoader.h"
46 #include "AliRunLoader.h"
47 #include "AliHeader.h"
48 #include "AliStack.h"
49 #include "AliCDBManager.h"
50
51 #include <TTree.h>
52 #include <Riostream.h>
53 #include <TClonesArray.h>
54 #include <TList.h>
55 #include <TParticle.h>
56 #include <TIterator.h>
57 #include <cstdlib>
58 #include <cassert>
59
60 /// \cond CLASSIMP
61 ClassImp(AliMUONMCDataInterface)
62 /// \endcond
63
64 Int_t AliMUONMCDataInterface::fgInstanceCounter(0);
65
66 //_____________________________________________________________________________
67 AliMUONMCDataInterface::AliMUONMCDataInterface(const char* filename) :
68 TObject(),
69 fLoader(0x0),
70 fHitStore(0x0),
71 fSDigitStore(0x0),
72 fDigitStore(0x0),
73 fTriggerStore(0x0),
74 fTrackRefs(0x0),
75 fCurrentEvent(-1),
76 fIsValid(kFALSE),
77 fCurrentIteratorType(kNoIterator),
78 fCurrentIndex(-1),
79 fDataX(-1),
80 fDataY(-1),
81 fIterator(0x0)
82 {
83   /// ctor
84   
85   ++fgInstanceCounter;
86   
87   if ( AliCDBManager::Instance() != NULL &&
88        AliCDBManager::Instance()->GetDefaultStorage() == NULL ) {
89       AliFatal("CDB default storage not defined.");
90   }
91   
92   Open(filename);
93
94   // Load mapping
95   if ( ! AliMpCDB::LoadMpSegmentation() ) {
96     AliFatal("Could not access mapping from OCDB !");
97   }
98 }
99
100 //_____________________________________________________________________________
101 AliMUONMCDataInterface::~AliMUONMCDataInterface()
102 {
103   /// dtor
104   if ( fLoader ) 
105   {
106     delete fLoader->GetRunLoader();
107   }
108   --fgInstanceCounter;
109 }
110
111 //_____________________________________________________________________________
112 AliMUONVHitStore* 
113 AliMUONMCDataInterface::HitStore(Int_t event, Int_t track)
114 {
115   /// Return the hitStore for a given track of one event
116   /// Return 0x0 if event and/or track not found
117   /// Returned pointer should not be deleted
118   ///
119   /// \note If a previous store has been retrieved by one of the methods of
120   /// this class, but for a different event number, then those stores will
121   /// be deleted and no longer valid.
122   /// If you require access to the data for the earlier retrieved store,
123   /// but for different events, then you should deep copy / clone the object.
124   
125   if (not IsValid()) return 0x0;
126
127   if (event == fCurrentEvent)
128   {
129     if (track == fDataX and fHitStore != 0x0)  // using fDataX as track number.
130       return fHitStore;
131   }
132   else
133   {
134     ResetStores();
135     if ( not LoadEvent(event) ) return 0x0;
136   }
137   
138   fLoader->LoadHits();
139   
140   TTree* treeH = fLoader->TreeH();
141   if (treeH == 0x0)
142   {
143     AliError("Could not get treeH");
144     return 0x0;
145   }
146   
147   fHitStore = AliMUONVHitStore::Create(*treeH);
148   AliDebug(1,"Creating hitStore from treeH");
149   if ( fHitStore != 0x0 )
150   {
151     fHitStore->Connect(*treeH);
152     if ( treeH->GetEvent(track) == 0 ) 
153     {
154       AliError(Form("Could not read track %d",track));
155       fHitStore->Clear();
156       return 0x0;
157     }
158     fDataX = track; // using fDataX as track number.
159   }
160   
161   fLoader->UnloadHits();
162
163   return fHitStore;
164 }
165
166 //_____________________________________________________________________________
167 AliMUONVDigitStore*
168 AliMUONMCDataInterface::SDigitStore(Int_t event)
169 {
170   /// Return the SDigit store for a given event.
171   /// Return 0 if event not found
172   /// Returned pointer should not be deleted
173   ///
174   /// \note If a previous store has been retrieved by one of the methods of
175   /// this class, but for a different event number, then those stores will
176   /// be deleted and no longer valid.
177   /// If you require access to the data for the earlier retrieved store,
178   /// but for different events, then you should deep copy / clone the object.
179   
180   if (not IsValid()) return 0x0;
181   
182   if (event == fCurrentEvent)
183   {
184     if (fSDigitStore != 0x0)
185       return fSDigitStore;
186   }
187   else
188   {
189     ResetStores();
190     if ( not LoadEvent(event) ) return 0x0;
191   }
192   
193   fLoader->LoadSDigits();
194   
195   TTree* treeS = fLoader->TreeS();
196   if (treeS == 0x0)
197   {
198     AliError("Could not get treeS");
199     return 0x0;
200   }
201   
202   fSDigitStore = AliMUONVDigitStore::Create(*treeS);
203   if ( fSDigitStore != 0x0 )
204   {
205     fSDigitStore->Clear();
206     fSDigitStore->Connect(*treeS);
207     treeS->GetEvent(0);
208   }
209   
210   fLoader->UnloadSDigits();
211   
212   return fSDigitStore;
213 }
214
215 //_____________________________________________________________________________
216 AliMUONVDigitStore*
217 AliMUONMCDataInterface::DigitStore(Int_t event)
218 {
219   /// Return a pointer to the digitStore for a given event (or 0 if not found)
220   /// Returned pointer should not be deleted
221   ///
222   /// \note If a previous store has been retrieved by one of the methods of
223   /// this class, but for a different event number, then those stores will
224   /// be deleted and no longer valid.
225   /// If you require access to the data for the earlier retrieved store,
226   /// but for different events, then you should deep copy / clone the object.
227   
228   if (not IsValid()) return 0x0;
229   
230   if (event == fCurrentEvent)
231   {
232     if (fDigitStore != 0x0)
233       return fDigitStore;
234   }
235   else
236   {
237     ResetStores();
238     if ( not LoadEvent(event) ) return 0x0;
239   }
240   
241   fLoader->LoadDigits();
242   
243   TTree* treeD = fLoader->TreeD();
244   if (treeD == 0x0)
245   {
246     AliError("Could not get treeD");
247     return 0x0;
248   }
249   
250   fDigitStore = AliMUONVDigitStore::Create(*treeD);
251   if ( fDigitStore != 0x0 ) 
252   {
253     fDigitStore->Clear();
254     fDigitStore->Connect(*treeD);
255     treeD->GetEvent(0);
256   }
257   
258   fLoader->UnloadDigits();
259   
260   return fDigitStore;
261 }
262
263 //_____________________________________________________________________________
264 AliStack*
265 AliMUONMCDataInterface::Stack(Int_t event)
266 {
267   /// Get the Stack (list of generated particles) for one event
268   /// Returned pointer should not be deleted
269   ///
270   /// \note If a previous store has been retrieved by one of the methods of
271   /// this class, but for a different event number, then those stores will
272   /// be deleted and no longer valid.
273   /// If you require access to the data for the earlier retrieved store,
274   /// but for different events, then you should deep copy / clone the object.
275   
276   if ( not IsValid() ) return 0x0;
277
278   if (event != fCurrentEvent)
279   {
280     ResetStores();
281     if ( not LoadEvent(event) ) return 0x0;
282   }
283   
284   fLoader->GetRunLoader()->LoadKinematics();
285   
286   return fLoader->GetRunLoader()->Stack();
287 }
288
289 //_____________________________________________________________________________
290 TClonesArray*
291 AliMUONMCDataInterface::TrackRefs(Int_t event, Int_t track)
292 {
293   /// Get the track references for a given (generated) track of one event
294   /// Returned pointer should not be deleted
295   ///
296   /// \note If a previous store has been retrieved by one of the methods of
297   /// this class, but for a different event number, then those stores will
298   /// be deleted and no longer valid.
299   /// If you require access to the data for the earlier retrieved store,
300   /// but for different events, then you should deep copy / clone the object.
301   
302   if ( not IsValid() ) return 0x0;
303   
304   if (event == fCurrentEvent)
305   {
306     if (track == fDataX and fTrackRefs != 0x0)  // using fDataX as track number.
307       return fTrackRefs;
308   }
309   else
310   {
311     ResetStores();
312     if ( not LoadEvent(event) ) return 0x0;
313   }
314   
315   fLoader->GetRunLoader()->LoadTrackRefs();
316   
317   TTree* treeTR = fLoader->GetRunLoader()->TreeTR();
318   
319   if ( fTrackRefs != 0x0 ) fTrackRefs->Clear("C");
320   
321   if (treeTR != 0x0)
322   {
323     if ( treeTR->GetEvent(track) > 0 ) 
324     {
325       TBranch* branch = treeTR->GetBranch("TrackReferences");
326       branch->SetAddress(&fTrackRefs);
327       branch->GetEvent(track);
328       fDataX = track;  // using fDataX as track number.
329     }
330   }
331   else
332   {
333     AliError("Could not get TreeTR");
334   }
335   
336   fLoader->GetRunLoader()->UnloadTrackRefs();
337   
338   return fTrackRefs;
339 }
340
341 //_____________________________________________________________________________
342 AliMUONVTriggerStore*
343 AliMUONMCDataInterface::TriggerStore(Int_t event)
344 {
345   /// Return the triggerStore for a given event.
346   /// Return 0x0 if event not found.
347   /// Returned pointer should not be deleted.
348   ///
349   /// \note If a previous store has been retrieved by one of the methods of
350   /// this class, but for a different event number, then those stores will
351   /// be deleted and no longer valid.
352   /// If you require access to the data for the earlier retrieved store,
353   /// but for different events, then you should deep copy / clone the object.
354   
355   if (not IsValid()) return 0x0;
356   
357   if (event == fCurrentEvent)
358   {
359     if (fTriggerStore != 0x0)
360       return fTriggerStore;
361   }
362   else
363   {
364     ResetStores();
365     if ( not LoadEvent(event) ) return 0x0;
366   }
367   
368   fLoader->LoadDigits();
369   
370   TTree* treeD = fLoader->TreeD();
371   if ( treeD == 0x0 ) 
372   {
373     AliError("Could not get treeD");
374     return 0x0;
375   }
376   
377   fTriggerStore = AliMUONVTriggerStore::Create(*treeD);
378   if ( fTriggerStore != 0x0 )
379   {
380     fTriggerStore->Clear();
381     fTriggerStore->Connect(*treeD);
382     treeD->GetEvent(0);
383   }
384   
385   fLoader->UnloadDigits();
386   
387   return fTriggerStore;
388 }
389
390 //_____________________________________________________________________________
391 void
392 AliMUONMCDataInterface::DumpDigits(Int_t event, Bool_t sorted)
393 {
394   /// Dump the digits for a given event, sorted if requested.
395   DigitStore(event);
396   
397   if ( fDigitStore != 0x0 ) 
398   {
399     if ( sorted ) 
400     {
401       DumpSorted(*fDigitStore);
402     }
403     else
404     {
405       fDigitStore->Print();
406     }  
407   }
408 }
409
410 //_____________________________________________________________________________
411 void
412 AliMUONMCDataInterface::DumpHits(Int_t event)
413 {
414   /// Dump all the hits for one event
415   
416   Int_t ntracks = NumberOfTracks(event);
417   
418   for ( Int_t i = 0; i < ntracks; ++i ) 
419   {
420     cout << ">> Track " << i << endl;
421     HitStore(event,i);
422     if ( fHitStore )
423     {
424       fHitStore->Print("","full");
425     }
426   }
427 }
428
429 //_____________________________________________________________________________
430 void
431 AliMUONMCDataInterface::DumpKine(Int_t event)
432 {
433   /// Dump all generated particles for one event
434   AliStack* stack = Stack(event);
435   
436   if ( stack != 0x0 ) 
437   {
438     Int_t nparticles = (Int_t) stack->GetNtrack();
439   
440     for (Int_t iparticle=0; iparticle<nparticles; ++iparticle) 
441     {
442       stack->Particle(iparticle)->Print("");  
443     }
444   }
445   else
446   {
447     AliError("Could not get stack");
448   }
449 }
450
451 //_____________________________________________________________________________
452 void
453 AliMUONMCDataInterface::DumpSDigits(Int_t event, Bool_t sorted)
454 {
455   /// Dump the SDigits for a given event, sorted if requested
456   SDigitStore(event);
457   
458   if ( fSDigitStore != 0x0 ) 
459   {
460     if ( sorted ) 
461     {
462       DumpSorted(*fSDigitStore);
463     }
464     else
465     {
466       fSDigitStore->Print();
467     }
468   }
469 }
470
471 //_____________________________________________________________________________
472 void
473 AliMUONMCDataInterface::DumpSorted(const AliMUONVStore& store) const
474 {
475   /// Dump the given store in sorted order
476   
477   TIter next(store.CreateIterator());
478   TObject* object;
479   TList list;
480   list.SetOwner(kFALSE);
481   
482   while ( ( object = next() ) )
483   {
484     list.Add(object);
485   }
486   
487   list.Sort();
488   
489   list.Print();
490 }
491
492 //_____________________________________________________________________________
493 void
494 AliMUONMCDataInterface::DumpTrackRefs(Int_t event)
495 {
496   /// Dump track references for one event
497   Int_t ntrackrefs = NumberOfTrackRefs(event);
498   
499   for ( Int_t i = 0; i < ntrackrefs; ++i ) 
500   {
501     TrackRefs(event,i);
502     if ( fTrackRefs != 0x0 ) 
503     {
504       fTrackRefs->Print("","*");
505     }
506   }
507 }
508
509 //_____________________________________________________________________________
510 void
511 AliMUONMCDataInterface::DumpTrigger(Int_t event)
512 {
513   /// Dump trigger for a given event (trigger is read from TreeD)
514   
515   TriggerStore(event);
516
517   if ( fTriggerStore != 0x0 ) 
518   {
519     fTriggerStore->Print();
520   }
521 }
522
523 //_____________________________________________________________________________
524 Bool_t
525 AliMUONMCDataInterface::LoadEvent(Int_t event)
526 {
527   /// Load event if different from the current one.
528   /// Returns kFALSE on error and kTRUE if the event was loaded.
529   
530   assert( IsValid() );
531   
532   AliDebug(1,Form("Loading event %d using runLoader %p",event,fLoader->GetRunLoader()));
533   if (fLoader->GetRunLoader()->GetEvent(event) == 0)
534   {
535     fCurrentEvent = event;
536     return kTRUE;
537   }
538   else
539     return kFALSE;
540 }
541
542
543 //_____________________________________________________________________________
544 Int_t 
545 AliMUONMCDataInterface::NumberOfEvents() const
546 {
547   /// Number of events in the file we're connected to
548   if (not IsValid()) return -1;
549   return fLoader->GetRunLoader()->GetNumberOfEvents();
550 }
551
552 //_____________________________________________________________________________
553 Int_t 
554 AliMUONMCDataInterface::NumberOfTracks(Int_t event)
555 {
556   /// Number of tracks in the event
557   if ( not IsValid()) return -1;
558   
559   if (event != fCurrentEvent)
560   {
561     ResetStores();
562     if ( not LoadEvent(event) ) return -1;
563   }
564   
565   fLoader->LoadHits();
566   
567   Int_t rv(-1);
568   
569   TTree* treeH = fLoader->TreeH();
570   if (treeH != 0x0)
571   {
572     rv = static_cast<Int_t>(treeH->GetEntries());
573   }
574   else
575   {
576     AliError("Could not get TreeH");
577   }
578
579   fLoader->UnloadHits();
580   
581   return rv;
582 }
583
584 //_____________________________________________________________________________
585 Int_t 
586 AliMUONMCDataInterface::NumberOfTrackRefs(Int_t event)
587 {
588   /// Number of track references in the event
589   if ( not IsValid()) return -1;
590   
591   if (event != fCurrentEvent)
592   {
593     ResetStores();
594     if ( not LoadEvent(event) ) return -1;
595   }
596
597   fLoader->GetRunLoader()->LoadTrackRefs();
598   
599   Int_t rv(-1);
600   
601   TTree* treeTR = fLoader->GetRunLoader()->TreeTR();
602   if (treeTR != 0x0)
603   {
604     rv = static_cast<Int_t>(treeTR->GetEntries());
605   }
606   else
607   {
608     AliError("Could not get TreeTR");
609   }
610   
611   fLoader->GetRunLoader()->UnloadTrackRefs();
612   
613   return rv;
614 }
615
616 //_____________________________________________________________________________
617 void
618 AliMUONMCDataInterface::Open(const char* filename)
619 {
620   /// Connect to a given galice.root file
621   
622   ResetStores();
623   
624   fCurrentEvent=-1;
625
626   if ( fLoader != 0x0 )
627   {
628     delete fLoader->GetRunLoader();
629   }
630   
631   fLoader = 0x0;
632   
633   fIsValid = kTRUE;
634   
635   TString foldername(Form("%s-%d",ClassName(),fgInstanceCounter));
636   
637   while (AliRunLoader::GetRunLoader(foldername)) 
638   {
639     delete AliRunLoader::GetRunLoader(foldername);
640   }
641   
642   AliRunLoader* runLoader = AliRunLoader::Open(filename,foldername);
643   if (runLoader == 0x0)
644   {
645     AliError(Form("Cannot open file %s",filename));    
646     fIsValid = kFALSE;
647     return;
648   }
649   
650   // Get run number and set it to CDB manager
651   runLoader->LoadHeader();
652   if ( ! runLoader->GetHeader() ) {
653     AliError("Cannot load header.");    
654     fIsValid = kFALSE;
655   }
656   else {
657     Int_t runNumber = runLoader->GetHeader()->GetRun();
658     AliCDBManager::Instance()->SetRun(runNumber);
659   }  
660   runLoader->UnloadHeader(); 
661
662   fLoader = runLoader->GetDetectorLoader("MUON");
663   if (fLoader == 0x0)
664   {
665     AliError("Cannot get AliMUONLoader");
666     fIsValid = kFALSE;
667   }
668   
669   if (not IsValid())
670   {
671     AliError(Form("Could not access %s filename. Object is unuseable",filename));
672   }
673 }
674
675 //_____________________________________________________________________________
676 Bool_t AliMUONMCDataInterface::GetEvent(Int_t event)
677 {
678 /// Loads all simulated data for the given event.
679
680   if (HitStore(event, 0) == 0x0) return kFALSE;
681   if (SDigitStore(event) == 0x0) return kFALSE;
682   if (DigitStore(event) == 0x0) return kFALSE;
683   if (TriggerStore(event) == 0x0) return kFALSE;
684   if (TrackRefs(event, 0) == 0x0) return kFALSE;
685   return kTRUE;
686 }
687
688 //_____________________________________________________________________________
689 Int_t AliMUONMCDataInterface::NumberOfParticles()
690 {
691 /// Returns the total number of particles in the kinematics tree.
692
693   AliStack* stack = Stack(fCurrentEvent);
694   if ( stack == 0x0 ) return -1;
695   return (Int_t) stack->GetNtrack();
696 }
697
698 //_____________________________________________________________________________
699 TParticle* AliMUONMCDataInterface::Particle(Int_t index)
700 {
701 /// Returns the index'th particle in the kinematics tree.
702 /// @param index  The index number of the particle in the range [0 ... N-1]
703 ///               where N = NumberOfParticles()
704
705   AliStack* stack = Stack(fCurrentEvent);
706   if ( stack == 0x0 ) return 0x0;
707   return static_cast<TParticle*>( stack->Particle(index) );
708 }
709
710 //_____________________________________________________________________________
711 Int_t AliMUONMCDataInterface::NumberOfTracks()
712 {
713 /// Returns the number of primary tracks (from primary particles) in the current event.
714
715   return NumberOfTracks(fCurrentEvent);
716 }
717
718 //_____________________________________________________________________________
719 Int_t AliMUONMCDataInterface::NumberOfHits(Int_t track)
720 {
721 /// Returns the number of hits for a given primary track/particle.
722 /// @param track  The track number in the range [0 .. N-1]
723 ///               where N = NumberOfTracks()
724
725   TIterator* iter = GetIterator(kHitIterator, track);
726   return CountObjects(iter);
727 }
728
729 //_____________________________________________________________________________
730 AliMUONHit* 
731 AliMUONMCDataInterface::Hit(Int_t track, Int_t index)
732 {
733 /// Returns a pointer to the index'th hit object.
734 /// @param track  The track number in the range [0 .. N-1]
735 ///               where N = NumberOfTracks()
736 /// @param index  The index number of the hit in the range [0 ... M-1]
737 ///               where M = NumberOfHits(track)
738
739   TIterator* iter = GetIterator(kHitIterator, track);
740   return static_cast<AliMUONHit*>( FetchObject(iter, index) );
741 }
742
743 //_____________________________________________________________________________
744 Int_t AliMUONMCDataInterface::NumberOfSDigits(Int_t detElemId)
745 {
746 /// Returns the number of summable digits to be found on a given detector element.
747 /// @param detElemId  The detector element ID number to search on.
748
749   TIterator* iter = GetIterator(kSDigitIteratorByDetectorElement, detElemId);
750   return CountObjects(iter);
751 }
752
753 //_____________________________________________________________________________
754 AliMUONVDigit* AliMUONMCDataInterface::SDigit(Int_t detElemId, Int_t index)
755 {
756 /// Returns the a pointer to the index'th summable digit on the specified detector element.
757 /// @param detElemId  The detector element ID number to search on.
758 /// @param index  The index number of the digit to fetch in the range [0 .. N-1],
759 ///   where N = NumberOfDigits(detElemId)
760
761   TIterator* iter = GetIterator(kSDigitIteratorByDetectorElement, detElemId);
762   return static_cast<AliMUONVDigit*>( FetchObject(iter, index) );
763 }
764
765 //_____________________________________________________________________________
766 Int_t AliMUONMCDataInterface::NumberOfSDigits(Int_t chamber, Int_t cathode)
767 {
768 /// Returns the number of summable digits to be found on a specific chamber and cathode.
769 /// @param chamber  The chamber number in the range [0 .. 13].
770 /// @param cathode  The cathode in the range [0 .. 1], where 0 is the bending and
771 ///   1 is the non-bending plane.
772
773   TIterator* iter = GetIterator(kSDigitIteratorByChamberAndCathode, chamber, cathode);
774   return CountObjects(iter);
775 }
776
777 //_____________________________________________________________________________
778 AliMUONVDigit* AliMUONMCDataInterface::SDigit(Int_t chamber, Int_t cathode, Int_t index)
779 {
780 /// Returns the a pointer to the index'th summable digit on the specified chamber and cathode.
781 /// @param chamber  The chamber number in the range [0 .. 13].
782 /// @param cathode  The cathode in the range [0 .. 1], where 0 is the bending and
783 ///   1 is the non-bending plane.
784 /// @param index  The index number of the digit to fetch in the range [0 .. N-1],
785 ///   where N = NumberOfDigits(chamber, cathode)
786
787   TIterator* iter = GetIterator(kSDigitIteratorByChamberAndCathode, chamber, cathode);
788   return static_cast<AliMUONVDigit*>( FetchObject(iter, index) );
789 }
790
791 //_____________________________________________________________________________
792 Int_t AliMUONMCDataInterface::NumberOfDigits(Int_t detElemId)
793 {
794 /// Returns the number of simulated digits to be found on a given detector element.
795 /// @param detElemId  The detector element ID number to search on.
796
797   TIterator* iter = GetIterator(kDigitIteratorByDetectorElement, detElemId);
798   return CountObjects(iter);
799 }
800
801 //_____________________________________________________________________________
802 AliMUONVDigit* AliMUONMCDataInterface::Digit(Int_t detElemId, Int_t index)
803 {
804 /// Returns the a pointer to the index'th simulated digit on the specified detector element.
805 /// @param detElemId  The detector element ID number to search on.
806 /// @param index  The index number of the digit to fetch in the range [0 .. N-1],
807 ///   where N = NumberOfDigits(detElemId)
808
809   TIterator* iter = GetIterator(kDigitIteratorByDetectorElement, detElemId);
810   return static_cast<AliMUONVDigit*>( FetchObject(iter, index) );
811 }
812
813 //_____________________________________________________________________________
814 Int_t AliMUONMCDataInterface::NumberOfDigits(Int_t chamber, Int_t cathode)
815 {
816 /// Returns the number of simulated digits to be found on a specific chamber and cathode.
817 /// @param chamber  The chamber number in the range [0 .. 13].
818 /// @param cathode  The cathode in the range [0 .. 1], where 0 is the bending and
819 ///   1 is the non-bending plane.
820
821   TIterator* iter = GetIterator(kDigitIteratorByChamberAndCathode, chamber, cathode);
822   return CountObjects(iter);
823 }
824
825 //_____________________________________________________________________________
826 AliMUONVDigit* AliMUONMCDataInterface::Digit(Int_t chamber, Int_t cathode, Int_t index)
827 {
828 /// Returns the a pointer to the index'th simulated digit on the specified chamber and cathode.
829 /// @param chamber  The chamber number in the range [0 .. 13].
830 /// @param cathode  The cathode in the range [0 .. 1], where 0 is the bending and
831 ///   1 is the non-bending plane.
832 /// @param index  The index number of the digit to fetch in the range [0 .. N-1],
833 ///   where N = NumberOfDigits(chamber, cathode)
834
835   TIterator* iter = GetIterator(kDigitIteratorByChamberAndCathode, chamber, cathode);
836   return static_cast<AliMUONVDigit*>( FetchObject(iter, index) );
837 }
838
839 //_____________________________________________________________________________
840 Int_t AliMUONMCDataInterface::NumberOfLocalTriggers()
841 {
842 /// Returns the number of simulated local trigger objects.
843
844   TIterator* iter = GetIterator(kLocalTriggerIterator);
845   return CountObjects(iter);
846 }
847
848 //_____________________________________________________________________________
849 AliMUONLocalTrigger* AliMUONMCDataInterface::LocalTrigger(Int_t index)
850 {
851 /// Returns a pointer to the index'th simulated local trigger object.
852 /// @param index  The index number of the local trigger object to fetch in the range [0 .. N-1],
853 ///   where N = NumberOfLocalTriggers()
854
855   TIterator* iter = GetIterator(kLocalTriggerIterator);
856   return static_cast<AliMUONLocalTrigger*>( FetchObject(iter, index) );
857 }
858
859 //_____________________________________________________________________________
860 Int_t AliMUONMCDataInterface::NumberOfRegionalTriggers()
861 {
862 /// Returns the number of simulated regional trigger objects.
863
864   TIterator* iter = GetIterator(kRegionalTriggerIterator);
865   return CountObjects(iter);
866 }
867
868 //_____________________________________________________________________________
869 AliMUONRegionalTrigger* AliMUONMCDataInterface::RegionalTrigger(Int_t index)
870 {
871 /// Returns a pointer to the index'th simulated regional trigger object.
872 /// @param index  The index number of the regional trigger object to fetch in the range [0 .. N-1],
873 ///   where N = NumberOfRegionalTriggers()
874
875   TIterator* iter = GetIterator(kRegionalTriggerIterator);
876   return static_cast<AliMUONRegionalTrigger*>( FetchObject(iter, index) );
877 }
878
879 //_____________________________________________________________________________
880 AliMUONGlobalTrigger* AliMUONMCDataInterface::GlobalTrigger()
881 {
882 /// Returns a pointer to the simulated global trigger object for the event.
883
884   AliMUONVTriggerStore* store = TriggerStore(fCurrentEvent);
885   if (store == 0x0) return 0x0;
886   return store->Global();
887 }
888
889 //_____________________________________________________________________________
890 Int_t AliMUONMCDataInterface::NumberOfTrackRefs()
891 {
892 /// Number of track references in the currently selected event.
893
894   return NumberOfTrackRefs(fCurrentEvent);
895 }
896
897 //_____________________________________________________________________________
898 TClonesArray* AliMUONMCDataInterface::TrackRefs(Int_t track)
899 {
900 /// Returns the track references for a given track in the current event.
901 /// @param track  The track to returns track references for. In the range [0 .. N-1]
902 ///               where N = NumberOfTrackRefs()
903
904   return TrackRefs(fCurrentEvent, track);
905 }
906
907 //_____________________________________________________________________________
908 void AliMUONMCDataInterface::ResetStores()
909 {
910 /// Deletes all the store objects that have been created and resets the pointers to 0x0.
911 /// The temporary iterator object is automatically reset. See ResetIterator for more details.
912
913   ResetIterator();
914   if (fHitStore != 0x0)
915   {
916     delete fHitStore;
917     fHitStore = 0x0;
918   }
919   if (fSDigitStore != 0x0)
920   {
921     delete fSDigitStore;
922     fSDigitStore = 0x0;
923   }
924   if (fDigitStore != 0x0)
925   {
926     delete fDigitStore;
927     fDigitStore = 0x0;
928   }
929   if (fTrackRefs != 0x0)
930   {
931     delete fTrackRefs;
932     fTrackRefs = 0x0;
933   }
934   if (fTriggerStore != 0x0)
935   {
936     delete fTriggerStore;
937     fTriggerStore = 0x0;
938   }
939 }
940
941 //_____________________________________________________________________________
942 TIterator* AliMUONMCDataInterface::GetIterator(IteratorType type, Int_t x, Int_t y)
943 {
944 /// Creates an appropriate iterator object and returns it.
945 /// If the iterator has already been created then that one is returned otherwise
946 /// a new object is created.
947 /// Depending on the value of 'type' the semantics of parameters x and y can change.
948 /// @param type  The type of iterator to create.
949 /// @param x  This is the detector element ID if type equals kDigitIteratorByDetectorElement
950 ///           or kSDigitIteratorByDetectorElement.
951 ///           If type equals kDigitIteratorByChamberAndCathode or
952 ///           kSDigitIteratorByChamberAndCathode then this is the chamber number.
953 ///           For type == kHitIterator the parameter x is the track number.
954 ///           In all other cases this parameter is ignored.
955 /// @param y  If type equals kDigitIteratorByChamberAndCathode or
956 ///           kSDigitIteratorByChamberAndCathode then this parameter is the cathode
957 ///           number. In all other cases this parameter is ignored.
958
959   if (type == fCurrentIteratorType and fDataX == x and fDataY == y)
960         return fIterator;
961   
962   if (fCurrentEvent == -1)
963   {
964     AliError("No event was selected. Try first using GetEvent().");
965     return 0x0;
966   }
967   
968   ResetIterator();
969   
970   switch (type)
971   {
972   case kHitIterator:
973     {
974       Int_t track = x;
975       AliMUONVHitStore* store = HitStore(fCurrentEvent, track);
976       if (store == 0x0) return 0x0;
977       fIterator = store->CreateIterator();
978       if (fIterator == 0x0) return 0x0;
979       fCurrentIteratorType = kHitIterator;
980       return fIterator;
981     }
982     
983   case kSDigitIteratorByDetectorElement:
984     {
985       Int_t detElem = x;
986       AliMUONVDigitStore* store = SDigitStore(fCurrentEvent);
987       if (store == 0x0) return 0x0;
988       fIterator = store->CreateIterator(detElem, detElem, 2);
989       if (fIterator == 0x0) return 0x0;
990       fCurrentIteratorType = kSDigitIteratorByDetectorElement;
991       fDataX = detElem;
992       return fIterator;
993     }
994     
995   case kSDigitIteratorByChamberAndCathode:
996     {
997       Int_t chamber = x;
998       Int_t cathode = y;
999       if (chamber < 0 or AliMpConstants::NofChambers() <= chamber)
1000       {
1001         AliError(Form(
1002           "Must have give a chamber value in the range [0..%d], but got a value of: %d",
1003           AliMpConstants::NofChambers() - 1,
1004           chamber
1005         ));
1006         return 0x0;
1007       }
1008       if (cathode < 0 or 1 < cathode)
1009       {
1010         AliError(Form("Must have give a cathode value in the range [0..1], but got a value of: %d", cathode));
1011         return 0x0;
1012       }
1013       
1014       AliMUONVDigitStore* store = SDigitStore(fCurrentEvent);
1015       if (store == 0x0) return 0x0;
1016       MpPair_t pair = AliMpDEManager::GetDetElemIdRange(chamber);
1017       fIterator = store->CreateIterator(AliMp::PairFirst(pair), AliMp::PairSecond(pair), cathode);
1018       if (fIterator == 0x0) return 0x0;
1019       fCurrentIteratorType = kSDigitIteratorByChamberAndCathode;
1020       fDataX = chamber;
1021       fDataY = cathode;
1022       return fIterator;
1023     }
1024     
1025   case kDigitIteratorByDetectorElement:
1026     {
1027       Int_t detElem = x;
1028       AliMUONVDigitStore* store = DigitStore(fCurrentEvent);
1029       if (store == 0x0) return 0x0;
1030       fIterator = store->CreateIterator(detElem, detElem, 2);
1031       if (fIterator == 0x0) return 0x0;
1032       fCurrentIteratorType = kDigitIteratorByDetectorElement;
1033       fDataX = detElem;
1034       return fIterator;
1035     }
1036     
1037   case kDigitIteratorByChamberAndCathode:
1038     {
1039       Int_t chamber = x;
1040       Int_t cathode = y;
1041       if (chamber < 0 or AliMpConstants::NofChambers() <= chamber)
1042       {
1043         AliError(Form(
1044           "Must have give a chamber value in the range [0..%d], but got a value of: %d",
1045           AliMpConstants::NofChambers() - 1,
1046           chamber
1047         ));
1048         return 0x0;
1049       }
1050       if (cathode < 0 or 1 < cathode)
1051       {
1052         AliError(Form("Must have give a cathode value in the range [0..1], but got a value of: %d", cathode));
1053         return 0x0;
1054       }
1055       
1056       AliMUONVDigitStore* store = DigitStore(fCurrentEvent);
1057       if (store == 0x0) return 0x0;
1058       MpPair_t pair = AliMpDEManager::GetDetElemIdRange(chamber);
1059       fIterator = store->CreateIterator(AliMp::PairFirst(pair), AliMp::PairSecond(pair), cathode);
1060       if (fIterator == 0x0) return 0x0;
1061       fCurrentIteratorType = kDigitIteratorByChamberAndCathode;
1062       fDataX = chamber;
1063       fDataY = cathode;
1064       return fIterator;
1065     }
1066     
1067   case kLocalTriggerIterator:
1068     {
1069       AliMUONVTriggerStore* store = TriggerStore(fCurrentEvent);
1070       if (store == 0x0) return 0x0;
1071       fIterator = store->CreateLocalIterator();
1072       if (fIterator == 0x0) return 0x0;
1073       fCurrentIteratorType = kLocalTriggerIterator;
1074       return fIterator;
1075     }
1076     
1077   case kRegionalTriggerIterator:
1078     {
1079       AliMUONVTriggerStore* store = TriggerStore(fCurrentEvent);
1080       if (store == 0x0) return 0x0;
1081       fIterator = store->CreateRegionalIterator();
1082       if (fIterator == 0x0) return 0x0;
1083       fCurrentIteratorType = kRegionalTriggerIterator;
1084       return fIterator;
1085     }
1086     
1087   default:
1088     return 0x0;
1089   }
1090 }
1091
1092 //_____________________________________________________________________________
1093 void AliMUONMCDataInterface::ResetIterator()
1094 {
1095 /// The temporary iterator object is deleted if it exists and the pointer reset to 0x0.
1096 /// The iterator type and temporary data indicating the state of the iterator are
1097 /// also reset.
1098
1099   if (fIterator != 0x0) delete fIterator;
1100   fCurrentIteratorType = kNoIterator;
1101   fCurrentIndex = fDataX = fDataY = -1;
1102   fIterator = 0x0;
1103 }
1104
1105 //_____________________________________________________________________________
1106 Int_t AliMUONMCDataInterface::CountObjects(TIterator* iter)
1107 {
1108 /// Counts the number of objects in the iterator and resets it.
1109 /// @return The number of objects in 'iter'.
1110
1111   if (iter == 0x0) return -1;
1112   Int_t count = 0;
1113   iter->Reset();
1114   while ( iter->Next() != 0x0 ) count++;
1115   iter->Reset();
1116   fCurrentIndex = -1;
1117   return count;
1118 }
1119
1120 //_____________________________________________________________________________
1121 TObject* AliMUONMCDataInterface::FetchObject(TIterator* iter, Int_t index)
1122 {
1123 /// Fetches the index'th object from the iterator counting the first object
1124 /// returned by iterator after it is reset as index == 0. The next object
1125 /// has index == 1 and so on where the last object returned by the iterator
1126 /// has index == N-1 where N = CountObjects(iter)
1127 /// This method will only reset the iterator if index is smaller than
1128 /// fCurrentIndex, which is used to track the iteration progress and is
1129 /// updated when a new object if returned by this method.
1130 /// @param iter  The iterator to fetch an object from.
1131 /// @param index The index number of the object to fetch in the range [0 .. N-1]
1132 ///        where N = CountObjects(iter)
1133
1134   if (index < 0)
1135   {
1136     AliError(Form("Index is out of bounds. Got a value of %d.", index));
1137     return 0x0;
1138   }
1139
1140   if (iter == 0x0) return 0x0;
1141   if (index <= fCurrentIndex)
1142   {
1143     iter->Reset();
1144     fCurrentIndex = -1;
1145   }
1146   
1147   TObject* object = 0x0;
1148   while (fCurrentIndex < index)
1149   {
1150     object = iter->Next();
1151     if (object == 0x0)
1152     {
1153       AliError(Form("Index is out of bounds. Got a value of %d.", index));
1154       iter->Reset();
1155       fCurrentIndex = -1;
1156       return 0x0;
1157     }
1158     fCurrentIndex++;
1159   }
1160   return object;
1161 }