]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONTriggerChamberEff.cxx
Intrinsic chamber efficiency calculation performed during reconstruction (Diego)
[u/mrichter/AliRoot.git] / MUON / AliMUONTriggerChamberEff.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 /// \class AliMUONTriggerChamberEff
19 /// implementation of the trigger chamber efficiency determination from
20 /// data, and returns the
21 /// efficiencyCells.dat with the calculated efficiencies
22 ///
23 /// \author Diego Stocco (Torino)
24
25 #include "AliMUONTriggerChamberEff.h"
26 #include "AliMUONVDigit.h"
27 #include "AliMUONConstants.h"
28 #include "AliMUONTriggerTrack.h"
29 #include "AliMUONDigitMaker.h"
30 #include "AliMUONLocalTrigger.h"
31 #include "AliMUONGeometryTransformer.h"
32
33 #include "AliMUONTrack.h"
34 #include "AliMUONTrackParam.h"
35 #include "AliMUONTrackExtrap.h"
36
37 #include "AliMUONDigitStoreV1.h"
38 #include "AliMUONVDigitStore.h"
39 #include "AliMUONVTriggerStore.h"
40 #include "AliMUONVTriggerTrackStore.h"
41 #include "AliMUONVTrackStore.h"
42
43 #include "AliMpVSegmentation.h"
44 #include "AliMpSegmentation.h"
45 #include "AliMpPad.h"
46 #include "AliMpDEIterator.h"
47 #include "AliMpPlaneType.h"
48 #include "AliMpDEManager.h"
49
50 #include "AliLog.h"
51
52 #include <Riostream.h>
53 #include <TFile.h>
54 #include <TH1F.h>
55 #include <TMath.h>
56
57 #include <TSeqCollection.h>
58 #include <TTree.h>
59 #include <TROOT.h>
60
61
62 /// \cond CLASSIMP
63 ClassImp(AliMUONTriggerChamberEff)
64 /// \endcond
65
66
67 //_____________________________________________________________________________
68 AliMUONTriggerChamberEff::AliMUONTriggerChamberEff()
69 : TObject(),
70   fTransformer(0x0),
71   fDigitMaker(0x0),
72   fReproduceTrigResponse(kFALSE),
73   fPrintInfo(kFALSE),
74   fWriteOnESD(kFALSE),
75   fDebugLevel(0),
76   fkMaxDistance(99999.)
77 {
78 /// Standard constructor
79     ResetArrays();
80 }
81
82
83 //_____________________________________________________________________________
84 AliMUONTriggerChamberEff::AliMUONTriggerChamberEff(const AliMUONGeometryTransformer* transformer,
85                                                    const AliMUONDigitMaker* digitMaker,
86                                                    Bool_t writeOnESD)
87 : TObject(),
88   fTransformer(transformer),
89   fDigitMaker(digitMaker),
90   fReproduceTrigResponse(kFALSE),
91   fPrintInfo(kFALSE),
92   fWriteOnESD(writeOnESD),
93   fDebugLevel(0),
94   fkMaxDistance(99999.)
95 {
96 /// Standard constructor
97     ResetArrays();
98 }
99
100
101 //_____________________________________________________________________________
102 AliMUONTriggerChamberEff::~AliMUONTriggerChamberEff()
103 {
104 /// Destructor
105     Bool_t writeOnESD=fWriteOnESD;
106     fWriteOnESD=kFALSE;
107     if(writeOnESD) SaveInESDFile();
108 }
109
110
111 //_____________________________________________________________________________
112 AliMUONTriggerChamberEff::AliMUONTriggerChamberEff(const AliMUONTriggerChamberEff& other)
113     :TObject(other),
114      fTransformer(0x0),
115      fDigitMaker(0x0),
116      fReproduceTrigResponse(other.fReproduceTrigResponse),
117      fPrintInfo(other.fPrintInfo),
118      fWriteOnESD(other.fWriteOnESD),
119      fDebugLevel(other.fDebugLevel),
120      fkMaxDistance(other.fkMaxDistance)
121 {
122     for(Int_t ch=0; ch<fgkNchambers; ch++){
123         for(Int_t cath=0; cath<fgkNcathodes; cath++){
124             fTrigger34[ch][cath] = other.fTrigger34[ch][cath];
125             fTrigger44[cath] = other.fTrigger44[cath];
126             for(Int_t slat=0; slat<fgkNslats; slat++){
127                 fInefficientSlat[ch][cath][slat] = other.fInefficientSlat[ch][cath][slat];
128                 fHitPerSlat[ch][cath][slat] = other.fHitPerSlat[ch][cath][slat];
129             }
130             for(Int_t board=0; board<fgkNboards; board++){
131                 fInefficientBoard[ch][cath][board] = other.fInefficientBoard[ch][cath][board];
132                 fHitPerBoard[ch][cath][board] = other.fHitPerBoard[ch][cath][board];
133             }
134         }
135     }
136 }
137
138
139 //_____________________________________________________________________________
140 AliMUONTriggerChamberEff& AliMUONTriggerChamberEff::operator=(const AliMUONTriggerChamberEff& other)
141 {
142     /// Asignment operator
143     // check assignement to self
144     if (this == &other)
145         return *this;
146
147     // base class assignement
148     TObject::operator=(other);
149
150     fTransformer = 0x0;
151     fDigitMaker = 0x0;
152     fReproduceTrigResponse = other.fReproduceTrigResponse;
153     fPrintInfo = other.fPrintInfo;
154     fWriteOnESD = other.fWriteOnESD;
155     fDebugLevel = other.fDebugLevel;
156     //fkMaxDistance = other.fkMaxDistance;
157     return *this;
158 }
159
160
161 //_____________________________________________________________________________
162 void AliMUONTriggerChamberEff::ResetArrays()
163 {
164     //
165     /// Sets the data member counters to 0.
166     //
167
168     for(Int_t ch=0; ch<fgkNchambers; ch++){
169         for(Int_t cath=0; cath<fgkNcathodes; cath++){
170             fTrigger34[ch][cath] = 0;
171             fTrigger44[cath] = 0;
172             for(Int_t slat=0; slat<fgkNslats; slat++){
173                 fInefficientSlat[ch][cath][slat] = 0;
174                 fHitPerSlat[ch][cath][slat] = 0;
175             }
176             for(Int_t board=0; board<fgkNboards; board++){
177                 fInefficientBoard[ch][cath][board] = 0;
178                 fHitPerBoard[ch][cath][board] = 0;
179             }
180         }
181     }
182 }
183
184
185 //______________________________________________________________________________
186 Bool_t 
187 AliMUONTriggerChamberEff::TriggerDigits(const AliMUONVTriggerStore& triggerStore,
188                                         AliMUONVDigitStore& digitStore) const
189 {
190     //
191     /// make (S)Digit for trigger
192     //
193     digitStore.Clear();
194
195     AliMUONLocalTrigger* locTrg;
196     TIter next(triggerStore.CreateLocalIterator());
197   
198     while ( ( locTrg = static_cast<AliMUONLocalTrigger*>(next()) ) ) 
199     {
200         if (locTrg->IsNull()) continue;
201    
202         TArrayS xyPattern[2];
203         locTrg->GetXPattern(xyPattern[0]);
204         locTrg->GetYPattern(xyPattern[1]);
205     
206         Int_t nBoard = locTrg->LoCircuit();
207         fDigitMaker->TriggerDigits(nBoard, xyPattern, digitStore);
208     }
209     return kTRUE;
210 }
211
212
213 //_____________________________________________________________________________
214 void AliMUONTriggerChamberEff::InfoDigit(AliMUONVDigitStore& digitStore)
215 {
216     //
217     /// Prints information on digits (for debugging)
218     //
219     TIter next(digitStore.CreateIterator());
220     AliMUONVDigit* mDigit=0x0;
221     
222     while ( ( mDigit = static_cast<AliMUONVDigit*>(next()) ) )
223     {
224         mDigit->Print();
225     } // end digit loop
226     printf("\n");
227 }
228
229
230 //_____________________________________________________________________________
231 Int_t AliMUONTriggerChamberEff::MatchingPad(AliMUONVDigitStore& digitStore, Int_t &detElemId,
232                                             Float_t coor[2], Bool_t isMatch[fgkNcathodes],
233                                             Int_t nboard[fgkNcathodes][4],
234                                             Float_t zRealMatch[fgkNchambers], Float_t y11)
235 {
236     //
237     /// Check slat and board number of digit matching track
238     //
239
240     enum {kBending, kNonBending};
241
242     Float_t minMatchDist[fgkNcathodes];
243     Int_t padsInCheckArea[fgkNcathodes];
244
245     for(Int_t cath=0; cath<fgkNcathodes; cath++){
246         isMatch[cath] = kFALSE;
247         minMatchDist[cath] = fkMaxDistance/10.;
248         padsInCheckArea[cath] = 0;
249     }
250     Int_t iChamber = AliMpDEManager::GetChamberId(detElemId);
251     Int_t ch = iChamber-10;
252     Float_t oldDeltaZ = AliMUONConstants::DefaultChamberZ(iChamber) - AliMUONConstants::DefaultChamberZ(10);
253     Float_t y = coor[1];
254     Int_t iSlat = detElemId%100;
255     Int_t trigDigitBendPlane = -1;
256     Int_t foundDetElemId = detElemId;
257     Float_t foundZmatch=999.;
258     Float_t yCoorAtPadZ=999.;
259
260     TIter next(digitStore.CreateIterator());
261     AliMUONVDigit* mDigit;
262     Int_t idigit=0;
263     
264     while ( ( mDigit = static_cast<AliMUONVDigit*>(next()) ) )
265     {
266         idigit++;
267         Int_t currDetElemId = mDigit->DetElemId();
268         Int_t currCh = AliMpDEManager::GetChamberId(currDetElemId);
269         if(currCh!=iChamber) continue;
270         Int_t currSlat = currDetElemId%100;
271         Int_t slatDiff = TMath::Abs(currSlat-iSlat);
272         if(slatDiff>1 && slatDiff<17) continue; // Check neighbour slats
273         Int_t cathode = mDigit->Cathode();
274         Int_t ix = mDigit->PadX();
275         Int_t iy = mDigit->PadY();
276         Float_t xpad, ypad, zpad;
277         const AliMpVSegmentation* seg = AliMpSegmentation::Instance()
278             ->GetMpSegmentation(currDetElemId,AliMp::GetCathodType(cathode));
279
280         AliMpPad pad = seg->PadByIndices(AliMpIntPair(ix,iy),kTRUE);
281         Float_t xlocal1 = pad.Position().X();
282         Float_t ylocal1 = pad.Position().Y();
283         Float_t dpx = pad.Dimensions().X();
284         Float_t dpy = pad.Dimensions().Y();
285         fTransformer->Local2Global(currDetElemId, xlocal1, ylocal1, 0, xpad, ypad, zpad);
286         if(fDebugLevel>2)printf("DetElemId = %i\tCathode = %i\t(x,y) Pad = (%i,%i) = (%.2f,%.2f)\tDim = (%.2f,%.2f)\tTrack = (%.2f,%.2f)\n",currDetElemId,cathode,ix,iy,xpad,ypad,dpx,dpy,coor[0],coor[1]);
287         // searching track intersection with chambers (second approximation)
288         if(ch%2==1){
289             //if(iChamber%2==1){
290             Float_t deltaZ = zpad - zRealMatch[0];
291             y = (coor[1]-y11)*deltaZ/oldDeltaZ + y11;
292             if(fDebugLevel>=3 && TMath::Abs(y-coor[1])>0.1)printf("oldDeltaZ = %7.2f   newDeltaZ = %7.2f\toldY = %7.2f   new y = %7.2f\n",oldDeltaZ,deltaZ,coor[1],y);
293         }
294         Float_t matchDist = PadMatchTrack(xpad, ypad, dpx, dpy, coor[0], y, ch);
295         if(matchDist<fkMaxDistance/2.) padsInCheckArea[cathode]++;
296         if(matchDist>minMatchDist[cathode])continue;
297         isMatch[cathode] = kTRUE;
298         minMatchDist[cathode] = matchDist;
299         foundDetElemId = currDetElemId;
300         foundZmatch=zpad;
301         yCoorAtPadZ=y;
302         if(cathode==kBending) trigDigitBendPlane = idigit;
303         for (Int_t loc=0; loc<pad.GetNofLocations(); loc++){
304             AliMpIntPair location = pad.GetLocation(loc);
305             nboard[cathode][loc] = location.GetFirst();
306         }
307         for(Int_t loc=pad.GetNofLocations(); loc<4; loc++){
308             nboard[cathode][loc]=-1;
309         }
310     }
311
312     for(Int_t cath=0; cath<fgkNcathodes; cath++){
313         if(padsInCheckArea[cath]>2) {
314             if(fDebugLevel>=1) printf("padsInCheckArea[%i] = %i\n",cath,padsInCheckArea[cath]);
315             return -500;
316         }
317     }
318
319     if(isMatch[kBending] || isMatch[kNonBending]){
320         detElemId = foundDetElemId;
321         zRealMatch[ch] = foundZmatch;
322         coor[1] = yCoorAtPadZ;
323         if(fDebugLevel>2){
324             Int_t whichCathode=kBending;
325             if(!isMatch[kBending])whichCathode=kNonBending;
326         }
327     }
328     return trigDigitBendPlane;
329 }
330
331 //_____________________________________________________________________________
332 Float_t AliMUONTriggerChamberEff::PadMatchTrack(Float_t xPad, Float_t yPad,
333                                                 Float_t dpx, Float_t dpy, 
334                                                 Float_t xTrackAtPad, Float_t yTrackAtPad,
335                                                 Int_t chamber)
336 {
337     //
338     /// Decides if the digit belongs to the trigger track.
339     //
340
341     Float_t maxDist = 2.;//3. // cm
342     Float_t maxDistCheckArea = 6.; // cm
343
344     Float_t matchDist = fkMaxDistance;
345
346     Float_t deltaX = TMath::Abs(xPad-xTrackAtPad)-dpx;
347     Float_t deltaY = TMath::Abs(yPad-yTrackAtPad)-dpy;
348     Float_t maxDistX = maxDist;
349     Float_t maxDistY = maxDist;
350     
351     if(fReproduceTrigResponse){
352         maxDistX = dpx;
353         maxDistY = dpy;
354         deltaX = TMath::Abs(xPad-xTrackAtPad);
355         deltaY = TMath::Abs(yPad-yTrackAtPad);
356         if(dpx<dpy && chamber>=2) maxDistX = 3.*dpx;// Non-bending plane: check the +- 1 strip between stations
357         if(dpy<dpx && chamber%2) maxDistY = 3.*dpy;// bending plane: check the +- 1 strip between planes in the same station
358     }
359
360     if(deltaX<=maxDistX && deltaY<=maxDistY) matchDist = TMath::Max(deltaX, deltaY);
361     else if(deltaX<=maxDistCheckArea && deltaY<=maxDistCheckArea) matchDist = fkMaxDistance/5.;
362     return matchDist;
363 }
364
365
366 //_____________________________________________________________________________
367 void AliMUONTriggerChamberEff::CalculateEfficiency(Int_t trigger44, Int_t trigger34,
368                                                    Float_t &efficiency, Float_t &error,
369                                                    Bool_t failuresAsInput)
370 {
371     //
372     /// Returns the efficiency.
373     //
374
375     efficiency=-9.;
376     error=0.;
377     if(trigger34>0){
378         efficiency=(Double_t)trigger44/((Double_t)trigger34);
379         if(failuresAsInput)efficiency=1.-(Double_t)trigger44/((Double_t)trigger34);
380     }
381     Double_t q = TMath::Abs(1-efficiency);
382     if(efficiency<0)error=0.0;
383     else error = TMath::Sqrt(efficiency*q/((Double_t)trigger34));
384 }
385
386
387 //_____________________________________________________________________________
388 Int_t AliMUONTriggerChamberEff::DetElemIdFromPos(Float_t x, Float_t y, 
389                                                  Int_t chamber, Int_t cathode)
390 {
391     //
392     /// Given the (x,y) position in the chamber,
393     /// it returns the corresponding slat
394     //
395
396     Int_t resultingDetElemId = -1;
397     AliMpDEIterator it;
398     Float_t minDist = 999.;
399     for ( it.First(chamber-1); ! it.IsDone(); it.Next() ){
400         Int_t detElemId = it.CurrentDEId();
401         Int_t ich = detElemId/100-10;
402         Float_t tolerance=0.2*((Float_t)ich);
403         Float_t currDist=9999.;
404
405         const AliMpVSegmentation* seg = 
406             AliMpSegmentation::Instance()
407             ->GetMpSegmentation(detElemId,AliMp::GetCathodType(cathode));
408         if (!seg) continue;
409
410         Float_t deltax = seg->Dimensions().X();
411         Float_t deltay = seg->Dimensions().Y();
412         Float_t xlocal1 =  -deltax;
413         Float_t ylocal1 =  -deltay;
414         Float_t xlocal2 =  +deltax;
415         Float_t ylocal2 =  +deltay;
416         Float_t xg01, yg01, zg1, xg02, yg02, zg2;
417         fTransformer->Local2Global(detElemId, xlocal1, ylocal1, 0, xg01, yg01, zg1);
418         fTransformer->Local2Global(detElemId, xlocal2, ylocal2, 0, xg02, yg02, zg2);
419
420         Float_t xg1 = xg01, xg2 = xg02, yg1 = yg01, yg2 = yg02;
421
422         if(xg01>xg02){
423             xg1 = xg02;
424             xg2 = xg01;
425         }
426         if(yg01>yg02){
427             yg1 = yg02;
428             yg2 = yg01;
429         }
430
431         if(x>=xg1-tolerance && x<=xg2+tolerance && y>=yg1-tolerance && y<=yg2+tolerance){ // takes into account errors in extrapolation
432             if(y<yg1) currDist = yg1-y;
433             else if(y>yg2) currDist = y-yg2;
434             if(currDist<minDist) {
435                 resultingDetElemId = detElemId;
436                 minDist=currDist;
437                 continue;
438             }
439             resultingDetElemId = detElemId;
440             break;
441         }
442     } // loop on detElemId
443     return resultingDetElemId;
444 }
445
446
447 //_____________________________________________________________________________
448 void AliMUONTriggerChamberEff::LocalBoardFromPos(Float_t x, Float_t y,
449                                                  Int_t detElemId, Int_t cathode,
450                                                  Int_t localBoard[4])
451 {
452     //
453     /// Given the (x,y) position in the chamber,
454     /// it returns the corresponding local board
455     //
456
457     for(Int_t loc=0; loc<4; loc++){
458         localBoard[loc]=-1;
459     }
460     Float_t xl, yl, zl;
461     fTransformer->Global2Local(detElemId, x, y, 0, xl, yl, zl);
462     TVector2 pos(xl,yl);
463     const AliMpVSegmentation* seg = 
464         AliMpSegmentation::Instance()
465           ->GetMpSegmentation(detElemId,AliMp::GetCathodType(cathode));
466     if (seg){
467         AliMpPad pad = seg->PadByPosition(pos,kFALSE);
468         for (Int_t loc=0; loc<pad.GetNofLocations(); loc++){
469             AliMpIntPair location = pad.GetLocation(loc);
470             localBoard[loc] = location.GetFirst();
471         }
472     }
473 }
474
475
476 //_____________________________________________________________________________
477 void AliMUONTriggerChamberEff::EventChamberEff(const AliMUONVTriggerStore& triggerStore,
478                                                const AliMUONVTriggerTrackStore& trigTrackStore,
479                                                const AliMUONVTrackStore& trackStore)
480 {
481     //
482     /// Main method.
483     /// It loops over the the trigger rec. tracks in the event.
484     /// Then it search for matching digits around the track.
485     /// Finally it calculates the efficiency for each trigger board.
486     /// Files with calculated efficiency are placed in the user defined outputDir.
487     //
488
489     if(!fTransformer || ! fDigitMaker) {
490         AliError(Form("AliMUONGeometryTransformer or AliMUONDigitMaker not properly initialized!!"));
491         return;
492     }
493
494     enum {kBending, kNonBending};
495     Float_t rad2deg = 180./TMath::Pi();
496
497     Int_t chOrder[fgkNchambers] = {0,2,1,3};
498     Float_t zRealMatch[fgkNchambers] = {0.0};
499     Float_t correctFactor[fgkNcathodes] = {1.};
500
501     Bool_t match[fgkNchambers][fgkNcathodes] = {{kFALSE}};
502     Bool_t matchPad[fgkNcathodes]={kFALSE};
503
504
505     Float_t zMeanChamber[fgkNchambers];
506     for(Int_t ch=0; ch<fgkNchambers; ch++){
507         zMeanChamber[ch] = AliMUONConstants::DefaultChamberZ(10+ch);
508     }
509
510     Int_t digitPerTrack[fgkNcathodes] = {0};
511
512     Float_t trackIntersectCh[fgkNchambers][2]={{0.0}};
513
514     Int_t triggeredDigits[2][fgkNchambers] = {{-1}};
515
516     Int_t trigScheme[fgkNchambers][fgkNcathodes]={{0}};
517     Int_t slatThatTriggered[fgkNchambers][fgkNcathodes]={{-1}};
518     Int_t boardThatTriggered[fgkNchambers][fgkNcathodes][4]={{{-1}}};
519     Int_t nboard[fgkNcathodes][4]={{-1}};
520     Int_t ineffBoard[4]={-1};
521
522     AliMUONDigitStoreV1 digitStore;   
523     TriggerDigits(triggerStore,digitStore);
524
525     for(Int_t ch=0; ch<fgkNchambers; ch++){
526         for(Int_t itrack=0; itrack<2; itrack++){
527             triggeredDigits[itrack][ch]=-1;
528         }
529     }
530
531     AliMUONTriggerTrack *recTrigTrack = 0x0;
532
533     TIter next(trigTrackStore.CreateIterator());
534     
535     while ( ( recTrigTrack = static_cast<AliMUONTriggerTrack*>(next()) ) )
536     {
537         for(Int_t cath=0; cath<fgkNcathodes; cath++){
538             digitPerTrack[cath]=0;
539         }
540         for(Int_t ch=0; ch<fgkNchambers; ch++){
541             for(Int_t cath=0; cath<fgkNcathodes; cath++){
542                 match[ch][cath]=kFALSE;
543                 slatThatTriggered[ch][cath]=-1;
544                 for(Int_t loc=0; loc<4; loc++){
545                     boardThatTriggered[ch][cath][loc]=-1;
546                 }
547             }
548         }
549
550         Bool_t isClearEvent = kTRUE;
551         Bool_t doubleCountTrack = kFALSE;
552
553         if(!IsCleanTrack(recTrigTrack, trackStore)) {
554             if(fDebugLevel>=1) printf("\tTrack %p (%f, %f) don't match tracker track: rejected!\n",recTrigTrack,recTrigTrack->GetX11(),recTrigTrack->GetY11());
555             continue;
556         }
557
558         Float_t x11 = recTrigTrack->GetX11();// x position (info from non-bending plane)
559         Float_t y11 = recTrigTrack->GetY11();// y position (info from bending plane)
560         Float_t thetaX = recTrigTrack->GetThetax();
561         Float_t thetaY = recTrigTrack->GetThetay();
562
563         if(fDebugLevel>=3) printf("\tTrack = %p\npos from track: (x,y) = (%f, %f), (thetaX, thetaY) = (%f, %f)\n",recTrigTrack,x11,y11,thetaX*rad2deg,thetaY*rad2deg);
564
565         for(Int_t ch=0; ch<fgkNchambers; ch++) {
566             zRealMatch[ch] = zMeanChamber[ch];
567             for(Int_t cath=0; cath<fgkNcathodes; cath++){
568                 trigScheme[ch][cath] = 0;
569             }
570         }
571
572         for(Int_t ch=0; ch<fgkNchambers; ch++) { // chamber loop
573             Int_t currCh = chOrder[ch];
574             if(fDebugLevel>=2)
575                 printf("zMeanChamber[%i] = %.2f\tzRealMatch[0] = %.2f\n",currCh,zMeanChamber[currCh],zRealMatch[0]);
576
577             for(Int_t cath=0; cath<fgkNcathodes; cath++){
578                 correctFactor[cath]=1.;
579             }
580             // calculate corrections to trigger track theta
581             if(ch>=1)correctFactor[kNonBending] = zMeanChamber[0]/zRealMatch[0];// corrects x position
582             if(ch>=2)correctFactor[kBending] = (zMeanChamber[2] - zMeanChamber[0]) / (zRealMatch[2] - zRealMatch[0]);// corrects y position
583
584             // searching track intersection with chambers (first approximation)
585             Float_t deltaZ = zMeanChamber[currCh] - zMeanChamber[0];
586             trackIntersectCh[currCh][0] = zMeanChamber[currCh] * TMath::Tan(thetaX) * correctFactor[kNonBending];// x position (info from non-bending plane) 
587             trackIntersectCh[currCh][1] = y11 + deltaZ * TMath::Tan(thetaY) * correctFactor[kBending];// y position (info from bending plane)
588             Int_t detElemIdFromTrack = DetElemIdFromPos(trackIntersectCh[currCh][0], trackIntersectCh[currCh][1], 11+currCh, 0);
589             if(detElemIdFromTrack<0) {
590                 if(fDebugLevel>1) printf("Warning: trigger track outside trigger chamber\n");
591                 continue;
592             }
593                 
594             triggeredDigits[1][currCh] = MatchingPad(digitStore, detElemIdFromTrack, trackIntersectCh[currCh], matchPad, nboard, zRealMatch, y11);
595
596             // if MatchingPad = -500 => too many digits matching pad =>
597             //                       => Event not clear => Reject track
598             if(triggeredDigits[1][currCh]<-100){
599                 isClearEvent = kFALSE;
600                 if(fDebugLevel>=1) printf("Warning: track = %p (%i) matches many pads. Rejected!\n",recTrigTrack, detElemIdFromTrack);
601                 break;
602             }
603
604             // deciding if digit matches track
605             Bool_t isDiffLocBoard = kFALSE;
606             if(fReproduceTrigResponse && ch>2){
607                 for(Int_t cath=0; cath<fgkNcathodes; cath++){
608                     if(boardThatTriggered[currCh][cath][0]>=0){
609                         if(boardThatTriggered[currCh][cath][0]!=boardThatTriggered[currCh-1][cath][0]) isDiffLocBoard = kTRUE;
610                     }
611                 }
612             }
613
614             if(isDiffLocBoard && fDebugLevel>=1)printf("\tDifferent local board\n");
615
616             for(Int_t cath=0; cath<fgkNcathodes; cath++){
617                 match[currCh][cath] = (matchPad[cath] && !isDiffLocBoard);
618                 if(!match[currCh][cath]) continue;
619                 digitPerTrack[cath]++;
620                 trigScheme[currCh][cath]++;
621                 slatThatTriggered[currCh][cath] = detElemIdFromTrack;
622                 for(Int_t loc=0; loc<4; loc++){
623                     boardThatTriggered[currCh][cath][loc] = nboard[cath][loc];
624                 }
625             }
626         } // end chamber loop
627
628         for(Int_t cath=0; cath<fgkNcathodes; cath++){
629             if(digitPerTrack[cath]<3)isClearEvent = kFALSE;
630             if(fDebugLevel>=1 && !isClearEvent)printf("Warning: found %i digits for trigger track cathode %i.\nRejecting event\n", digitPerTrack[cath],cath);
631         }
632
633         if(!isClearEvent && !fReproduceTrigResponse) continue;
634
635         Int_t commonDigits = 0;
636         for(Int_t ch=0; ch<fgkNchambers; ch++){
637             if(triggeredDigits[1][ch]==triggeredDigits[0][ch]) commonDigits++; // Compare with previous track
638             triggeredDigits[0][ch] = triggeredDigits[1][ch]; // Store this track parameters for comparison with next one
639         }
640         if(commonDigits>=2){
641             doubleCountTrack=kTRUE;
642         }
643
644         if(!doubleCountTrack || fReproduceTrigResponse){
645             for(Int_t cath=0; cath<fgkNcathodes; cath++){
646                 Int_t is44 = 1;
647                 Bool_t goodForSlatEff = kTRUE;
648                 Bool_t goodForBoardEff = kTRUE;
649                 Int_t ineffSlat = -1;
650                 Int_t ineffDetElId = -1;
651                 Int_t firstSlat = slatThatTriggered[0][cath]%100;
652                 if(firstSlat<0) firstSlat=slatThatTriggered[1][cath]%100;
653                 Int_t firstBoard = boardThatTriggered[0][kBending][0];
654                 if(firstBoard<0) firstBoard=boardThatTriggered[1][kBending][0];
655                 for(Int_t ch=0; ch<fgkNchambers; ch++){
656                     Bool_t isCurrChIneff = kFALSE;
657                     is44 *= trigScheme[ch][cath];
658                     Int_t currSlat = slatThatTriggered[ch][cath]%100;
659                     if(currSlat<0){
660                         ineffDetElId = DetElemIdFromPos(trackIntersectCh[ch][0], trackIntersectCh[ch][1], 11+ch, cath);
661                         currSlat = ineffDetElId%100;
662                         ineffSlat = currSlat;
663                         isCurrChIneff = kTRUE;
664                     }
665                     if(currSlat!=firstSlat)goodForSlatEff=kFALSE;
666                     Bool_t atLeastOneLoc=kFALSE;
667                     if(isCurrChIneff) LocalBoardFromPos(trackIntersectCh[ch][0], trackIntersectCh[ch][1], ineffDetElId, cath, ineffBoard);
668                     for(Int_t loc=0; loc<4; loc++){
669                         Int_t currBoard = boardThatTriggered[ch][cath][loc];
670                         if(isCurrChIneff) currBoard = ineffBoard[loc];
671                         if(currBoard==firstBoard){
672                             atLeastOneLoc=kTRUE;
673                             break;
674                         }
675                     }
676                     if(!atLeastOneLoc)goodForBoardEff=kFALSE;
677                 } // end chamber loop
678
679                 // Trigger 4/4
680                 if(is44==1){
681                     fTrigger44[cath]++;
682                     if(fDebugLevel>=1)printf("Trigger44[%i] = %i\n",cath,fTrigger44[cath]);
683                     if(goodForSlatEff){
684                         for(Int_t ch=0; ch<fgkNchambers; ch++){
685                             fHitPerSlat[ch][cath][firstSlat]++;
686                             if(fDebugLevel>=1)printf("Slat that triggered = %i\n",slatThatTriggered[ch][cath]);
687                             if(goodForBoardEff && firstBoard>0){
688                                 fHitPerBoard[ch][cath][firstBoard-1]++;
689                                 if(fDebugLevel>=1)printf("Board that triggered = %i\n",firstBoard);
690                             }
691                             else if(fDebugLevel>=1) printf("Track = %p: Particle crossed different boards: rejected!\n",recTrigTrack);
692                         }
693                     }
694                     else if(fDebugLevel>=1) printf("Track = %p: Particle crossed different slats: rejected!\n",recTrigTrack);
695                     //cout<<"fTrigger44["<<cath<<"] = "<<fTrigger44[cath]<<"\tfHitPerSlat["<<0<<"]["<<cath<<"]["<<firstSlat<<"] = "<<fHitPerSlat[0][cath][firstSlat]<<"\tfHitPerBoard["<<0<<"]["<<cath<<"]["<<firstBoard-1<<"] = "<<fHitPerBoard[0][cath][firstBoard-1]<<endl; //REMEMBER TO CUT
696                 }
697
698                 // Trigger 3/4
699                 if(ineffDetElId>0){
700                     Int_t ineffCh = ineffDetElId/100-11;
701                     fTrigger34[ineffCh][cath]++;
702                     if(fDebugLevel>=1) printf("Trigger34[%i][%i] = %i\n",ineffCh,cath,fTrigger34[ineffCh][cath]);
703                     if(goodForSlatEff){
704                         if(fDebugLevel>=1) printf("Slat non efficient = %i\n",ineffDetElId);
705                         fInefficientSlat[ineffCh][cath][ineffSlat]++;
706
707                         if(goodForBoardEff && firstBoard>0){
708                             if(fDebugLevel>=1) printf("Board non efficient = %i\n",firstBoard);
709                             fInefficientBoard[ineffCh][cath][firstBoard-1]++;
710                         }
711                         else if(fDebugLevel>=1) printf("Track = %p: Particle crossed different boards: rejected!\n",recTrigTrack);
712                     }
713                     else if(fDebugLevel>=1) printf("Track = %p: Particle crossed different slats: rejected!\n",recTrigTrack);
714                     //cout<<"fTrigger34["<<ineffCh<<"]["<<cath<<"] = "<<fTrigger34[ineffCh][cath]<<"\tfInefficientSlat["<<ineffCh<<"]["<<cath<<"]["<<ineffSlat<<"] = "<<fInefficientSlat[ineffCh][cath][ineffSlat]<<"\tfInefficientBoard["<<ineffCh<<"]["<<cath<<"]["<<firstBoard-1<<"] = "<<fInefficientBoard[ineffCh][cath][firstBoard-1]<<endl; //REMEMBER TO CUT
715                 }
716             } // end loop on cathodes
717         }
718         else if(doubleCountTrack){
719             if(fDebugLevel>=1)
720                 printf("\n\tTrack = %p: \nDouble Count Track: Track rejected!\n",recTrigTrack);
721         }
722     } // end trigger tracks loop
723
724     if(fPrintInfo) InfoDigit(digitStore);
725 }
726
727 //_____________________________________________________________________________
728 void AliMUONTriggerChamberEff::WriteEfficiencyMap(const char* outputDir)
729 {
730     //
731     /// Writes information on calculated efficiency.
732     /// It writes: triggerChamberEff.root file containing efficiency histograms.
733     //
734
735     char *cathCode[fgkNcathodes] = {"bendPlane", "nonBendPlane"};
736
737     char outFileName[100];
738
739     sprintf(outFileName, "%s/MUON.TriggerEfficiencyMap.root",outputDir);
740     TFile *outputHistoFile = new TFile(outFileName,"RECREATE");
741     TDirectory *dir = gDirectory;
742
743     enum {kSlatIn11, kSlatIn12, kSlatIn13, kSlatIn14, kChamberEff};
744     char *yAxisTitle = "trigger efficiency (a.u.)";
745     char *xAxisTitle = "chamber";
746
747     TH1F *histo[fgkNcathodes][fgkNchambers+1];
748     TH1F *histoBoard[fgkNcathodes][fgkNchambers];
749
750     // ADDED for check
751     enum {allChEff, chNonEff, numOfHistoTypes};
752     char *histoTypeName[numOfHistoTypes] = {"CountInCh", "NonCountInCh"};
753     char *histoTypeTitle[numOfHistoTypes] = {"counted", "non counted"};
754     TH1F *histoCheckSlat[fgkNcathodes][fgkNchambers][numOfHistoTypes];
755     TH1F *histoCheckBoard[fgkNcathodes][fgkNchambers][numOfHistoTypes];
756     // end ADDED for check
757
758     char histoName[40];
759     char histoTitle[90];
760
761     for(Int_t cath=0; cath<fgkNcathodes; cath++){
762         for(Int_t ch=0; ch<fgkNchambers+1; ch++){
763             if(ch==kChamberEff){
764                 sprintf(histoName, "%sChamberEff", cathCode[cath]);
765                 sprintf(histoTitle, "Chamber efficiency %s", cathCode[cath]);
766                 histo[cath][ch] = new TH1F(histoName, histoTitle, fgkNchambers, 11-0.5, 15-0.5);
767                 histo[cath][ch]->SetXTitle(xAxisTitle);
768                 histo[cath][ch]->SetYTitle(yAxisTitle);
769                 histo[cath][ch]->GetXaxis()->SetNdivisions(fgkNchambers);
770             }
771             else {
772                 sprintf(histoName, "%sSlatEffChamber%i", cathCode[cath], 11+ch);
773                 sprintf(histoTitle, "Chamber %i: slat efficiency %s", 11+ch, cathCode[cath]);
774                 histo[cath][ch] = new TH1F(histoName, histoTitle, fgkNslats, 0-0.5, fgkNslats-0.5);
775                 histo[cath][ch]->SetXTitle("slat");
776                 histo[cath][ch]->SetYTitle(yAxisTitle);
777                 histo[cath][ch]->GetXaxis()->SetNdivisions(fgkNslats);
778                 
779                 sprintf(histoName, "%sBoardEffChamber%i", cathCode[cath], 11+ch);
780                 sprintf(histoTitle, "Chamber %i: board efficiency %s", 11+ch, cathCode[cath]);
781                 histoBoard[cath][ch] = new TH1F(histoName, histoTitle, fgkNboards, 1-0.5, fgkNboards+1.-0.5);
782                 histoBoard[cath][ch]->SetXTitle("boards");
783                 histoBoard[cath][ch]->SetYTitle(yAxisTitle);
784                 histoBoard[cath][ch]->GetXaxis()->SetNdivisions(fgkNboards);
785
786                 // ADDED for check
787                 for(Int_t hType=0; hType<numOfHistoTypes; hType++){
788                     sprintf(histoName, "%sSlat%s%i", cathCode[cath], histoTypeName[hType], 11+ch);
789                     sprintf(histoTitle, "Chamber %i: slat %s %s", 11+ch, histoTypeTitle[hType], cathCode[cath]);
790                     histoCheckSlat[cath][ch][hType] = new TH1F(histoName, histoTitle, fgkNslats, 0-0.5, fgkNslats-0.5);
791                     histoCheckSlat[cath][ch][hType]->SetXTitle("slat");
792                     histoCheckSlat[cath][ch][hType]->SetYTitle(yAxisTitle);
793                     histoCheckSlat[cath][ch][hType]->GetXaxis()->SetNdivisions(fgkNslats);
794
795                     sprintf(histoName, "%sBoard%s%i", cathCode[cath], histoTypeName[hType], 11+ch);
796                     sprintf(histoTitle, "Chamber %i: board %s %s", 11+ch, histoTypeTitle[hType], cathCode[cath]);
797                     histoCheckBoard[cath][ch][hType] = new TH1F(histoName, histoTitle, fgkNboards, 1-0.5, fgkNboards+1.-0.5);
798                     histoCheckBoard[cath][ch][hType]->SetXTitle("boards");
799                     histoCheckBoard[cath][ch][hType]->SetYTitle(yAxisTitle);
800                     histoCheckBoard[cath][ch][hType]->GetXaxis()->SetNdivisions(fgkNboards);
801                 }
802                 // end ADDED for check
803             }
804         }
805     }
806
807     Float_t efficiency, efficiencyError;
808     Int_t bin;
809
810     for(Int_t cath=0; cath<fgkNcathodes; cath++){
811         for(Int_t ch=0; ch<fgkNchambers; ch++){
812             for(Int_t slat=0; slat<fgkNslats; slat++){
813                 CalculateEfficiency(fHitPerSlat[ch][cath][slat], fHitPerSlat[ch][cath][slat]+fInefficientSlat[ch][cath][slat], efficiency, efficiencyError, kFALSE);
814                 bin = histo[cath][ch]->FindBin(slat);
815                 histo[cath][ch]->SetBinContent(bin, efficiency);
816                 histo[cath][ch]->SetBinError(bin, efficiencyError);
817
818                 // ADDED for check
819                 histoCheckSlat[cath][ch][allChEff]->SetBinContent(bin, fHitPerSlat[ch][cath][slat]);
820                 histoCheckSlat[cath][ch][chNonEff]->SetBinContent(bin, fInefficientSlat[ch][cath][slat]);
821             }
822             CalculateEfficiency(fTrigger44[cath], fTrigger34[ch][cath]+fTrigger44[cath], efficiency, efficiencyError, kFALSE);
823             bin = histo[cath][ch]->FindBin(11+ch);
824             histo[cath][kChamberEff]->SetBinContent(bin, efficiency);
825             histo[cath][kChamberEff]->SetBinError(bin, efficiencyError);
826
827             for(Int_t board=0; board<fgkNboards; board++){
828                 CalculateEfficiency(fHitPerBoard[ch][cath][board], fHitPerBoard[ch][cath][board]+fInefficientBoard[ch][cath][board], efficiency, efficiencyError, kFALSE);
829                 bin = histoBoard[cath][ch]->FindBin(board+1);
830                 histoBoard[cath][ch]->SetBinContent(bin, efficiency);
831                 histoBoard[cath][ch]->SetBinError(bin, efficiencyError);
832
833                 // ADDED for check
834                 histoCheckBoard[cath][ch][allChEff]->SetBinContent(bin, fHitPerBoard[ch][cath][board]);
835                 histoCheckBoard[cath][ch][chNonEff]->SetBinContent(bin, fInefficientBoard[ch][cath][board]);
836             }
837         }
838     }
839
840 // write all histos
841     outputHistoFile->cd();
842     dir->GetList()->Write();
843     outputHistoFile->Close();
844 }
845
846
847 //_____________________________________________________________________________
848 void AliMUONTriggerChamberEff::WriteEfficiencyMapTxt(const char* outputDir)
849 {
850     //
851     /// Writes the calculated efficiency in the text file efficiencyCells.dat
852     ///
853     /// The file can be further put in $ALICE_ROOT/MUON/data
854     /// and used to run simulations with measured trigger chamber efficiencies.
855     //
856
857     Int_t effOutWidth=4;
858
859     Float_t efficiency, efficiencyError;
860
861     Int_t aCapo[] = {16, 38, 60, 76, 92, 108, 117, 133, 155, 177, 193, 209, 225, 234};
862
863     char filename[70];
864     sprintf(filename, "%s/efficiencyCells.dat", outputDir);
865     ofstream outFile(filename);
866     outFile << "localBoards" << endl;
867     for(Int_t ch=0; ch<fgkNchambers; ch++){
868         //Print information
869         outFile << "\n\ndetElemId:\t" << 11+ch;
870         outFile << "00";
871         for(Int_t cath=0; cath<fgkNcathodes; cath++){
872             outFile << "\n cathode:\t" << cath << endl;
873             Int_t currLine=0;
874             for(Int_t board=0; board<fgkNboards; board++){
875
876                 if(board==aCapo[currLine]){
877                     outFile << endl;
878                     currLine++;
879                 }
880                 CalculateEfficiency(fHitPerBoard[ch][cath][board], fHitPerBoard[ch][cath][board]+fInefficientBoard[ch][cath][board], efficiency, efficiencyError, kFALSE);
881                 outFile << " " << setw(effOutWidth) << efficiency;
882             }// loop on boards
883             outFile << endl;
884         }// loop on cathodes
885     }// loop on chambers    
886 }
887
888
889 //_____________________________________________________________________________
890 Bool_t AliMUONTriggerChamberEff::IsCleanTrack(AliMUONTriggerTrack *triggerTrack,
891                                               const AliMUONVTrackStore& trackStore)
892 {
893     //
894     /// Try to match track from tracking system with trigger track
895     //
896     const Double_t kDistSigma[3]={1,1,0.02}; // sigma of distributions (trigger-track) X,Y,slopeY
897     const Double_t kMaxChi2MatchTrigger = 16.0;
898   
899     AliMUONTrackParam trackParam; 
900
901     Double_t distTriggerTrack[3];
902     Double_t xTrack, yTrack, ySlopeTrack, chi2;
903   
904     AliMUONTrack* track;
905     TIter next(trackStore.CreateIterator());
906     
907     while ( ( track = static_cast<AliMUONTrack*>(next()) ) )
908     {
909         trackParam = *((AliMUONTrackParam*) (track->GetTrackParamAtHit()->Last()));
910         AliMUONTrackExtrap::ExtrapToZ(&trackParam, AliMUONConstants::DefaultChamberZ(10)); // extrap to 1st trigger chamber
911     
912         xTrack = trackParam.GetNonBendingCoor();
913         yTrack = trackParam.GetBendingCoor();
914         ySlopeTrack = trackParam.GetBendingSlope();
915   
916         distTriggerTrack[0] = (triggerTrack->GetX11()-xTrack)/kDistSigma[0];
917         distTriggerTrack[1] = (triggerTrack->GetY11()-yTrack)/kDistSigma[1];
918         distTriggerTrack[2] = (TMath::Tan(triggerTrack->GetThetay())-ySlopeTrack)/kDistSigma[2];
919         chi2 = 0.;
920         for (Int_t iVar = 0; iVar < 3; iVar++) chi2 += distTriggerTrack[iVar]*distTriggerTrack[iVar];
921         chi2 /= 3.; // Normalized Chi2: 3 degrees of freedom (X,Y,slopeY)
922         if (chi2 < kMaxChi2MatchTrigger) return kTRUE;
923     }
924
925     return kFALSE;
926 }
927
928
929 //_____________________________________________________________________________
930 void AliMUONTriggerChamberEff::SaveInESDFile()
931 {
932     //
933     /// Store AliMUONTriggerChamberEff in esd file
934     //
935     TDirectory *dir = gDirectory;
936     TFile *logFile = 0x0;
937     TSeqCollection *list = gROOT->GetListOfFiles();
938     Int_t n = list->GetEntries();
939     for(Int_t i=0; i<n; i++) {
940         logFile = (TFile*)list->At(i);
941         if (strstr(logFile->GetName(), "AliESDs.root")) break;
942     }
943     if(logFile){
944         TTree *esdTree = (TTree*)logFile->Get("esdTree");
945         if(esdTree){
946             if(!esdTree->GetUserInfo()->FindObject("AliMUONTriggerChamberEff")){
947                 AliInfo(Form("Adding AliMUONTrigChamberEff in %s",logFile->GetName()));
948                 esdTree->GetUserInfo()->Add(this->Clone());
949                 esdTree->Write("",TObject::kOverwrite);
950             }
951         }
952     }
953     dir->cd();
954 }