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