682733d19603019c25baa5275a40a57d65e8f0bf
[u/mrichter/AliRoot.git] / MUON / AliMUONVTrackReconstructor.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 //-----------------------------------------------------------------------------
19 /// \class AliMUONVTrackReconstructor
20 /// Virtual MUON track reconstructor in ALICE (class renamed from AliMUONEventReconstructor)
21 ///
22 /// This class contains as data:
23 /// * a pointer to the array of hits to be reconstructed (the event)
24 /// * a pointer to the array of reconstructed tracks
25 ///
26 /// It contains as methods, among others:
27 /// * EventReconstruct to build the muon tracks
28 /// * EventReconstructTrigger to build the trigger tracks
29 ///
30 /// Several options and adjustable parameters are available for both Kalman and Original
31 /// tracking algorithms (hard coded for the moment in AliMUONVTrackReconstructor.cxx):
32 /// - *fgkSigmaToCutForTracking* : quality cut used to select new clusters to be
33 ///   attached to the track candidate and to select good tracks.
34 /// - *fgkMakeTrackCandidatesFast* : if this flag is set to 'true', the track candidates
35 ///   are made assuming linear propagation between stations 4 and 5.
36 /// - *fgkTrackAllTracks* : according to the value of this flag, in case that several
37 ///   new clusters pass the quality cut, either we consider all the possibilities
38 ///   (duplicating tracks) or we attach only the best cluster.
39 /// - *fgkRecoverTracks* : if this flag is set to 'true', we try to recover the tracks
40 ///   lost during the tracking by removing the worst of the 2 clusters attached in the
41 ///   previous station.
42 /// - *fgkImproveTracks* : if this flag is set to 'true', we try to improve the quality
43 ///   of the tracks at the end of the tracking by removing clusters that do not pass
44 ///   new quality cut (the track is removed is it does not contain enough cluster anymore).
45 /// - *fgkComplementTracks* : if this flag is set to 'true', we try to improve the quality
46 ///   of the tracks at the end of the tracking by adding potentially missing clusters
47 ///   (we may have 2 clusters in the same chamber because of the overlapping of detection
48 ///   elements, which is not handle by the tracking algorithm).
49 /// - *fgkSigmaToCutForImprovement* : quality cut used when we try to improve the
50 ///   quality of the tracks.
51 ///
52 ///  \author Philippe Pillot
53 //-----------------------------------------------------------------------------
54
55 #include "AliMUONVTrackReconstructor.h"
56
57 #include "AliMUONConstants.h"
58 #include "AliMUONHitForRec.h"
59 #include "AliMUONObjectPair.h"
60 #include "AliMUONTriggerTrack.h"
61 #include "AliMUONTriggerCircuit.h"
62 #include "AliMUONLocalTrigger.h"
63 #include "AliMUONGlobalTrigger.h"
64 #include "AliMUONTrack.h"
65 #include "AliMUONTrackParam.h"
66 #include "AliMUONTrackExtrap.h"
67 #include "AliMUONTrackHitPattern.h"
68 #include "AliMUONVTrackStore.h"
69 #include "AliMUONVClusterStore.h"
70 #include "AliMUONVCluster.h"
71 #include "AliMUONVTriggerStore.h"
72 #include "AliMUONVTriggerTrackStore.h"
73 #include "AliMpDEManager.h"
74
75 #include "AliLog.h"
76 #include "AliCodeTimer.h"
77 #include "AliTracker.h"
78
79 #include <TClonesArray.h>
80 #include <TMath.h>
81 #include <TMatrixD.h>
82
83 #include <Riostream.h>
84
85 /// \cond CLASSIMP
86 ClassImp(AliMUONVTrackReconstructor) // Class implementation in ROOT context
87 /// \endcond
88
89   //__________________________________________________________________________
90 AliMUONVTrackReconstructor::AliMUONVTrackReconstructor()
91   : TObject(),
92     fHitsForRecPtr(0x0),
93     fNHitsForRec(0),
94     fNHitsForRecPerChamber(0x0),
95     fIndexOfFirstHitForRecPerChamber(0x0),
96     fRecTracksPtr(0x0),
97     fNRecTracks(0)
98 {
99   /// Constructor for class AliMUONVTrackReconstructor
100   fNHitsForRecPerChamber = new Int_t[AliMUONConstants::NTrackingCh()];
101   fIndexOfFirstHitForRecPerChamber = new Int_t[AliMUONConstants::NTrackingCh()];
102
103   // Memory allocation for the TClonesArray of hits for reconstruction
104   // Is 10000 the right size ????
105   fHitsForRecPtr = new TClonesArray("AliMUONHitForRec", 10000);
106   
107   // Memory allocation for the TClonesArray of reconstructed tracks
108   fRecTracksPtr = new TClonesArray("AliMUONTrack", 10);
109   
110   // set the magnetic field for track extrapolations
111   const AliMagF* kField = AliTracker::GetFieldMap();
112   if (!kField) AliFatal("No field available");
113   AliMUONTrackExtrap::SetField(kField);
114 }
115
116   //__________________________________________________________________________
117 AliMUONVTrackReconstructor::~AliMUONVTrackReconstructor()
118 {
119   /// Destructor for class AliMUONVTrackReconstructor
120   delete [] fNHitsForRecPerChamber;
121   delete [] fIndexOfFirstHitForRecPerChamber;
122   delete fHitsForRecPtr;
123   delete fRecTracksPtr;
124 }
125
126   //__________________________________________________________________________
127 void AliMUONVTrackReconstructor::ResetHitsForRec()
128 {
129   /// To reset the TClonesArray of HitsForRec,
130   /// and the number of HitForRec and the index of the first HitForRec per chamber
131   if (fHitsForRecPtr) fHitsForRecPtr->Clear("C");
132   fNHitsForRec = 0;
133   for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
134     fNHitsForRecPerChamber[ch] = 0;
135     fIndexOfFirstHitForRecPerChamber[ch] = 0;
136   }
137 }
138
139   //__________________________________________________________________________
140 void AliMUONVTrackReconstructor::ResetTracks()
141 {
142   /// To reset the TClonesArray of reconstructed tracks
143   if (fRecTracksPtr) fRecTracksPtr->Clear("C");
144   fNRecTracks = 0;
145   return;
146 }
147
148   //__________________________________________________________________________
149 void AliMUONVTrackReconstructor::EventReconstruct(const AliMUONVClusterStore& clusterStore, AliMUONVTrackStore& trackStore)
150 {
151   /// To reconstruct one event
152   AliDebug(1,"");
153   AliCodeTimerAuto("");
154   
155   ResetTracks();
156   ResetHitsForRec();
157   AddHitsForRecFromRawClusters(clusterStore);
158   MakeTracks();
159
160   // Add tracks to MUON data container 
161   for (Int_t i=0; i<fNRecTracks; ++i) 
162   {
163     AliMUONTrack * track = (AliMUONTrack*) fRecTracksPtr->At(i);
164     trackStore.Add(*track);
165   }
166 }
167
168   //__________________________________________________________________________
169 void AliMUONVTrackReconstructor::AddHitsForRecFromRawClusters(const AliMUONVClusterStore& clusterStore)
170 {
171   /// Build internal array of hit for rec from clusterStore
172   
173   AliMUONVCluster* clus(0x0);
174   Int_t iclus(0);
175   
176   TIter next(clusterStore.CreateIterator());
177   
178   while ( ( clus = static_cast<AliMUONVCluster*>(next()) ) )
179   {
180     // new AliMUONHitForRec from raw cluster
181     // and increment number of AliMUONHitForRec's (total and in chamber)
182     AliMUONHitForRec* hitForRec = new ((*fHitsForRecPtr)[fNHitsForRec]) AliMUONHitForRec(clus);
183     fNHitsForRec++;
184     // more information into HitForRec
185     hitForRec->SetNonBendingReso2(clus->GetErrX2());
186     hitForRec->SetBendingReso2(clus->GetErrY2());
187     //  original raw cluster
188     Int_t ch = AliMpDEManager::GetChamberId(clus->GetDetElemId());
189     hitForRec->SetChamberNumber(ch);
190     hitForRec->SetHitNumber(iclus);
191     // Z coordinate of the raw cluster (cm)
192     hitForRec->SetZ(clus->GetZ());
193     if (AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 3) {
194       cout << "Chamber " << ch <<" raw cluster  " << iclus << " : " << endl;
195       clus->Print("full");
196       cout << "AliMUONHitForRec number (1...): " << fNHitsForRec << endl;
197       hitForRec->Print("full");
198     }
199     ++iclus;
200   } // end of chamber loop
201   
202   SortHitsForRecWithIncreasingChamber(); 
203   
204   AliDebug(1,"End of AddHitsForRecFromRawClusters");
205   
206   if (AliLog::GetGlobalDebugLevel() > 0) 
207   {
208     AliDebug(1, Form("NHitsForRec: %d",fNHitsForRec));
209     for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) 
210     {
211       AliDebug(1, Form("Chamber(0...): %d",ch));
212       AliDebug(1, Form("NHitsForRec: %d", fNHitsForRecPerChamber[ch]));
213       AliDebug(1, Form("Index(first HitForRec): %d", fIndexOfFirstHitForRecPerChamber[ch]));
214       for (Int_t hit = fIndexOfFirstHitForRecPerChamber[ch];
215            hit < fIndexOfFirstHitForRecPerChamber[ch] + fNHitsForRecPerChamber[ch];
216            hit++) {
217         AliDebug(1, Form("HitForRec index(0...): %d",hit));
218         ((*fHitsForRecPtr)[hit])->Dump();
219       }
220     }
221   }
222 }
223
224   //__________________________________________________________________________
225 void AliMUONVTrackReconstructor::SortHitsForRecWithIncreasingChamber()
226 {
227   /// Sort HitsForRec's in increasing order with respect to chamber number.
228   /// Uses the function "Compare".
229   /// Update the information for HitsForRec per chamber too.
230   Int_t ch, nhits, prevch;
231   fHitsForRecPtr->Sort();
232   for (ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
233     fNHitsForRecPerChamber[ch] = 0;
234     fIndexOfFirstHitForRecPerChamber[ch] = 0;
235   }
236   prevch = 0; // previous chamber
237   nhits = 0; // number of hits in current chamber
238   // Loop over HitsForRec
239   for (Int_t hit = 0; hit < fNHitsForRec; hit++) {
240     // chamber number (0...)
241     ch = ((AliMUONHitForRec*)  ((*fHitsForRecPtr)[hit]))->GetChamberNumber();
242     // increment number of hits in current chamber
243     (fNHitsForRecPerChamber[ch])++;
244     // update index of first HitForRec in current chamber
245     // if chamber number different from previous one
246     if (ch != prevch) {
247       fIndexOfFirstHitForRecPerChamber[ch] = hit;
248       prevch = ch;
249     }
250   }
251   return;
252 }
253
254   //__________________________________________________________________________
255 void AliMUONVTrackReconstructor::MakeTracks()
256 {
257   /// To make the tracks from the list of segments and points in all stations
258   AliDebug(1,"Enter MakeTracks");
259   // Look for candidates from at least 3 aligned points in stations(1..) 4 and 5
260   MakeTrackCandidates();
261   if (fRecTracksPtr->GetEntriesFast() == 0) return;
262   // Follow tracks in stations(1..) 3, 2 and 1
263   FollowTracks();
264   // Complement the reconstructed tracks
265   if (AliMUONReconstructor::GetRecoParam()->ComplementTracks()) ComplementTracks();
266   // Improve the reconstructed tracks
267   if (AliMUONReconstructor::GetRecoParam()->ImproveTracks()) ImproveTracks();
268   // Remove double tracks
269   RemoveDoubleTracks();
270   // Fill AliMUONTrack data members
271   Finalize();
272 }
273
274   //__________________________________________________________________________
275 TClonesArray* AliMUONVTrackReconstructor::MakeSegmentsInStation(Int_t station)
276 {
277   /// To make the list of segments in station(0..) "Station" from the list of hits to be reconstructed.
278   /// Return a new TClonesArray of segments.
279   /// It is the responsibility of the user to delete it afterward.
280   AliDebug(1,Form("Enter MakeSegmentsPerStation (0...) %d",station));
281   
282   AliMUONHitForRec *hit1Ptr, *hit2Ptr;
283   AliMUONObjectPair *segment;
284   Double_t bendingSlope = 0, impactParam = 0., bendingMomentum = 0.; // to avoid compilation warning
285                                                                      // first and second chambers (0...) in the station
286   Int_t ch1 = 2 * station;
287   Int_t ch2 = ch1 + 1;
288   
289   // list of segments
290   TClonesArray *segments = new TClonesArray("AliMUONObjectPair", fNHitsForRecPerChamber[ch2]);
291   segments->SetOwner(kTRUE);
292   
293   // Loop over HitForRec's in the first chamber of the station
294   for (Int_t hit1 = fIndexOfFirstHitForRecPerChamber[ch1];
295        hit1 < fIndexOfFirstHitForRecPerChamber[ch1] + fNHitsForRecPerChamber[ch1];
296        hit1++) 
297   {
298     // pointer to the HitForRec
299     hit1Ptr = (AliMUONHitForRec*) ((*fHitsForRecPtr)[hit1]);
300     // Loop over HitsForRec's in the second chamber of the station
301     for (Int_t hit2 = fIndexOfFirstHitForRecPerChamber[ch2];
302          hit2 < fIndexOfFirstHitForRecPerChamber[ch2] + fNHitsForRecPerChamber[ch2];
303          hit2++) 
304     {
305       // pointer to the HitForRec
306       hit2Ptr = (AliMUONHitForRec*) ((*fHitsForRecPtr)[hit2]);
307       if ( hit1Ptr->GetZ() - hit2Ptr->GetZ() != 0. ) 
308       {
309         // bending slope
310         bendingSlope = (hit1Ptr->GetBendingCoor() - hit2Ptr->GetBendingCoor()) / (hit1Ptr->GetZ() - hit2Ptr->GetZ());
311         // impact parameter
312         impactParam = hit1Ptr->GetBendingCoor() - hit1Ptr->GetZ() * bendingSlope;
313         // absolute value of bending momentum
314         bendingMomentum = TMath::Abs(AliMUONTrackExtrap::GetBendingMomentumFromImpactParam(impactParam));
315       } else 
316       {
317         AliWarning("hit1Ptr->GetZ() = hit2Ptr->GetZ(): no segment created");
318         continue;
319       }   
320       // check for bending momentum within tolerances
321       if ((bendingMomentum < AliMUONReconstructor::GetRecoParam()->GetMaxBendingMomentum()) &&
322           (bendingMomentum > AliMUONReconstructor::GetRecoParam()->GetMinBendingMomentum())) 
323       {
324         // make new segment
325         segment = new ((*segments)[segments->GetLast()+1]) AliMUONObjectPair(hit1Ptr, hit2Ptr, kFALSE, kFALSE);
326         if (AliLog::GetGlobalDebugLevel() > 1) {
327           cout << "segmentIndex(0...): " << segments->GetLast() << endl;
328           segment->Dump();
329           cout << "HitForRec in first chamber" << endl;
330           hit1Ptr->Dump();
331           cout << "HitForRec in second chamber" << endl;
332           hit2Ptr->Dump();
333         }
334       }
335     } //for (Int_t hit2
336   } // for (Int_t hit1...
337   AliDebug(1,Form("Station: %d  NSegments:  %d ", station, segments->GetEntriesFast()));
338   return segments;
339 }
340
341   //__________________________________________________________________________
342 void AliMUONVTrackReconstructor::RemoveIdenticalTracks()
343 {
344   /// To remove identical tracks:
345   /// Tracks are considered identical if they have all their hits in common.
346   /// One keeps the track with the larger number of hits if need be
347   AliMUONTrack *track1, *track2, *trackToRemove;
348   Int_t hitsInCommon, nHits1, nHits2;
349   Bool_t removedTrack1;
350   // Loop over first track of the pair
351   track1 = (AliMUONTrack*) fRecTracksPtr->First();
352   while (track1) {
353     removedTrack1 = kFALSE;
354     nHits1 = track1->GetNTrackHits();
355     // Loop over second track of the pair
356     track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
357     while (track2) {
358       nHits2 = track2->GetNTrackHits();
359       // number of hits in common between two tracks
360       hitsInCommon = track1->HitsInCommon(track2);
361       // check for identical tracks
362       if ((hitsInCommon == nHits1) || (hitsInCommon == nHits2)) {
363         // decide which track to remove
364         if (nHits2 > nHits1) {
365           // remove track1 and continue the first loop with the track next to track1
366           trackToRemove = track1;
367           track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
368           fRecTracksPtr->Remove(trackToRemove);
369           fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
370           fNRecTracks--;
371           removedTrack1 = kTRUE;
372           break;
373         } else {
374           // remove track2 and continue the second loop with the track next to track2
375           trackToRemove = track2;
376           track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
377           fRecTracksPtr->Remove(trackToRemove);
378           fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
379           fNRecTracks--;
380         }
381       } else track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
382     } // track2
383     if (removedTrack1) continue;
384     track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
385   } // track1
386   return;
387 }
388
389   //__________________________________________________________________________
390 void AliMUONVTrackReconstructor::RemoveDoubleTracks()
391 {
392   /// To remove double tracks:
393   /// Tracks are considered identical if more than half of the hits of the track
394   /// which has the smaller number of hits are in common with the other track.
395   /// Among two identical tracks, one keeps the track with the larger number of hits
396   /// or, if these numbers are equal, the track with the minimum chi2.
397   AliMUONTrack *track1, *track2, *trackToRemove;
398   Int_t hitsInCommon, nHits1, nHits2;
399   Bool_t removedTrack1;
400   // Loop over first track of the pair
401   track1 = (AliMUONTrack*) fRecTracksPtr->First();
402   while (track1) {
403     removedTrack1 = kFALSE;
404     nHits1 = track1->GetNTrackHits();
405     // Loop over second track of the pair
406     track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
407     while (track2) {
408       nHits2 = track2->GetNTrackHits();
409       // number of hits in common between two tracks
410       hitsInCommon = track1->HitsInCommon(track2);
411       // check for identical tracks
412       if (((nHits1 < nHits2) && (2 * hitsInCommon > nHits1)) || (2 * hitsInCommon > nHits2)) {
413         // decide which track to remove
414         if ((nHits1 > nHits2) || ((nHits1 == nHits2) && (track1->GetFitFMin() <= track2->GetFitFMin()))) {
415           // remove track2 and continue the second loop with the track next to track2
416           trackToRemove = track2;
417           track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
418           fRecTracksPtr->Remove(trackToRemove);
419           fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
420           fNRecTracks--;
421         } else {
422           // else remove track1 and continue the first loop with the track next to track1
423           trackToRemove = track1;
424           track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
425           fRecTracksPtr->Remove(trackToRemove);
426           fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
427           fNRecTracks--;
428           removedTrack1 = kTRUE;
429           break;
430         }
431       } else track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
432     } // track2
433     if (removedTrack1) continue;
434     track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
435   } // track1
436   return;
437 }
438
439   //__________________________________________________________________________
440 Double_t AliMUONVTrackReconstructor::TryOneHitForRec(const AliMUONTrackParam &trackParam, AliMUONHitForRec* hitForRec,
441                                                      AliMUONTrackParam &trackParamAtHit, Bool_t updatePropagator)
442 {
443 /// Test the compatibility between the track and the hitForRec (using trackParam's covariance matrix):
444 /// return the corresponding Chi2
445 /// return trackParamAtHit
446   
447   // extrapolate track parameters and covariances at the z position of the tested hit
448   trackParamAtHit = trackParam;
449   AliMUONTrackExtrap::ExtrapToZCov(&trackParamAtHit, hitForRec->GetZ(), updatePropagator);
450   
451   // set pointer to hit into trackParamAtHit
452   trackParamAtHit.SetHitForRecPtr(hitForRec);
453   
454   // Set differences between trackParam and hitForRec in the bending and non bending directions
455   Double_t dX = hitForRec->GetNonBendingCoor() - trackParamAtHit.GetNonBendingCoor();
456   Double_t dY = hitForRec->GetBendingCoor() - trackParamAtHit.GetBendingCoor();
457   
458   // Calculate errors and covariances
459   const TMatrixD& kParamCov = trackParamAtHit.GetCovariances();
460   Double_t sigma2X = kParamCov(0,0) + hitForRec->GetNonBendingReso2();
461   Double_t sigma2Y = kParamCov(2,2) + hitForRec->GetBendingReso2();
462   
463   // Compute chi2
464   return dX * dX / sigma2X + dY * dY / sigma2Y;
465   
466 }
467
468   //__________________________________________________________________________
469 Bool_t AliMUONVTrackReconstructor::TryOneHitForRecFast(const AliMUONTrackParam &trackParam, AliMUONHitForRec* hitForRec)
470 {
471 /// Test the compatibility between the track and the hitForRec within a wide fix window
472 /// assuming linear propagation of the track:
473 /// return kTRUE if they are compatibles
474   
475   Double_t dZ = hitForRec->GetZ() - trackParam.GetZ();
476   Double_t dX = hitForRec->GetNonBendingCoor() - (trackParam.GetNonBendingCoor() + trackParam.GetNonBendingSlope() * dZ);
477   Double_t dY = hitForRec->GetBendingCoor() - (trackParam.GetBendingCoor() + trackParam.GetBendingSlope() * dZ);
478   
479   if (TMath::Abs(dX) > AliMUONReconstructor::GetRecoParam()->GetMaxNonBendingDistanceToTrack() ||
480       TMath::Abs(dY) > AliMUONReconstructor::GetRecoParam()->GetMaxBendingDistanceToTrack()) return kFALSE;
481   
482   return kTRUE;
483   
484 }
485
486   //__________________________________________________________________________
487 Double_t AliMUONVTrackReconstructor::TryTwoHitForRecFast(const AliMUONTrackParam &trackParamAtHit1, AliMUONHitForRec* hitForRec2,
488                                                          AliMUONTrackParam &trackParamAtHit2)
489 {
490 /// Test the compatibility between the track and the 2 hitForRec together (using trackParam's covariance matrix)
491 /// assuming linear propagation between the two hits:
492 /// return the corresponding Chi2 accounting for covariances between the 2 hitForRec
493 /// return trackParamAtHit1 & 2
494   
495   // extrapolate linearly track parameters at the z position of the second hit
496   trackParamAtHit2 = trackParamAtHit1;
497   AliMUONTrackExtrap::LinearExtrapToZ(&trackParamAtHit2, hitForRec2->GetZ());
498   
499   // set pointer to hit2 into trackParamAtHit2
500   trackParamAtHit2.SetHitForRecPtr(hitForRec2);
501   
502   // Set differences between track and hitForRec in the bending and non bending directions
503   AliMUONHitForRec* hitForRec1 = trackParamAtHit1.GetHitForRecPtr();
504   Double_t dX1 = hitForRec1->GetNonBendingCoor() - trackParamAtHit1.GetNonBendingCoor();
505   Double_t dX2 = hitForRec2->GetNonBendingCoor() - trackParamAtHit2.GetNonBendingCoor();
506   Double_t dY1 = hitForRec1->GetBendingCoor() - trackParamAtHit1.GetBendingCoor();
507   Double_t dY2 = hitForRec2->GetBendingCoor() - trackParamAtHit2.GetBendingCoor();
508   
509   // Calculate errors and covariances
510   const TMatrixD& kParamCov1 = trackParamAtHit1.GetCovariances();
511   const TMatrixD& kParamCov2 = trackParamAtHit2.GetCovariances();
512   Double_t dZ = trackParamAtHit2.GetZ() - trackParamAtHit1.GetZ();
513   Double_t sigma2X1 = kParamCov1(0,0) + hitForRec1->GetNonBendingReso2();
514   Double_t sigma2X2 = kParamCov2(0,0) + hitForRec2->GetNonBendingReso2();
515   Double_t covX1X2  = kParamCov1(0,0) + dZ * kParamCov1(0,1);
516   Double_t sigma2Y1 = kParamCov1(2,2) + hitForRec1->GetBendingReso2();
517   Double_t sigma2Y2 = kParamCov2(2,2) + hitForRec2->GetBendingReso2();
518   Double_t covY1Y2  = kParamCov1(2,2) + dZ * kParamCov1(2,3);
519   
520   // Compute chi2
521   Double_t detX = sigma2X1 * sigma2X2 - covX1X2 * covX1X2;
522   Double_t detY = sigma2Y1 * sigma2Y2 - covY1Y2 * covY1Y2;
523   if (detX == 0. || detY == 0.) return 1.e10;
524   return   (dX1 * dX1 * sigma2X2 + dX2 * dX2 * sigma2X1 - 2. * dX1 * dX2 * covX1X2) / detX
525          + (dY1 * dY1 * sigma2Y2 + dY2 * dY2 * sigma2Y1 - 2. * dY1 * dY2 * covY1Y2) / detY;
526   
527 }
528
529   //__________________________________________________________________________
530 Bool_t AliMUONVTrackReconstructor::FollowLinearTrackInStation(AliMUONTrack &trackCandidate, Int_t nextStation)
531 {
532   /// Follow trackCandidate in station(0..) nextStation assuming linear propagation, and search for compatible HitForRec(s)
533   /// Keep all possibilities or only the best one(s) according to the flag fgkTrackAllTracks:
534   /// kTRUE:  duplicate "trackCandidate" if there are several possibilities and add the new tracks at the end of
535   ///         fRecTracksPtr to avoid conficts with other track candidates at this current stage of the tracking procedure.
536   ///         Remove the obsolete "trackCandidate" at the end.
537   /// kFALSE: add only the best hit(s) to the "trackCandidate". Try to add a couple of hits in priority.
538   /// return kTRUE if new hits have been found (otherwise return kFALSE)
539   AliDebug(1,Form("Enter FollowLinearTrackInStation(1..) %d", nextStation+1));
540   
541   // Order the chamber according to the propagation direction (tracking starts with chamber 2):
542   // - nextStation == station(1...) 5 => forward propagation
543   // - nextStation < station(1...) 5 => backward propagation
544   Int_t ch1, ch2;
545   if (nextStation==4) {
546     ch1 = 2*nextStation+1;
547     ch2 = 2*nextStation;
548   } else {
549     ch1 = 2*nextStation;
550     ch2 = 2*nextStation+1;
551   }
552   
553   Double_t chi2WithOneHitForRec = 1.e10;
554   Double_t chi2WithTwoHitForRec = 1.e10;
555   Double_t maxChi2WithOneHitForRec = 2. * AliMUONReconstructor::GetRecoParam()->GetSigmaCutForTracking() *
556                                           AliMUONReconstructor::GetRecoParam()->GetSigmaCutForTracking(); // 2 because 2 quantities in chi2
557   Double_t maxChi2WithTwoHitForRec = 4. * AliMUONReconstructor::GetRecoParam()->GetSigmaCutForTracking() *
558                                           AliMUONReconstructor::GetRecoParam()->GetSigmaCutForTracking(); // 4 because 4 quantities in chi2
559   Double_t bestChi2WithOneHitForRec = maxChi2WithOneHitForRec;
560   Double_t bestChi2WithTwoHitForRec = maxChi2WithTwoHitForRec;
561   Bool_t foundOneHit = kFALSE;
562   Bool_t foundTwoHits = kFALSE;
563   AliMUONTrack *newTrack = 0x0;
564   AliMUONHitForRec *hitForRecCh1, *hitForRecCh2;
565   AliMUONTrackParam extrapTrackParamAtHit1;
566   AliMUONTrackParam extrapTrackParamAtHit2;
567   AliMUONTrackParam bestTrackParamAtHit1;
568   AliMUONTrackParam bestTrackParamAtHit2;
569   Bool_t *hitForRecCh1Used = new Bool_t[fNHitsForRecPerChamber[ch1]];
570   for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) hitForRecCh1Used[hit1] = kFALSE;
571   
572   // Get track parameters
573   AliMUONTrackParam trackParam(*(AliMUONTrackParam*)trackCandidate.GetTrackParamAtHit()->First());
574   
575   // Add MCS effect
576   AliMUONTrackExtrap::AddMCSEffect(&trackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
577   
578   // Printout for debuging
579   if ((AliLog::GetDebugLevel("MUON","AliMUONVTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
580     cout << "FollowLinearTrackInStation: look for hits in chamber(1..): " << ch2+1 << endl;
581   }
582   
583   // look for candidates in chamber 2 
584   for (Int_t hit2 = 0; hit2 < fNHitsForRecPerChamber[ch2]; hit2++) {
585     
586     hitForRecCh2 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch2]+hit2);
587     
588     // try to add the current hit fast
589     if (!TryOneHitForRecFast(trackParam, hitForRecCh2)) continue;
590     
591     // try to add the current hit accuratly
592     extrapTrackParamAtHit2 = trackParam;
593     AliMUONTrackExtrap::LinearExtrapToZ(&extrapTrackParamAtHit2, hitForRecCh2->GetZ());
594     chi2WithOneHitForRec = TryOneHitForRec(extrapTrackParamAtHit2, hitForRecCh2, extrapTrackParamAtHit2);
595     
596     // if good chi2 then try to attach a hitForRec in the other chamber too
597     if (chi2WithOneHitForRec < maxChi2WithOneHitForRec) {
598       Bool_t foundSecondHit = kFALSE;
599       
600       // Printout for debuging
601       if ((AliLog::GetDebugLevel("MUON","AliMUONVTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
602         cout << "FollowLinearTrackInStation: found one hit in chamber(1..): " << ch2+1
603              << " (Chi2 = " << chi2WithOneHitForRec << ")" << endl;
604         cout << "                      look for second hits in chamber(1..): " << ch1+1 << " ..." << endl;
605       }
606       
607       // add MCS effect
608       AliMUONTrackExtrap::AddMCSEffect(&extrapTrackParamAtHit2,AliMUONConstants::ChamberThicknessInX0(),1.);
609       
610       for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) {
611         
612         hitForRecCh1 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch1]+hit1);
613         
614         // try to add the current hit fast
615         if (!TryOneHitForRecFast(extrapTrackParamAtHit2, hitForRecCh1)) continue;
616         
617         // try to add the current hit in addition to the one found on the previous chamber
618         chi2WithTwoHitForRec = TryTwoHitForRecFast(extrapTrackParamAtHit2, hitForRecCh1, extrapTrackParamAtHit1);
619         
620         // if good chi2 then consider to add the 2 hitForRec to the "trackCandidate"
621         if (chi2WithTwoHitForRec < maxChi2WithTwoHitForRec) {
622           foundSecondHit = kTRUE;
623           foundTwoHits = kTRUE;
624           
625           // Printout for debuging
626           if ((AliLog::GetDebugLevel("MUON","AliMUONVTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
627             cout << "FollowLinearTrackInStation: found one hit in chamber(1..): " << ch1+1
628                  << " (Chi2 = " << chi2WithTwoHitForRec << ")" << endl;
629           }
630           
631           if (AliMUONReconstructor::GetRecoParam()->TrackAllTracks()) {
632             // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
633             newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
634             extrapTrackParamAtHit1.SetRemovable(kTRUE);
635             newTrack->AddTrackParamAtHit(&extrapTrackParamAtHit1,hitForRecCh1);
636             extrapTrackParamAtHit2.SetRemovable(kTRUE);
637             newTrack->AddTrackParamAtHit(&extrapTrackParamAtHit2,hitForRecCh2);
638             newTrack->GetTrackParamAtHit()->Sort();
639             fNRecTracks++;
640             
641             // Tag hitForRecCh1 as used
642             hitForRecCh1Used[hit1] = kTRUE;
643             
644             // Printout for debuging
645             if ((AliLog::GetDebugLevel("MUON","AliMUONVTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
646               cout << "FollowLinearTrackInStation: added two hits in station(1..): " << nextStation+1 << endl;
647               if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
648             }
649             
650           } else if (chi2WithTwoHitForRec < bestChi2WithTwoHitForRec) {
651             // keep track of the best couple of hits
652             bestChi2WithTwoHitForRec = chi2WithTwoHitForRec;
653             bestTrackParamAtHit1 = extrapTrackParamAtHit1;
654             bestTrackParamAtHit2 = extrapTrackParamAtHit2;
655           }
656           
657         }
658         
659       }
660       
661       // if no hitForRecCh1 found then consider to add hitForRecCh2 only
662       if (!foundSecondHit) {
663         foundOneHit = kTRUE;
664         
665         if (AliMUONReconstructor::GetRecoParam()->TrackAllTracks()) {
666           // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
667           newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
668           extrapTrackParamAtHit2.SetRemovable(kFALSE);
669           newTrack->AddTrackParamAtHit(&extrapTrackParamAtHit2,hitForRecCh2);
670           newTrack->GetTrackParamAtHit()->Sort();
671           fNRecTracks++;
672           
673           // Printout for debuging
674           if ((AliLog::GetDebugLevel("MUON","AliMUONVTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
675             cout << "FollowLinearTrackInStation: added one hit in chamber(1..): " << ch2+1 << endl;
676             if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
677           }
678           
679         } else if (!foundTwoHits && chi2WithOneHitForRec < bestChi2WithOneHitForRec) {
680           // keep track of the best single hitForRec except if a couple of hits has already been found
681           bestChi2WithOneHitForRec = chi2WithOneHitForRec;
682           bestTrackParamAtHit1 = extrapTrackParamAtHit2;
683         }
684         
685       }
686       
687     }
688     
689   }
690   
691   // look for candidates in chamber 1 not already attached to a track
692   // if we want to keep all possible tracks or if no good couple of hitForRec has been found
693   if (AliMUONReconstructor::GetRecoParam()->TrackAllTracks() || !foundTwoHits) {
694     
695     // Printout for debuging
696     if ((AliLog::GetDebugLevel("MUON","AliMUONVTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
697       cout << "FollowLinearTrackInStation: look for single hits in chamber(1..): " << ch1+1 << endl;
698     }
699     
700     //Extrapolate trackCandidate to chamber "ch2"
701     AliMUONTrackExtrap::LinearExtrapToZ(&trackParam, AliMUONConstants::DefaultChamberZ(ch2));
702     
703     // add MCS effect for next step
704     AliMUONTrackExtrap::AddMCSEffect(&trackParam,AliMUONConstants::ChamberThicknessInX0(),1.);
705       
706     for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) {
707       
708       hitForRecCh1 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch1]+hit1);
709       
710       if (hitForRecCh1Used[hit1]) continue; // Skip hitForRec already used
711       
712       // try to add the current hit fast
713       if (!TryOneHitForRecFast(trackParam, hitForRecCh1)) continue;
714         
715       // try to add the current hit accuratly
716       extrapTrackParamAtHit1 = trackParam;
717       AliMUONTrackExtrap::LinearExtrapToZ(&extrapTrackParamAtHit1, hitForRecCh1->GetZ());
718       chi2WithOneHitForRec = TryOneHitForRec(extrapTrackParamAtHit1, hitForRecCh1, extrapTrackParamAtHit1);
719     
720       // if good chi2 then consider to add hitForRecCh1
721       // We do not try to attach a hitForRec in the other chamber too since it has already been done above
722       if (chi2WithOneHitForRec < maxChi2WithOneHitForRec) {
723         foundOneHit = kTRUE;
724         
725         // Printout for debuging
726         if ((AliLog::GetDebugLevel("MUON","AliMUONVTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
727           cout << "FollowLinearTrackInStation: found one hit in chamber(1..): " << ch1+1
728                << " (Chi2 = " << chi2WithOneHitForRec << ")" << endl;
729         }
730         
731         if (AliMUONReconstructor::GetRecoParam()->TrackAllTracks()) {
732           // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
733           newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(trackCandidate);
734           extrapTrackParamAtHit1.SetRemovable(kFALSE);
735           newTrack->AddTrackParamAtHit(&extrapTrackParamAtHit1,hitForRecCh1);
736           newTrack->GetTrackParamAtHit()->Sort();
737           fNRecTracks++;
738           
739           // Printout for debuging
740           if ((AliLog::GetDebugLevel("MUON","AliMUONVTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
741             cout << "FollowLinearTrackInStation: added one hit in chamber(1..): " << ch1+1 << endl;
742             if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
743           }
744           
745         } else if (chi2WithOneHitForRec < bestChi2WithOneHitForRec) {
746           // keep track of the best single hitForRec except if a couple of hits has already been found
747           bestChi2WithOneHitForRec = chi2WithOneHitForRec;
748           bestTrackParamAtHit1 = extrapTrackParamAtHit1;
749         }
750         
751       }
752       
753     }
754     
755   }
756   
757   // fill out the best track if required else clean up the fRecTracksPtr array
758   if (!AliMUONReconstructor::GetRecoParam()->TrackAllTracks()) {
759     if (foundTwoHits) {
760       bestTrackParamAtHit1.SetRemovable(kTRUE);
761       trackCandidate.AddTrackParamAtHit(&bestTrackParamAtHit1,bestTrackParamAtHit1.GetHitForRecPtr());
762       bestTrackParamAtHit2.SetRemovable(kTRUE);
763       trackCandidate.AddTrackParamAtHit(&bestTrackParamAtHit2,bestTrackParamAtHit2.GetHitForRecPtr());
764       trackCandidate.GetTrackParamAtHit()->Sort();
765       
766       // Printout for debuging
767       if ((AliLog::GetDebugLevel("MUON","AliMUONVTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
768         cout << "FollowLinearTrackInStation: added the two best hits in station(1..): " << nextStation+1 << endl;
769         if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
770       }
771       
772     } else if (foundOneHit) {
773       bestTrackParamAtHit1.SetRemovable(kFALSE);
774       trackCandidate.AddTrackParamAtHit(&bestTrackParamAtHit1,bestTrackParamAtHit1.GetHitForRecPtr());
775       trackCandidate.GetTrackParamAtHit()->Sort();
776       
777       // Printout for debuging
778       if ((AliLog::GetDebugLevel("MUON","AliMUONVTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
779         cout << "FollowLinearTrackInStation: added the best hit in chamber(1..): " << bestTrackParamAtHit1.GetHitForRecPtr()->GetChamberNumber()+1 << endl;
780         if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
781       }
782       
783     } else {
784       delete [] hitForRecCh1Used;
785       return kFALSE;
786     }
787     
788   } else if (foundOneHit || foundTwoHits) {
789     
790     // remove obsolete track
791     fRecTracksPtr->Remove(&trackCandidate);
792     fNRecTracks--;
793     
794   } else {
795     delete [] hitForRecCh1Used;  
796     return kFALSE;
797   }
798   
799   delete [] hitForRecCh1Used;
800   return kTRUE;
801   
802 }
803
804   //__________________________________________________________________________
805 void AliMUONVTrackReconstructor::ValidateTracksWithTrigger(AliMUONVTrackStore& trackStore,
806                                                            const AliMUONVTriggerTrackStore& triggerTrackStore,
807                                                            const AliMUONVTriggerStore& triggerStore,
808                                                            const AliMUONTrackHitPattern& trackHitPattern)
809 {
810   /// Try to match track from tracking system with trigger track
811   AliCodeTimerAuto("");
812   
813   static const Double_t kDistSigma[3]={1,1,0.02}; // sigma of distributions (trigger-track) X,Y,slopeY
814   
815   Int_t matchTrigger;
816   Int_t loTrgNum(-1);
817   Double_t distTriggerTrack[3];
818   Double_t xTrack, yTrack, ySlopeTrack, chi2MatchTrigger, minChi2MatchTrigger, chi2;
819
820   TIter itTrack(trackStore.CreateIterator());
821   AliMUONTrack* track;
822   
823   while ( ( track = static_cast<AliMUONTrack*>(itTrack()) ) )
824   {
825     matchTrigger = 0;
826     chi2MatchTrigger = 0.;
827     loTrgNum = -1;
828     Int_t doubleMatch=-1; // Check if track matches 2 trigger tracks
829     Double_t doubleChi2 = -1.;
830     
831     AliMUONTrackParam trackParam(*((AliMUONTrackParam*) (track->GetTrackParamAtHit()->Last())));
832     AliMUONTrackExtrap::ExtrapToZ(&trackParam, AliMUONConstants::DefaultChamberZ(10)); // extrap to 1st trigger chamber
833     
834     xTrack = trackParam.GetNonBendingCoor();
835     yTrack = trackParam.GetBendingCoor();
836     ySlopeTrack = trackParam.GetBendingSlope();
837     minChi2MatchTrigger = 999.;
838     
839     AliMUONTriggerTrack *triggerTrack;
840     TIter itTriggerTrack(triggerTrackStore.CreateIterator());
841     while ( ( triggerTrack = static_cast<AliMUONTriggerTrack*>(itTriggerTrack() ) ) )
842     {
843       distTriggerTrack[0] = (triggerTrack->GetX11()-xTrack)/kDistSigma[0];
844       distTriggerTrack[1] = (triggerTrack->GetY11()-yTrack)/kDistSigma[1];
845       distTriggerTrack[2] = (TMath::Tan(triggerTrack->GetThetay())-ySlopeTrack)/kDistSigma[2];
846       chi2 = 0.;
847       for (Int_t iVar = 0; iVar < 3; iVar++) chi2 += distTriggerTrack[iVar]*distTriggerTrack[iVar];
848       chi2 /= 3.; // Normalized Chi2: 3 degrees of freedom (X,Y,slopeY)
849       if (chi2 < AliMUONReconstructor::GetRecoParam()->GetMaxNormChi2MatchTrigger()) 
850       {
851         Bool_t isDoubleTrack = (TMath::Abs(chi2 - minChi2MatchTrigger)<1.);
852         if (chi2 < minChi2MatchTrigger && chi2 < AliMUONReconstructor::GetRecoParam()->GetMaxNormChi2MatchTrigger()) 
853         {
854           if(isDoubleTrack)
855           {
856             doubleMatch = loTrgNum;
857             doubleChi2 = chi2MatchTrigger;
858           }
859           minChi2MatchTrigger = chi2;
860           chi2MatchTrigger = chi2;
861           loTrgNum = triggerTrack->GetLoTrgNum();
862           AliMUONLocalTrigger* locTrg = triggerStore.FindLocal(loTrgNum);
863           matchTrigger=1;
864           if(locTrg->LoLpt()>0)matchTrigger=2;
865           if(locTrg->LoHpt()>0)matchTrigger=3;
866         }
867         else if(isDoubleTrack) 
868         {
869           doubleMatch = triggerTrack->GetLoTrgNum();
870           doubleChi2 = chi2;
871         }
872       }
873     }
874     if(doubleMatch>=0)
875     { // If two trigger tracks match, select the one passing more trigger cuts
876       AliDebug(1, Form("Two candidates found: %i and %i",loTrgNum,doubleMatch));
877       AliMUONLocalTrigger* locTrg1 = triggerStore.FindLocal(doubleMatch);
878       if((locTrg1->LoLpt()>0 && matchTrigger<2) || (locTrg1->LoHpt() && matchTrigger<3))
879       {
880         if(locTrg1->LoHpt()>0)matchTrigger=3;
881         else matchTrigger=2;
882         loTrgNum = doubleMatch;
883         chi2MatchTrigger=doubleChi2;
884       }
885     }
886     
887     track->SetMatchTrigger(matchTrigger);
888     track->SetLoTrgNum(loTrgNum);
889     track->SetChi2MatchTrigger(chi2MatchTrigger);
890     
891     AliMUONLocalTrigger* locTrg = static_cast<AliMUONLocalTrigger*>(triggerStore.FindLocal(loTrgNum));
892     
893     if (locTrg)
894     {    
895       track->SetLocalTrigger(locTrg->LoCircuit(),
896                              locTrg->LoStripX(),
897                              locTrg->LoStripY(),
898                              locTrg->LoDev(),
899                              locTrg->LoLpt(),
900                              locTrg->LoHpt());
901     }    
902   }  
903   
904   trackHitPattern.GetHitPattern(trackStore,triggerStore);
905 }
906
907   //__________________________________________________________________________
908 void AliMUONVTrackReconstructor::EventReconstructTrigger(const AliMUONTriggerCircuit& circuit,
909                                                          const AliMUONVTriggerStore& triggerStore,
910                                                          AliMUONVTriggerTrackStore& triggerTrackStore)
911 {
912   /// To make the trigger tracks from Local Trigger
913   AliDebug(1, "");
914   AliCodeTimerAuto("");
915   
916   AliMUONGlobalTrigger* globalTrigger = triggerStore.Global();
917   
918   UChar_t gloTrigPat = 0;
919
920   if (globalTrigger)
921   {
922     gloTrigPat = globalTrigger->GetGlobalResponse();
923   }
924   
925   TIter next(triggerStore.CreateIterator());
926   AliMUONLocalTrigger* locTrg(0x0);
927
928   Float_t z11 = AliMUONConstants::DefaultChamberZ(10);
929   Float_t z21 = AliMUONConstants::DefaultChamberZ(12);
930       
931   AliMUONTriggerTrack triggerTrack;
932   
933   while ( ( locTrg = static_cast<AliMUONLocalTrigger*>(next()) ) )
934   {
935     Bool_t xTrig=kFALSE;
936     Bool_t yTrig=kFALSE;
937     
938     Int_t localBoardId = locTrg->LoCircuit();
939     if ( locTrg->LoSdev()==1 && locTrg->LoDev()==0 && 
940          locTrg->LoStripX()==0) xTrig=kFALSE; // no trigger in X
941     else xTrig=kTRUE;                         // trigger in X
942     if (locTrg->LoTrigY()==1 && 
943         locTrg->LoStripY()==15 ) yTrig = kFALSE; // no trigger in Y
944     else yTrig = kTRUE;                          // trigger in Y
945     
946     if (xTrig && yTrig) 
947     { // make Trigger Track if trigger in X and Y
948       
949       Float_t y11 = circuit.GetY11Pos(localBoardId, locTrg->LoStripX()); 
950       // need first to convert deviation to [0-30] 
951       // (see AliMUONLocalTriggerBoard::LocalTrigger)
952       Int_t deviation = locTrg->LoDev(); 
953       Int_t sign = 0;
954       if ( !locTrg->LoSdev() &&  deviation ) sign=-1;
955       if ( !locTrg->LoSdev() && !deviation ) sign= 0;
956       if (  locTrg->LoSdev() == 1 )          sign=+1;
957       deviation *= sign;
958       deviation += 15;
959       Int_t stripX21 = locTrg->LoStripX()+deviation+1;
960       Float_t y21 = circuit.GetY21Pos(localBoardId, stripX21);       
961       Float_t x11 = circuit.GetX11Pos(localBoardId, locTrg->LoStripY());
962       
963       AliDebug(1, Form(" MakeTriggerTrack %d %d %d %d %f %f %f \n",locTrg->LoCircuit(),
964                        locTrg->LoStripX(),locTrg->LoStripX()+locTrg->LoDev()+1,locTrg->LoStripY(),y11, y21, x11));
965       
966       Float_t thetax = TMath::ATan2( x11 , z11 );
967       Float_t thetay = TMath::ATan2( (y21-y11) , (z21-z11) );
968       
969       triggerTrack.SetX11(x11);
970       triggerTrack.SetY11(y11);
971       triggerTrack.SetThetax(thetax);
972       triggerTrack.SetThetay(thetay);
973       triggerTrack.SetGTPattern(gloTrigPat);
974       triggerTrack.SetLoTrgNum(localBoardId);
975       
976       triggerTrackStore.Add(triggerTrack);
977     } // board is fired 
978   } // end of loop on Local Trigger
979 }
980