]> git.uio.no Git - u/mrichter/AliRoot.git/blob - MUON/AliMUONEventReconstructor.cxx
Compiler Warning removed
[u/mrichter/AliRoot.git] / MUON / AliMUONEventReconstructor.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 //
20 // MUON event reconstructor in ALICE
21 //
22 // This class contains as data:
23 // * the parameters for the event reconstruction
24 // * a pointer to the array of hits to be reconstructed (the event)
25 // * a pointer to the array of segments made with these hits inside each station
26 // * a pointer to the array of reconstructed tracks
27 //
28 // It contains as methods, among others:
29 // * MakeEventToBeReconstructed to build the array of hits to be reconstructed
30 // * MakeSegments to build the segments
31 // * MakeTracks to build the tracks
32 //
33 ////////////////////////////////////
34
35 #include <Riostream.h> // for cout
36 #include <stdlib.h> // for exit()
37
38 #include <TTree.h>
39
40 #include "AliMUON.h"
41 #include "AliMUONChamber.h"
42 #include "AliMUONEventReconstructor.h"
43 #include "AliMUONHitForRec.h"
44 #include "AliMUONTriggerTrack.h"
45 //#include "AliMUONTriggerConstants.h"
46 #include "AliMUONTriggerCircuit.h"
47 #include "AliMUONRawCluster.h"
48 #include "AliMUONLocalTrigger.h"
49 #include "AliMUONRecoEvent.h"
50 #include "AliMUONSegment.h"
51 #include "AliMUONTrack.h"
52 #include "AliMUONTrackHit.h"
53 #include "AliMagF.h"
54 #include "AliRun.h" // for gAlice
55 #include "AliConfig.h"
56 #include "AliRunLoader.h"
57 #include "AliLoader.h"
58 #include "AliMUONTrackK.h" //AZ
59 #include <TMatrixD.h> //AZ
60 #include "AliMC.h"
61
62 //************* Defaults parameters for reconstruction
63 static const Double_t kDefaultMinBendingMomentum = 3.0;
64 static const Double_t kDefaultMaxBendingMomentum = 500.0;
65 static const Double_t kDefaultMaxChi2 = 100.0;
66 static const Double_t kDefaultMaxSigma2Distance = 16.0;
67 static const Double_t kDefaultBendingResolution = 0.01;
68 static const Double_t kDefaultNonBendingResolution = 0.144;
69 static const Double_t kDefaultChamberThicknessInX0 = 0.03;
70 // Simple magnetic field:
71 // Value taken from macro MUONtracking.C: 0.7 T, hence 7 kG
72 // Length and Position from reco_muon.F, with opposite sign:
73 // Length = ZMAGEND-ZCOIL
74 // Position = (ZMAGEND+ZCOIL)/2
75 // to be ajusted differently from real magnetic field ????
76 static const Double_t kDefaultSimpleBValue = 7.0;
77 static const Double_t kDefaultSimpleBLength = 428.0;
78 static const Double_t kDefaultSimpleBPosition = 1019.0;
79 static const Int_t kDefaultRecGeantHits = 0;
80 static const Double_t kDefaultEfficiency = 0.95;
81
82 static const Int_t kDefaultPrintLevel = 0;
83
84 ClassImp(AliMUONEventReconstructor) // Class implementation in ROOT context
85
86   //__________________________________________________________________________
87 AliMUONEventReconstructor::AliMUONEventReconstructor(void)
88 {
89   // Constructor for class AliMUONEventReconstructor
90   SetReconstructionParametersToDefaults();
91   fTrackMethod = 1; //AZ - tracking method (1-default, 2-Kalman)
92   // Memory allocation for the TClonesArray of hits for reconstruction
93   // Is 10000 the right size ????
94   fHitsForRecPtr = new TClonesArray("AliMUONHitForRec", 10000);
95   fNHitsForRec = 0; // really needed or GetEntriesFast sufficient ????
96   // Memory allocation for the TClonesArray's of segments in stations
97   // Is 2000 the right size ????
98   for (Int_t st = 0; st < kMaxMuonTrackingStations; st++) {
99     fSegmentsPtr[st] = new TClonesArray("AliMUONSegment", 2000);
100     fNSegments[st] = 0; // really needed or GetEntriesFast sufficient ????
101   }
102   // Memory allocation for the TClonesArray of reconstructed tracks
103   // Is 10 the right size ????
104   fRecTracksPtr = new TClonesArray("AliMUONTrack", 10);
105   fNRecTracks = 0; // really needed or GetEntriesFast sufficient ????
106 // trigger tracks
107   fRecTriggerTracksPtr = new TClonesArray("AliMUONTriggerTrack", 10);
108   fNRecTriggerTracks = 0; // really needed or GetEntriesFast sufficient ????
109   // Memory allocation for the TClonesArray of hits on reconstructed tracks
110   // Is 100 the right size ????
111   fRecTrackHitsPtr = new TClonesArray("AliMUONTrack", 100);
112   fNRecTrackHits = 0; // really needed or GetEntriesFast sufficient ????
113
114   // Sign of fSimpleBValue according to sign of Bx value at (50,50,-950).
115   Float_t b[3], x[3];
116   x[0] = 50.; x[1] = 50.; x[2] = -950.;
117   gAlice->Field()->Field(x, b);
118   fSimpleBValue = TMath::Sign(fSimpleBValue,(Double_t) b[0]);
119   fSimpleBPosition = TMath::Sign(fSimpleBPosition,(Double_t) x[2]);
120   // See how to get fSimple(BValue, BLength, BPosition)
121   // automatically calculated from the actual magnetic field ????
122
123   if (fPrintLevel >= 0) {
124     cout << "AliMUONEventReconstructor constructed with defaults" << endl; Dump();
125     cout << endl << "Magnetic field from root file:" << endl;
126     gAlice->Field()->Dump();
127     cout << endl;
128   }
129   
130   // Initializions for GEANT background events
131   fBkgGeantFile = 0;
132   fBkgGeantTK = 0;
133   fBkgGeantParticles = 0;
134   fBkgGeantTH = 0;
135   fBkgGeantHits = 0;
136   fBkgGeantEventNumber = -1;
137   
138   // Initialize to 0 pointers to RecoEvent, tree and tree file
139   fRecoEvent = 0;
140   fEventTree = 0;
141   fTreeFile  = 0;
142   
143   return;
144 }
145
146 AliMUONEventReconstructor::AliMUONEventReconstructor (const AliMUONEventReconstructor& Reconstructor):TObject(Reconstructor)
147 {
148   // Dummy copy constructor
149 }
150
151 AliMUONEventReconstructor & AliMUONEventReconstructor::operator=(const AliMUONEventReconstructor& /*Reconstructor*/)
152 {
153   // Dummy assignment operator
154     return *this;
155 }
156
157   //__________________________________________________________________________
158 AliMUONEventReconstructor::~AliMUONEventReconstructor(void)
159 {
160   // Destructor for class AliMUONEventReconstructor
161   if (fTreeFile) {
162      fTreeFile->Close();
163      delete fTreeFile;
164   }
165 //  if (fEventTree) delete fEventTree;
166   if (fRecoEvent) delete fRecoEvent;
167   delete fHitsForRecPtr; // Correct destruction of everything ???? or delete [] ????
168   for (Int_t st = 0; st < kMaxMuonTrackingStations; st++)
169     delete fSegmentsPtr[st]; // Correct destruction of everything ????
170   return;
171 }
172
173   //__________________________________________________________________________
174 void AliMUONEventReconstructor::SetReconstructionParametersToDefaults(void)
175 {
176   // Set reconstruction parameters to default values
177   // Would be much more convenient with a structure (or class) ????
178   fMinBendingMomentum = kDefaultMinBendingMomentum;
179   fMaxBendingMomentum = kDefaultMaxBendingMomentum;
180   fMaxChi2 = kDefaultMaxChi2;
181   fMaxSigma2Distance = kDefaultMaxSigma2Distance;
182
183   AliMUON *pMUON = (AliMUON*) gAlice->GetModule("MUON");
184   // ******** Parameters for making HitsForRec
185   // minimum radius,
186   // like in TRACKF_STAT:
187   // 2 degrees for stations 1 and 2, or ch(0...) from 0 to 3;
188   // 30 cm for stations 3 to 5, or ch(0...) from 4 to 9
189   for (Int_t ch = 0; ch < kMaxMuonTrackingChambers; ch++) {
190     if (ch < 4) fRMin[ch] = TMath::Abs((&(pMUON->Chamber(ch)))->Z()) *
191                   2.0 * TMath::Pi() / 180.0;
192     else fRMin[ch] = 30.0;
193     // maximum radius at 10 degrees and Z of chamber
194     fRMax[ch] = TMath::Abs((&(pMUON->Chamber(ch)))->Z()) *
195                   10.0 * TMath::Pi() / 180.0;
196   }
197
198   // ******** Parameters for making segments
199   // should be parametrized ????
200   // according to interval between chambers in a station ????
201   // Maximum distance in non bending plane
202   // 5 * 0.22 just to remember the way it was made in TRACKF_STAT
203   // SIGCUT*DYMAX(IZ)
204   for (Int_t st = 0; st < kMaxMuonTrackingStations; st++)
205     fSegmentMaxDistNonBending[st] = 5. * 0.22;
206   // Maximum distance in bending plane:
207   // values from TRACKF_STAT, corresponding to (J psi 20cm),
208   // scaled to the real distance between chambers in a station
209   fSegmentMaxDistBending[0] = TMath::Abs( 1.5 *
210     ((&(pMUON->Chamber(1)))->Z() - (&(pMUON->Chamber(0)))->Z()) / 20.0);
211   fSegmentMaxDistBending[1] =  TMath::Abs( 1.5 *
212     ((&(pMUON->Chamber(3)))->Z() - (&(pMUON->Chamber(2)))->Z()) / 20.0);
213   fSegmentMaxDistBending[2] =  TMath::Abs( 3.0 *
214     ((&(pMUON->Chamber(5)))->Z() - (&(pMUON->Chamber(4)))->Z()) / 20.0);
215   fSegmentMaxDistBending[3] =  TMath::Abs( 6.0 *
216     ((&(pMUON->Chamber(7)))->Z() - (&(pMUON->Chamber(6)))->Z()) / 20.0);
217   fSegmentMaxDistBending[4] =  TMath::Abs( 6.0 *
218     ((&(pMUON->Chamber(9)))->Z() - (&(pMUON->Chamber(8)))->Z()) / 20.0);
219   
220   fBendingResolution = kDefaultBendingResolution;
221   fNonBendingResolution = kDefaultNonBendingResolution;
222   fChamberThicknessInX0 = kDefaultChamberThicknessInX0;
223   fSimpleBValue = kDefaultSimpleBValue;
224   fSimpleBLength = kDefaultSimpleBLength;
225   fSimpleBPosition = kDefaultSimpleBPosition;
226   fRecGeantHits = kDefaultRecGeantHits;
227   fEfficiency = kDefaultEfficiency;
228   fPrintLevel = kDefaultPrintLevel;
229   return;
230 }
231
232 //__________________________________________________________________________
233 Double_t AliMUONEventReconstructor::GetImpactParamFromBendingMomentum(Double_t BendingMomentum) const
234 {
235   // Returns impact parameter at vertex in bending plane (cm),
236   // from the signed bending momentum "BendingMomentum" in bending plane (GeV/c),
237   // using simple values for dipole magnetic field.
238   // The sign of "BendingMomentum" is the sign of the charge.
239   return (-0.0003 * fSimpleBValue * fSimpleBLength * fSimpleBPosition /
240           BendingMomentum);
241 }
242
243 //__________________________________________________________________________
244 Double_t AliMUONEventReconstructor::GetBendingMomentumFromImpactParam(Double_t ImpactParam) const
245 {
246   // Returns signed bending momentum in bending plane (GeV/c),
247   // the sign being the sign of the charge for particles moving forward in Z,
248   // from the impact parameter "ImpactParam" at vertex in bending plane (cm),
249   // using simple values for dipole magnetic field.
250   return (-0.0003 * fSimpleBValue * fSimpleBLength * fSimpleBPosition /
251           ImpactParam);
252 }
253
254 //__________________________________________________________________________
255 void AliMUONEventReconstructor::SetBkgGeantFile(Text_t *BkgGeantFileName)
256 {
257   // Set background file ... for GEANT hits
258   // Must be called after having loaded the firts signal event
259   if (fPrintLevel >= 0) {
260     cout << "Enter SetBkgGeantFile with BkgGeantFileName ``"
261          << BkgGeantFileName << "''" << endl;}
262   if (strlen(BkgGeantFileName)) {
263     // BkgGeantFileName not empty: try to open the file
264     if (fPrintLevel >= 2) {cout << "Before File(Bkg)" << endl; gDirectory->Dump();}
265     fBkgGeantFile = new TFile(BkgGeantFileName);
266     if (fPrintLevel >= 2) {cout << "After File(Bkg)" << endl; gDirectory->Dump();}
267     if (fBkgGeantFile-> IsOpen()) {
268       if (fPrintLevel >= 0) {
269         cout << "Background for GEANT hits in file: ``" << BkgGeantFileName
270              << "'' successfully opened" << endl;}
271     }
272     else {
273       cout << "Background for GEANT hits in file: " << BkgGeantFileName << endl;
274       cout << "NOT FOUND: EXIT" << endl;
275       exit(0); // right instruction for exit ????
276     }
277     // Arrays for "particles" and "hits"
278     fBkgGeantParticles = new TClonesArray("TParticle", 200);
279     fBkgGeantHits = new TClonesArray("AliMUONHit", 2000);
280     // Event number to -1 for initialization
281     fBkgGeantEventNumber = -1;
282     // Back to the signal file:
283     // first signal event must have been loaded previously,
284     // otherwise, Segmentation violation at the next instruction
285     // How is it possible to do smething better ????
286     ((gAlice->TreeK())->GetCurrentFile())->cd();
287     if (fPrintLevel >= 2) {cout << "After cd(gAlice)" << endl; gDirectory->Dump();}
288   }
289   return;
290 }
291
292 //__________________________________________________________________________
293 void AliMUONEventReconstructor::NextBkgGeantEvent(void)
294 {
295   // Get next event in background file for GEANT hits
296   // Goes back to event number 0 when end of file is reached
297   char treeName[20];
298   TBranch *branch;
299   if (fPrintLevel >= 0) {
300     cout << "Enter NextBkgGeantEvent" << endl;}
301   // Clean previous event
302   if(fBkgGeantTK) delete fBkgGeantTK;
303   fBkgGeantTK = NULL;
304   if(fBkgGeantParticles) fBkgGeantParticles->Clear();
305   if(fBkgGeantTH) delete fBkgGeantTH;
306   fBkgGeantTH = NULL;
307   if(fBkgGeantHits) fBkgGeantHits->Clear();
308   // Increment event number
309   fBkgGeantEventNumber++;
310   // Get access to Particles and Hits for event from background file
311   if (fPrintLevel >= 2) {cout << "Before cd(Bkg)" << endl; gDirectory->Dump();}
312   fBkgGeantFile->cd();
313   if (fPrintLevel >= 2) {cout << "After cd(Bkg)" << endl; gDirectory->Dump();}
314   // Particles: TreeK for event and branch "Particles"
315   sprintf(treeName, "TreeK%d", fBkgGeantEventNumber);
316   fBkgGeantTK = (TTree*)gDirectory->Get(treeName);
317   if (!fBkgGeantTK) {
318     if (fPrintLevel >= 0) {
319       cout << "Cannot find Kine Tree for background event: " <<
320         fBkgGeantEventNumber << endl;
321       cout << "Goes back to event 0" << endl;
322     }
323     fBkgGeantEventNumber = 0;
324     sprintf(treeName, "TreeK%d", fBkgGeantEventNumber);
325     fBkgGeantTK = (TTree*)gDirectory->Get(treeName);
326     if (!fBkgGeantTK) {
327       cout << "ERROR: cannot find Kine Tree for background event: " <<
328         fBkgGeantEventNumber << endl;
329       exit(0);
330     }
331   }
332   if (fBkgGeantTK) 
333     fBkgGeantTK->SetBranchAddress("Particles", &fBkgGeantParticles);
334   fBkgGeantTK->GetEvent(0); // why event 0 ???? necessary ????
335   // Hits: TreeH for event and branch "MUON"
336   sprintf(treeName, "TreeH%d", fBkgGeantEventNumber);
337   fBkgGeantTH = (TTree*)gDirectory->Get(treeName);
338   if (!fBkgGeantTH) {
339     cout << "ERROR: cannot find Hits Tree for background event: " <<
340       fBkgGeantEventNumber << endl;
341       exit(0);
342   }
343   if (fBkgGeantTH && fBkgGeantHits) {
344     branch = fBkgGeantTH->GetBranch("MUON");
345     if (branch) branch->SetAddress(&fBkgGeantHits);
346   }
347   fBkgGeantTH->GetEntries(); // necessary ????
348   // Back to the signal file
349   ((gAlice->TreeK())->GetCurrentFile())->cd();
350   if (fPrintLevel >= 2) {cout << "After cd(gAlice)" << endl; gDirectory->Dump();}
351   return;
352 }
353
354 //__________________________________________________________________________
355 void AliMUONEventReconstructor::EventReconstruct(void)
356 {
357   // To reconstruct one event
358   if (fPrintLevel >= 1) cout << "enter EventReconstruct" << endl;
359   MakeEventToBeReconstructed();
360   MakeSegments();
361   MakeTracks();
362   return;
363 }
364
365 //__________________________________________________________________________
366 void AliMUONEventReconstructor::EventReconstructTrigger(void)
367 {
368   // To reconstruct one event
369   if (fPrintLevel >= 1) cout << "enter EventReconstructTrigger" << endl;
370   MakeTriggerTracks();  
371   return;
372 }
373
374   //__________________________________________________________________________
375 void AliMUONEventReconstructor::ResetHitsForRec(void)
376 {
377   // To reset the array and the number of HitsForRec,
378   // and also the number of HitsForRec
379   // and the index of the first HitForRec per chamber
380   if (fHitsForRecPtr) fHitsForRecPtr->Clear();
381   fNHitsForRec = 0;
382   for (Int_t ch = 0; ch < kMaxMuonTrackingChambers; ch++)
383     fNHitsForRecPerChamber[ch] = fIndexOfFirstHitForRecPerChamber[ch] = 0;
384   return;
385 }
386
387   //__________________________________________________________________________
388 void AliMUONEventReconstructor::ResetSegments(void)
389 {
390   // To reset the TClonesArray of segments and the number of Segments
391   // for all stations
392   for (Int_t st = 0; st < kMaxMuonTrackingStations; st++) {
393     if (fSegmentsPtr[st]) fSegmentsPtr[st]->Clear();
394     fNSegments[st] = 0;
395   }
396   return;
397 }
398
399   //__________________________________________________________________________
400 void AliMUONEventReconstructor::ResetTracks(void)
401 {
402   // To reset the TClonesArray of reconstructed tracks
403   if (fRecTracksPtr) fRecTracksPtr->Delete();
404   // Delete in order that the Track destructors are called,
405   // hence the space for the TClonesArray of pointers to TrackHit's is freed
406   fNRecTracks = 0;
407   return;
408 }
409
410   //__________________________________________________________________________
411 void AliMUONEventReconstructor::ResetTriggerTracks(void)
412 {
413   // To reset the TClonesArray of reconstructed trigger tracks
414     if (fRecTriggerTracksPtr) fRecTriggerTracksPtr->Delete();
415   // Delete in order that the Track destructors are called,
416   // hence the space for the TClonesArray of pointers to TrackHit's is freed
417     fNRecTriggerTracks = 0;
418   return;
419 }
420
421   //__________________________________________________________________________
422 void AliMUONEventReconstructor::ResetTrackHits(void)
423 {
424   // To reset the TClonesArray of hits on reconstructed tracks
425   if (fRecTrackHitsPtr) fRecTrackHitsPtr->Clear();
426   fNRecTrackHits = 0;
427   return;
428 }
429
430   //__________________________________________________________________________
431 void AliMUONEventReconstructor::MakeEventToBeReconstructed(void)
432 {
433   // To make the list of hits to be reconstructed,
434   // either from the GEANT hits or from the raw clusters
435   // according to the parameter set for the reconstructor
436   TString evfoldname = AliConfig::fgkDefaultEventFolderName;//to be interfaced properly
437   
438   AliRunLoader* rl = AliRunLoader::GetRunLoader(evfoldname);
439   if (rl == 0x0)
440    {
441      Error("MakeEventToBeReconstructed",
442            "Can not find Run Loader in Event Folder named %s.",
443            evfoldname.Data());
444      return;
445    }
446   AliLoader* gime = rl->GetLoader("MUONLoader");
447   if (gime == 0x0)
448    {
449      Error("MakeEventToBeReconstructed","Can not get MUON Loader from Run Loader.");
450      return;
451    }
452   
453   if (fPrintLevel >= 1) cout << "enter MakeEventToBeReconstructed" << endl;
454   ResetHitsForRec();
455   if (fRecGeantHits == 1) {
456     // Reconstruction from GEANT hits
457     // Back to the signal file
458       TTree* treeH = gime->TreeH();
459       if (treeH == 0x0)
460        {
461          Int_t retval = gime->LoadHits();
462          if ( retval)
463           {
464             Error("MakeEventToBeReconstructed","Error occured while loading hits.");
465             return;
466           }
467          treeH = gime->TreeH();
468          if (treeH == 0x0)
469           {
470            Error("MakeEventToBeReconstructed","Can not get TreeH");
471            return;
472           }
473        }
474     
475     AddHitsForRecFromGEANT(treeH);
476     
477     // Background hits
478     AddHitsForRecFromBkgGEANT(fBkgGeantTH, fBkgGeantHits);
479     // Sort HitsForRec in increasing order with respect to chamber number
480     SortHitsForRecWithIncreasingChamber();
481   }
482   else {
483     // Reconstruction from raw clusters
484     // AliMUON *MUON  = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
485     // Security on MUON ????
486     // TreeR assumed to be be "prepared" in calling function
487     // by "MUON->GetTreeR(nev)" ????
488     TTree *treeR = gime->TreeR();
489     AddHitsForRecFromRawClusters(treeR);
490     // No sorting: it is done automatically in the previous function
491   }
492   if (fPrintLevel >= 10) {
493     cout << "end of MakeEventToBeReconstructed" << endl;
494     cout << "NHitsForRec: " << fNHitsForRec << endl;
495     for (Int_t ch = 0; ch < kMaxMuonTrackingChambers; ch++) {
496       cout << "chamber(0...): " << ch
497            << "  NHitsForRec: " << fNHitsForRecPerChamber[ch]
498            << "  index(first HitForRec): " << fIndexOfFirstHitForRecPerChamber[ch]
499            << endl;
500       for (Int_t hit = fIndexOfFirstHitForRecPerChamber[ch];
501            hit < fIndexOfFirstHitForRecPerChamber[ch] + fNHitsForRecPerChamber[ch];
502            hit++) {
503         cout << "HitForRec index(0...): " << hit << endl;
504         ((*fHitsForRecPtr)[hit])->Dump();
505       }
506     }
507   }
508   return;
509 }
510
511   //__________________________________________________________________________
512 void AliMUONEventReconstructor::AddHitsForRecFromGEANT(TTree *TH)
513 {
514   // To add to the list of hits for reconstruction
515   // the GEANT signal hits from a hit tree TH.
516   Int_t hitBits, chamBits; //AZ
517   if (fPrintLevel >= 2)
518     cout << "enter AddHitsForRecFromGEANT with TH: " << TH << endl;
519   if (TH == NULL) return;
520   AliMUON *pMUON  = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
521   AliMUONData * muondata = pMUON->GetMUONData();
522   // Security on MUON ????
523   // See whether it could be the same for signal and background ????
524   // Loop over tracks in tree
525   Int_t ntracks = (Int_t) TH->GetEntries();
526   if (fPrintLevel >= 2)
527     cout << "ntracks: " << ntracks << endl;
528   fMuons = 0; //AZ
529   for (Int_t track = 0; track < ntracks; track++) {
530     muondata->ResetHits();
531     TH->GetEvent(track);
532     // Loop over hits
533     Int_t hit = 0;
534     hitBits = 0; // AZ
535     chamBits = 0; // AZ
536     Int_t itrack = track; //AZ
537
538     Int_t ihit, nhits=0;
539       nhits = (Int_t) muondata->Hits()->GetEntriesFast();
540       AliMUONHit* mHit=0x0;
541
542       for(ihit=0; ihit<nhits; ihit++) {
543         mHit = static_cast<AliMUONHit*>(muondata->Hits()->At(ihit));
544         Int_t ipart = TMath::Abs ((Int_t) mHit->Particle()); //AZ
545         if (NewHitForRecFromGEANT(mHit,track, hit, 1) && ipart == 13
546             //if (NewHitForRecFromGEANT(mHit,itrack-1, hit, 1) && ipart == 13 
547             && itrack <= 2 && !BIT(mHit->Chamber()-1)  ) chamBits |= BIT(mHit->Chamber()-1); //AZ - set bit
548       }
549
550     if (chamBits&3 && chamBits>>2&3 && chamBits>>4&3 && chamBits>>6&3 && 
551         chamBits>>8&3 && ((chamBits>>6&3)==3 || (chamBits>>8&3)==3)) 
552       fMuons += 1; //AZ
553     //if (chamBits&3 && chamBits>>2&3 && chamBits>>4&3 && chamBits>>6&3 && 
554     //      chamBits>>8&3 && ((chamBits>>6&3)==3 || (chamBits>>8&3)==3) && 
555     //      ((chamBits&3)==3 || (chamBits>>2&3)==3)) fMuons += 1;
556   } // end of track loop
557   return;
558 }
559
560   //__________________________________________________________________________
561 void AliMUONEventReconstructor::AddHitsForRecFromBkgGEANT(TTree *TH, TClonesArray *Hits)
562 {
563   // To add to the list of hits for reconstruction
564   // the GEANT background hits from a hit tree TH and a pointer Hits to a hit list.
565   // How to have only one function "AddHitsForRecFromGEANT" ????
566   if (fPrintLevel >= 2)
567     cout << "enter AddHitsForRecFromBkgGEANT with TH: " << TH << endl;
568   if (TH == NULL) return;
569   // Loop over tracks in tree
570   Int_t ntracks = (Int_t) TH->GetEntries();
571   if (fPrintLevel >= 2)
572     cout << "ntracks: " << ntracks << endl;
573   for (Int_t track = 0; track < ntracks; track++) {
574     if (Hits) Hits->Clear();
575     TH->GetEvent(track);
576     // Loop over hits
577     for (Int_t hit = 0; hit < Hits->GetEntriesFast(); hit++) {
578       NewHitForRecFromGEANT((AliMUONHit*) (*Hits)[hit], track, hit, 0);
579     } // end of hit loop
580   } // end of track loop
581   return;
582 }
583
584   //__________________________________________________________________________
585 AliMUONHitForRec* AliMUONEventReconstructor::NewHitForRecFromGEANT(AliMUONHit* Hit, Int_t TrackNumber, Int_t HitNumber, Int_t Signal)
586 {
587   // To make a new hit for reconstruction from a GEANT hit pointed to by "Hit",
588   // with hit number "HitNumber" in the track numbered "TrackNumber",
589   // either from signal ("Signal" = 1) or background ("Signal" = 0) event.
590   // Selects hits in tracking (not trigger) chambers.
591   // Takes into account the efficiency (fEfficiency)
592   // and the smearing from resolution (fBendingResolution and fNonBendingResolution).
593   // Adds a condition on the radius between RMin and RMax
594   // to better simulate the real chambers.
595   // Returns the pointer to the new hit for reconstruction,
596   // or NULL in case of inefficiency or non tracking chamber or bad radius.
597   // No condition on at most 20 cm from a muon from a resonance
598   // like in Fortran TRACKF_STAT.
599   AliMUONHitForRec* hitForRec;
600   Double_t bendCoor, nonBendCoor, radius;
601   Int_t chamber = Hit->Chamber() - 1; // chamber(0...)
602   // only in tracking chambers (fChamber starts at 1)
603   if (chamber >= kMaxMuonTrackingChambers) return NULL;
604   // only if hit is efficient (keep track for checking ????)
605   if (gRandom->Rndm() > fEfficiency) return NULL;
606   // only if radius between RMin and RMax
607   bendCoor = Hit->Y();
608   nonBendCoor = Hit->X();
609   radius = TMath::Sqrt((bendCoor * bendCoor) + (nonBendCoor * nonBendCoor));
610   // This cut is not needed with a realistic chamber geometry !!!!
611 //   if ((radius < fRMin[chamber]) || (radius > fRMax[chamber])) return NULL;
612   // new AliMUONHitForRec from GEANT hit and increment number of AliMUONHitForRec's
613   hitForRec = new ((*fHitsForRecPtr)[fNHitsForRec]) AliMUONHitForRec(Hit);
614   fNHitsForRec++;
615   // add smearing from resolution
616   hitForRec->SetBendingCoor(bendCoor + gRandom->Gaus(0., fBendingResolution));
617   hitForRec->SetNonBendingCoor(nonBendCoor
618                                + gRandom->Gaus(0., fNonBendingResolution));
619 //   // !!!! without smearing
620 //   hitForRec->SetBendingCoor(bendCoor);
621 //   hitForRec->SetNonBendingCoor(nonBendCoor);
622   // more information into HitForRec
623   //  resolution: angular effect to be added here ????
624   hitForRec->SetBendingReso2(fBendingResolution * fBendingResolution);
625   hitForRec->SetNonBendingReso2(fNonBendingResolution * fNonBendingResolution);
626   //  GEANT track info
627   hitForRec->SetHitNumber(HitNumber);
628   hitForRec->SetTHTrack(TrackNumber);
629   hitForRec->SetGeantSignal(Signal);
630   if (fPrintLevel >= 10) {
631     cout << "track: " << TrackNumber << " hit: " << HitNumber << endl;
632     Hit->Dump();
633     cout << "AliMUONHitForRec number (1...): " << fNHitsForRec << endl;
634     hitForRec->Dump();}
635   return hitForRec;
636 }
637
638   //__________________________________________________________________________
639 void AliMUONEventReconstructor::SortHitsForRecWithIncreasingChamber()
640 {
641   // Sort HitsForRec's in increasing order with respect to chamber number.
642   // Uses the function "Compare".
643   // Update the information for HitsForRec per chamber too.
644   Int_t ch, nhits, prevch;
645   fHitsForRecPtr->Sort();
646   for (ch = 0; ch < kMaxMuonTrackingChambers; ch++) {
647     fNHitsForRecPerChamber[ch] = 0;
648     fIndexOfFirstHitForRecPerChamber[ch] = 0;
649   }
650   prevch = 0; // previous chamber
651   nhits = 0; // number of hits in current chamber
652   // Loop over HitsForRec
653   for (Int_t hit = 0; hit < fNHitsForRec; hit++) {
654     // chamber number (0...)
655     ch = ((AliMUONHitForRec*)  ((*fHitsForRecPtr)[hit]))->GetChamberNumber();
656     // increment number of hits in current chamber
657     (fNHitsForRecPerChamber[ch])++;
658     // update index of first HitForRec in current chamber
659     // if chamber number different from previous one
660     if (ch != prevch) {
661       fIndexOfFirstHitForRecPerChamber[ch] = hit;
662       prevch = ch;
663     }
664   }
665   return;
666 }
667
668 //   //__________________________________________________________________________
669 // void AliMUONEventReconstructor::AddHitsForRecFromCathodeCorrelations(TTree* TC)
670 // {
671 //   // OLD VERSION WHEN ONE ONE WAS USING SO CALLED CATHODE CORRELATIONS
672 //   // To add to the list of hits for reconstruction
673 //   // the (cathode correlated) raw clusters
674 //   // No condition added, like in Fortran TRACKF_STAT,
675 //   // on the radius between RMin and RMax.
676 //   AliMUONHitForRec *hitForRec;
677 //   if (fPrintLevel >= 1) cout << "enter AddHitsForRecFromCathodeCorrelations" << endl;
678 //   AliMUON *MUON  = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
679 //   // Security on MUON ????
680 //   // Loop over tracking chambers
681 //   for (Int_t ch = 0; ch < kMaxMuonTrackingChambers; ch++) {
682 //     // number of HitsForRec to 0 for the chamber
683 //     fNHitsForRecPerChamber[ch] = 0;
684 //     // index of first HitForRec for the chamber
685 //     if (ch == 0) fIndexOfFirstHitForRecPerChamber[ch] = 0;
686 //     else fIndexOfFirstHitForRecPerChamber[ch] = fNHitsForRec;
687 //     TClonesArray *reconst_hits  = MUON->ReconstHitsAddress(ch);
688 //     MUON->ResetReconstHits();
689 //     TC->GetEvent();
690 //     Int_t ncor = (Int_t)reconst_hits->GetEntries();
691 //     // Loop over (cathode correlated) raw clusters
692 //     for (Int_t cor = 0; cor < ncor; cor++) {
693 //       AliMUONReconstHit * mCor = 
694 //      (AliMUONReconstHit*) reconst_hits->UncheckedAt(cor);
695 //       // new AliMUONHitForRec from (cathode correlated) raw cluster
696 //       // and increment number of AliMUONHitForRec's (total and in chamber)
697 //       hitForRec = new ((*fHitsForRecPtr)[fNHitsForRec]) AliMUONHitForRec(mCor);
698 //       fNHitsForRec++;
699 //       (fNHitsForRecPerChamber[ch])++;
700 //       // more information into HitForRec
701 //       hitForRec->SetChamberNumber(ch);
702 //       hitForRec->SetHitNumber(cor);
703 //       // Z coordinate of the chamber (cm) with sign opposite to GEANT sign
704 //       // could (should) be more exact from chamber geometry ???? 
705 //       hitForRec->SetZ(-(&(MUON->Chamber(ch)))->Z());
706 //       if (fPrintLevel >= 10) {
707 //      cout << "chamber (0...): " << ch <<
708 //        " cathcorrel (0...): " << cor << endl;
709 //      mCor->Dump();
710 //      cout << "AliMUONHitForRec number (1...): " << fNHitsForRec << endl;
711 //      hitForRec->Dump();}
712 //     } // end of cluster loop
713 //   } // end of chamber loop
714 //   return;
715 // }
716
717   //__________________________________________________________________________
718 void AliMUONEventReconstructor::AddHitsForRecFromRawClusters(TTree* TR)
719 {
720   // To add to the list of hits for reconstruction all the raw clusters
721   // No condition added, like in Fortran TRACKF_STAT,
722   // on the radius between RMin and RMax.
723   AliMUONHitForRec *hitForRec;
724   AliMUONRawCluster *clus;
725   Int_t iclus, nclus, nTRentries;
726   TClonesArray *rawclusters;
727   if (fPrintLevel >= 1) cout << "enter AddHitsForRecFromRawClusters" << endl;
728
729   TString evfoldname = AliConfig::fgkDefaultEventFolderName;//to be interfaced properly
730   AliRunLoader* rl = AliRunLoader::GetRunLoader(evfoldname);
731   if (rl == 0x0)
732    {
733      Error("MakeEventToBeReconstructed",
734            "Can not find Run Loader in Event Folder named %s.",
735            evfoldname.Data());
736      return;
737    }
738   AliLoader* gime = rl->GetLoader("MUONLoader");
739   if (gime == 0x0)
740    {
741      Error("MakeEventToBeReconstructed","Can not get MUON Loader from Run Loader.");
742      return;
743    }
744    // Loading AliRun master
745   rl->LoadgAlice();
746   gAlice = rl->GetAliRun();
747
748   // Loading MUON subsystem
749   AliMUON * pMUON = (AliMUON *) gAlice->GetDetector("MUON");
750
751   nTRentries = Int_t(TR->GetEntries());
752   if (nTRentries != 1) {
753     cout << "Error in AliMUONEventReconstructor::AddHitsForRecFromRawClusters"
754          << endl;
755     cout << "nTRentries = " << nTRentries << " not equal to 1" << endl;
756     exit(0);
757   }
758   gime->TreeR()->GetEvent(0); // only one entry  
759   // Loop over tracking chambers
760   for (Int_t ch = 0; ch < kMaxMuonTrackingChambers; ch++) {
761     // number of HitsForRec to 0 for the chamber
762     fNHitsForRecPerChamber[ch] = 0;
763     // index of first HitForRec for the chamber
764     if (ch == 0) fIndexOfFirstHitForRecPerChamber[ch] = 0;
765     else fIndexOfFirstHitForRecPerChamber[ch] = fNHitsForRec;
766     rawclusters = pMUON->GetMUONData()->RawClusters(ch);
767 //     pMUON->ResetRawClusters();
768 //     TR->GetEvent((Int_t) (TR->GetEntries()) - 1); // to be checked ????
769     nclus = (Int_t) (rawclusters->GetEntries());
770     // Loop over (cathode correlated) raw clusters
771     for (iclus = 0; iclus < nclus; iclus++) {
772       clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(iclus);
773       // new AliMUONHitForRec from raw cluster
774       // and increment number of AliMUONHitForRec's (total and in chamber)
775       hitForRec = new ((*fHitsForRecPtr)[fNHitsForRec]) AliMUONHitForRec(clus);
776       fNHitsForRec++;
777       (fNHitsForRecPerChamber[ch])++;
778       // more information into HitForRec
779       //  resolution: info should be already in raw cluster and taken from it ????
780       hitForRec->SetBendingReso2(fBendingResolution * fBendingResolution);
781       hitForRec->SetNonBendingReso2(fNonBendingResolution * fNonBendingResolution);
782       //  original raw cluster
783       hitForRec->SetChamberNumber(ch);
784       hitForRec->SetHitNumber(iclus);
785       // Z coordinate of the raw cluster (cm)
786       hitForRec->SetZ(clus->fZ[0]);
787       if (fPrintLevel >= 10) {
788         cout << "chamber (0...): " << ch <<
789           " raw cluster (0...): " << iclus << endl;
790         clus->Dump();
791         cout << "AliMUONHitForRec number (1...): " << fNHitsForRec << endl;
792         hitForRec->Dump();}
793     } // end of cluster loop
794   } // end of chamber loop
795   SortHitsForRecWithIncreasingChamber(); //AZ 
796   return;
797 }
798
799   //__________________________________________________________________________
800 void AliMUONEventReconstructor::MakeSegments(void)
801 {
802   // To make the list of segments in all stations,
803   // from the list of hits to be reconstructed
804   if (fPrintLevel >= 1) cout << "enter MakeSegments" << endl;
805   ResetSegments();
806   // Loop over stations
807   Int_t nb = (fTrackMethod == 2) ? 3 : 0; //AZ
808   //AZ for (Int_t st = 0; st < kMaxMuonTrackingStations; st++)
809   for (Int_t st = nb; st < kMaxMuonTrackingStations; st++) //AZ
810     MakeSegmentsPerStation(st); 
811   if (fPrintLevel >= 10) {
812     cout << "end of MakeSegments" << endl;
813     for (Int_t st = 0; st < kMaxMuonTrackingStations; st++) {
814       cout << "station(0...): " << st
815            << "  Segments: " << fNSegments[st]
816            << endl;
817       for (Int_t seg = 0;
818            seg < fNSegments[st];
819            seg++) {
820         cout << "Segment index(0...): " << seg << endl;
821         ((*fSegmentsPtr[st])[seg])->Dump();
822       }
823     }
824   }
825   return;
826 }
827
828   //__________________________________________________________________________
829 void AliMUONEventReconstructor::MakeSegmentsPerStation(Int_t Station)
830 {
831   // To make the list of segments in station number "Station" (0...)
832   // from the list of hits to be reconstructed.
833   // Updates "fNSegments"[Station].
834   // Segments in stations 4 and 5 are sorted
835   // according to increasing absolute value of "impact parameter"
836   AliMUONHitForRec *hit1Ptr, *hit2Ptr;
837   AliMUONSegment *segment;
838   Bool_t last2st;
839   Double_t bendingSlope, distBend, distNonBend, extBendCoor, extNonBendCoor,
840       impactParam = 0., maxImpactParam = 0., minImpactParam = 0.; // =0 to avoid compilation warnings.
841   AliMUON *pMUON  = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
842   if (fPrintLevel >= 1)
843     cout << "enter MakeSegmentsPerStation (0...) " << Station << endl;
844   // first and second chambers (0...) in the station
845   Int_t ch1 = 2 * Station;
846   Int_t ch2 = ch1 + 1;
847   // variable true for stations downstream of the dipole:
848   // Station(0..4) equal to 3 or 4
849   if ((Station == 3) || (Station == 4)) {
850     last2st = kTRUE;
851     // maximum impact parameter (cm) according to fMinBendingMomentum...
852     maxImpactParam =
853       TMath::Abs(GetImpactParamFromBendingMomentum(fMinBendingMomentum));
854     // minimum impact parameter (cm) according to fMaxBendingMomentum...
855     minImpactParam =
856       TMath::Abs(GetImpactParamFromBendingMomentum(fMaxBendingMomentum));
857   }
858   else last2st = kFALSE;
859   // extrapolation factor from Z of first chamber to Z of second chamber
860   // dZ to be changed to take into account fine structure of chambers ????
861   Double_t extrapFact =
862     (&(pMUON->Chamber(ch2)))->Z() / (&(pMUON->Chamber(ch1)))->Z();
863   // index for current segment
864   Int_t segmentIndex = 0;
865   // Loop over HitsForRec in the first chamber of the station
866   for (Int_t hit1 = fIndexOfFirstHitForRecPerChamber[ch1];
867        hit1 < fIndexOfFirstHitForRecPerChamber[ch1] + fNHitsForRecPerChamber[ch1];
868        hit1++) {
869     // pointer to the HitForRec
870     hit1Ptr = (AliMUONHitForRec*) ((*fHitsForRecPtr)[hit1]);
871     // extrapolation,
872     // on the straight line joining the HitForRec to the vertex (0,0,0),
873     // to the Z of the second chamber of the station
874     extBendCoor = extrapFact * hit1Ptr->GetBendingCoor();
875     extNonBendCoor = extrapFact * hit1Ptr->GetNonBendingCoor();
876     // Loop over HitsForRec in the second chamber of the station
877     for (Int_t hit2 = fIndexOfFirstHitForRecPerChamber[ch2];
878          hit2 < fIndexOfFirstHitForRecPerChamber[ch2] + fNHitsForRecPerChamber[ch2];
879          hit2++) {
880       // pointer to the HitForRec
881       hit2Ptr = (AliMUONHitForRec*) ((*fHitsForRecPtr)[hit2]);
882       // absolute values of distances, in bending and non bending planes,
883       // between the HitForRec in the second chamber
884       // and the previous extrapolation
885       distBend = TMath::Abs(hit2Ptr->GetBendingCoor() - extBendCoor);
886       distNonBend = TMath::Abs(hit2Ptr->GetNonBendingCoor() - extNonBendCoor);
887       if (last2st) {
888         // bending slope
889         bendingSlope = (hit1Ptr->GetBendingCoor() - hit2Ptr->GetBendingCoor()) /
890           (hit1Ptr->GetZ() - hit2Ptr->GetZ());
891         // absolute value of impact parameter
892         impactParam =
893           TMath::Abs(hit1Ptr->GetBendingCoor() - hit1Ptr->GetZ() * bendingSlope);
894       }
895       // check for distances not too large,
896       // and impact parameter not too big if stations downstream of the dipole.
897       // Conditions "distBend" and "impactParam" correlated for these stations ????
898       if ((distBend < fSegmentMaxDistBending[Station]) &&
899           (distNonBend < fSegmentMaxDistNonBending[Station]) &&
900           (!last2st || (impactParam < maxImpactParam)) &&
901           (!last2st || (impactParam > minImpactParam))) {
902         // make new segment
903         segment = new ((*fSegmentsPtr[Station])[segmentIndex])
904           AliMUONSegment(hit1Ptr, hit2Ptr);
905         // update "link" to this segment from the hit in the first chamber
906         if (hit1Ptr->GetNSegments() == 0)
907           hit1Ptr->SetIndexOfFirstSegment(segmentIndex);
908         hit1Ptr->SetNSegments(hit1Ptr->GetNSegments() + 1);
909         if (fPrintLevel >= 10) {
910           cout << "segmentIndex(0...): " << segmentIndex
911                << "  distBend: " << distBend
912                << "  distNonBend: " << distNonBend
913                << endl;
914           segment->Dump();
915           cout << "HitForRec in first chamber" << endl;
916           hit1Ptr->Dump();
917           cout << "HitForRec in second chamber" << endl;
918           hit2Ptr->Dump();
919         };
920         // increment index for current segment
921         segmentIndex++;
922       }
923     } //for (Int_t hit2
924   } // for (Int_t hit1...
925   fNSegments[Station] = segmentIndex;
926   // Sorting according to "impact parameter" if station(1..5) 4 or 5,
927   // i.e. Station(0..4) 3 or 4, using the function "Compare".
928   // After this sorting, it is impossible to use
929   // the "fNSegments" and "fIndexOfFirstSegment"
930   // of the HitForRec in the first chamber to explore all segments formed with it.
931   // Is this sorting really needed ????
932   if ((Station == 3) || (Station == 4)) (fSegmentsPtr[Station])->Sort();
933   if (fPrintLevel >= 1) cout << "Station: " << Station << "  NSegments: "
934                              << fNSegments[Station] << endl;
935   return;
936 }
937
938   //__________________________________________________________________________
939 void AliMUONEventReconstructor::MakeTracks(void)
940 {
941   // To make the tracks,
942   // from the list of segments and points in all stations
943   if (fPrintLevel >= 1) cout << "enter MakeTracks" << endl;
944   // The order may be important for the following Reset's
945   ResetTracks();
946   ResetTrackHits();
947   if (fTrackMethod == 2) { //AZ - Kalman filter
948     MakeTrackCandidatesK();
949     // Follow tracks in stations(1..) 3, 2 and 1
950     FollowTracksK();
951     // Remove double tracks
952     RemoveDoubleTracksK();
953     // Propagate tracks to the vertex thru absorber
954     GoToVertex();
955   } else { //AZ
956     // Look for candidates from at least 3 aligned points in stations(1..) 4 and 5
957     MakeTrackCandidates();
958     // Follow tracks in stations(1..) 3, 2 and 1
959     FollowTracks();
960     // Remove double tracks
961     RemoveDoubleTracks();
962   }
963   return;
964 }
965
966   //__________________________________________________________________________
967 void AliMUONEventReconstructor::MakeTriggerTracks(void)
968 {
969     // To make the trigger tracks from Local Trigger
970     if (fPrintLevel >= 1) cout << "enter MakeTriggerTracks" << endl;
971     ResetTriggerTracks();
972     
973     Int_t nTRentries;
974     TClonesArray *localTrigger;
975     AliMUONLocalTrigger *locTrg;
976     AliMUONTriggerCircuit *circuit;
977     AliMUONTriggerTrack *recTriggerTrack;
978     
979     TString evfoldname = AliConfig::fgkDefaultEventFolderName;//to be interfaced properly
980     AliRunLoader* rl = AliRunLoader::GetRunLoader(evfoldname);
981     if (rl == 0x0)
982     {
983         Error("MakeTriggerTracks",
984               "Can not find Run Loader in Event Folder named %s.",
985               evfoldname.Data());
986         return;
987     }
988     AliLoader* gime = rl->GetLoader("MUONLoader");
989     if (gime == 0x0)
990     {
991         Error("MakeTriggerTracks","Can not get MUON Loader from Run Loader.");
992         return;
993     }
994     TTree* TR = gime->TreeR();
995     
996     // Loading AliRun master
997     rl->LoadgAlice();
998     gAlice = rl->GetAliRun();
999     
1000     // Loading MUON subsystem
1001     AliMUON * pMUON = (AliMUON *) gAlice->GetDetector("MUON");
1002     
1003     nTRentries = Int_t(TR->GetEntries());
1004     if (nTRentries != 1) {
1005         cout << "Error in AliMUONEventReconstructor::MakeTriggerTracks"
1006              << endl;
1007         cout << "nTRentries = " << nTRentries << " not equal to 1" << endl;
1008         exit(0);
1009     }
1010     gime->TreeR()->GetEvent(0); // only one entry  
1011
1012     pMUON->GetMUONData()->SetTreeAddress("GLT");
1013     pMUON->GetMUONData()->GetTrigger();
1014     
1015     localTrigger = pMUON->GetMUONData()->LocalTrigger();    
1016     Int_t nlocals = (Int_t) (localTrigger->GetEntries());
1017     Float_t z11 = ( &(pMUON->Chamber(10)) )->Z();
1018     Float_t z21 = ( &(pMUON->Chamber(12)) )->Z();
1019
1020     for (Int_t i=0; i<nlocals; i++) { // loop on Local Trigger
1021         locTrg = (AliMUONLocalTrigger*)localTrigger->UncheckedAt(i);    
1022         circuit = &(pMUON->TriggerCircuit(locTrg->LoCircuit()));
1023         Float_t y11 = circuit->GetY11Pos(locTrg->LoStripX()); 
1024         Float_t y21 = circuit->GetY21Pos(locTrg->LoStripX());
1025         Float_t x11 = circuit->GetX11Pos(locTrg->LoStripY());
1026         Float_t thetax = TMath::ATan2( x11 , z11 );
1027         Float_t thetay = TMath::ATan2( (y21-y11) , (z21-z11) );
1028
1029         recTriggerTrack = new ((*fRecTriggerTracksPtr)[fNRecTriggerTracks])
1030             AliMUONTriggerTrack(x11,y11,thetax,thetay,this);
1031         fNRecTriggerTracks++;
1032     } // end of loop on Local Trigger
1033     return;    
1034 }
1035
1036   //__________________________________________________________________________
1037 Int_t AliMUONEventReconstructor::MakeTrackCandidatesWithTwoSegments(AliMUONSegment *BegSegment)
1038 {
1039   // To make track candidates with two segments in stations(1..) 4 and 5,
1040   // the first segment being pointed to by "BegSegment".
1041   // Returns the number of such track candidates.
1042   Int_t endStation, iEndSegment, nbCan2Seg;
1043   AliMUONSegment *endSegment, *extrapSegment;
1044   AliMUONTrack *recTrack;
1045   Double_t mcsFactor;
1046   if (fPrintLevel >= 1) cout << "enter MakeTrackCandidatesWithTwoSegments" << endl;
1047   // Station for the end segment
1048   endStation = 7 - (BegSegment->GetHitForRec1())->GetChamberNumber() / 2;
1049   // multiple scattering factor corresponding to one chamber
1050   mcsFactor = 0.0136 /
1051     GetBendingMomentumFromImpactParam(BegSegment->GetBendingImpact());
1052   mcsFactor     = fChamberThicknessInX0 * mcsFactor * mcsFactor;
1053   // linear extrapolation to end station
1054   extrapSegment =
1055     BegSegment->CreateSegmentFromLinearExtrapToStation(endStation, mcsFactor);
1056   // number of candidates with 2 segments to 0
1057   nbCan2Seg = 0;
1058   // Loop over segments in the end station
1059   for (iEndSegment = 0; iEndSegment < fNSegments[endStation]; iEndSegment++) {
1060     // pointer to segment
1061     endSegment = (AliMUONSegment*) ((*fSegmentsPtr[endStation])[iEndSegment]);
1062     // test compatibility between current segment and "extrapSegment"
1063     // 4 because 4 quantities in chi2
1064     if ((endSegment->
1065          NormalizedChi2WithSegment(extrapSegment,
1066                                    fMaxSigma2Distance)) <= 4.0) {
1067       // both segments compatible:
1068       // make track candidate from "begSegment" and "endSegment"
1069       if (fPrintLevel >= 2)
1070         cout << "TrackCandidate with Segment " << iEndSegment <<
1071           " in Station(0..) " << endStation << endl;
1072       // flag for both segments in one track:
1073       // to be done in track constructor ????
1074       BegSegment->SetInTrack(kTRUE);
1075       endSegment->SetInTrack(kTRUE);
1076       recTrack = new ((*fRecTracksPtr)[fNRecTracks])
1077         AliMUONTrack(BegSegment, endSegment, this);
1078       fNRecTracks++;
1079       if (fPrintLevel >= 10) recTrack->RecursiveDump();
1080       // increment number of track candidates with 2 segments
1081       nbCan2Seg++;
1082     }
1083   } // for (iEndSegment = 0;...
1084   delete extrapSegment; // should not delete HitForRec's it points to !!!!
1085   return nbCan2Seg;
1086 }
1087
1088   //__________________________________________________________________________
1089 Int_t AliMUONEventReconstructor::MakeTrackCandidatesWithOneSegmentAndOnePoint(AliMUONSegment *BegSegment)
1090 {
1091   // To make track candidates with one segment and one point
1092   // in stations(1..) 4 and 5,
1093   // the segment being pointed to by "BegSegment".
1094   Int_t ch, ch1, ch2, endStation, iHit, iHitMax, iHitMin, nbCan1Seg1Hit;
1095   AliMUONHitForRec *extrapHitForRec, *hit;
1096   AliMUONTrack *recTrack;
1097   Double_t mcsFactor;
1098   if (fPrintLevel >= 1)
1099     cout << "enter MakeTrackCandidatesWithOneSegmentAndOnePoint" << endl;
1100   // station for the end point
1101   endStation = 7 - (BegSegment->GetHitForRec1())->GetChamberNumber() / 2;
1102   // multiple scattering factor corresponding to one chamber
1103   mcsFactor = 0.0136 /
1104     GetBendingMomentumFromImpactParam(BegSegment->GetBendingImpact());
1105   mcsFactor     = fChamberThicknessInX0 * mcsFactor * mcsFactor;
1106   // first and second chambers(0..) in the end station
1107   ch1 = 2 * endStation;
1108   ch2 = ch1 + 1;
1109   // number of candidates to 0
1110   nbCan1Seg1Hit = 0;
1111   // Loop over chambers of the end station
1112   for (ch = ch2; ch >= ch1; ch--) {
1113     // linear extrapolation to chamber
1114     extrapHitForRec =
1115       BegSegment->CreateHitForRecFromLinearExtrapToChamber(ch, mcsFactor);
1116     // limits for the hit index in the loop
1117     iHitMin = fIndexOfFirstHitForRecPerChamber[ch];
1118     iHitMax = iHitMin + fNHitsForRecPerChamber[ch];
1119     // Loop over HitForRec's in the chamber
1120     for (iHit = iHitMin; iHit < iHitMax; iHit++) {
1121       // pointer to HitForRec
1122       hit = (AliMUONHitForRec*) ((*fHitsForRecPtr)[iHit]);
1123       // test compatibility between current HitForRec and "extrapHitForRec"
1124       // 2 because 2 quantities in chi2
1125       if ((hit->
1126            NormalizedChi2WithHitForRec(extrapHitForRec,
1127                                        fMaxSigma2Distance)) <= 2.0) {
1128         // both HitForRec's compatible:
1129         // make track candidate from begSegment and current HitForRec
1130         if (fPrintLevel >= 2)
1131           cout << "TrackCandidate with HitForRec " << iHit <<
1132             " in Chamber(0..) " << ch << endl;
1133         // flag for beginning segments in one track:
1134         // to be done in track constructor ????
1135         BegSegment->SetInTrack(kTRUE);
1136         recTrack = new ((*fRecTracksPtr)[fNRecTracks])
1137           AliMUONTrack(BegSegment, hit, this);
1138         // the right place to eliminate "double counting" ???? how ????
1139         fNRecTracks++;
1140         if (fPrintLevel >= 10) recTrack->RecursiveDump();
1141         // increment number of track candidates
1142         nbCan1Seg1Hit++;
1143       }
1144     } // for (iHit = iHitMin;...
1145     delete extrapHitForRec;
1146   } // for (ch = ch2;...
1147   return nbCan1Seg1Hit;
1148 }
1149
1150   //__________________________________________________________________________
1151 void AliMUONEventReconstructor::MakeTrackCandidates(void)
1152 {
1153   // To make track candidates
1154   // with at least 3 aligned points in stations(1..) 4 and 5
1155   // (two Segment's or one Segment and one HitForRec)
1156   Int_t begStation, iBegSegment, nbCan1Seg1Hit, nbCan2Seg;
1157   AliMUONSegment *begSegment;
1158   if (fPrintLevel >= 1) cout << "enter MakeTrackCandidates" << endl;
1159   // Loop over stations(1..) 5 and 4 for the beginning segment
1160   for (begStation = 4; begStation > 2; begStation--) {
1161     // Loop over segments in the beginning station
1162     for (iBegSegment = 0; iBegSegment < fNSegments[begStation]; iBegSegment++) {
1163       // pointer to segment
1164       begSegment = (AliMUONSegment*) ((*fSegmentsPtr[begStation])[iBegSegment]);
1165       if (fPrintLevel >= 2)
1166         cout << "look for TrackCandidate's with Segment " << iBegSegment <<
1167           " in Station(0..) " << begStation << endl;
1168       // Look for track candidates with two segments,
1169       // "begSegment" and all compatible segments in other station.
1170       // Only for beginning station(1..) 5
1171       // because candidates with 2 segments have to looked for only once.
1172       if (begStation == 4)
1173         nbCan2Seg = MakeTrackCandidatesWithTwoSegments(begSegment);
1174       // Look for track candidates with one segment and one point,
1175       // "begSegment" and all compatible HitForRec's in other station.
1176       // Only if "begSegment" does not belong already to a track candidate.
1177       // Is that a too strong condition ????
1178       if (!(begSegment->GetInTrack()))
1179         nbCan1Seg1Hit = MakeTrackCandidatesWithOneSegmentAndOnePoint(begSegment);
1180     } // for (iBegSegment = 0;...
1181   } // for (begStation = 4;...
1182   return;
1183 }
1184
1185   //__________________________________________________________________________
1186 void AliMUONEventReconstructor::FollowTracks(void)
1187 {
1188   // Follow tracks in stations(1..) 3, 2 and 1
1189   // too long: should be made more modular !!!!
1190   AliMUONHitForRec *bestHit, *extrapHit, *extrapCorrHit, *hit;
1191   AliMUONSegment *bestSegment, *extrapSegment, *extrapCorrSegment, *segment;
1192   AliMUONTrack *track, *nextTrack;
1193   AliMUONTrackParam *trackParam1, trackParam[2], trackParamVertex;
1194   // -1 to avoid compilation warnings
1195   Int_t ch = -1, chInStation, chBestHit = -1, iHit, iSegment, station, trackIndex; 
1196   Double_t bestChi2, chi2, dZ1, dZ2, dZ3, maxSigma2Distance, mcsFactor;
1197   Double_t bendingMomentum, chi2Norm = 0.;
1198   AliMUON *pMUON = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
1199   // local maxSigma2Distance, for easy increase in testing
1200   maxSigma2Distance = fMaxSigma2Distance;
1201   if (fPrintLevel >= 2)
1202     cout << "enter FollowTracks" << endl;
1203   // Loop over track candidates
1204   track = (AliMUONTrack*) fRecTracksPtr->First();
1205   trackIndex = -1;
1206   while (track) {
1207     // Follow function for each track candidate ????
1208     trackIndex++;
1209     nextTrack = (AliMUONTrack*) fRecTracksPtr->After(track); // prepare next track
1210     if (fPrintLevel >= 2)
1211       cout << "FollowTracks: track candidate(0..): " << trackIndex << endl;
1212     // Fit track candidate
1213     track->SetFitMCS(0); // without multiple Coulomb scattering
1214     track->SetFitNParam(3); // with 3 parameters (X = Y = 0)
1215     track->SetFitStart(0); // from parameters at vertex
1216     track->Fit();
1217     if (fPrintLevel >= 10) {
1218       cout << "FollowTracks: track candidate(0..): " << trackIndex
1219            << " after fit in stations(0..) 3 and 4" << endl;
1220       track->RecursiveDump();
1221     }
1222     // Loop over stations(1..) 3, 2 and 1
1223     // something SPECIAL for stations 2 and 1 for majority 3 coincidence ????
1224     // otherwise: majority coincidence 2 !!!!
1225     for (station = 2; station >= 0; station--) {
1226       // Track parameters at first track hit (smallest Z)
1227       trackParam1 = ((AliMUONTrackHit*)
1228                      (track->GetTrackHitsPtr()->First()))->GetTrackParam();
1229       // extrapolation to station
1230       trackParam1->ExtrapToStation(station, trackParam);
1231       extrapSegment = new AliMUONSegment(); //  empty segment
1232       extrapCorrSegment = new AliMUONSegment(); //  empty corrected segment
1233       // multiple scattering factor corresponding to one chamber
1234       // and momentum in bending plane (not total)
1235       mcsFactor = 0.0136 * trackParam1->GetInverseBendingMomentum();
1236       mcsFactor = fChamberThicknessInX0 * mcsFactor * mcsFactor;
1237       // Z difference from previous station
1238       dZ1 = (&(pMUON->Chamber(2 * station)))->Z() -
1239         (&(pMUON->Chamber(2 * station + 2)))->Z();
1240       // Z difference between the two previous stations
1241       dZ2 = (&(pMUON->Chamber(2 * station + 2)))->Z() -
1242         (&(pMUON->Chamber(2 * station + 4)))->Z();
1243       // Z difference between the two chambers in the previous station
1244       dZ3 = (&(pMUON->Chamber(2 * station)))->Z() -
1245         (&(pMUON->Chamber(2 * station + 1)))->Z();
1246       extrapSegment->SetBendingCoorReso2(fBendingResolution * fBendingResolution);
1247       extrapSegment->
1248         SetNonBendingCoorReso2(fNonBendingResolution * fNonBendingResolution);
1249       extrapSegment->UpdateFromStationTrackParam
1250         (trackParam, mcsFactor, dZ1, dZ2, dZ3, station,
1251          trackParam1->GetInverseBendingMomentum());
1252       // same thing for corrected segment
1253       // better to use copy constructor, after checking that it works properly !!!!
1254       extrapCorrSegment->SetBendingCoorReso2(fBendingResolution * fBendingResolution);
1255       extrapCorrSegment->
1256         SetNonBendingCoorReso2(fNonBendingResolution * fNonBendingResolution);
1257       extrapCorrSegment->UpdateFromStationTrackParam
1258         (trackParam, mcsFactor, dZ1, dZ2, dZ3, station,
1259          trackParam1->GetInverseBendingMomentum());
1260       bestChi2 = 5.0;
1261       bestSegment = NULL;
1262       if (fPrintLevel >= 10) {
1263         cout << "FollowTracks: track candidate(0..): " << trackIndex
1264              << " Look for segment in station(0..): " << station << endl;
1265       }
1266       // Loop over segments in station
1267       for (iSegment = 0; iSegment < fNSegments[station]; iSegment++) {
1268         // Look for best compatible Segment in station
1269         // should consider all possibilities ????
1270         // multiple scattering ????
1271         // separation in 2 functions: Segment and HitForRec ????
1272         segment = (AliMUONSegment*) ((*fSegmentsPtr[station])[iSegment]);
1273         // correction of corrected segment (fBendingCoor and fNonBendingCoor)
1274         // according to real Z value of "segment" and slopes of "extrapSegment"
1275         extrapCorrSegment->
1276           SetBendingCoor(extrapSegment->GetBendingCoor() +
1277                          extrapSegment->GetBendingSlope() *
1278                          (segment->GetHitForRec1()->GetZ() -
1279                           (&(pMUON->Chamber(2 * station)))->Z()));
1280         extrapCorrSegment->
1281           SetNonBendingCoor(extrapSegment->GetNonBendingCoor() +
1282                             extrapSegment->GetNonBendingSlope() *
1283                             (segment->GetHitForRec1()->GetZ() -
1284                              (&(pMUON->Chamber(2 * station)))->Z()));
1285         chi2 = segment->
1286           NormalizedChi2WithSegment(extrapCorrSegment, maxSigma2Distance);
1287         if (chi2 < bestChi2) {
1288           // update best Chi2 and Segment if better found
1289           bestSegment = segment;
1290           bestChi2 = chi2;
1291         }
1292       }
1293       if (bestSegment) {
1294         // best segment found: add it to track candidate
1295         track->AddSegment(bestSegment);
1296         // set track parameters at these two TrakHit's
1297         track->SetTrackParamAtHit(track->GetNTrackHits() - 2, &(trackParam[0]));
1298         track->SetTrackParamAtHit(track->GetNTrackHits() - 1, &(trackParam[1]));
1299         if (fPrintLevel >= 10) {
1300           cout << "FollowTracks: track candidate(0..): " << trackIndex
1301                << " Added segment in station(0..): " << station << endl;
1302           track->RecursiveDump();
1303         }
1304       }
1305       else {
1306         // No best segment found:
1307         // Look for best compatible HitForRec in station:
1308         // should consider all possibilities ????
1309         // multiple scattering ???? do about like for extrapSegment !!!!
1310         extrapHit = new AliMUONHitForRec(); //  empty hit
1311         extrapCorrHit = new AliMUONHitForRec(); //  empty corrected hit
1312         bestChi2 = 3.0;
1313         bestHit = NULL;
1314         if (fPrintLevel >= 10) {
1315           cout << "FollowTracks: track candidate(0..): " << trackIndex
1316                << " Segment not found, look for hit in station(0..): " << station
1317                << endl;
1318         }
1319         // Loop over chambers of the station
1320         for (chInStation = 0; chInStation < 2; chInStation++) {
1321           // coordinates of extrapolated hit
1322           extrapHit->
1323             SetBendingCoor((&(trackParam[chInStation]))->GetBendingCoor());
1324           extrapHit->
1325             SetNonBendingCoor((&(trackParam[chInStation]))->GetNonBendingCoor());
1326           // resolutions from "extrapSegment"
1327           extrapHit->SetBendingReso2(extrapSegment->GetBendingCoorReso2());
1328           extrapHit->SetNonBendingReso2(extrapSegment->GetNonBendingCoorReso2());
1329           // same things for corrected hit
1330           // better to use copy constructor, after checking that it works properly !!!!
1331           extrapCorrHit->
1332             SetBendingCoor((&(trackParam[chInStation]))->GetBendingCoor());
1333           extrapCorrHit->
1334             SetNonBendingCoor((&(trackParam[chInStation]))->GetNonBendingCoor());
1335           extrapHit->SetBendingReso2(extrapSegment->GetBendingCoorReso2());
1336           extrapHit->SetNonBendingReso2(extrapSegment->GetNonBendingCoorReso2());
1337           // Loop over hits in the chamber
1338           ch = 2 * station + chInStation;
1339           for (iHit = fIndexOfFirstHitForRecPerChamber[ch];
1340                iHit < fIndexOfFirstHitForRecPerChamber[ch] +
1341                  fNHitsForRecPerChamber[ch];
1342                iHit++) {
1343             hit = (AliMUONHitForRec*) ((*fHitsForRecPtr)[iHit]);
1344             // correction of corrected hit (fBendingCoor and fNonBendingCoor)
1345             // according to real Z value of "hit" and slopes of right "trackParam"
1346             extrapCorrHit->
1347               SetBendingCoor((&(trackParam[chInStation]))->GetBendingCoor() +
1348                              (&(trackParam[chInStation]))->GetBendingSlope() *
1349                              (hit->GetZ() -
1350                               (&(trackParam[chInStation]))->GetZ()));
1351             extrapCorrHit->
1352               SetNonBendingCoor((&(trackParam[chInStation]))->GetNonBendingCoor() +
1353                                 (&(trackParam[chInStation]))->GetNonBendingSlope() *
1354                                 (hit->GetZ() -
1355                                  (&(trackParam[chInStation]))->GetZ()));
1356             // condition for hit not already in segment ????
1357             chi2 = hit->NormalizedChi2WithHitForRec(extrapHit, maxSigma2Distance);
1358             if (chi2 < bestChi2) {
1359               // update best Chi2 and HitForRec if better found
1360               bestHit = hit;
1361               bestChi2 = chi2;
1362               chBestHit = chInStation;
1363             }
1364           }
1365         }
1366         if (bestHit) {
1367           // best hit found: add it to track candidate
1368           track->AddHitForRec(bestHit);
1369           // set track parameters at this TrackHit
1370           track->SetTrackParamAtHit(track->GetNTrackHits() - 1,
1371                                     &(trackParam[chBestHit]));
1372           if (fPrintLevel >= 10) {
1373             cout << "FollowTracks: track candidate(0..): " << trackIndex
1374                  << " Added hit in station(0..): " << station << endl;
1375             track->RecursiveDump();
1376           }
1377         }
1378         else {
1379           // Remove current track candidate
1380           // and corresponding TrackHit's, ...
1381           track->Remove();
1382           delete extrapSegment;
1383           delete extrapCorrSegment;
1384           delete extrapHit;
1385           delete extrapCorrHit;
1386           break; // stop the search for this candidate:
1387           // exit from the loop over station
1388         }
1389         delete extrapHit;
1390         delete extrapCorrHit;
1391       }
1392       delete extrapSegment;
1393       delete extrapCorrSegment;
1394       // Sort track hits according to increasing Z
1395       track->GetTrackHitsPtr()->Sort();
1396       // Update track parameters at first track hit (smallest Z)
1397       trackParam1 = ((AliMUONTrackHit*)
1398                      (track->GetTrackHitsPtr()->First()))->GetTrackParam();
1399       bendingMomentum = 0.;
1400       if (TMath::Abs(trackParam1->GetInverseBendingMomentum()) > 0.)
1401         bendingMomentum = TMath::Abs(1/(trackParam1->GetInverseBendingMomentum()));
1402       // Track removed if bendingMomentum not in window [min, max]
1403       if ((bendingMomentum < fMinBendingMomentum) || (bendingMomentum > fMaxBendingMomentum)) {
1404         track->Remove();
1405         break; // stop the search for this candidate:
1406         // exit from the loop over station 
1407       }
1408       // Track fit
1409       // with multiple Coulomb scattering if all stations
1410       if (station == 0) track->SetFitMCS(1);
1411       // without multiple Coulomb scattering if not all stations
1412       else track->SetFitMCS(0);
1413       track->SetFitNParam(5);  // with 5 parameters (momentum and position)
1414       track->SetFitStart(1);  // from parameters at first hit
1415       track->Fit();
1416       Double_t numberOfDegFree = (2.0 * track->GetNTrackHits() - 5);
1417       if (numberOfDegFree > 0) {
1418         chi2Norm =  track->GetFitFMin() / numberOfDegFree;
1419       } else {
1420         chi2Norm = 1.e10;
1421       }
1422       // Track removed if normalized chi2 too high
1423       if (chi2Norm > fMaxChi2) {
1424         track->Remove();
1425         break; // stop the search for this candidate:
1426         // exit from the loop over station 
1427       }
1428       if (fPrintLevel >= 10) {
1429         cout << "FollowTracks: track candidate(0..): " << trackIndex
1430              << " after fit from station(0..): " << station << " to 4" << endl;
1431         track->RecursiveDump();
1432       }
1433       // Track extrapolation to the vertex through the absorber (Branson)
1434       // after going through the first station
1435       if (station == 0) {
1436         trackParamVertex = *trackParam1;
1437         (&trackParamVertex)->ExtrapToVertex();
1438         track->SetTrackParamAtVertex(&trackParamVertex);
1439         if (fPrintLevel >= 1) {
1440           cout << "FollowTracks: track candidate(0..): " << trackIndex
1441                << " after extrapolation to vertex" << endl;
1442           track->RecursiveDump();
1443         }
1444       }
1445     } // for (station = 2;...
1446     // go really to next track
1447     track = nextTrack;
1448   } // while (track)
1449   // Compression of track array (necessary after Remove ????)
1450   fRecTracksPtr->Compress();
1451   return;
1452 }
1453
1454   //__________________________________________________________________________
1455 void AliMUONEventReconstructor::RemoveDoubleTracks(void)
1456 {
1457   // To remove double tracks.
1458   // Tracks are considered identical
1459   // if they have at least half of their hits in common.
1460   // Among two identical tracks, one keeps the track with the larger number of hits
1461   // or, if these numbers are equal, the track with the minimum Chi2.
1462   AliMUONTrack *track1, *track2, *trackToRemove;
1463   Bool_t identicalTracks;
1464   Int_t hitsInCommon, nHits1, nHits2;
1465   identicalTracks = kTRUE;
1466   while (identicalTracks) {
1467     identicalTracks = kFALSE;
1468     // Loop over first track of the pair
1469     track1 = (AliMUONTrack*) fRecTracksPtr->First();
1470     while (track1 && (!identicalTracks)) {
1471       nHits1 = track1->GetNTrackHits();
1472       // Loop over second track of the pair
1473       track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
1474       while (track2 && (!identicalTracks)) {
1475         nHits2 = track2->GetNTrackHits();
1476         // number of hits in common between two tracks
1477         hitsInCommon = track1->HitsInCommon(track2);
1478         // check for identical tracks
1479         if ((4 * hitsInCommon) >= (nHits1 + nHits2)) {
1480           identicalTracks = kTRUE;
1481           // decide which track to remove
1482           if (nHits1 > nHits2) trackToRemove = track2;
1483           else if (nHits1 < nHits2) trackToRemove = track1;
1484           else if ((track1->GetFitFMin()) < (track2->GetFitFMin()))
1485             trackToRemove = track2;
1486           else trackToRemove = track1;
1487           // remove it
1488           trackToRemove->Remove();
1489         }
1490         track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
1491       } // track2
1492       track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
1493     } // track1
1494   }
1495   return;
1496 }
1497
1498   //__________________________________________________________________________
1499 void AliMUONEventReconstructor::EventDump(void)
1500 {
1501   // Dump reconstructed event (track parameters at vertex and at first hit),
1502   // and the particle parameters
1503
1504   AliMUONTrack *track;
1505   AliMUONTrackParam *trackParam, *trackParam1;
1506   Double_t bendingSlope, nonBendingSlope, pYZ;
1507   Double_t pX, pY, pZ, x, y, z, c;
1508   Int_t np, trackIndex, nTrackHits;
1509  
1510   if (fPrintLevel >= 1) cout << "****** enter EventDump ******" << endl;
1511   if (fPrintLevel >= 1) {
1512     cout << " Number of Reconstructed tracks :" <<  fNRecTracks << endl; 
1513   }
1514   fRecTracksPtr->Compress(); // for simple loop without "Next" since no hole
1515   // Loop over reconstructed tracks
1516   for (trackIndex = 0; trackIndex < fNRecTracks; trackIndex++) {
1517     if (fTrackMethod != 1) continue; //AZ - skip the rest for now
1518     if (fPrintLevel >= 1)
1519       cout << " track number: " << trackIndex << endl;
1520     // function for each track for modularity ????
1521     track = (AliMUONTrack*) ((*fRecTracksPtr)[trackIndex]);
1522     nTrackHits = track->GetNTrackHits();
1523     if (fPrintLevel >= 1)
1524       cout << " number of track hits: " << nTrackHits << endl;
1525     // track parameters at Vertex
1526     trackParam = track->GetTrackParamAtVertex();
1527     x = trackParam->GetNonBendingCoor();
1528     y = trackParam->GetBendingCoor();
1529     z = trackParam->GetZ();
1530     bendingSlope = trackParam->GetBendingSlope();
1531     nonBendingSlope = trackParam->GetNonBendingSlope();
1532     pYZ = 1/TMath::Abs(trackParam->GetInverseBendingMomentum());
1533     pZ = pYZ/TMath::Sqrt(1+bendingSlope*bendingSlope);
1534     pX = pZ * nonBendingSlope;
1535     pY = pZ * bendingSlope;
1536     c = TMath::Sign(1.0, trackParam->GetInverseBendingMomentum());
1537     if (fPrintLevel >= 1)
1538       printf(" track parameters at Vertex z= %f: X= %f Y= %f pX= %f pY= %f pZ= %f c= %f\n",
1539              z, x, y, pX, pY, pZ, c);
1540
1541     // track parameters at first hit
1542     trackParam1 = ((AliMUONTrackHit*)
1543                    (track->GetTrackHitsPtr()->First()))->GetTrackParam();
1544     x = trackParam1->GetNonBendingCoor();
1545     y = trackParam1->GetBendingCoor();
1546     z = trackParam1->GetZ();
1547     bendingSlope = trackParam1->GetBendingSlope();
1548     nonBendingSlope = trackParam1->GetNonBendingSlope();
1549     pYZ = 1/TMath::Abs(trackParam1->GetInverseBendingMomentum());
1550     pZ = pYZ/TMath::Sqrt(1.0 + bendingSlope * bendingSlope);
1551     pX = pZ * nonBendingSlope;
1552     pY = pZ * bendingSlope;
1553     c = TMath::Sign(1.0, trackParam1->GetInverseBendingMomentum());
1554     if (fPrintLevel >= 1)
1555       printf(" track parameters at z= %f: X= %f Y= %f pX= %f pY= %f pZ= %f c= %f\n",
1556              z, x, y, pX, pY, pZ, c);
1557   }
1558   // informations about generated particles
1559   np = gAlice->GetMCApp()->GetNtrack();
1560   printf(" **** number of generated particles: %d  \n", np);
1561   
1562 //    for (Int_t iPart = 0; iPart < np; iPart++) {
1563 //      p = gAlice->Particle(iPart);
1564 //      printf(" particle %d: type= %d px= %f py= %f pz= %f pdg= %d\n",
1565 //         iPart, p->GetPdgCode(), p->Px(), p->Py(), p->Pz(), p->GetPdgCode());    
1566 //    }
1567   return;
1568 }
1569
1570
1571 //__________________________________________________________________________
1572 void AliMUONEventReconstructor::EventDumpTrigger(void)
1573 {
1574   // Dump reconstructed trigger event 
1575   // and the particle parameters
1576     
1577   AliMUONTriggerTrack *triggertrack;
1578   Int_t trackIndex;
1579  
1580   if (fPrintLevel >= 1) cout << "****** enter EventDumpTrigger ******" << endl;
1581   if (fPrintLevel >= 1) {
1582       cout << " Number of Reconstructed tracks :" <<  fNRecTriggerTracks << endl;
1583   }
1584   // Loop over reconstructed tracks
1585   for (trackIndex = 0; trackIndex < fNRecTriggerTracks; trackIndex++) {
1586       triggertrack = (AliMUONTriggerTrack*) ((*fRecTriggerTracksPtr)[trackIndex]);
1587       printf(" trigger track number %i x11=%f y11=%f thetax=%f thetay=%f \n",
1588              trackIndex,
1589              triggertrack->GetX11(),triggertrack->GetY11(),
1590              triggertrack->GetThetax(),triggertrack->GetThetay());      
1591   } 
1592 }
1593
1594 //__________________________________________________________________________
1595 void AliMUONEventReconstructor::FillEvent()
1596 {
1597 // Create a new AliMUONRecoEvent, fill its track list, then add it as a
1598 // leaf in the Event branch of TreeRecoEvent tree
1599    cout << "Enter FillEvent() ...\n";
1600
1601    if (!fRecoEvent) {
1602       fRecoEvent = new AliMUONRecoEvent();
1603    } else {
1604       fRecoEvent->Clear();
1605    }
1606    //save current directory
1607    TDirectory *current =  gDirectory;
1608    if (!fTreeFile)  fTreeFile  = new TFile("tree_reco.root", "RECREATE");
1609    if (!fEventTree) fEventTree = new TTree("TreeRecoEvent", "MUON reconstructed events");
1610    //AZif (fRecoEvent->MakeDumpTracks(fRecTracksPtr)) {
1611    if (fRecoEvent->MakeDumpTracks(fMuons, fRecTracksPtr, this)) { //AZ
1612       if (fPrintLevel > 1) fRecoEvent->EventInfo();
1613       TBranch *branch = fEventTree->GetBranch("Event");
1614       if (!branch) branch = fEventTree->Branch("Event", "AliMUONRecoEvent", &fRecoEvent, 64000);
1615       branch->SetAutoDelete();
1616       fTreeFile->cd();
1617       fEventTree->Fill();
1618       fTreeFile->Write();
1619    }
1620    // restore directory
1621    current->cd();
1622 }
1623
1624 //__________________________________________________________________________
1625 void AliMUONEventReconstructor::MakeTrackCandidatesK(void)
1626 {
1627   // To make initial tracks for Kalman filter from the list of segments
1628   Int_t istat, iseg;
1629   AliMUONSegment *segment;
1630   AliMUONTrackK *trackK;
1631
1632   if (fPrintLevel >= 1) cout << "enter MakeTrackCandidatesK" << endl;
1633   // Reset the TClonesArray of reconstructed tracks
1634   if (fRecTracksPtr) fRecTracksPtr->Delete();
1635   // Delete in order that the Track destructors are called,
1636   // hence the space for the TClonesArray of pointers to TrackHit's is freed
1637   fNRecTracks = 0;
1638
1639   AliMUONTrackK a(this, fHitsForRecPtr); // bad idea ???
1640   // Loop over stations(1...) 5 and 4
1641   for (istat=4; istat>=3; istat--) {
1642     // Loop over segments in the station
1643     for (iseg=0; iseg<fNSegments[istat]; iseg++) {
1644       // Transform segments to tracks and evaluate covariance matrix
1645       segment = (AliMUONSegment*) ((*fSegmentsPtr[istat])[iseg]);
1646       trackK = new ((*fRecTracksPtr)[fNRecTracks]) AliMUONTrackK(segment);
1647       fNRecTracks++;
1648     } // for (iseg=0;...)
1649   } // for (istat=4;...)
1650   return;
1651 }
1652
1653 //__________________________________________________________________________
1654 void AliMUONEventReconstructor::FollowTracksK(void)
1655 {
1656   // Follow tracks using Kalman filter
1657   Bool_t Ok;
1658   Int_t icand, ichamBeg, ichamEnd, chamBits;
1659   Double_t zDipole1, zDipole2;
1660   AliMUONTrackK *trackK;
1661   AliMUONHitForRec *hit;
1662   AliMUONRawCluster *clus;
1663   TClonesArray *rawclusters;
1664   AliMUON *pMUON;
1665   clus = 0; rawclusters = 0;
1666
1667   zDipole1 = GetSimpleBPosition() - GetSimpleBLength()/2;
1668   zDipole2 = zDipole1 + GetSimpleBLength();
1669
1670   // Print hits
1671   pMUON  = (AliMUON*) gAlice->GetModule("MUON");
1672   for (Int_t i1=0; i1<fNHitsForRec; i1++) {
1673     hit = (AliMUONHitForRec*) ((*fHitsForRecPtr)[i1]);
1674     //if (hit->GetTHTrack() > 1 || hit->GetGeantSignal() == 0) continue;
1675     /*
1676     cout << " Hit #" << hit->GetChamberNumber() << " ";
1677     cout << hit->GetBendingCoor() << " ";
1678     cout << hit->GetNonBendingCoor() << " ";
1679     cout << hit->GetZ() << " ";
1680     cout << hit->GetGeantSignal() << " ";
1681     cout << hit->GetTHTrack() << endl;
1682     */
1683     /*
1684     printf(" Hit # %d %10.4f %10.4f %10.4f",
1685            hit->GetChamberNumber(), hit->GetBendingCoor(),
1686            hit->GetNonBendingCoor(), hit->GetZ());
1687     if (fRecGeantHits) {
1688       // from GEANT hits
1689       printf(" %3d %3d \n", hit->GetGeantSignal(), hit->GetTHTrack());
1690     } else {
1691       // from raw clusters
1692       rawclusters = pMUON->RawClustAddress(hit->GetChamberNumber());
1693       clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(hit->
1694                                                GetHitNumber());
1695       printf("%3d", clus->fTracks[1]-1);
1696       if (clus->fTracks[2] != 0) printf("%3d \n", clus->fTracks[2]-1);
1697       else printf("\n");
1698     }
1699     */
1700   }
1701
1702   icand = -1;
1703   Int_t nSeeds = fNRecTracks; // starting number of seeds
1704   // Loop over track candidates
1705   while (icand < fNRecTracks-1) {
1706     icand ++;
1707     trackK = (AliMUONTrackK*) ((*fRecTracksPtr)[icand]);
1708
1709     // Discard candidate which will produce the double track
1710     if (icand > 0) {
1711       Ok = CheckCandidateK(icand,nSeeds);
1712       if (!Ok) {
1713         //trackK->SetRecover(-1); // mark candidate to be removed
1714         //continue;
1715       }
1716     }
1717
1718     Ok = kTRUE;
1719     if (trackK->GetRecover() == 0) hit = (AliMUONHitForRec*) 
1720                                    trackK->GetHitOnTrack()->Last(); // last hit
1721     else hit = (AliMUONHitForRec*) (*trackK->GetHitOnTrack())[1]; // 2'nd hit
1722     ichamBeg = hit->GetChamberNumber();
1723     ichamEnd = 0;
1724     // Check propagation direction
1725     if (trackK->GetTrackDir() > 0) {
1726       ichamEnd = 9; // forward propagation
1727       Ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kFALSE,zDipole1,zDipole2);
1728       if (Ok) {
1729         ichamBeg = ichamEnd;
1730         ichamEnd = 6; // backward propagation
1731         // Change weight matrix and zero fChi2 for backpropagation
1732         trackK->StartBack();
1733         Ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kTRUE,zDipole1,zDipole2);
1734         ichamBeg = ichamEnd;
1735         ichamEnd = 0;
1736       }
1737     } else {
1738       if (trackK->GetBPFlag()) {
1739         // backpropagation
1740         ichamEnd = 6; // backward propagation
1741         // Change weight matrix and zero fChi2 for backpropagation
1742         trackK->StartBack();
1743         Ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kTRUE,zDipole1,zDipole2);
1744         ichamBeg = ichamEnd;
1745         ichamEnd = 0;
1746       }
1747     }
1748
1749     if (Ok) {
1750       trackK->SetTrackDir(-1);
1751       trackK->SetBPFlag(kFALSE);
1752       Ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kFALSE,zDipole1,zDipole2);
1753     }
1754     if (Ok) trackK->SetTrackQuality(0); // compute "track quality"
1755     else trackK->SetRecover(-1); // mark candidate to be removed
1756
1757     // Majority 3 of 4 in first 2 stations
1758     chamBits = 0;
1759     for (Int_t i=0; i<trackK->GetNTrackHits(); i++) {
1760       hit = (AliMUONHitForRec*) (*trackK->GetHitOnTrack())[i];
1761       chamBits |= BIT(hit->GetChamberNumber()-1);
1762     }
1763     //if (!((chamBits&3)==3 || (chamBits>>2&3)==3)) trackK->SetRecover(-1); 
1764                                  //mark candidate to be removed
1765   } // while
1766
1767   for (Int_t i=0; i<fNRecTracks; i++) {
1768     trackK = (AliMUONTrackK*) ((*fRecTracksPtr)[i]);
1769     if (trackK->GetRecover() < 0) fRecTracksPtr->RemoveAt(i);
1770   }
1771
1772   // Compress TClonesArray
1773   fRecTracksPtr->Compress();
1774   fNRecTracks = fRecTracksPtr->GetEntriesFast();
1775   return;
1776 }
1777
1778 //__________________________________________________________________________
1779 Bool_t AliMUONEventReconstructor::CheckCandidateK(Int_t icand, Int_t nSeeds)
1780 {
1781   // Discards track candidate if it will produce the double track (having
1782   // the same seed segment hits as hits of a good track found before)
1783   AliMUONTrackK *track1, *track2;
1784   AliMUONHitForRec *hit1, *hit2, *hit;
1785
1786   track1 = (AliMUONTrackK*) ((*fRecTracksPtr)[icand]);
1787   hit1 = (AliMUONHitForRec*) (*track1->GetHitOnTrack())[0]; // 1'st hit
1788   hit2 = (AliMUONHitForRec*) (*track1->GetHitOnTrack())[1]; // 2'nd hit
1789
1790   for (Int_t i=0; i<icand; i++) {
1791     track2 = (AliMUONTrackK*) ((*fRecTracksPtr)[i]);
1792     //if (track2->GetRecover() < 0) continue;
1793     if (track2->GetRecover() < 0 && icand >= nSeeds) continue;
1794
1795     if (track1->GetStartSegment() == track2->GetStartSegment()) {
1796       return kFALSE;
1797     } else {
1798       Int_t nSame = 0;
1799       for (Int_t j=0; j<track2->GetNTrackHits(); j++) {
1800         hit = (AliMUONHitForRec*) (*track2->GetHitOnTrack())[j];
1801         if (hit == hit1 || hit == hit2) {
1802           nSame++;
1803           if (nSame == 2) return kFALSE;
1804         }
1805       } // for (Int_t j=0;
1806     }
1807   } // for (Int_t i=0;
1808   return kTRUE;
1809 }
1810
1811 //__________________________________________________________________________
1812 void AliMUONEventReconstructor::RemoveDoubleTracksK(void)
1813 {
1814   // Removes double tracks (sharing more than half of their hits). Keeps
1815   // the track with higher quality
1816   AliMUONTrackK *track1, *track2, *trackToKill;
1817
1818   // Sort tracks according to their quality
1819   fRecTracksPtr->Sort();
1820
1821   // Loop over first track of the pair
1822   track1 = (AliMUONTrackK*) fRecTracksPtr->First();
1823   while (track1) {
1824     // Loop over second track of the pair
1825     track2 = (AliMUONTrackK*) fRecTracksPtr->After(track1);
1826     while (track2) {
1827       // Check whether or not to keep track2
1828       if (!track2->KeepTrack(track1)) {
1829         cout << " Killed track: " << 1/(*track2->GetTrackParameters())(4,0) <<
1830           " " << track2->GetTrackQuality() << endl;
1831         trackToKill = track2;
1832         track2 = (AliMUONTrackK*) fRecTracksPtr->After(track2);
1833         trackToKill->Kill();
1834         fRecTracksPtr->Compress();
1835       } else track2 = (AliMUONTrackK*) fRecTracksPtr->After(track2);
1836     } // track2
1837     track1 = (AliMUONTrackK*) fRecTracksPtr->After(track1);
1838   } // track1
1839
1840   fNRecTracks = fRecTracksPtr->GetEntriesFast();
1841   cout << " Number of Kalman tracks: " << fNRecTracks << endl;
1842 }
1843
1844 //__________________________________________________________________________
1845 void AliMUONEventReconstructor::GoToVertex(void)
1846 {
1847   // Propagates track to the vertex thru absorber
1848   // (using Branson correction for now)
1849
1850   Double_t zVertex;
1851   zVertex = 0;
1852   for (Int_t i=0; i<fNRecTracks; i++) {
1853     //((AliMUONTrackK*)(*fRecTracksPtr)[i])->Branson();
1854     //((AliMUONTrackK*)(*fRecTracksPtr)[i])->GoToZ(zVertex); // w/out absorber
1855     ((AliMUONTrackK*)(*fRecTracksPtr)[i])->SetTrackQuality(1); // compute Chi2
1856     ((AliMUONTrackK*)(*fRecTracksPtr)[i])->GoToVertex(); // with absorber
1857   }
1858 }