- Disentangle masks effect from trigger chamber efficiency estimation.
[u/mrichter/AliRoot.git] / MUON / MUONCheckDI.C
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 /// \ingroup macros
19 /// \file MUONCheckDI.C
20 /// \brief Macro for checking AliMUONDataInterface and AliMUONMCDataInterface.
21 ///
22 /// \author Bruce Becker, DAPNIA/SPhN/CEA Saclay
23 ///
24 /// Modified to updated versions of data interfaces
25 /// by Artur Szostak <artursz@iafrica.com> (University of Cape Town)
26
27 #if !defined(__CINT__) || defined(__MAKECINT__)
28 #include "AliMUONHit.h"
29 #include "AliMUONVDigit.h"
30 #include "AliMUONVCluster.h"
31 #include "AliMUONLocalTrigger.h"
32 #include "AliMUONRegionalTrigger.h"
33 #include "AliMUONGlobalTrigger.h"
34 #include "AliMUONMCDataInterface.h"
35 #include "AliMUONDataInterface.h"
36 #include "AliMUONVHitStore.h"
37 #include "AliMUONVDigitStore.h"
38 #include "AliMUONVClusterStore.h"
39 #include "AliMUONVTriggerStore.h"
40 #include "AliMpConstants.h"
41 #include "AliMpDEManager.h"
42
43 #include "AliCDBManager.h"
44
45 #include <Rtypes.h>
46 #include <Riostream.h>
47 #include <TObjArray.h>
48 #include <TIterator.h>
49 #include <TMatrixD.h>
50
51 #include <cstdlib>
52
53 #endif
54
55
56 /**
57  * This routine implements a the comparison functionality which is missing for
58  * classes like AliMUONTrack and the various AliMUONxxxTrigger classes.
59  * A result of -1 is returned if a < b, 0 if a == b and +1 if a > b.
60  */
61 Int_t Compare(const TObject* a, const TObject* b)
62 {
63         int result = -999;
64         if (a->IsA() == AliMUONLocalTrigger::Class() && b->IsA() == AliMUONLocalTrigger::Class())
65         {
66                 result = memcmp(a, b, sizeof(AliMUONLocalTrigger));
67         }
68         else if (a->IsA() == AliMUONRegionalTrigger::Class() && b->IsA() == AliMUONRegionalTrigger::Class())
69         {
70                 const AliMUONRegionalTrigger* ra = static_cast<const AliMUONRegionalTrigger*>(a);
71                 const AliMUONRegionalTrigger* rb = static_cast<const AliMUONRegionalTrigger*>(b);
72                 if (ra->GetId() < rb->GetId()) return -1;
73                 if (ra->GetId() > rb->GetId()) return 1;
74                 if (ra->GetLocalOutput(0) < rb->GetLocalOutput(0)) return -1;
75                 if (ra->GetLocalOutput(0) > rb->GetLocalOutput(0)) return 1;
76                 if (ra->GetLocalOutput(1) < rb->GetLocalOutput(1)) return -1;
77                 if (ra->GetLocalOutput(1) > rb->GetLocalOutput(1)) return 1;
78                 if (ra->GetLocalMask() < rb->GetLocalMask()) return -1;
79                 if (ra->GetLocalMask() > rb->GetLocalMask()) return 1;
80                 if (ra->GetOutput() < rb->GetOutput()) return -1;
81                 if (ra->GetOutput() > rb->GetOutput()) return 1;
82                 return 0;
83         }
84         else if (a->IsA() == AliMUONGlobalTrigger::Class() && b->IsA() == AliMUONGlobalTrigger::Class())
85         {
86                 result = memcmp(a, b, sizeof(AliMUONGlobalTrigger));
87         }
88         else
89         {
90                 result = memcmp(a, b, sizeof(TObject));
91         }
92         
93         if (result < 0) return -1;
94         if (result > 0) return 1;
95         return 0;
96 }
97
98 /**
99  * This method fills internal arrays with local and regional triggers returned
100  * by AliMUONMCDataInterface. For each set of interface methods available in
101  * AliMUONMCDataInterface a TObjArray is created for local and another for regional
102  * triggers. These arrays are filled with copies of the trigger objects.
103  * The global trigger object is also copied out using the 2 different methods.
104  * The arrays and objects are then compared to each other. The arrays and objects
105  * should contain the same information if everything is working correctly with
106  * AliMUONMCDataInterface. If not then the difference is printed together with an
107  * error message and false is returned.
108  */
109 bool SimTriggersOk()
110 {
111         AliMUONMCDataInterface data("generated/galice.root");
112         for (Int_t event = 0; event < data.NumberOfEvents(); event++)
113         {
114                 TObjArray localsFromStore, regionalsFromStore;
115                 localsFromStore.SetOwner(kTRUE);
116                 regionalsFromStore.SetOwner(kTRUE);
117                 AliMUONVTriggerStore* store = data.TriggerStore(event);
118                 if (store == NULL) return false;
119                 AliMUONGlobalTrigger* globalFromStore = static_cast<AliMUONGlobalTrigger*>(store->Global()->Clone());
120                 TIter nextLocal(store->CreateLocalIterator());
121                 AliMUONLocalTrigger* localTrig;
122                 while ( (localTrig = static_cast<AliMUONLocalTrigger*>( nextLocal() )) != NULL )
123                 {
124                         localsFromStore.Add(localTrig->Clone());
125                 }
126                 TIter nextRegional(store->CreateRegionalIterator());
127                 AliMUONRegionalTrigger* regionalTrig;
128                 while ( (regionalTrig = static_cast<AliMUONRegionalTrigger*>( nextRegional() )) != NULL )
129                 {
130                         regionalsFromStore.Add(regionalTrig->Clone());
131                 }
132                 
133                 TObjArray localsByIndex, regionalsByIndex;
134                 localsByIndex.SetOwner(kTRUE);
135                 regionalsByIndex.SetOwner(kTRUE);
136                 data.GetEvent(event);
137                 AliMUONGlobalTrigger* globalByMethod = static_cast<AliMUONGlobalTrigger*>(data.GlobalTrigger()->Clone());
138                 Int_t nlocals = data.NumberOfLocalTriggers();
139                 for (Int_t i = 0; i < nlocals; i++)
140                 {
141                         localTrig = data.LocalTrigger(i);
142                         localsByIndex.Add(localTrig->Clone());
143                 }
144                 Int_t nregionals = data.NumberOfRegionalTriggers();
145                 for (Int_t i = 0; i < nregionals; i++)
146                 {
147                         regionalTrig = data.RegionalTrigger(i);
148                         regionalsByIndex.Add(regionalTrig->Clone());
149                 }
150                 
151                 // Now check that all the lists of local, regional and global triggers
152                 // contain the same results.
153                 // They must. If they do not then something is wrong with the implementation
154                 // of AliMUONMCDataInterface.
155                 if (Compare(globalFromStore, globalByMethod) != 0)
156                 {
157                         Error(  "SimTriggersOk",
158                                 "The AliMUONMCDataInterface does not return identical global"
159                                   " triggers through all its user interface methods."
160                         );
161                         globalFromStore->Print();
162                         globalByMethod->Print();
163                         return false;
164                 }
165                 delete globalFromStore;
166                 delete globalByMethod;
167                 if (localsFromStore.GetEntriesFast() != localsByIndex.GetEntriesFast())
168                 {
169                         Error(  "SimTriggersOk",
170                                 "The AliMUONMCDataInterface does not return all the local triggers"
171                                   " correctly through all its user interface methods. We got the"
172                                   " following numbers of local triggers: %d and %d",
173                                 localsFromStore.GetEntriesFast(),
174                                 localsByIndex.GetEntriesFast()
175                         );
176                         return false;
177                 }
178                 if (regionalsFromStore.GetEntriesFast() != regionalsByIndex.GetEntriesFast())
179                 {
180                         Error(  "SimTriggersOk",
181                                 "The AliMUONMCDataInterface does not return all the regional triggers"
182                                   " correctly through all its user interface methods. We got the"
183                                   " following numbers of regional triggers: %d and %d",
184                                 regionalsFromStore.GetEntriesFast(),
185                                 regionalsByIndex.GetEntriesFast()
186                         );
187                         return false;
188                 }
189                 for (Int_t i = 0; i < localsFromStore.GetEntriesFast(); i++)
190                 {
191                         if (Compare(localsFromStore[i], localsByIndex[i]) != 0)
192                         {
193                                 Error(  "SimTriggersOk",
194                                         "The AliMUONMCDataInterface does not return identical local"
195                                           " triggers through all its user interface methods. The"
196                                           " incorrect local trigger has index %d.",
197                                         i
198                                 );
199                                 localsFromStore[i]->Print();
200                                 localsByIndex[i]->Print();
201                                 return false;
202                         }
203                 }
204                 for (Int_t i = 0; i < regionalsFromStore.GetEntriesFast(); i++)
205                 {
206                         if (Compare(regionalsFromStore[i], regionalsByIndex[i]) != 0)
207                         {
208                                 Error(  "SimTriggersOk",
209                                         "The AliMUONMCDataInterface does not return identical regional"
210                                           " triggers through all its user interface methods. The"
211                                           " incorrect regional trigger has index %d.",
212                                         i
213                                 );
214                                 regionalsFromStore[i]->Print();
215                                 regionalsByIndex[i]->Print();
216                                 return false;
217                         }
218                                 regionalsFromStore[i]->Print();
219                                 regionalsByIndex[i]->Print();
220                 }
221         }
222         return true;
223 }
224
225 /**
226  * This method fills internal arrays with s-digits returned by the AliMUONMCDataInterface.
227  * For each set of interface methods available a TObjArray is filled with copies of 
228  * the s-digits. These arrays are sorted and then compared to each other. The arrays
229  * should contain the same s-digit information if everything is working correctly with
230  * AliMUONMCDataInterface. If not then the difference is printed together with an
231  * error message and false is returned.
232  */
233 bool SimSDigitsOk()
234 {
235         AliMUONMCDataInterface data("generated/galice.root");
236         for (Int_t event = 0; event < data.NumberOfEvents(); event++)
237         {
238                 TObjArray digitsFromStore;
239                 digitsFromStore.SetOwner(kTRUE);
240                 AliMUONVDigitStore* store = data.SDigitStore(event);
241                 if (store == NULL) return false;
242                 TIter next(store->CreateIterator());
243                 AliMUONVDigit* digit;
244                 while ( (digit = static_cast<AliMUONVDigit*>( next() )) != NULL )
245                 {
246                         digitsFromStore.Add(digit->Clone());
247                 }
248                 digitsFromStore.Sort();
249                 
250                 TObjArray digitsByDetElem;
251                 digitsByDetElem.SetOwner(kTRUE);
252                 data.GetEvent(event);
253                 for (Int_t detElem = 0; detElem < 1500; detElem++)
254                 {
255                         if (! AliMpDEManager::IsValidDetElemId(detElem)) continue;
256                         Int_t ndigits = data.NumberOfSDigits(detElem);
257                         for (Int_t i = 0; i < ndigits; i++)
258                         {
259                                 AliMUONVDigit* digit = data.SDigit(detElem, i);
260                                 digitsByDetElem.Add(digit->Clone());
261                         }
262                 }
263                 digitsByDetElem.Sort();
264                 
265                 TObjArray digitsByChamber;
266                 digitsByChamber.SetOwner(kTRUE);
267                 data.GetEvent(event);
268                 for (Int_t chamber = 0; chamber < AliMpConstants::NofChambers(); chamber++)
269                 for (Int_t cathode = 0; cathode < 2; cathode++)
270                 {
271                         Int_t ndigits = data.NumberOfSDigits(chamber, cathode);
272                         for (Int_t i = 0; i < ndigits; i++)
273                         {
274                                 AliMUONVDigit* digit = data.SDigit(chamber, cathode, i);
275                                 digitsByChamber.Add(digit->Clone());
276                         }
277                 }
278                 digitsByChamber.Sort();
279                 
280                 // Now check that all the lists of s-digits contain the same results.
281                 // They must. If they do not then something is wrong with the implementation
282                 // of AliMUONMCDataInterface.
283                 if (digitsFromStore.GetEntriesFast() != digitsByDetElem.GetEntriesFast()
284                     || digitsFromStore.GetEntriesFast() != digitsByChamber.GetEntriesFast())
285                 {
286                         Error(  "SimSDigitsOk",
287                                 "The AliMUONMCDataInterface does not return all the s-digits correctly"
288                                   " through all its user interface methods. We got the following"
289                                   " numbers of s-digits: %d, %d and %d",
290                                 digitsFromStore.GetEntriesFast(),
291                                 digitsByDetElem.GetEntriesFast(),
292                                 digitsByChamber.GetEntriesFast()
293                         );
294                         return false;
295                 }
296                 for (Int_t i = 0; i < digitsFromStore.GetEntriesFast(); i++)
297                 {
298                         if (digitsFromStore[i]->Compare(digitsByDetElem[i]) != 0
299                             || digitsFromStore[i]->Compare(digitsByChamber[i]) != 0)
300                         {
301                                 Error(  "SimSDigitsOk",
302                                         "The AliMUONMCDataInterface does not return identical s-digits"
303                                           " through all its user interface methods. The incorrect"
304                                           " s-digit has index %d after sorting.",
305                                         i
306                                 );
307                                 digitsFromStore[i]->Print();
308                                 digitsByChamber[i]->Print();
309                                 digitsByDetElem[i]->Print();
310                                 return false;
311                         }
312                 }
313         }
314         return true;
315 }
316
317 /**
318  * This method fills internal arrays with digits returned by the AliMUONMCDataInterface.
319  * For each set of interface methods available a TObjArray is filled with copies of 
320  * the digits. These arrays are sorted and then compared to each other. The arrays
321  * should contain the same digit information if everything is working correctly with
322  * AliMUONMCDataInterface. If not then the difference is printed together with an
323  * error message and false is returned.
324  */
325 bool SimDigitsOk()
326 {
327         AliMUONMCDataInterface data("generated/galice.root");
328         for (Int_t event = 0; event < data.NumberOfEvents(); event++)
329         {
330                 TObjArray digitsFromStore;
331                 digitsFromStore.SetOwner(kTRUE);
332                 AliMUONVDigitStore* store = data.DigitStore(event);
333                 if (store == NULL) return false;
334                 TIter next(store->CreateIterator());
335                 AliMUONVDigit* digit;
336                 while ( (digit = static_cast<AliMUONVDigit*>( next() )) != NULL )
337                 {
338                         digitsFromStore.Add(digit->Clone());
339                 }
340                 digitsFromStore.Sort();
341                 
342                 TObjArray digitsByDetElem;
343                 digitsByDetElem.SetOwner(kTRUE);
344                 data.GetEvent(event);
345                 for (Int_t detElem = 0; detElem < 1500; detElem++)
346                 {
347                         if (! AliMpDEManager::IsValidDetElemId(detElem)) continue;
348                         Int_t ndigits = data.NumberOfDigits(detElem);
349                         for (Int_t i = 0; i < ndigits; i++)
350                         {
351                                 AliMUONVDigit* digit = data.Digit(detElem, i);
352                                 digitsByDetElem.Add(digit->Clone());
353                         }
354                 }
355                 digitsByDetElem.Sort();
356                 
357                 TObjArray digitsByChamber;
358                 digitsByChamber.SetOwner(kTRUE);
359                 data.GetEvent(event);
360                 for (Int_t chamber = 0; chamber < AliMpConstants::NofChambers(); chamber++)
361                 for (Int_t cathode = 0; cathode < 2; cathode++)
362                 {
363                         Int_t ndigits = data.NumberOfDigits(chamber, cathode);
364                         for (Int_t i = 0; i < ndigits; i++)
365                         {
366                                 AliMUONVDigit* digit = data.Digit(chamber, cathode, i);
367                                 digitsByChamber.Add(digit->Clone());
368                         }
369                 }
370                 digitsByChamber.Sort();
371                 
372                 // Now check that all the lists of digits contain the same results.
373                 // They must. If they do not then something is wrong with the implementation
374                 // of AliMUONMCDataInterface.
375                 if (digitsFromStore.GetEntriesFast() != digitsByDetElem.GetEntriesFast()
376                     || digitsFromStore.GetEntriesFast() != digitsByChamber.GetEntriesFast())
377                 {
378                         Error(  "SimDigitsOk",
379                                 "The AliMUONMCDataInterface does not return all the digits correctly"
380                                   " through all its user interface methods. We got the following"
381                                   " numbers of digits: %d, %d and %d",
382                                 digitsFromStore.GetEntriesFast(),
383                                 digitsByDetElem.GetEntriesFast(),
384                                 digitsByChamber.GetEntriesFast()
385                         );
386                         return false;
387                 }
388                 for (Int_t i = 0; i < digitsFromStore.GetEntriesFast(); i++)
389                 {
390                         if (digitsFromStore[i]->Compare(digitsByDetElem[i]) != 0
391                             || digitsFromStore[i]->Compare(digitsByChamber[i]) != 0)
392                         {
393                                 Error(  "SimDigitsOk",
394                                         "The AliMUONMCDataInterface does not return identical digits"
395                                           " through all its user interface methods. The incorrect"
396                                           " digit has index %d after sorting.",
397                                         i
398                                 );
399                                 digitsFromStore[i]->Print();
400                                 digitsByChamber[i]->Print();
401                                 digitsByDetElem[i]->Print();
402                                 return false;
403                         }
404                 }
405         }
406         return true;
407 }
408
409 /**
410  * This method fills internal arrays with hits returned by the AliMUONMCDataInterface.
411  * For each set of interface methods available a TObjArray is filled with copies of 
412  * the hits. These arrays are then compared to each other. The arrays should contain
413  * the same hit information if everything is working correctly with AliMUONMCDataInterface.
414  * If not then the difference is printed together with an error message and false is returned.
415  */
416 bool SimHitsOk()
417 {
418         AliMUONMCDataInterface data("generated/galice.root");
419         for (Int_t event = 0; event < data.NumberOfEvents(); event++)
420         {
421                 if (data.NumberOfTracks(event) != data.NumberOfTracks())
422                 {
423                         Error(  "SimHitsOk",
424                                 "The AliMUONMCDataInterface does not return the same number of tracks"
425                                   " through all its user interface methods. We got the following"
426                                   " numbers of tracks: %d and %d",
427                                 data.NumberOfTracks(event),
428                                 data.NumberOfTracks()
429                         );
430                         return false;
431                 }
432                 
433                 for (Int_t track = 0; track < data.NumberOfTracks(); track++)
434                 {
435                         TObjArray hitsFromStore;
436                         hitsFromStore.SetOwner(kTRUE);
437                         AliMUONVHitStore* store = data.HitStore(event, track);
438                         if (store == NULL) return false;
439                         TIter next(store->CreateIterator());
440                         AliMUONHit* hit;
441                         while ( (hit = static_cast<AliMUONHit*>( next() )) != NULL )
442                         {
443                                 hitsFromStore.Add(hit->Clone());
444                         }
445                         //hitsFromStore.Sort();  // Unfortunately hits do not implement the Compare method.
446                         
447                         TObjArray hitsByMethod;
448                         hitsByMethod.SetOwner(kTRUE);
449                         data.GetEvent(event);
450                         for (Int_t i = 0; i < data.NumberOfHits(track); i++)
451                         {
452                                 AliMUONHit* hit = data.Hit(track, i);
453                                 hitsByMethod.Add(hit->Clone());
454                         }
455                         //hitsByMethod.Sort();  // Unfortunately hits do not implement the Compare method.
456                         
457                         // Now check that both lists of hits contain the same results.
458                         // They must. If they do not then something is wrong with the implementation
459                         // of AliMUONMCDataInterface.
460                         if (hitsFromStore.GetEntriesFast() != hitsByMethod.GetEntriesFast())
461                         {
462                                 Error(  "SimHitsOk",
463                                         "The AliMUONMCDataInterface does not return all the hits correctly"
464                                         " through all its user interface methods. We got the following"
465                                         " numbers of hits: %d and %d",
466                                         hitsFromStore.GetEntriesFast(),
467                                         hitsByMethod.GetEntriesFast()
468                                 );
469                                 return false;
470                         }
471                         for (Int_t i = 0; i < hitsFromStore.GetEntriesFast(); i++)
472                         {
473                                 if (Compare(hitsFromStore[i], hitsByMethod[i]) != 0)
474                                 {
475                                         Error(  "SimHitsOk",
476                                                 "The AliMUONMCDataInterface does not return identical hits"
477                                                 " through all its user interface methods. The incorrect"
478                                                 " hit has index %d after sorting, for track %d.",
479                                                 i, track
480                                         );
481                                         hitsFromStore[i]->Print();
482                                         hitsByMethod[i]->Print();
483                                         return false;
484                                 }
485                         }
486                 }
487         }
488         return true;
489 }
490
491 /**
492  * This method fills internal arrays with digits returned by the AliMUONDataInterface.
493  * For each set of interface methods available a TObjArray is filled with copies of 
494  * the digits. These arrays are sorted and then compared to each other. The arrays
495  * should contain the same digit information if everything is working correctly with
496  * AliMUONDataInterface. If not then the difference is printed together with an
497  * error message and false is returned.
498  */
499 bool RecDigitsOk()
500 {
501         AliMUONDataInterface data;
502         for (Int_t event = 0; event < data.NumberOfEvents(); event++)
503         {
504                 TObjArray digitsFromStore;
505                 digitsFromStore.SetOwner(kTRUE);
506                 AliMUONVDigitStore* store = data.DigitStore(event);
507                 if (store == NULL) return false;
508                 TIter next(store->CreateIterator());
509                 AliMUONVDigit* digit;
510                 while ( (digit = static_cast<AliMUONVDigit*>( next() )) != NULL )
511                 {
512                         digitsFromStore.Add(digit->Clone());
513                 }
514                 digitsFromStore.Sort();
515                 
516                 TObjArray digitsByDetElem;
517                 digitsByDetElem.SetOwner(kTRUE);
518                 data.GetEvent(event);
519                 for (Int_t detElem = 0; detElem < 1500; detElem++)
520                 {
521                         if (! AliMpDEManager::IsValidDetElemId(detElem)) continue;
522                         Int_t ndigits = data.NumberOfDigits(detElem);
523                         for (Int_t i = 0; i < ndigits; i++)
524                         {
525                                 AliMUONVDigit* digit = data.Digit(detElem, i);
526                                 digitsByDetElem.Add(digit->Clone());
527                         }
528                 }
529                 digitsByDetElem.Sort();
530                 
531                 TObjArray digitsByChamber;
532                 digitsByChamber.SetOwner(kTRUE);
533                 data.GetEvent(event);
534                 for (Int_t chamber = 0; chamber < AliMpConstants::NofChambers(); chamber++)
535                 for (Int_t cathode = 0; cathode < 2; cathode++)
536                 {
537                         Int_t ndigits = data.NumberOfDigits(chamber, cathode);
538                         for (Int_t i = 0; i < ndigits; i++)
539                         {
540                                 AliMUONVDigit* digit = data.Digit(chamber, cathode, i);
541                                 digitsByChamber.Add(digit->Clone());
542                         }
543                 }
544                 digitsByChamber.Sort();
545                 
546                 // Now check that all the lists of digits contain the same results.
547                 // They must. If they do not then something is wrong with the implementation
548                 // of AliMUONDataInterface.
549                 if (digitsFromStore.GetEntriesFast() != digitsByDetElem.GetEntriesFast()
550                     || digitsFromStore.GetEntriesFast() != digitsByChamber.GetEntriesFast())
551                 {
552                         Error(  "RecDigitsOk",
553                                 "The AliMUONDataInterface does not return all the digits correctly"
554                                   " through all its user interface methods. We got the following"
555                                   " numbers of digits: %d, %d and %d",
556                                 digitsFromStore.GetEntriesFast(),
557                                 digitsByDetElem.GetEntriesFast(),
558                                 digitsByChamber.GetEntriesFast()
559                         );
560                         return false;
561                 }
562                 for (Int_t i = 0; i < digitsFromStore.GetEntriesFast(); i++)
563                 {
564                         if (digitsFromStore[i]->Compare(digitsByDetElem[i]) != 0
565                             || digitsFromStore[i]->Compare(digitsByChamber[i]) != 0)
566                         {
567                                 Error(  "RecDigitsOk",
568                                         "The AliMUONDataInterface does not return identical digits"
569                                           " through all its user interface methods. The incorrect"
570                                           " digit has index %d after sorting.",
571                                         i
572                                 );
573                                 digitsFromStore[i]->Print();
574                                 digitsByChamber[i]->Print();
575                                 digitsByDetElem[i]->Print();
576                                 return false;
577                         }
578                 }
579         }
580         return true;
581 }
582
583 /**
584  * This method fills internal arrays with raw clusters returned by AliMUONDataInterface.
585  * For each set of interface methods available in AliMUONDataInterface a TObjArray is
586  * filled with copies of the raw clusters. These arrays are sorted and then compared
587  * to each other. The arrays should contain the same information if everything is
588  * working correctly with AliMUONDataInterface. If not then the difference is printed
589  * together with an error message and false is returned.
590  */
591 bool RawClustersOk()
592 {
593         AliMUONDataInterface data;
594         for (Int_t event = 0; event < data.NumberOfEvents(); event++)
595         {
596                 TObjArray clustersFromStore;
597                 clustersFromStore.SetOwner(kTRUE);
598                 AliMUONVClusterStore* store = data.ClusterStore(event);
599                 if (store == NULL) return false;
600                 TIter next(store->CreateIterator());
601                 AliMUONVCluster* cluster;
602                 while ( (cluster = static_cast<AliMUONVCluster*>( next() )) != NULL )
603                 {
604                         clustersFromStore.Add(cluster->Clone());
605                 }
606                 clustersFromStore.Sort();
607                 
608                 TObjArray clustersByChamber;
609                 clustersByChamber.SetOwner(kTRUE);
610                 data.GetEvent(event);
611                 for (Int_t chamber = 0; chamber < AliMpConstants::NofTrackingChambers(); chamber++)
612                 {
613                         Int_t nclusters = data.NumberOfRawClusters(chamber);
614                         for (Int_t i = 0; i < nclusters; i++)
615                         {
616                                 AliMUONVCluster* cluster = data.RawCluster(chamber, i);
617                                 clustersByChamber.Add(cluster->Clone());
618                         }
619                 }
620                 clustersByChamber.Sort();
621                 
622                 // Now check that all the lists of clusters contain the same results.
623                 // They must. If they do not then something is wrong with the implementation
624                 // of AliMUONDataInterface.
625                 if (clustersFromStore.GetEntriesFast() != clustersByChamber.GetEntriesFast())
626                 {
627                         Error(  "RawClustersOk",
628                                 "The AliMUONDataInterface does not return all the clusters correctly"
629                                   " through all its user interface methods. We got the following"
630                                   " numbers of clusters: %d and %d",
631                                 clustersFromStore.GetEntriesFast(),
632                                 clustersByChamber.GetEntriesFast()
633                         );
634                         return false;
635                 }
636                 for (Int_t i = 0; i < clustersFromStore.GetEntriesFast(); i++)
637                 {
638                         if (clustersFromStore[i]->Compare(clustersByChamber[i]) != 0)
639                         {
640                                 Error(  "RawClustersOk",
641                                         "The AliMUONDataInterface does not return identical clusters"
642                                           " through all its user interface methods. The incorrect"
643                                           " cluster has index %d after sorting.",
644                                         i
645                                 );
646                                 clustersFromStore[i]->Print();
647                                 clustersByChamber[i]->Print();
648                                 return false;
649                         }
650                 }
651         }
652         return true;
653 }
654
655 /**
656  * This method fills internal arrays with local and regional triggers returned
657  * by AliMUONDataInterface. For each set of interface methods available in
658  * AliMUONDataInterface a TObjArray is created for local and another for regional
659  * triggers. These arrays are filled with copies of the trigger objects.
660  * The global trigger object is also copied out using the 2 different methods.
661  * The arrays and objects are then compared to each other. The arrays and objects
662  * should contain the same information if everything is working correctly with
663  * AliMUONDataInterface. If not then the difference is printed together with an
664  * error message and false is returned.
665  */
666 bool TriggersOk()
667 {
668         AliMUONDataInterface data;
669         for (Int_t event = 0; event < data.NumberOfEvents(); event++)
670         {
671                 TObjArray localsFromStore, regionalsFromStore;
672                 localsFromStore.SetOwner(kTRUE);
673                 regionalsFromStore.SetOwner(kTRUE);
674                 AliMUONVTriggerStore* store = data.TriggerStore(event);
675                 if (store == NULL) return false;
676                 AliMUONGlobalTrigger* globalFromStore = static_cast<AliMUONGlobalTrigger*>(store->Global()->Clone());
677                 TIter nextLocal(store->CreateLocalIterator());
678                 AliMUONLocalTrigger* localTrig;
679                 while ( (localTrig = static_cast<AliMUONLocalTrigger*>( nextLocal() )) != NULL )
680                 {
681                         localsFromStore.Add(localTrig->Clone());
682                 }
683                 TIter nextRegional(store->CreateRegionalIterator());
684                 AliMUONRegionalTrigger* regionalTrig;
685                 while ( (regionalTrig = static_cast<AliMUONRegionalTrigger*>( nextRegional() )) != NULL )
686                 {
687                         regionalsFromStore.Add(regionalTrig->Clone());
688                 }
689                 
690                 TObjArray localsByIndex, regionalsByIndex;
691                 localsByIndex.SetOwner(kTRUE);
692                 regionalsByIndex.SetOwner(kTRUE);
693                 data.GetEvent(event);
694                 AliMUONGlobalTrigger* globalByMethod = static_cast<AliMUONGlobalTrigger*>(data.GlobalTrigger()->Clone());
695                 Int_t nlocals = data.NumberOfLocalTriggers();
696                 for (Int_t i = 0; i < nlocals; i++)
697                 {
698                         localTrig = data.LocalTrigger(i);
699                         localsByIndex.Add(localTrig->Clone());
700                 }
701                 Int_t nregionals = data.NumberOfRegionalTriggers();
702                 for (Int_t i = 0; i < nregionals; i++)
703                 {
704                         regionalTrig = data.RegionalTrigger(i);
705                         regionalsByIndex.Add(regionalTrig->Clone());
706                 }
707                 
708                 // Now check that all the lists of local, regional and global triggers
709                 // contain the same results.
710                 // They must. If they do not then something is wrong with the implementation
711                 // of AliMUONDataInterface.
712                 if (Compare(globalFromStore, globalByMethod) != 0)
713                 {
714                         Error(  "TriggersOk",
715                                 "The AliMUONDataInterface does not return identical global"
716                                   " triggers through all its user interface methods."
717                         );
718                         globalFromStore->Print();
719                         globalByMethod->Print();
720                         return false;
721                 }
722                 delete globalFromStore;
723                 delete globalByMethod;
724                 if (localsFromStore.GetEntriesFast() != localsByIndex.GetEntriesFast())
725                 {
726                         Error(  "TriggersOk",
727                                 "The AliMUONDataInterface does not return all the local triggers"
728                                   " correctly through all its user interface methods. We got the"
729                                   " following numbers of local triggers: %d and %d",
730                                 localsFromStore.GetEntriesFast(),
731                                 localsByIndex.GetEntriesFast()
732                         );
733                         return false;
734                 }
735                 if (regionalsFromStore.GetEntriesFast() != regionalsByIndex.GetEntriesFast())
736                 {
737                         Error(  "TriggersOk",
738                                 "The AliMUONDataInterface does not return all the regional triggers"
739                                   " correctly through all its user interface methods. We got the"
740                                   " following numbers of regional triggers: %d and %d",
741                                 regionalsFromStore.GetEntriesFast(),
742                                 regionalsByIndex.GetEntriesFast()
743                         );
744                         return false;
745                 }
746                 for (Int_t i = 0; i < localsFromStore.GetEntriesFast(); i++)
747                 {
748                         if (Compare(localsFromStore[i], localsByIndex[i]) != 0)
749                         {
750                                 Error(  "TriggersOk",
751                                         "The AliMUONDataInterface does not return identical local"
752                                           " triggers through all its user interface methods. The"
753                                           " incorrect local trigger has index %d.",
754                                         i
755                                 );
756                                 localsFromStore[i]->Print();
757                                 localsByIndex[i]->Print();
758                                 return false;
759                         }
760                 }
761                 for (Int_t i = 0; i < regionalsFromStore.GetEntriesFast(); i++)
762                 {
763                         if (Compare(regionalsFromStore[i], regionalsByIndex[i]) != 0)
764                         {
765                                 Error(  "TriggersOk",
766                                         "The AliMUONDataInterface does not return identical regional"
767                                           " triggers through all its user interface methods. The"
768                                           " incorrect regional trigger has index %d.",
769                                         i
770                                 );
771                                 regionalsFromStore[i]->Print();
772                                 regionalsByIndex[i]->Print();
773                                 return false;
774                         }
775                 }
776         }
777         return true;
778 }
779
780 /**
781  * This method performs a check of the AliMUONDataInterface and AliMUONMCDataInterface
782  * classes. Basically there are at least 2 ways to fetch data using these interfaces:
783  * The expert way using the store objects returned by these interface classes or
784  * the much slower but easier way of using the NumberOfxxx and Digit(...),
785  * RawCluster(...), Track(...) etc. methods to fetch individual data objects.
786  * The MUONCheckDI will check that all these various ways of fetching data results
787  * in the same information being returned. If yes then kTRUE is returned and a
788  * confirmation message is printed, if not then kFALSE is returned with the failure
789  * reason printed to screen.
790  */
791 bool MUONCheckDI(bool checkSim = true, bool checkRec = true)
792 {
793         AliCDBManager::Instance()->SetDefaultStorage("local://$ALICE_ROOT/OCDB");
794
795         // Note: we do not bother checking the AliMUONMCDataInterface::Particle,
796         // AliMUONMCDataInterface::Stack and AliMUONMCDataInterface::TrackRefs methods
797         // because they are trivial enough to validate from a quick inspecition of
798         // the source code.
799         
800         if (checkSim)
801         {
802                 cout << "Checking simulated hits..." << endl;
803                 if (! SimHitsOk()) return false;
804                 cout << "Simulated hits look OK." << endl;
805                 
806                 cout << "Checking simulated s-digits..." << endl;
807                 if (! SimSDigitsOk()) return false;
808                 cout << "Simulated s-digits look OK." << endl;
809                 
810                 cout << "Checking simulated digits..." << endl;
811                 if (! SimDigitsOk()) return false;
812                 cout << "Simulated digits look OK." << endl;
813                 
814                 cout << "Checking simulated triggers..." << endl;
815                 if (! SimTriggersOk()) return false;
816                 cout << "Simulated triggers look OK." << endl;
817         }
818         
819         if (checkRec)
820         {
821                 cout << "Checking reconstructed digits..." << endl;
822                 if (! RecDigitsOk()) return false;
823                 cout << "Reconstructed digits look OK." << endl;
824                 
825                 cout << "Checking raw clusters..." << endl;
826                 if (! RawClustersOk()) return false;
827                 cout << "Raw clusters look OK." << endl;
828         
829                 cout << "Checking reconstructed triggers..." << endl;
830                 if (! TriggersOk()) return false;
831                 cout << "Reconstructed triggers look OK." << endl;
832         }
833
834         return true;
835 }