]> git.uio.no Git - u/mrichter/AliRoot.git/blob - HLT/MUON/OnlineAnalysis/AliHLTMUONMansoTrackerFSM.cxx
Applying line fit to trigger record hits to get better idea of where the track traver...
[u/mrichter/AliRoot.git] / HLT / MUON / OnlineAnalysis / AliHLTMUONMansoTrackerFSM.cxx
1 /**************************************************************************
2  * This file is property of and copyright by the ALICE HLT Project        * 
3  * All rights reserved.                                                   *
4  *                                                                        *
5  * Primary Authors:                                                       *
6  *   Artur Szostak <artursz@iafrica.com>                                  *
7  *                                                                        *
8  * Permission to use, copy, modify and distribute this software and its   *
9  * documentation strictly for non-commercial purposes is hereby granted   *
10  * without fee, provided that the above copyright notice appears in all   *
11  * copies and that both the copyright notice and this permission notice   *
12  * appear in the supporting documentation. The authors make no claims     *
13  * about the suitability of this software for any purpose. It is          * 
14  * provided "as is" without express or implied warranty.                  *
15  **************************************************************************/
16
17 /* $Id$ */
18
19 /**
20  *  @file   AliHLTMUONMansoTrackerFSM.cxx
21  *  @author Artur Szostak <artursz@iafrica.com>
22  *  @date   
23  *  @brief  Implementation of AliHLTMUONMansoTrackerFSM class.
24  */
25
26 #include "AliHLTMUONMansoTrackerFSM.h"
27 #include "AliHLTMUONCalculations.h"
28 #include "AliHLTMUONConstants.h"
29 #include "AliHLTMUONUtils.h"
30 #include <cmath>
31
32
33 #ifdef DEBUG
34 #include <ostream>
35 namespace
36 {
37
38 std::ostream& operator << (std::ostream& os, AliHLTMUONMansoTrackerFSM::StatesSM4 state)
39 {
40         switch (state)
41         {
42         case AliHLTMUONMansoTrackerFSM::kSM4Idle:          os << "kSM4Idle"; break;
43         case AliHLTMUONMansoTrackerFSM::kWaitChamber8:     os << "kWaitChamber8"; break;
44         case AliHLTMUONMansoTrackerFSM::kWaitMoreChamber8: os << "kWaitMoreChamber8"; break;
45         case AliHLTMUONMansoTrackerFSM::kWaitChamber7:     os << "kWaitChamber7"; break;
46         case AliHLTMUONMansoTrackerFSM::kWaitMoreChamber7: os << "kWaitMoreChamber7"; break;
47         default:                                           os << "FAULT!!"; 
48         }
49         return os;
50 }
51
52 std::ostream& operator << (std::ostream& os, AliHLTMUONMansoTrackerFSM::StatesSM5 state)
53 {
54         switch (state)
55         {
56         case AliHLTMUONMansoTrackerFSM::kSM5Idle:           os << "kSM5Idle"; break;
57         case AliHLTMUONMansoTrackerFSM::kWaitChamber10:     os << "kWaitChamber10"; break;
58         case AliHLTMUONMansoTrackerFSM::kWaitMoreChamber10: os << "kWaitMoreChamber10"; break;
59         case AliHLTMUONMansoTrackerFSM::kWaitChamber9:      os << "kWaitChamber9"; break;
60         case AliHLTMUONMansoTrackerFSM::kWaitMoreChamber9:  os << "kWaitMoreChamber9"; break;
61         case AliHLTMUONMansoTrackerFSM::kSM5Done:           os << "kSM5Done"; break;
62         default:                                            os << "FAULT!!"; 
63         }
64         return os;
65 }
66
67 } // end of namespace
68 #endif // DEBUG
69
70
71 // Deviate from the Manso implementation by allowing a and b
72 // parameters per chamber and not just per station.
73 // The default values are derived from the work done in
74 //    "A first algorithm for dimuon High Level Trigger"
75 //    Ref ID:  ALICE-INT-2002-04 version 1.0
76 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgA7  = 0.016f;
77 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgB7  = 2.0f;
78 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgA8  = 0.016f;
79 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgB8  = 2.0f;
80 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgA9  = 0.020f;
81 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgB9  = 3.0f;
82 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgA10 = 0.020f;
83 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgB10 = 3.0f;
84 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ7  = -1274.5f;
85 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ8  = -1305.5f;
86 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ9  = -1408.6f;
87 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ10 = -1439.6f;
88 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ11 = -1603.5f;
89 AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ13 = -1703.5f;
90
91
92 void AliHLTMUONMansoTrackerFSM::AliRegionOfInterest::Create(
93                 AliHLTMUONRecHitStruct p, AliHLTFloat32_t a, AliHLTFloat32_t b
94         )
95 {
96 // Creates a region of interest specific to the Manso algorithm from a point and
97 // two Manso specific parameters.
98
99         fCentre = p;
100         // Compute the radius Rp
101         AliHLTFloat32_t rp = (AliHLTFloat32_t) sqrt( p.fX * p.fX + p.fY * p.fY );
102
103         // The radius Rs for the region of interest is computed from the
104         // specification given in the document:
105         //   "A first algorithm for dimuon High Level Trigger"
106         //   Ref ID:  ALICE-INT-2002-04 version 1.0
107         //   equation:
108         //     Rs = a * Rp + b
109         //   given on page 3 section 4.
110         fRs = a * rp + b;
111 }
112
113
114 bool AliHLTMUONMansoTrackerFSM::AliRegionOfInterest::Contains(AliHLTMUONRecHitStruct p) const
115 {
116         // Compute the distance between the centre of the region of interest and
117         // the point p. This distance must be less than the radius of the region
118         // of interest for p to be contained in the region of interest.
119         register AliHLTFloat32_t lx = fCentre.fX - p.fX;
120         register AliHLTFloat32_t ly = fCentre.fY - p.fY;
121         register AliHLTFloat32_t r = (AliHLTFloat32_t) sqrt( lx * lx + ly * ly );
122         DebugTrace("\tAliRegionOfInterest::Contains : p = " << p
123                 << " , centre = " << fCentre << " , r = " << r << " , Rs = " << fRs
124         );
125         return r <= fRs;
126 }
127
128
129 void AliHLTMUONMansoTrackerFSM::AliRegionOfInterest::GetBoundaryBox(
130                 AliHLTFloat32_t& left, AliHLTFloat32_t& right,
131                 AliHLTFloat32_t& bottom, AliHLTFloat32_t& top
132         ) const
133 {
134 // Works out the smallest boundary box that will contain the region of interest.
135
136         left = fCentre.fX - fRs;
137         right = fCentre.fX + fRs;
138         bottom = fCentre.fY - fRs;
139         top = fCentre.fY + fRs;
140 }
141
142
143 AliHLTMUONMansoTrackerFSM::AliVertex::AliVertex(
144                 AliHLTFloat32_t x, AliHLTFloat32_t y, AliHLTFloat32_t z
145         )
146         : fX(x), fY(y), fZ(z)
147 {
148 // Constructor for vertex.
149 }
150
151
152 AliHLTMUONMansoTrackerFSM::AliVertex::AliVertex(AliHLTMUONRecHitStruct xy, AliHLTFloat32_t z)
153         : fX(xy.fX), fY(xy.fY), fZ(z)
154 {
155 // Construct vertex from a point on the XY plane and z coordinate.
156 }
157
158
159 AliHLTMUONMansoTrackerFSM::AliLine::AliLine(
160                 AliHLTFloat32_t ax, AliHLTFloat32_t ay, AliHLTFloat32_t az,
161                 AliHLTFloat32_t bx, AliHLTFloat32_t by, AliHLTFloat32_t bz
162         ) :
163         fMx(ax - bx),
164         fMy(ay - by),
165         fMz(az - bz),
166         fCx(bx),
167         fCy(by),
168         fCz(bz)
169 {
170 // Construct a line defined by L = M*t + C = (A-B)*t + B
171 // where M and C are 3D vectors and t is a free parameter.
172 // A = (ax, ay, az) and B = (bx, by, bz)
173 }
174
175
176 AliHLTMUONMansoTrackerFSM::AliLine::AliLine(AliVertex a, AliVertex b) :
177         fMx(a.X() - b.X()),
178         fMy(a.Y() - b.Y()),
179         fMz(a.Z() - b.Z()),
180         fCx(b.X()),
181         fCy(b.Y()),
182         fCz(b.Z())
183 {
184 // Contruct a line to go through two vertices a and b.
185 }
186
187
188 AliHLTMUONRecHitStruct AliHLTMUONMansoTrackerFSM::AliLine::FindIntersectWithXYPlain(
189                 AliHLTFloat32_t z
190         ) const
191 {
192 // Find the point of intersection of the line and the XY plane at z.
193
194         AliHLTFloat32_t t;
195         if (fMz != 0)  // Should not have a ray perpendicular to the beam axis.
196                 t = (z - fCz) / fMz;
197         else
198                 t = 0;
199         AliHLTMUONRecHitStruct p;
200         p.fX = fMx*t + fCx;
201         p.fY = fMy*t + fCy;
202         p.fZ = z;
203         return p;
204 }
205
206
207 AliHLTMUONMansoTrackerFSM::AliHLTMUONMansoTrackerFSM() :
208         fCallback(NULL),
209         fSm4state(kSM4Idle),
210         fSm5state(kSM5Idle),
211         fRequestsCompleted(0),
212         fSt4chamber(kChamber1),
213         fV1(),
214         fMc1(),
215         fSt5data(),
216         fSt4points(),
217         fSt5rec(),
218         fFoundPoint(),
219         fTriggerId(-1),
220         fTrackId(0)
221 {
222 // Default constructor
223 }
224
225
226 bool AliHLTMUONMansoTrackerFSM::LineFit(
227                 const AliHLTMUONTriggerRecordStruct& trigger,
228                 AliHLTMUONRecHitStruct& pa, AliHLTMUONRecHitStruct& pb
229         )
230 {
231         // Apply least squares fit to the hits on the trigger record.
232         // http://mathworld.wolfram.com/LeastSquaresFitting.html
233         
234         AliHLTMUONParticleSign sign;
235         bool hitset[4];
236         AliHLTMUONUtils::UnpackTriggerRecordFlags(trigger.fFlags, sign, hitset);
237         DebugTrace("hitset = {" << hitset[0] << ", " << hitset[1] << ", "
238                 << hitset[2] << ", " << hitset[3] << "}"
239         );
240         
241         AliHLTFloat32_t sumX = 0;
242         AliHLTFloat32_t sumY = 0;
243         AliHLTFloat32_t sumZ = 0;
244         int n = 0;
245         for (int i = 0; i < 4; i++)
246         {
247                 if (hitset[i])
248                 {
249                         sumX += trigger.fHit[i].fX;
250                         sumY += trigger.fHit[i].fY;
251                         sumZ += trigger.fHit[i].fZ;
252                         n++;
253                 }
254         }
255         if (n < 2) return false;
256         AliHLTFloat32_t meanX = sumX / AliHLTFloat32_t(n);
257         AliHLTFloat32_t meanY = sumY / AliHLTFloat32_t(n);
258         AliHLTFloat32_t meanZ = sumZ / AliHLTFloat32_t(n);
259         
260         AliHLTFloat32_t SSzz = 0;
261         AliHLTFloat32_t SSzx = 0;
262         AliHLTFloat32_t SSzy = 0;
263         for (int i = 0; i < 4; i++)
264         {
265                 if (hitset[i])
266                 {
267                         SSzz += (trigger.fHit[i].fZ - meanZ)*(trigger.fHit[i].fZ - meanZ);
268                         SSzx += (trigger.fHit[i].fZ - meanZ)*(trigger.fHit[i].fX - meanX);
269                         SSzy += (trigger.fHit[i].fZ - meanZ)*(trigger.fHit[i].fY - meanY);
270                 }
271         }
272         
273         // Calculate params for lines x = Mzx * z + Czx and y = Mzy * z + Czy.
274         if (SSzz == 0) return false;
275         AliHLTFloat32_t Mzx = SSzx / SSzz;
276         AliHLTFloat32_t Mzy = SSzy / SSzz;
277         AliHLTFloat32_t Czx = meanX - Mzx * meanZ;
278         AliHLTFloat32_t Czy = meanY - Mzy * meanZ;
279         
280         // Calculate ideal points on chambers 11 and 13:
281         pa.fZ = fgZ11;
282         pa.fX = Mzx * pa.fZ + Czx;
283         pa.fY = Mzy * pa.fZ + Czy;
284         pb.fZ = fgZ13;
285         pb.fX = Mzx * pb.fZ + Czx;
286         pb.fY = Mzy * pb.fZ + Czy;
287         
288         return true;
289 }
290
291
292 void AliHLTMUONMansoTrackerFSM::FindTrack(const AliHLTMUONTriggerRecordStruct& trigger)
293 {
294 // Tries to find the track from the trigger seed.
295
296         DebugTrace("SM5 state = " << fSm5state << " , SM4 state = " << fSm4state);
297         DebugTrace("Processing trigger with ID = " << trigger.fId);
298         
299         fTriggerId = trigger.fId;
300         
301         AliHLTMUONRecHitStruct pa, pb;
302         if (not LineFit(trigger, pa, pb))
303         {
304                 NoTrackFound();
305                 return;
306         }
307         
308         fV1 = AliVertex(pa.fX, pa.fY, pa.fZ);
309         AliVertex v2 = AliVertex(pb.fX, pb.fY, pb.fZ);
310         
311         DebugTrace("Using fV1 = {x = " << fV1.X() << ", y = " << fV1.Y() << ", " << fV1.Z() << "}");
312         DebugTrace("Using v2 = {x = " << v2.X() << ", y = " << v2.Y() << ", " << v2.Z() << "}");
313
314         // Form the vector line between the above two impact points and
315         // find the crossing point of the line with chamber 10 (i.e. station 5).
316         fMc1.fLine = AliLine(fV1, v2);
317         AliHLTMUONRecHitStruct p10 = fMc1.fLine.FindIntersectWithXYPlain( fgZ10 );
318
319         // Build a region of interest for tracking station 5 (chamber 10).
320         // Remember the parameters a and b are station specific.
321         fMc1.fChamber = kChamber10;
322         fMc1.fRoi.Create(p10, fgA10, fgB10);
323         
324         // Make SM5 state transition before the call to RequestClusters since
325         // that method could call one of our methods again, so we need to be
326         // in a consistant internal state.
327         fSm5state = kWaitChamber10;
328
329         AliHLTFloat32_t left, right, bottom, top;
330         fMc1.fRoi.GetBoundaryBox(left, right, bottom, top);
331         RequestClusters(left, right, bottom, top, kChamber10, &fMc1);
332 }
333
334
335 void AliHLTMUONMansoTrackerFSM::ReturnClusters(
336                 void* tag, const AliHLTMUONRecHitStruct* clusters,
337                 AliHLTUInt32_t count
338         )
339 {
340 // Implementation of AliHLTMUONMansoTrackerFSM::ReturnClusters.
341
342         assert( count > 0 );
343         assert( clusters != NULL );
344         
345         AliTagData* data = (AliTagData*)tag;
346         DebugTrace("Got AliHLTMUONMansoTrackerFSM::ReturnClusters(tag = " << tag
347                 << ", chamber = " << data->fChamber
348                 << ", clusters = " << clusters <<  ", count = " << count << ")"
349         );
350         DebugTrace("SM5 state = " << fSm5state << " , SM4 state = " << fSm4state);
351
352         switch (data->fChamber)
353         {
354         case kChamber7:  ReceiveClustersChamber7(clusters, count, data); break;
355         case kChamber8:  ReceiveClustersChamber8(clusters, count, data); break;
356         case kChamber9:  ReceiveClustersChamber9(clusters, count); break;
357         case kChamber10: ReceiveClustersChamber10(clusters, count); break;
358         default:
359                 // Error
360                 DebugTrace("ERROR: Got tag with an invalid value: " << data->fChamber);
361         }
362 }
363
364
365 void AliHLTMUONMansoTrackerFSM::EndOfClusters(void* tag)
366 {
367 // Implementation of AliHLTMUONMansoTrackerFSM::EndOfClusters.
368
369         AliTagData* data = (AliTagData*)tag;
370         DebugTrace("Got AliHLTMUONMansoTrackerFSM::EndOfClusters(chamber = " << data->fChamber << ")");
371         DebugTrace("SM5 state = " << fSm5state << " , SM4 state = " << fSm4state);
372
373         switch (data->fChamber)
374         {
375         case kChamber7:  EndOfClustersChamber7(); break;
376         case kChamber8:  EndOfClustersChamber8(); break;
377         case kChamber9:  EndOfClustersChamber9(); break;
378         case kChamber10: EndOfClustersChamber10(); break;
379         default:
380                 // Error
381                 DebugTrace("ERROR: Got tag with an invalid value: " << data->fChamber);
382         }
383 }
384
385
386 bool AliHLTMUONMansoTrackerFSM::FillTrackData(AliHLTMUONMansoTrackStruct& track)
387 {
388 // Implementation of AliHLTMUONMansoTrackerFSM::FillTrackData
389
390         DebugTrace("FillTrack: st5 = " << fSt5rec->fClusterPoint << ", st4 = " << fFoundPoint->fClusterPoint);
391         
392         track.fId = fTrackId;
393         // Increment track Id and keep it positive.
394         //TODO: handle the wrapparound better.
395         if (fTrackId < 0x7FFFFFFF)
396                 fTrackId++;
397         else
398                 fTrackId = 0;
399         
400         track.fTrigRec = fTriggerId;
401         
402         AliHLTFloat32_t x1 = fFoundPoint->fClusterPoint.fX;
403         AliHLTFloat32_t y1 = fFoundPoint->fClusterPoint.fY;
404         AliHLTFloat32_t z1 = fFoundPoint->fClusterPoint.fZ;
405         AliHLTFloat32_t y2 = fSt5rec->fClusterPoint.fY;
406         AliHLTFloat32_t z2 = fSt5rec->fClusterPoint.fZ;
407         
408         bool calculated = AliHLTMUONCalculations::ComputeMomentum(x1, y1, y2, z1, z2);
409         
410         track.fPx = AliHLTMUONCalculations::Px();
411         track.fPy = AliHLTMUONCalculations::Py();
412         track.fPz = AliHLTMUONCalculations::Pz();
413         DebugTrace("Calculated Px = " << track.fPx << ", Py = " << track.fPy
414                 << ", Pz = " << track.fPx
415         );
416         DebugTrace("\tusing x1 = " << x1 << " , y1 = " << y1 << " , y2 = " << y2
417                 << " , z1 = " << z1 << " , z2 = " << z2
418         );
419         
420         track.fChi2 = 0;
421         
422         bool hitset[4];
423         // Depending on which chamber we found reconstructed hits, fill the hit
424         // in the appropriate location. This is done for station 4 then 5.
425         if (fSt4chamber == kChamber8)
426         {
427                 track.fHit[0] = AliHLTMUONConstants::NilRecHitStruct();
428                 hitset[0] = false;
429                 track.fHit[1] = fFoundPoint->fClusterPoint;
430                 hitset[1] = true;
431         }
432         else
433         {
434                 track.fHit[0] = fFoundPoint->fClusterPoint;
435                 hitset[0] = true;
436                 track.fHit[1] = AliHLTMUONConstants::NilRecHitStruct();
437                 hitset[1] = false;
438         }
439         if (fMc1.fChamber == kChamber10)
440         {
441                 track.fHit[2] = AliHLTMUONConstants::NilRecHitStruct();
442                 hitset[2] = false;
443                 track.fHit[3] = fSt5rec->fClusterPoint;
444                 hitset[3] = true;
445         }
446         else
447         {
448                 track.fHit[2] = fSt5rec->fClusterPoint;
449                 hitset[2] = true;
450                 track.fHit[3] = AliHLTMUONConstants::NilRecHitStruct();
451                 hitset[3] = false;
452         }
453         
454         track.fFlags = AliHLTMUONUtils::PackMansoTrackFlags(
455                         AliHLTMUONCalculations::Sign(), hitset
456                 );
457         return calculated;
458 }
459
460
461 void AliHLTMUONMansoTrackerFSM::Reset()
462 {
463 // Implementation of AliHLTMUONMansoTrackerFSM::Reset
464
465         DebugTrace("SM5 state = " << fSm5state << " , SM4 state = " << fSm4state);
466         fSt5data.Clear();
467         fSt4points.Clear();
468         fSm4state = kSM4Idle;
469         fSm5state = kSM5Idle;
470         fRequestsCompleted = 0;
471         fTriggerId = -1;
472 }
473
474
475 // Note: In the following ReceiveClustersXXX and EndOfClustersXXX methods we make
476 // the state machine transitions before calls to RequestClusters, FoundTrack, 
477 // NoTrackFound or EndOfClusterRequests. This is important since the callback
478 // object will make recursive calls to the tracker's methods so we need to maintain
479 // a consistant internal state.
480 // The same would go for updating internal variables.
481 // In general one should only call the callback methods at the end of any of the
482 // following routines.
483
484 void AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber7(
485                 const AliHLTMUONRecHitStruct* clusters, AliHLTUInt32_t count,
486                 const AliTagData* data
487         )
488 {
489 // State change method for Station 4 state machine.
490
491         switch (fSm4state)
492         {
493         case kWaitChamber7:
494                 fSm4state = kWaitMoreChamber7;
495         
496         case kWaitMoreChamber7:
497                 for (AliHLTUInt32_t j = 0; j < count; j++)
498                 {
499                         AliHLTMUONRecHitStruct cluster = clusters[j];
500                         // Check that the cluster actually is in our region of interest on station 4.
501                         if ( data->fRoi.Contains(cluster) )
502                         {
503                                 DebugTrace("Adding cluster [" << cluster.fX << ", " << cluster.fY << "] from chamber 7.");
504                                 AliStation4Data* newdata = fSt4points.Add();
505                                 newdata->fClusterPoint = cluster;
506                                 newdata->fSt5tag = data;
507                         }
508                 }
509                 break;
510         
511         default:
512                 DebugTrace("ERROR: Unexpected state for SM4 in AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber7!");
513         }
514 }
515
516
517 void AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber8(
518                 const AliHLTMUONRecHitStruct* clusters, AliHLTUInt32_t count,
519                 const AliTagData* data
520         )
521 {
522 // State change method for Station 4 state machine.
523
524         switch (fSm4state)
525         {
526         case kWaitChamber8:
527                 fSm4state = kWaitMoreChamber8;
528                 fSt4chamber = kChamber8;
529         
530         case kWaitMoreChamber8:
531                 for (AliHLTUInt32_t j = 0; j < count; j++)
532                 {
533                         AliHLTMUONRecHitStruct cluster = clusters[j];
534                         // Check that the cluster actually is in our region of interest on station 4.
535                         if ( data->fRoi.Contains(cluster) )
536                         {
537                                 DebugTrace("Adding cluster [" << cluster.fX << ", " << cluster.fY << "] from chamber 8.");
538                                 AliStation4Data* newdata = fSt4points.Add();
539                                 newdata->fClusterPoint = cluster;
540                                 newdata->fSt5tag = data;
541                         }
542                 }
543                 break;
544                 
545         default:
546                 DebugTrace("ERROR: Unexpected state for SM4 in AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber8!");
547         }
548 }
549
550
551 void AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber9(
552                 const AliHLTMUONRecHitStruct* clusters, AliHLTUInt32_t count
553         )
554 {
555 // State change method for Station 5 state machine.
556
557         switch (fSm5state)
558         {
559         case kWaitChamber9:
560                 fSm5state = kWaitMoreChamber9;
561                 fSm4state = kWaitChamber8;  // Start SM4.
562         
563         case kWaitMoreChamber9:
564                 for (AliHLTUInt32_t j = 0; j < count; j++)
565                 {
566                         AliHLTMUONRecHitStruct cluster = clusters[j];
567                         // Check that the cluster actually is in our region of interest on station 5.
568                         if ( fMc1.fRoi.Contains(cluster) )
569                         {
570                                 DebugTrace("Adding cluster [" << cluster.fX << ", " << cluster.fY << "] from chamber 9.");
571                                 AliStation5Data* data = fSt5data.Add();
572                                 data->fClusterPoint = cluster;
573                                 ProjectToStation4(data, fgZ9);  // This adds a new request for station 4.
574                         }
575                 }
576                 break;
577
578         default:
579                 DebugTrace("ERROR: Unexpected state for SM5 in AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber9!");
580         }
581 }
582
583
584 void AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber10(
585                 const AliHLTMUONRecHitStruct* clusters, AliHLTUInt32_t count
586         )
587 {
588 // State change method for Station 5 state machine.
589
590         switch (fSm5state)
591         {
592         case kWaitChamber10:
593                 fSm5state = kWaitMoreChamber10;
594                 fSm4state = kWaitChamber8;  // Start SM4.
595         
596         case kWaitMoreChamber10:
597                 for (AliHLTUInt32_t j = 0; j < count; j++)
598                 {
599                         AliHLTMUONRecHitStruct cluster = clusters[j];
600                         // Check that the cluster actually is in our region of interest on station 5.
601                         if ( fMc1.fRoi.Contains(cluster) )
602                         {
603                                 DebugTrace("Adding cluster [" << cluster.fX << ", " << cluster.fY << "] from chamber 10.");
604                                 AliStation5Data* data = fSt5data.Add();
605                                 data->fClusterPoint = cluster;
606                                 ProjectToStation4(data, fgZ10);  // This adds a new request for station 4.
607                         }
608                 }
609                 break;
610
611         default:
612                 DebugTrace("ERROR: Unexpected state for SM5 in AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber10!");
613         }
614 }
615
616
617 void AliHLTMUONMansoTrackerFSM::EndOfClustersChamber7()
618 {
619 // State change method for Station 4 state machine.
620
621         fRequestsCompleted++;  // Increment the number of requests completed for station 4.
622         DebugTrace("fRequestsCompleted = " << fRequestsCompleted );
623
624         switch (fSm4state)
625         {
626         case kWaitChamber7:
627                 // If all data from station 5 is received and no data found on
628                 // chambers 7 or 8 then we can not find a track.
629                 if (fSm5state == kSM5Done) NoTrackFound();
630                 break;
631         
632         case kWaitMoreChamber7:
633                 if (fRequestsCompleted == fSt5data.Count() && fSm5state == kSM5Done)
634                         ProcessClusters();
635                 break;
636         
637         default:
638                 DebugTrace("ERROR: Unexpected state for SM4 in AliHLTMUONMansoTrackerFSM::EndOfClustersChamber7!");
639         }
640 }
641
642
643 void AliHLTMUONMansoTrackerFSM::EndOfClustersChamber8()
644 {
645 // State change method for Station 4 state machine.
646
647         fRequestsCompleted++;  // Increment the number of requests completed for station 4.
648         DebugTrace("fRequestsCompleted = " << fRequestsCompleted );
649
650         switch (fSm4state)
651         {
652         case kWaitChamber7:
653                 // Ignore. The requests for chamber 8 are already re-requested below.
654                 break;
655                 
656         case kWaitChamber8:
657                 {
658                 fSm4state = kWaitChamber7;
659                 fSt4chamber = kChamber7;
660         
661                 // We need to resend the requests for chamber 8, but change the request
662                 // to get data for chamber 7 instead:
663                 AliHLTUInt32_t reqlistsize = fSt5data.Count();
664                 DebugTrace("Re-requesting clusters from chamber 7... reqlistsize = " << reqlistsize);
665
666                 Station5List::Iterator rec = fSt5data.First();
667                 for (AliHLTUInt32_t i = 0; i < reqlistsize; i++, rec++)
668                 {
669                         // Need to create a new st5 data block for the request.
670                         AliStation5Data* data = fSt5data.Add();
671                         data->fClusterPoint = rec->fClusterPoint;
672                         data->fTag.fLine = rec->fTag.fLine;
673
674                         // Rebuild a region of interest for chamber 7.
675                         // Remember the parameters a and b are station specific.
676                         AliHLTMUONRecHitStruct p7 = data->fTag.fLine.FindIntersectWithXYPlain( fgZ7 );
677                         data->fTag.fChamber = kChamber7;
678                         data->fTag.fRoi.Create(p7, fgA7, fgB7);
679                         
680                         AliHLTFloat32_t left, right, bottom, top;
681                         data->fTag.fRoi.GetBoundaryBox(left, right, bottom, top);
682                         // Make request for chamber 7 data.
683                         RequestClusters(left, right, bottom, top, kChamber7, &data->fTag);
684                 }
685                 }
686                 break;
687         
688         case kWaitMoreChamber8:
689                 if (fRequestsCompleted == fSt5data.Count() && fSm5state == kSM5Done)
690                         ProcessClusters();
691                 break;
692         
693         default:
694                 DebugTrace("ERROR: Unexpected state for SM4 in AliHLTMUONMansoTrackerFSM::EndOfClustersChamber8!");
695         }
696 }
697
698
699 void AliHLTMUONMansoTrackerFSM::EndOfClustersChamber9()
700 {
701 // State change method for Station 5 state machine.
702
703         switch (fSm5state)
704         {
705         case kWaitChamber9:
706                 fSm5state = kSM5Done;
707                 EndOfClusterRequests();
708                 NoTrackFound();
709                 break;
710                 
711         case kWaitMoreChamber9:
712                 fSm5state = kSM5Done;
713                 EndOfClusterRequests();
714                 if (fRequestsCompleted == fSt5data.Count())
715                         ProcessClusters();
716                 break;
717
718         default:
719                 DebugTrace("ERROR: Unexpected state for SM5 in AliHLTMUONMansoTrackerFSM::EndOfClustersChamber9!");
720         }
721 }
722
723
724 void AliHLTMUONMansoTrackerFSM::EndOfClustersChamber10()
725 {
726 // State change method for Station 5 state machine.
727
728         switch (fSm5state)
729         {
730         case kWaitChamber10:
731                 {
732                 fSm5state = kWaitChamber9;
733                 
734                 // No clusters found on chamber 10 so we need to make a request for
735                 // clusters from chamber 9:
736                 AliHLTMUONRecHitStruct p9 = fMc1.fLine.FindIntersectWithXYPlain( fgZ9 );
737
738                 // Build a region of interest for tracking station 5 (chamber 9).
739                 // Remember the parameters a and b are station specific.
740                 fMc1.fChamber = kChamber9;
741                 fMc1.fRoi.Create(p9, fgA9, fgB9);
742
743                 AliHLTFloat32_t left, right, bottom, top;
744                 fMc1.fRoi.GetBoundaryBox(left, right, bottom, top);
745                 RequestClusters(left, right, bottom, top, kChamber9, &fMc1);
746                 }
747                 break;
748
749         case kWaitMoreChamber10:
750                 fSm5state = kSM5Done;
751                 EndOfClusterRequests();
752                 if (fRequestsCompleted == fSt5data.Count())
753                         ProcessClusters();
754                 break;
755
756         default:
757                 DebugTrace("ERROR: Unexpected state for SM5 in AliHLTMUONMansoTrackerFSM::EndOfClustersChamber10!");
758         }
759 }
760
761
762 void AliHLTMUONMansoTrackerFSM::ProjectToStation4(
763                 AliStation5Data* data, register AliHLTFloat32_t station5z
764         )
765 {
766         // Perform chamber specific operations:
767         // Since certain states of SM4 means that it is fetching for Chamber8
768         // and other states are for fetching from Chamber7. We need to make
769         // requests for the correct chamber.
770         assert( fSm4state == kWaitChamber8 
771                 || fSm4state == kWaitMoreChamber8
772                 || fSm4state == kWaitChamber7
773                 || fSm4state == kWaitMoreChamber7
774         );
775         AliTagData* tag = &data->fTag;
776         if (fSm4state == kWaitChamber8 || fSm4state == kWaitMoreChamber8)
777         {
778                 // Form the vector line between trigger station 1 and tracking station 5,
779                 // and find the intersection point of the line with station 4 (chamber8).
780                 AliLine line51( AliVertex(data->fClusterPoint, station5z), fV1 );
781                 AliHLTMUONRecHitStruct intercept = line51.FindIntersectWithXYPlain( fgZ8 );
782                 tag->fLine = line51;
783                 
784                 // Build a region of interest for tracking station 4.
785                 tag->fChamber = kChamber8;
786                 tag->fRoi.Create(intercept, fgA8, fgB8);
787         }
788         else
789         {
790                 // Form the vector line between trigger station 1 and tracking station 5,
791                 // and find the intersection point of the line with station 4 (chamber7).
792                 AliLine line51( AliVertex(data->fClusterPoint, station5z), fV1 );
793                 AliHLTMUONRecHitStruct intercept = line51.FindIntersectWithXYPlain( fgZ7 );
794                 tag->fLine = line51;
795                 
796                 // Build a region of interest for tracking station 4.
797                 tag->fChamber = kChamber7;
798                 tag->fRoi.Create(intercept, fgA7, fgB7);
799         }
800
801         // Make the request for clusters from station 4.
802         AliHLTFloat32_t left, right, bottom, top;
803         tag->fRoi.GetBoundaryBox(left, right, bottom, top);
804         RequestClusters(left, right, bottom, top, tag->fChamber, tag);
805 }
806
807
808 void AliHLTMUONMansoTrackerFSM::ProcessClusters()
809 {
810 // Process clusters that have been received.
811 // This is called once all clusters have been found.
812
813         DebugTrace("ProcessClusters...");
814         
815         // Check if the cluster point list on station 4 is empty.
816         // If it is then we have not found any tracks.
817         fFoundPoint = fSt4points.First();
818         if (fFoundPoint == fSt4points.End())
819         {
820                 NoTrackFound();
821                 return;
822         }
823         
824         fSt5rec = fSt5data.First();
825         if (fSt5rec != fSt5data.End())
826         {
827                 // Only look at station 5 data records that are for the found chamber number.
828                 // Note: either we only have chamber 8 data or we have chamber 7 data followed
829                 // by chamber 8 data.
830                 // Thus if we hit records that we are not interested in already then the list
831                 // contains no interesting data and we can signal no track found.
832                 if (fSt5rec->fTag.fChamber != fSt4chamber)
833                 {
834                         NoTrackFound();
835                         return;
836                 }
837                  
838                 // For all combinations of cluster point pairs from station 4 and 5
839                 // signal a found track:
840                 do
841                 {
842                         DebugTrace("\tfSt5rec->fTag.chamber = " << fSt5rec->fTag.fChamber
843                                 << " , fSt4chamber = " << fSt4chamber
844                         );
845
846                         for (fFoundPoint = fSt4points.First(); fFoundPoint != fSt4points.End(); fFoundPoint++)
847                         {
848                                 if (fFoundPoint->fSt5tag == &fSt5rec->fTag)
849                                         FoundTrack();
850                         }
851
852                         fSt5rec++;  // Get next station 5 cluster point.
853                 } while (fSt5rec != fSt5data.End() && fSt5rec->fTag.fChamber == fSt4chamber);
854         }
855         else
856                 NoTrackFound();
857 }
858