--- /dev/null
+/**************************************************************************
+ * Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
+ * *
+ * Author: The ALICE Off-line Project. *
+ * Contributors are mentioned in the code where appropriate. *
+ * *
+ * Permission to use, copy, modify and distribute this software and its *
+ * documentation strictly for non-commercial purposes is hereby granted *
+ * without fee, provided that the above copyright notice appears in all *
+ * copies and that both the copyright notice and this permission notice *
+ * appear in the supporting documentation. The authors make no claims *
+ * about the suitability of this software for any purpose. It is *
+ * provided "as is" without express or implied warranty. *
+ **************************************************************************/
+
+/* $Id$ */
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Author: Artur Szostak
+// Email: artur@alice.phy.uct.ac.za | artursz@iafrica.com
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "AliHLTMUONMansoTrackerFSM.h"
+#include "AliHLTMUONCalculations.h"
+#include "AliHLTMUONUtils.h"
+#include <cmath>
+
+
+#ifdef DEBUG
+#include <ostream>
+namespace
+{
+
+std::ostream& operator << (std::ostream& os, AliHLTMUONMansoTrackerFSM::StatesSM4 state)
+{
+ switch (state)
+ {
+ case AliHLTMUONMansoTrackerFSM::kSM4Idle: os << "kSM4Idle"; break;
+ case AliHLTMUONMansoTrackerFSM::kWaitChamber8: os << "kWaitChamber8"; break;
+ case AliHLTMUONMansoTrackerFSM::kWaitMoreChamber8: os << "kWaitMoreChamber8"; break;
+ case AliHLTMUONMansoTrackerFSM::kWaitChamber7: os << "kWaitChamber7"; break;
+ case AliHLTMUONMansoTrackerFSM::kWaitMoreChamber7: os << "kWaitMoreChamber7"; break;
+ default: os << "FAULT!!";
+ }
+ return os;
+}
+
+std::ostream& operator << (std::ostream& os, AliHLTMUONMansoTrackerFSM::StatesSM5 state)
+{
+ switch (state)
+ {
+ case AliHLTMUONMansoTrackerFSM::kSM5Idle: os << "kSM5Idle"; break;
+ case AliHLTMUONMansoTrackerFSM::kWaitChamber10: os << "kWaitChamber10"; break;
+ case AliHLTMUONMansoTrackerFSM::kWaitMoreChamber10: os << "kWaitMoreChamber10"; break;
+ case AliHLTMUONMansoTrackerFSM::kWaitChamber9: os << "kWaitChamber9"; break;
+ case AliHLTMUONMansoTrackerFSM::kWaitMoreChamber9: os << "kWaitMoreChamber9"; break;
+ case AliHLTMUONMansoTrackerFSM::kSM5Done: os << "kSM5Done"; break;
+ default: os << "FAULT!!";
+ }
+ return os;
+}
+
+} // end of namespace
+#endif // DEBUG
+
+
+// Deviate from the Manso implementation by allowing a and b
+// parameters per chamber and not just per station.
+// The default values are derived from the work done in
+// "A first algorithm for dimuon High Level Trigger"
+// Ref ID: ALICE-INT-2002-04 version 1.0
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgA7 = 0.016f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgB7 = 2.0f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgA8 = 0.016f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgB8 = 2.0f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgA9 = 0.020f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgB9 = 3.0f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgA10 = 0.020f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgB10 = 3.0f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ7 = 1274.5f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ8 = 1305.5f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ9 = 1408.6f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ10 = 1439.6f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ11 = 1603.5f;
+AliHLTFloat32_t AliHLTMUONMansoTrackerFSM::fgZ13 = 1703.5f;
+
+
+void AliHLTMUONMansoTrackerFSM::AliRegionOfInterest::Create(AliHLTMUONCorePoint p, AliHLTFloat32_t a, AliHLTFloat32_t b)
+{
+// Creates a region of interest specific to the Manso algorithm from a point and
+// two Manso specific parameters.
+
+ fCentre = p;
+ // Compute the radius Rp
+ AliHLTFloat32_t rp = (AliHLTFloat32_t) sqrt( p.X() * p.X() + p.Y() * p.Y() );
+
+ // The radius Rs for the region of interest is computed from the
+ // specification given in the document:
+ // "A first algorithm for dimuon High Level Trigger"
+ // Ref ID: ALICE-INT-2002-04 version 1.0
+ // equation:
+ // Rs = a * Rp + b
+ // given on page 3 section 4.
+ fRs = a * rp + b;
+}
+
+
+bool AliHLTMUONMansoTrackerFSM::AliRegionOfInterest::Contains(AliHLTMUONCorePoint p) const
+{
+ // Compute the distance between the centre of the region of interest and
+ // the point p. This distance must be less than the radius of the region
+ // of interest for p to be contained in the region of interest.
+ register AliHLTFloat32_t lx = fCentre.X() - p.X();
+ register AliHLTFloat32_t ly = fCentre.Y() - p.Y();
+ register AliHLTFloat32_t r = (AliHLTFloat32_t) sqrt( lx * lx + ly * ly );
+ DebugTrace("\tAliRegionOfInterest::Contains : p = " << p
+ << " , centre = " << fCentre << " , r = " << r << " , Rs = " << fRs
+ );
+ return r <= fRs;
+}
+
+
+void AliHLTMUONMansoTrackerFSM::AliRegionOfInterest::GetBoundaryBox(
+ AliHLTFloat32_t& left, AliHLTFloat32_t& right, AliHLTFloat32_t& bottom, AliHLTFloat32_t& top
+ ) const
+{
+// Works out the smallest boundary box that will contain the region of interest.
+
+ left = fCentre.X() - fRs;
+ right = fCentre.X() + fRs;
+ bottom = fCentre.Y() - fRs;
+ top = fCentre.Y() + fRs;
+}
+
+
+AliHLTMUONMansoTrackerFSM::AliVertex::AliVertex(AliHLTFloat32_t x, AliHLTFloat32_t y, AliHLTFloat32_t z)
+ : fX(x), fY(y), fZ(z)
+{
+// Constructor for vertex.
+
+ fX = x;
+ fY = y;
+ fZ = z;
+}
+
+
+AliHLTMUONMansoTrackerFSM::AliVertex::AliVertex(AliHLTMUONCorePoint xy, AliHLTFloat32_t z)
+ : fX(xy.X()), fY(xy.Y()), fZ(z)
+{
+// Construct vertex from a point on the XY plane and z coordinate.
+
+ fX = xy.X();
+ fY = xy.Y();
+ fZ = z;
+}
+
+
+AliHLTMUONMansoTrackerFSM::AliLine::AliLine(
+ AliHLTFloat32_t ax, AliHLTFloat32_t ay, AliHLTFloat32_t az,
+ AliHLTFloat32_t bx, AliHLTFloat32_t by, AliHLTFloat32_t bz
+ ) :
+ fMx(ax - bx), fMy(ay - by), fMz(az - bz),
+ fCx(bx), fCy(by), fCz(bz)
+{
+// Construct a line defined by L = M*t + C = (A-B)*t + B
+// where M and C are 3D vectors and t is a free parameter.
+// A = (ax, ay, az) and B = (bx, by, bz)
+
+ fMx = ax - bx;
+ fMy = ay - by;
+ fMz = az - bz;
+ fCx = bx;
+ fCy = by;
+ fCz = bz;
+}
+
+
+AliHLTMUONMansoTrackerFSM::AliLine::AliLine(AliVertex a, AliVertex b) :
+ fMx(a.X() - b.X()), fMy(a.Y() - b.Y()), fMz(a.Z() - b.Z()),
+ fCx(b.X()), fCy(b.Y()), fCz(b.Z())
+{
+// Contruct a line to go through two vertices a and b.
+
+ fMx = a.X() - b.X();
+ fMy = a.Y() - b.Y();
+ fMz = a.Z() - b.Z();
+ fCx = b.X();
+ fCy = b.Y();
+ fCz = b.Z();
+}
+
+
+AliHLTMUONCorePoint AliHLTMUONMansoTrackerFSM::AliLine::FindIntersectWithXYPlain(AliHLTFloat32_t z) const
+{
+// Find the point of intersection of the line and the XY plane at z.
+
+ Assert( fMz != 0.0 ); // Should not have a ray perpendicular to the beam axis.
+ AliHLTFloat32_t t = (z - fCz) / fMz;
+ AliHLTFloat32_t lx = fMx*t + fCx;
+ AliHLTFloat32_t ly = fMy*t + fCy;
+
+ return AliHLTMUONCorePoint(lx, ly);
+}
+
+
+AliHLTMUONMansoTrackerFSM::AliHLTMUONMansoTrackerFSM() :
+ fCallback(NULL),
+ fSm4state(kSM4Idle),
+ fSm5state(kSM5Idle),
+ fRequestsCompleted(0),
+ fSt4chamber(kChamber1),
+ fV1(),
+ fMc1(),
+ fSt5z(0),
+ fSt5data(),
+ fSt4z(0),
+ fSt4points(),
+ fSt5rec(),
+ fFoundPoint()
+{
+// Default constructor
+}
+
+
+void AliHLTMUONMansoTrackerFSM::FindTrack(const AliHLTMUONCoreTriggerRecord& trigger)
+{
+// Tries to find the track from the trigger seed.
+
+ DebugTrace("SM5 state = " << fSm5state << " , SM4 state = " << fSm4state);
+ DebugTrace("Processing trigger with pt = " << trigger.fPt);
+ fV1 = AliVertex( trigger.fStation1impact, fgZ11 );
+ AliVertex v2 = AliVertex( trigger.fStation2impact, fgZ13 );
+
+ // Form the vector line between the above two impact points and
+ // find the crossing point of the line with chamber 10 (i.e. station 5).
+ fMc1.fLine = AliLine(fV1, v2);
+ AliHLTMUONCorePoint p10 = fMc1.fLine.FindIntersectWithXYPlain( fgZ10 );
+
+ // Build a region of interest for tracking station 5 (chamber 10).
+ // Remember the parameters a and b are station specific.
+ fMc1.fChamber = kChamber10;
+ fMc1.fRoi.Create(p10, fgA10, fgB10);
+
+ // Make SM5 state transition before the call to RequestClusters since
+ // that method could call one of our methods again, so we need to be
+ // in a consistant internal state.
+ fSm5state = kWaitChamber10;
+
+ AliHLTFloat32_t left, right, bottom, top;
+ fMc1.fRoi.GetBoundaryBox(left, right, bottom, top);
+ RequestClusters(left, right, bottom, top, kChamber10, &fMc1);
+}
+
+
+void AliHLTMUONMansoTrackerFSM::ReturnClusters(void* tag, const AliHLTMUONCoreClusterPoint* clusters, UInt count)
+{
+// Implementation of AliHLTMUONCoreTracker::ReturnClusters.
+
+ Assert( count > 0 );
+ Assert( clusters != NULL );
+
+ AliTagData* data = (AliTagData*)tag;
+ DebugTrace("Got AliHLTMUONMansoTrackerFSM::ReturnClusters(tag = " << tag
+ << ", chamber = " << data->fChamber
+ << ", clusters = " << clusters << ", count = " << count << ")"
+ );
+ DebugTrace("SM5 state = " << fSm5state << " , SM4 state = " << fSm4state);
+
+ switch (data->fChamber)
+ {
+ case kChamber7: ReceiveClustersChamber7(clusters, count, data); break;
+ case kChamber8: ReceiveClustersChamber8(clusters, count, data); break;
+ case kChamber9: ReceiveClustersChamber9(clusters, count); break;
+ case kChamber10: ReceiveClustersChamber10(clusters, count); break;
+ default:
+ // Error
+ DebugTrace("ERROR: Got tag with an invalid value: " << data->fChamber);
+ }
+}
+
+
+void AliHLTMUONMansoTrackerFSM::EndOfClusters(void* tag)
+{
+// Implementation of AliHLTMUONCoreTracker::EndOfClusters.
+
+ AliTagData* data = (AliTagData*)tag;
+ DebugTrace("Got AliHLTMUONMansoTrackerFSM::EndOfClusters(chamber = " << data->fChamber << ")");
+ DebugTrace("SM5 state = " << fSm5state << " , SM4 state = " << fSm4state);
+
+ switch (data->fChamber)
+ {
+ case kChamber7: EndOfClustersChamber7(); break;
+ case kChamber8: EndOfClustersChamber8(); break;
+ case kChamber9: EndOfClustersChamber9(); break;
+ case kChamber10: EndOfClustersChamber10(); break;
+ default:
+ // Error
+ DebugTrace("ERROR: Got tag with an invalid value: " << data->fChamber);
+ }
+}
+
+
+void AliHLTMUONMansoTrackerFSM::FillTrackData(AliHLTMUONCoreTrack& track)
+{
+// Implementation of AliHLTMUONCoreTracker::FillTrackData
+
+ DebugTrace("FillTrack: st5 = " << fSt5rec->fClusterPoint << ", st4 = " << fFoundPoint->fClusterPoint);
+
+ AliHLTFloat32_t x1 = fFoundPoint->fClusterPoint.X();
+ AliHLTFloat32_t y1 = fFoundPoint->fClusterPoint.Y();
+ AliHLTFloat32_t y2 = fSt5rec->fClusterPoint.Y();
+ AliHLTFloat32_t momentum;
+ AliHLTFloat32_t pt = AliHLTMUONCoreCalculateSignedPt(x1, y1, y2, fSt4z, fSt5z, momentum);
+ DebugTrace("Calculated Pt = " << pt);
+ DebugTrace("\tusing x1 = " << x1 << " , y1 = " << y1 << " , y2 = " << y2
+ << " , z1 = " << fSt4z << " , z2 = " << fSt5z
+ );
+
+ if (pt < 0)
+ track.fSign = kSignMinus;
+ else if (pt > 0)
+ track.fSign = kSignPlus;
+ else
+ track.fSign = kUnknownSign;
+
+ track.fP = momentum;
+ track.fPt = (AliHLTFloat32_t) fabs(pt);
+ for (UInt i = 0; i < 6; i++)
+ {
+ track.fPoint[i] = AliHLTMUONCorePoint(0.0, 0.0);
+ track.fRegion[i] = kInvalidROI;
+ }
+
+ AliHLTFloat32_t left, right, bottom, top;
+
+ // Have to create the ROI numbers from the internal region of interest structures.
+ fSt5rec->fTag.fRoi.GetBoundaryBox(left, right, bottom, top);
+ AliHLTMUONCoreRegionOfInterest region4(left, right, bottom, top, fSt4chamber);
+ fMc1.fRoi.GetBoundaryBox(left, right, bottom, top);
+ AliHLTMUONCoreRegionOfInterest region5(left, right, bottom, top, fMc1.fChamber);
+
+ // Depending on the chamber we received cluster points from, fill the appropriate
+ // point and ROI number. This is done for station 4 then 5.
+ if (fSt4chamber == kChamber8)
+ {
+ track.fPoint[6] = AliHLTMUONCorePoint(0.0, 0.0);
+ track.fRegion[6] = kInvalidROI;
+ track.fPoint[7] = fFoundPoint->fClusterPoint;
+ track.fRegion[7] = region4;
+ }
+ else
+ {
+ track.fPoint[6] = fFoundPoint->fClusterPoint;
+ track.fRegion[6] = region4;
+ track.fPoint[7] = AliHLTMUONCorePoint(0.0, 0.0);
+ track.fRegion[7] = kInvalidROI;
+ }
+ if (fMc1.fChamber == kChamber10)
+ {
+ track.fPoint[8] = AliHLTMUONCorePoint(0.0, 0.0);
+ track.fRegion[8] = kInvalidROI;
+ track.fPoint[9] = fSt5rec->fClusterPoint;
+ track.fRegion[9] = region5;
+ }
+ else
+ {
+ track.fPoint[8] = fSt5rec->fClusterPoint;
+ track.fRegion[8] = region5;
+ track.fPoint[9] = AliHLTMUONCorePoint(0.0, 0.0);
+ track.fRegion[9] = kInvalidROI;
+ }
+}
+
+
+void AliHLTMUONMansoTrackerFSM::Reset()
+{
+// Implementation of AliHLTMUONCoreTracker::Reset
+
+ DebugTrace("SM5 state = " << fSm5state << " , SM4 state = " << fSm4state);
+ fSt5data.Clear();
+ fSt4points.Clear();
+ fSm4state = kSM4Idle;
+ fSm5state = kSM5Idle;
+ fRequestsCompleted = 0;
+}
+
+
+// Note: In the following ReceiveClustersXXX and EndOfClustersXXX methods we make
+// the state machine transitions before calls to RequestClusters, FoundTrack,
+// NoTrackFound or EndOfClusterRequests. This is important since the callback
+// object will make recursive calls to the tracker's methods so we need to maintain
+// a consistant internal state.
+// The same would go for updating internal variables.
+// In general one should only call the callback methods at the end of any of the
+// following routines.
+
+void AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber7(
+ const AliHLTMUONCoreClusterPoint* clusters, UInt count, const AliTagData* data
+ )
+{
+// State change method for Station 4 state machine.
+
+ switch (fSm4state)
+ {
+ case kWaitChamber7:
+ fSm4state = kWaitMoreChamber7;
+
+ case kWaitMoreChamber7:
+ for (UInt j = 0; j < count; j++)
+ {
+ AliHLTMUONCoreClusterPoint cluster = clusters[j];
+ // Check that the cluster actually is in our region of interest on station 4.
+ if ( data->fRoi.Contains(cluster) )
+ {
+ DebugTrace("Adding cluster [" << cluster.X() << ", " << cluster.Y() << "] from chamber 7.");
+ AliStation4Data* newdata = fSt4points.New();
+ newdata->fClusterPoint = cluster;
+ newdata->fSt5tag = data;
+ }
+ }
+ break;
+
+ default:
+ DebugTrace("ERROR: Unexpected state for SM4 in AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber7!");
+ }
+}
+
+
+void AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber8(
+ const AliHLTMUONCoreClusterPoint* clusters, UInt count, const AliTagData* data
+ )
+{
+// State change method for Station 4 state machine.
+
+ switch (fSm4state)
+ {
+ case kWaitChamber8:
+ fSm4state = kWaitMoreChamber8;
+ fSt4z = fgZ8;
+ fSt4chamber = kChamber8;
+
+ case kWaitMoreChamber8:
+ for (UInt j = 0; j < count; j++)
+ {
+ AliHLTMUONCoreClusterPoint cluster = clusters[j];
+ // Check that the cluster actually is in our region of interest on station 4.
+ if ( data->fRoi.Contains(cluster) )
+ {
+ DebugTrace("Adding cluster [" << cluster.X() << ", " << cluster.Y() << "] from chamber 8.");
+ AliStation4Data* newdata = fSt4points.New();
+ newdata->fClusterPoint = cluster;
+ newdata->fSt5tag = data;
+ }
+ }
+ break;
+
+ default:
+ DebugTrace("ERROR: Unexpected state for SM4 in AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber8!");
+ }
+}
+
+
+void AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber9(const AliHLTMUONCoreClusterPoint* clusters, UInt count)
+{
+// State change method for Station 5 state machine.
+
+ switch (fSm5state)
+ {
+ case kWaitChamber9:
+ fSm5state = kWaitMoreChamber9;
+ fSm4state = kWaitChamber8; // Start SM4.
+
+ case kWaitMoreChamber9:
+ for (UInt j = 0; j < count; j++)
+ {
+ AliHLTMUONCoreClusterPoint cluster = clusters[j];
+ // Check that the cluster actually is in our region of interest on station 5.
+ if ( fMc1.fRoi.Contains(cluster) )
+ {
+ DebugTrace("Adding cluster [" << cluster.X() << ", " << cluster.Y() << "] from chamber 9.");
+ AliStation5Data* data = fSt5data.New();
+ data->fClusterPoint = cluster;
+ ProjectToStation4(data, fgZ9); // This adds a new request for station 4.
+ }
+ }
+ break;
+
+ default:
+ DebugTrace("ERROR: Unexpected state for SM5 in AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber9!");
+ }
+}
+
+
+void AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber10(const AliHLTMUONCoreClusterPoint* clusters, UInt count)
+{
+// State change method for Station 5 state machine.
+
+ switch (fSm5state)
+ {
+ case kWaitChamber10:
+ fSm5state = kWaitMoreChamber10;
+ fSt5z = fgZ10;
+ fSm4state = kWaitChamber8; // Start SM4.
+
+ case kWaitMoreChamber10:
+ for (UInt j = 0; j < count; j++)
+ {
+ AliHLTMUONCoreClusterPoint cluster = clusters[j];
+ // Check that the cluster actually is in our region of interest on station 5.
+ if ( fMc1.fRoi.Contains(cluster) )
+ {
+ DebugTrace(4, "Adding cluster [" << cluster.X() << ", " << cluster.Y() << "] from chamber 10.");
+ AliStation5Data* data = fSt5data.New();
+ data->fClusterPoint = cluster;
+ ProjectToStation4(data, fgZ10); // This adds a new request for station 4.
+ }
+ }
+ break;
+
+ default:
+ DebugTrace("ERROR: Unexpected state for SM5 in AliHLTMUONMansoTrackerFSM::ReceiveClustersChamber10!");
+ }
+}
+
+
+void AliHLTMUONMansoTrackerFSM::EndOfClustersChamber7()
+{
+// State change method for Station 4 state machine.
+
+ fRequestsCompleted++; // Increment the number of requests completed for station 4.
+ DebugTrace("fRequestsCompleted = " << fRequestsCompleted );
+
+ switch (fSm4state)
+ {
+ case kWaitChamber7:
+ // If all data from station 5 is received and no data found on
+ // chambers 7 or 8 then we can not find a track.
+ if (fSm5state == kSM5Done) NoTrackFound();
+ break;
+
+ case kWaitMoreChamber7:
+ if (fRequestsCompleted == fSt5data.Count() && fSm5state == kSM5Done)
+ ProcessClusters();
+ break;
+
+ default:
+ DebugTrace("ERROR: Unexpected state for SM4 in AliHLTMUONMansoTrackerFSM::EndOfClustersChamber7!");
+ }
+}
+
+
+void AliHLTMUONMansoTrackerFSM::EndOfClustersChamber8()
+{
+// State change method for Station 4 state machine.
+
+ fRequestsCompleted++; // Increment the number of requests completed for station 4.
+ DebugTrace("fRequestsCompleted = " << fRequestsCompleted );
+
+ switch (fSm4state)
+ {
+ case kWaitChamber7:
+ // Ignore. The requests for chamber 8 are already re-requested below.
+ break;
+
+ case kWaitChamber8:
+ {
+ fSm4state = kWaitChamber7;
+ fSt4z = fgZ7;
+ fSt4chamber = kChamber7;
+
+ // We need to resend the requests for chamber 8, but change the request
+ // to get data for chamber 7 instead:
+ UInt reqlistsize = fSt5data.Count();
+ DebugTrace("Re-requesting clusters from chamber 7... reqlistsize = " << reqlistsize);
+
+ Station5List::Iterator rec = fSt5data.First();
+ for (UInt i = 0; i < reqlistsize; i++, rec++)
+ {
+ // Need to create a new st5 data block for the request.
+ AliStation5Data* data = fSt5data.New();
+ data->fClusterPoint = rec->fClusterPoint;
+ data->fTag.fLine = rec->fTag.fLine;
+
+ // Rebuild a region of interest for chamber 7.
+ // Remember the parameters a and b are station specific.
+ AliHLTMUONCorePoint p7 = data->fTag.fLine.FindIntersectWithXYPlain( fgZ7 );
+ data->fTag.fChamber = kChamber7;
+ data->fTag.fRoi.Create(p7, fgA7, fgB7);
+
+ AliHLTFloat32_t left, right, bottom, top;
+ data->fTag.fRoi.GetBoundaryBox(left, right, bottom, top);
+ // Make request for chamber 7 data.
+ RequestClusters(left, right, bottom, top, kChamber7, &data->fTag);
+ }
+ }
+ break;
+
+ case kWaitMoreChamber8:
+ if (fRequestsCompleted == fSt5data.Count() && fSm5state == kSM5Done)
+ ProcessClusters();
+ break;
+
+ default:
+ DebugTrace("ERROR: Unexpected state for SM4 in AliHLTMUONMansoTrackerFSM::EndOfClustersChamber8!");
+ }
+}
+
+
+void AliHLTMUONMansoTrackerFSM::EndOfClustersChamber9()
+{
+// State change method for Station 5 state machine.
+
+ switch (fSm5state)
+ {
+ case kWaitChamber9:
+ fSm5state = kSM5Done;
+ EndOfClusterRequests();
+ NoTrackFound();
+ break;
+
+ case kWaitMoreChamber9:
+ fSm5state = kSM5Done;
+ EndOfClusterRequests();
+ if (fRequestsCompleted == fSt5data.Count())
+ ProcessClusters();
+ break;
+
+ default:
+ DebugTrace("ERROR: Unexpected state for SM5 in AliHLTMUONMansoTrackerFSM::EndOfClustersChamber9!");
+ }
+}
+
+
+void AliHLTMUONMansoTrackerFSM::EndOfClustersChamber10()
+{
+// State change method for Station 5 state machine.
+
+ switch (fSm5state)
+ {
+ case kWaitChamber10:
+ {
+ fSm5state = kWaitChamber9;
+ fSt5z = fgZ9;
+
+ // No clusters found on chamber 10 so we need to make a request for
+ // clusters from chamber 9:
+ AliHLTMUONCorePoint p9 = fMc1.fLine.FindIntersectWithXYPlain( fgZ9 );
+
+ // Build a region of interest for tracking station 5 (chamber 9).
+ // Remember the parameters a and b are station specific.
+ fMc1.fChamber = kChamber9;
+ fMc1.fRoi.Create(p9, fgA9, fgB9);
+
+ AliHLTFloat32_t left, right, bottom, top;
+ fMc1.fRoi.GetBoundaryBox(left, right, bottom, top);
+ RequestClusters(left, right, bottom, top, kChamber9, &fMc1);
+ }
+ break;
+
+ case kWaitMoreChamber10:
+ fSm5state = kSM5Done;
+ EndOfClusterRequests();
+ if (fRequestsCompleted == fSt5data.Count())
+ ProcessClusters();
+ break;
+
+ default:
+ DebugTrace("ERROR: Unexpected state for SM5 in AliHLTMUONMansoTrackerFSM::EndOfClustersChamber10!");
+ }
+}
+
+
+void AliHLTMUONMansoTrackerFSM::ProjectToStation4(AliStation5Data* data, register AliHLTFloat32_t station5z)
+{
+ // Perform chamber specific operations:
+ // Since certain states of SM4 means that it is fetching for Chamber8
+ // and other states are for fetching from Chamber7. We need to make
+ // requests for the correct chamber.
+ Assert( fSm4state == kWaitChamber8
+ || fSm4state == kWaitMoreChamber8
+ || fSm4state == kWaitChamber7
+ || fSm4state == kWaitMoreChamber7
+ );
+ AliTagData* tag = &data->fTag;
+ if (fSm4state == kWaitChamber8 || fSm4state == kWaitMoreChamber8)
+ {
+ // Form the vector line between trigger station 1 and tracking station 5,
+ // and find the intersection point of the line with station 4 (chamber8).
+ AliLine line51( AliVertex(data->fClusterPoint, station5z), fV1 );
+ AliHLTMUONCorePoint intercept = line51.FindIntersectWithXYPlain( fgZ8 );
+ tag->fLine = line51;
+
+ // Build a region of interest for tracking station 4.
+ tag->fChamber = kChamber8;
+ tag->fRoi.Create(intercept, fgA8, fgB8);
+ }
+ else
+ {
+ // Form the vector line between trigger station 1 and tracking station 5,
+ // and find the intersection point of the line with station 4 (chamber7).
+ AliLine line51( AliVertex(data->fClusterPoint, station5z), fV1 );
+ AliHLTMUONCorePoint intercept = line51.FindIntersectWithXYPlain( fgZ7 );
+ tag->fLine = line51;
+
+ // Build a region of interest for tracking station 4.
+ tag->fChamber = kChamber7;
+ tag->fRoi.Create(intercept, fgA7, fgB7);
+ }
+
+ // Make the request for clusters from station 4.
+ AliHLTFloat32_t left, right, bottom, top;
+ tag->fRoi.GetBoundaryBox(left, right, bottom, top);
+ RequestClusters(left, right, bottom, top, tag->fChamber, tag);
+}
+
+
+void AliHLTMUONMansoTrackerFSM::ProcessClusters()
+{
+// Process clusters that have been received.
+// This is called once all clusters have been found.
+
+ DebugTrace("ProcessClusters...");
+
+ // Check if the cluster point list on station 4 is empty.
+ // If it is then we have not found any tracks.
+ fFoundPoint = fSt4points.First();
+ if (fFoundPoint == fSt4points.End())
+ {
+ NoTrackFound();
+ return;
+ }
+
+ fSt5rec = fSt5data.First();
+ if (fSt5rec != fSt5data.End())
+ {
+ // Only look at station 5 data records that are for the found chamber number.
+ // Note: either we only have chamber 8 data or we have chamber 7 data followed
+ // by chamber 8 data.
+ // Thus if we hit records that we are not interested in already then the list
+ // contains no interesting data and we can signal no track found.
+ if (fSt5rec->fTag.fChamber != fSt4chamber)
+ {
+ NoTrackFound();
+ return;
+ }
+
+ // For all combinations of cluster point pairs from station 4 and 5
+ // signal a found track:
+ do
+ {
+ DebugTrace("\tfSt5rec->fTag.chamber = " << fSt5rec->fTag.fChamber
+ << " , fSt4chamber = " << fSt4chamber
+ );
+
+ for (fFoundPoint = fSt4points.First(); fFoundPoint != fSt4points.End(); fFoundPoint++)
+ {
+ if (fFoundPoint->fSt5tag == &fSt5rec->fTag)
+ FoundTrack();
+ }
+
+ fSt5rec++; // Get next station 5 cluster point.
+ } while (fSt5rec != fSt5data.End() && fSt5rec->fTag.fChamber == fSt4chamber);
+ }
+ else
+ NoTrackFound();
+}
+
--- /dev/null
+#ifndef ALIHLTMUONMANSOTRACKERFSM_H
+#define ALIHLTMUONMANSOTRACKERFSM_H
+/* Copyright(c) 1998-2007, ALICE Experiment at CERN, All rights reserved. *
+ * See cxx source for full Copyright notice */
+
+/* $Id$ */
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Author: Artur Szostak
+// Email: artur@alice.phy.uct.ac.za | artursz@iafrica.com
+//
+////////////////////////////////////////////////////////////////////////////////
+
+#include "AliHLTMUONDataTypes.h"
+#include "AliHLTMUONList.h"
+#include "AliHLTMUONCountedList.h"
+#include "AliHLTMUONRecHitsBlockStruct.h"
+
+
+class AliHLTMUONMansoTrackerFSM : public AliHLTMUONCoreTracker
+{
+public:
+
+ AliHLTMUONMansoTrackerFSM();
+ virtual ~AliHLTMUONMansoTrackerFSM() {}
+
+
+ /* This is the starting point for the tracking algorithm. The tracker is
+ called at this point with the specified trigger record. It needs to figure
+ out which cluster blocks it needs and request them with calls to
+ RequestClusters.
+ Any memory allocated at this point should be released in the Reset method.
+
+ Note: Reset should be called for before calling FindTrack, for the
+ second or subsequent method calls to FindTrack.
+ */
+ virtual void FindTrack(const AliHLTMUONCoreTriggerRecord& trigger);
+
+ /* When requested clusters have been found by the framework they are returned
+ to the tracker using this method.
+ This method should implement any processing of the cluster blocks. If more
+ more regions of interest are identified then appropriate request should me
+ made using RequestClusters. The tag parameter will be the same one as was
+ passed to RequestClusters.
+ */
+ virtual void ReturnClusters(void* tag, const AliHLTMUONRecHitStruct* clusters, UInt count);
+
+ /* When no more clusters are to be expected for the request with the corresponding
+ tag value, then this method is called.
+ Any final processing can be placed in here and when the track is found then
+ the algorithm can call FoundTrack otherwise NoTrackFound to indicate end of
+ processing.
+ */
+ virtual void EndOfClusters(void* tag);
+
+ /* Called to receive track information after receiving a FoundTrack call.
+ The tracker should fill the track data block with all relevant information.
+ Note: the track.triggerid field need not be filled in this method. It should
+ be overwritten by the caller.
+ */
+ virtual void FillTrackData(AliHLTMUONCoreTrack& track);
+
+ /* Called when the tracker should be reset to a initial state.
+ All extra internal allocated data structured should be released.
+ */
+ virtual void Reset();
+
+ /* To set the TrackerCallback callback object.
+ */
+ inline void SetCallback(AliHLTMUONCoreTrackerCallback* callback)
+ {
+ fCallback = callback;
+ };
+
+
+ /* Get and set methods for the a and b parameters used to build the region
+ of interests. Refer to MansoFilter() for details about a and b parameters.
+ */
+ static AliHLTFloat32_t GetA7() { return fgA7; };
+ static void SetA7(AliHLTFloat32_t value) { fgA7 = value; };
+ static AliHLTFloat32_t GetA8() { return fgA8; };
+ static void SetA8(AliHLTFloat32_t value) { fgA8 = value; };
+ static AliHLTFloat32_t GetA9() { return fgA9; };
+ static void SetA9(AliHLTFloat32_t value) { fgA9 = value; };
+ static AliHLTFloat32_t GetA10() { return fgA10; };
+ static void SetA10(AliHLTFloat32_t value) { fgA10 = value; };
+
+ static AliHLTFloat32_t GetB7() { return fgB7; };
+ static void SetB7(AliHLTFloat32_t value) { fgB7 = value; };
+ static AliHLTFloat32_t GetB8() { return fgB8; };
+ static void SetB8(AliHLTFloat32_t value) { fgB8 = value; };
+ static AliHLTFloat32_t GetB9() { return fgB9; };
+ static void SetB9(AliHLTFloat32_t value) { fgB9 = value; };
+ static AliHLTFloat32_t GetB10() { return fgB10; };
+ static void SetB10(AliHLTFloat32_t value) { fgB10 = value; };
+
+ static AliHLTFloat32_t GetZ7() { return fgZ7; };
+ static void SetZ7(AliHLTFloat32_t value) { fgZ7 = value; };
+ static AliHLTFloat32_t GetZ8() { return fgZ8; };
+ static void SetZ8(AliHLTFloat32_t value) { fgZ8 = value; };
+ static AliHLTFloat32_t GetZ9() { return fgZ9; };
+ static void SetZ9(AliHLTFloat32_t value) { fgZ9 = value; };
+ static AliHLTFloat32_t GetZ10() { return fgZ10; };
+ static void SetZ10(AliHLTFloat32_t value) { fgZ10 = value; };
+ static AliHLTFloat32_t GetZ11() { return fgZ11; };
+ static void SetZ11(AliHLTFloat32_t value) { fgZ11 = value; };
+ static AliHLTFloat32_t GetZ13() { return fgZ13; };
+ static void SetZ13(AliHLTFloat32_t value) { fgZ13 = value; };
+
+
+protected:
+
+ class AliRegionOfInterest
+ {
+ public:
+
+ AliRegionOfInterest() : fCentre(), fRs(0.0) {};
+
+ AliRegionOfInterest(AliHLTMUONCorePoint p, AliHLTFloat32_t a, AliHLTFloat32_t b)
+ : fCentre(), fRs(0)
+ {
+ Create(p, a, b);
+ };
+
+ /* Creates a region of interest. In this implementation it is a
+ circular disk.
+
+ The point p is the intersecting point of the track with the chamber.
+ For more details and for details about the parameters a and b refer to:
+ "A first algorithm for dimuon High Level Trigger"
+ Ref ID: ALICE-INT-2002-04 version 1.0
+ equation:
+ Rs = a * Rp + b
+ given on page 3 section 4.
+ */
+ void Create(AliHLTMUONCorePoint p, AliHLTFloat32_t a, AliHLTFloat32_t b);
+
+ /* Returns true if the point p is within the region of interest.
+ */
+ bool Contains(AliHLTMUONCorePoint p) const;
+
+ void GetBoundaryBox(AliHLTFloat32_t& left, AliHLTFloat32_t& right, AliHLTFloat32_t& bottom, AliHLTFloat32_t& top) const;
+
+ private:
+
+ AliHLTMUONCorePoint fCentre; // The centre point of the region of interest.
+ AliHLTFloat32_t fRs; // The redius of the region of interest around fcentre.
+ };
+
+
+ class AliVertex
+ {
+ public:
+
+ AliVertex(AliHLTFloat32_t x = 0.0, AliHLTFloat32_t y = 0.0, AliHLTFloat32_t z = 0.0);
+ AliVertex(AliHLTMUONCorePoint xy, AliHLTFloat32_t z);
+
+ AliHLTMUONCorePoint AsXYPoint() const
+ {
+ return AliHLTMUONCorePoint(fX, fY);
+ };
+
+ // Get/set methods:
+ AliHLTFloat32_t X() const { return fX; };
+ AliHLTFloat32_t Y() const { return fY; };
+ AliHLTFloat32_t Z() const { return fZ; };
+ AliHLTFloat32_t& X() { return fX; };
+ AliHLTFloat32_t& Y() { return fY; };
+ AliHLTFloat32_t& Z() { return fZ; };
+ void X(AliHLTFloat32_t value) { fX = value; };
+ void Y(AliHLTFloat32_t value) { fY = value; };
+ void Z(AliHLTFloat32_t value) { fZ = value; };
+
+ private:
+
+ AliHLTFloat32_t fX, fY, fZ; // 3D coordinates.
+ };
+
+
+ class AliLine
+ {
+ public:
+
+ /* Creates a vector line between points A and B.
+ ax, ay, az are x, y and z coordinates for space point A respectively.
+ simmilarly for B.
+ */
+ AliLine(
+ AliHLTFloat32_t ax = 0.0, AliHLTFloat32_t ay = 0.0, AliHLTFloat32_t az = 0.0,
+ AliHLTFloat32_t bx = 0.0, AliHLTFloat32_t by = 0.0, AliHLTFloat32_t bz = 0.0
+ );
+
+ /* Creates a vector line between vertices A and B.
+ */
+ AliLine(AliVertex a, AliVertex b);
+
+ /* Finds the intersection point with the xy plain specified by the z coordinate.
+ The z coordiante would be the distance of the n'th chamber to the interaction
+ vertex.
+ */
+ AliHLTMUONCorePoint FindIntersectWithXYPlain(AliHLTFloat32_t z) const;
+
+ private:
+
+ // Parameters for the vector line: L = M*t + C
+ AliHLTFloat32_t fMx, fMy, fMz, fCx, fCy, fCz; // line parameters.
+ };
+
+
+ struct AliTagData
+ {
+ AliHLTMUONCoreChamberID fChamber; // The chamber on which the region of interest lies.
+ AliRegionOfInterest fRoi; // Region of interest on the next station.
+ AliLine fLine; // line between a cluster point and the previous station.
+
+ AliTagData() : fChamber(kChamber1), fRoi(), fLine() {};
+ };
+
+ struct AliStation5Data
+ {
+ AliHLTMUONCoreClusterPoint fClusterPoint; // Cluster point found on station 5.
+ AliTagData fTag; // Chamber, ROI and line data for station 5.
+
+ AliStation5Data() : fClusterPoint(), fTag() {};
+ };
+
+ typedef AliHLTMUONCoreCountedList<AliStation5Data> Station5List;
+
+ struct AliStation4Data
+ {
+ AliHLTMUONCoreClusterPoint fClusterPoint; // Cluster point found on station 4.
+ const AliTagData* fSt5tag; // Corresponding station 5 tag.
+
+ AliStation4Data() : fClusterPoint(), fSt5tag() {};
+
+ AliStation4Data(const AliStation4Data& data) :
+ fClusterPoint(data.fClusterPoint), fSt5tag(data.fSt5tag)
+ {};
+
+ AliStation4Data& operator = (const AliStation4Data& data)
+ {
+ fClusterPoint = data.fClusterPoint;
+ fSt5tag = data.fSt5tag;
+ return *this;
+ };
+ };
+
+ typedef AliHLTMUONCoreList<AliStation4Data> Station4List;
+
+
+ void ReceiveClustersChamber7(const AliHLTMUONCoreClusterPoint* clusters, UInt count, const AliTagData* data);
+ void ReceiveClustersChamber8(const AliHLTMUONCoreClusterPoint* clusters, UInt count, const AliTagData* data);
+ void ReceiveClustersChamber9(const AliHLTMUONCoreClusterPoint* clusters, UInt count);
+ void ReceiveClustersChamber10(const AliHLTMUONCoreClusterPoint* clusters, UInt count);
+ void EndOfClustersChamber7();
+ void EndOfClustersChamber8();
+ void EndOfClustersChamber9();
+ void EndOfClustersChamber10();
+
+ void ProjectToStation4(AliStation5Data* data, register AliHLTFloat32_t station5z);
+ void ProcessClusters();
+
+#ifdef DEBUG
+public:
+#endif
+ // States for state machine 4 (SM4).
+ enum StatesSM4
+ {
+ kSM4Idle,
+ kWaitChamber8,
+ kWaitMoreChamber8,
+ kWaitChamber7,
+ kWaitMoreChamber7
+ };
+
+ // States for state machine 5 (SM5).
+ enum StatesSM5
+ {
+ kSM5Idle,
+ kWaitChamber10,
+ kWaitMoreChamber10,
+ kWaitChamber9,
+ kWaitMoreChamber9,
+ kSM5Done
+ };
+
+protected:
+
+ AliHLTMUONCoreTrackerCallback* fCallback;
+
+ StatesSM4 fSm4state; // State of SM4 used for fetching clusters on chambers 7 and 8.
+ StatesSM5 fSm5state; // State of SM5 used for fetching clusters on chambers 9 and 10.
+ UInt fRequestsCompleted; // Number of requests for station 4 that have completed.
+ AliHLTMUONCoreChamberID fSt4chamber; // The chamber on station 4 that data was retreived from.
+
+ AliVertex fV1; // The impact (hit) vertex for trigger station 1.
+ AliTagData fMc1; // Trigger station 1 data.
+
+ AliHLTFloat32_t fSt5z; // The z coordinate to use for station 5.
+ Station5List fSt5data; // List of found cluster points for station 5 and their tag data.
+ AliHLTFloat32_t fSt4z; // The z coordinate to use for station 4.
+ Station4List fSt4points; // The found cluster points for station 4.
+
+ // Iterators used in the FoundTrack, FillTrackData methods.
+ Station5List::Iterator fSt5rec; // current station 5 record
+ Station4List::Iterator fFoundPoint; // current found point
+
+
+ /* To request clusters from the boundary box specified by the 'left', 'right',
+ 'top' and 'bottom' boundaries and on the given chamber use this method call.
+ Supply a tag parameter if you want the request uniquely identified.
+ This is usefull to supply a pointer to some internal state data structure
+ to figure out where processing should continue in the ReturnClusters or
+ EndOfClusters methods.
+ */
+ inline void RequestClusters(
+ AliHLTFloat32_t left, AliHLTFloat32_t right, AliHLTFloat32_t bottom, AliHLTFloat32_t top,
+ AliHLTMUONCoreChamberID chamber, const void* tag = NULL
+ )
+ {
+ Assert( fCallback != NULL );
+ fCallback->RequestClusters(this, left, right, bottom, top, chamber, tag);
+ };
+
+ /* When no more cluster requests will be generated by this tracker then this
+ method should be called.
+ DO NOT request more clusters after calling this method.
+ */
+ inline void EndOfClusterRequests()
+ {
+ Assert( fCallback != NULL );
+ fCallback->EndOfClusterRequests(this);
+ };
+
+ /* When the tracker has found a track it should call this method to inform
+ the rest of the system. At this point all cluster blocks received with
+ ReturnClusters are to be considered released and MUST NOT be accessed.
+ */
+ inline void FoundTrack()
+ {
+ Assert( fCallback != NULL );
+ fCallback->FoundTrack(this);
+ };
+
+ /* If the tracker is finished processing the trigger record but has not found
+ a track it should call this method to inform the rest of the system.
+ At this point all cluster blocks received with ReturnClusters are to be
+ considered released and MUST NOT be accessed.
+ */
+ inline void NoTrackFound()
+ {
+ Assert( fCallback != NULL );
+ fCallback->NoTrackFound(this);
+ };
+
+private:
+
+ // Not allowed to copy this object.
+ AliHLTMUONMansoTrackerFSM(const AliHLTMUONMansoTrackerFSM& tracker);
+ AliHLTMUONCoreTracker& operator = (const AliHLTMUONCoreTracker& tracker);
+
+ static AliHLTFloat32_t fgA7, fgB7; // Parameters used to create a region of interest for the 7'th chamber.
+ static AliHLTFloat32_t fgA8, fgB8; // Parameters used to create a region of interest for the 8'th chamber.
+ static AliHLTFloat32_t fgA9, fgB9; // Parameters used to create a region of interest for the 9'th chamber.
+ static AliHLTFloat32_t fgA10, fgB10; // Parameters used to create a region of interest for the 10'th chamber.
+ static AliHLTFloat32_t fgZ7, fgZ8, fgZ9, fgZ10, fgZ11, fgZ13; // Z coordinates of chambers 7 to 10.
+
+};
+
+
+class AliHLTMUONMansoTrackerFSMCallback
+{
+public:
+
+ virtual ~AliHLTMUONMansoTrackerFSMCallback() {};
+
+ /* All clusters that fall within the specified boundary box on the specified
+ chamber should be returned to the tracker, by calling the ReturnClusters
+ method of the given tracker. The same tag parameter must be passed on the
+ ReturnClusters method's parameter list.
+ */
+ virtual void RequestClusters(
+ AliHLTMUONCoreTracker* tracker,
+ AliHLTFloat32_t left, AliHLTFloat32_t right, AliHLTFloat32_t bottom, AliHLTFloat32_t top,
+ AliHLTMUONCoreChamberID chamber, const void* tag
+ ) = 0;
+
+ /* When this method is called then one knows no more RequestClusters method
+ calls are expected.
+ */
+ virtual void EndOfClusterRequests(AliHLTMUONCoreTracker* tracker) = 0;
+
+ /* This method is called when the tracker has found a track. The FillTrackData
+ method of the given tracker should be called to receive the track data.
+ At this point all cluster blocks can be released.
+ */
+ virtual void FoundTrack(AliHLTMUONCoreTracker* tracker) = 0;
+
+ /* When the tracker is finished with its work but no track was found then
+ this method is called. At this point no more work should be performed by
+ the tracker and all cluster blocks can be released.
+ */
+ virtual void NoTrackFound(AliHLTMUONCoreTracker* tracker) = 0;
+};
+
+
+#endif // ALIHLTMUONMANSOTRACKERFSM_H