/* $Id$ */
-////////////////////////////////////
-//
-// MUON track reconstructor in ALICE (class renamed from AliMUONEventReconstructor)
-//
-// This class contains as data:
-// * the parameters for the track reconstruction
-// * a pointer to the array of hits to be reconstructed (the event)
-// * a pointer to the array of segments made with these hits inside each station
-// * a pointer to the array of reconstructed tracks
-//
-// It contains as methods, among others:
-// * MakeEventToBeReconstructed to build the array of hits to be reconstructed
-// * MakeSegments to build the segments
-// * MakeTracks to build the tracks
-//
-////////////////////////////////////
+/// \class AliMUONTrackReconstructor
+/// MUON track reconstructor using the original method
+///
+/// This class contains as data:
+/// - the parameters for the track reconstruction
+///
+/// It contains as methods, among others:
+/// - MakeTracks to build the tracks
+///
#include <stdlib.h>
#include <Riostream.h>
-#include <TDirectory.h>
-#include <TFile.h>
#include <TMatrixD.h>
+#include "AliMUONVTrackReconstructor.h"
#include "AliMUONTrackReconstructor.h"
#include "AliMUONData.h"
#include "AliMUONConstants.h"
-#include "AliMUONHitForRec.h"
-#include "AliMUONTriggerTrack.h"
-#include "AliMUONTriggerCircuitNew.h"
#include "AliMUONRawCluster.h"
-#include "AliMUONLocalTrigger.h"
-#include "AliMUONGlobalTrigger.h"
-#include "AliMUONSegment.h"
+#include "AliMUONHitForRec.h"
+#include "AliMUONObjectPair.h"
#include "AliMUONTrack.h"
-#include "AliMUONTrackHit.h"
-#include "AliMagF.h"
-//#include "AliRunLoader.h"
-#include "AliLoader.h"
-#include "AliMUONTrackK.h"
+#include "AliMUONTrackParam.h"
+#include "AliMUONTrackExtrap.h"
#include "AliLog.h"
-#include "AliTracker.h"
+#include <TMinuit.h>
-//************* Defaults parameters for reconstruction
-const Double_t AliMUONTrackReconstructor::fgkDefaultMinBendingMomentum = 3.0;
-const Double_t AliMUONTrackReconstructor::fgkDefaultMaxBendingMomentum = 3000.0;
-const Double_t AliMUONTrackReconstructor::fgkDefaultMaxChi2 = 100.0;
-const Double_t AliMUONTrackReconstructor::fgkDefaultMaxSigma2Distance = 16.0;
-const Double_t AliMUONTrackReconstructor::fgkDefaultBendingResolution = 0.01;
-const Double_t AliMUONTrackReconstructor::fgkDefaultNonBendingResolution = 0.144;
-const Double_t AliMUONTrackReconstructor::fgkDefaultChamberThicknessInX0 = 0.03;
-// Simple magnetic field:
-// Value taken from macro MUONtracking.C: 0.7 T, hence 7 kG
-// Length and Position from reco_muon.F, with opposite sign:
-// Length = ZMAGEND-ZCOIL
-// Position = (ZMAGEND+ZCOIL)/2
-// to be ajusted differently from real magnetic field ????
-const Double_t AliMUONTrackReconstructor::fgkDefaultSimpleBValue = 7.0;
-const Double_t AliMUONTrackReconstructor::fgkDefaultSimpleBLength = 428.0;
-const Double_t AliMUONTrackReconstructor::fgkDefaultSimpleBPosition = 1019.0;
-const Double_t AliMUONTrackReconstructor::fgkDefaultEfficiency = 0.95;
+// Functions to be minimized with Minuit
+void TrackChi2(Int_t &NParam, Double_t *Gradient, Double_t &Chi2, Double_t *Param, Int_t Flag);
+void TrackChi2MCS(Int_t &NParam, Double_t *Gradient, Double_t &Chi2, Double_t *Param, Int_t Flag);
+
+Double_t MultipleScatteringAngle2(AliMUONTrackParam *param);
+/// \cond CLASSIMP
ClassImp(AliMUONTrackReconstructor) // Class implementation in ROOT context
+/// \endcond
+
+//************* Defaults parameters for reconstruction
+const Double_t AliMUONTrackReconstructor::fgkMaxNormChi2 = 100.0;
+const Bool_t AliMUONTrackReconstructor::fgkTrackAllTracks = kFALSE;
//__________________________________________________________________________
-AliMUONTrackReconstructor::AliMUONTrackReconstructor(AliLoader* loader, AliMUONData* data)
- : TObject(),
- fTrackMethod(1), //AZ - tracking method (1-default, 2-Kalman)
- fMinBendingMomentum(fgkDefaultMinBendingMomentum),
- fMaxBendingMomentum(fgkDefaultMaxBendingMomentum),
- fMaxChi2(fgkDefaultMaxChi2),
- fMaxSigma2Distance(fgkDefaultMaxSigma2Distance),
- fBendingResolution(fgkDefaultBendingResolution),
- fNonBendingResolution(fgkDefaultNonBendingResolution),
- fChamberThicknessInX0(fgkDefaultChamberThicknessInX0),
- fSimpleBValue(fgkDefaultSimpleBValue),
- fSimpleBLength(fgkDefaultSimpleBLength),
- fSimpleBPosition(fgkDefaultSimpleBPosition),
- fEfficiency(fgkDefaultEfficiency),
- fHitsForRecPtr(0x0),
- fNHitsForRec(0),
- fRecTracksPtr(0x0),
- fNRecTracks(0),
- fRecTrackHitsPtr(0x0),
- fNRecTrackHits(0),
- fMUONData(data),
- fLoader(loader),
- fMuons(0),
- fTriggerTrack(new AliMUONTriggerTrack()),
- fTriggerCircuit(0x0)
+AliMUONTrackReconstructor::AliMUONTrackReconstructor(AliMUONData* data)
+ : AliMUONVTrackReconstructor(data)
{
- // Constructor for class AliMUONTrackReconstructor
- SetReconstructionParametersToDefaults();
-
- // Memory allocation for the TClonesArray of hits for reconstruction
- // Is 10000 the right size ????
- fHitsForRecPtr = new TClonesArray("AliMUONHitForRec", 10000);
-
- // Memory allocation for the TClonesArray's of segments in stations
- // Is 2000 the right size ????
- for (Int_t st = 0; st < AliMUONConstants::NTrackingCh()/2; st++) {
- fSegmentsPtr[st] = new TClonesArray("AliMUONSegment", 2000);
- fNSegments[st] = 0; // really needed or GetEntriesFast sufficient ????
- }
+ /// Constructor for class AliMUONTrackReconstructor
+
// Memory allocation for the TClonesArray of reconstructed tracks
- // Is 10 the right size ????
fRecTracksPtr = new TClonesArray("AliMUONTrack", 10);
-
- // Memory allocation for the TClonesArray of hits on reconstructed tracks
- // Is 100 the right size ????
- fRecTrackHitsPtr = new TClonesArray("AliMUONTrackHit", 100);
-
- const AliMagF* kField = AliTracker::GetFieldMap();
- if (!kField) AliFatal("No field available");
- // Sign of fSimpleBValue according to sign of Bx value at (50,50,-950).
- Float_t b[3], x[3];
- x[0] = 50.; x[1] = 50.; x[2] = -950.;
- kField->Field(x,b);
-
- fSimpleBValue = TMath::Sign(fSimpleBValue,(Double_t) b[0]);
- fSimpleBPosition = TMath::Sign(fSimpleBPosition,(Double_t) x[2]);
- // See how to get fSimple(BValue, BLength, BPosition)
- // automatically calculated from the actual magnetic field ????
-
- return;
}
//__________________________________________________________________________
AliMUONTrackReconstructor::~AliMUONTrackReconstructor(void)
{
- // Destructor for class AliMUONTrackReconstructor
- delete fHitsForRecPtr; // Correct destruction of everything ???? or delete [] ????
- for (Int_t st = 0; st < AliMUONConstants::NTrackingCh()/2; st++)
- delete fSegmentsPtr[st]; // Correct destruction of everything ????
-
- delete fTriggerTrack;
-}
- //__________________________________________________________________________
-void AliMUONTrackReconstructor::SetReconstructionParametersToDefaults(void)
-{
- // Set reconstruction parameters to default values
- // Would be much more convenient with a structure (or class) ????
-
- // ******** Parameters for making HitsForRec
- // minimum radius,
- // like in TRACKF_STAT:
- // 2 degrees for stations 1 and 2, or ch(0...) from 0 to 3;
- // 30 cm for stations 3 to 5, or ch(0...) from 4 to 9
- for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
- if (ch < 4) fRMin[ch] = TMath::Abs(AliMUONConstants::DefaultChamberZ(ch)) *
- 2.0 * TMath::Pi() / 180.0;
- else fRMin[ch] = 30.0;
- // maximum radius at 10 degrees and Z of chamber
- fRMax[ch] = TMath::Abs(AliMUONConstants::DefaultChamberZ(ch)) *
- 10.0 * TMath::Pi() / 180.0;
- }
-
- // ******** Parameters for making segments
- // should be parametrized ????
- // according to interval between chambers in a station ????
- // Maximum distance in non bending plane
- // 5 * 0.22 just to remember the way it was made in TRACKF_STAT
- // SIGCUT*DYMAX(IZ)
- for (Int_t st = 0; st < AliMUONConstants::NTrackingCh()/2; st++)
- fSegmentMaxDistNonBending[st] = 5. * 0.22;
- // Maximum distance in bending plane:
- // values from TRACKF_STAT, corresponding to (J psi 20cm),
- // scaled to the real distance between chambers in a station
- fSegmentMaxDistBending[0] = TMath::Abs( 1.5 *
- (AliMUONConstants::DefaultChamberZ(1) - AliMUONConstants::DefaultChamberZ(0)) / 20.0);
- fSegmentMaxDistBending[1] = TMath::Abs( 1.5 *
- (AliMUONConstants::DefaultChamberZ(3) - AliMUONConstants::DefaultChamberZ(2)) / 20.0);
- fSegmentMaxDistBending[2] = TMath::Abs( 3.0 *
- (AliMUONConstants::DefaultChamberZ(5) - AliMUONConstants::DefaultChamberZ(4)) / 20.0);
- fSegmentMaxDistBending[3] = TMath::Abs( 6.0 *
- (AliMUONConstants::DefaultChamberZ(7) - AliMUONConstants::DefaultChamberZ(6)) / 20.0);
- fSegmentMaxDistBending[4] = TMath::Abs( 6.0 *
- (AliMUONConstants::DefaultChamberZ(9) - AliMUONConstants::DefaultChamberZ(8)) / 20.0);
-
- return;
-}
-
-//__________________________________________________________________________
-Double_t AliMUONTrackReconstructor::GetImpactParamFromBendingMomentum(Double_t BendingMomentum) const
-{
- // Returns impact parameter at vertex in bending plane (cm),
- // from the signed bending momentum "BendingMomentum" in bending plane (GeV/c),
- // using simple values for dipole magnetic field.
- // The sign of "BendingMomentum" is the sign of the charge.
- return (-0.0003 * fSimpleBValue * fSimpleBLength * fSimpleBPosition /
- BendingMomentum);
-}
-
-//__________________________________________________________________________
-Double_t AliMUONTrackReconstructor::GetBendingMomentumFromImpactParam(Double_t ImpactParam) const
-{
- // Returns signed bending momentum in bending plane (GeV/c),
- // the sign being the sign of the charge for particles moving forward in Z,
- // from the impact parameter "ImpactParam" at vertex in bending plane (cm),
- // using simple values for dipole magnetic field.
- return (-0.0003 * fSimpleBValue * fSimpleBLength * fSimpleBPosition /
- ImpactParam);
-}
-
-//__________________________________________________________________________
-void AliMUONTrackReconstructor::EventReconstruct(void)
-{
- // To reconstruct one event
- AliDebug(1,"Enter EventReconstruct");
- ResetTracks(); //AZ
- ResetTrackHits(); //AZ
- ResetSegments(); //AZ
- ResetHitsForRec(); //AZ
- MakeEventToBeReconstructed();
- MakeSegments();
- MakeTracks();
- if (fMUONData->IsTriggerTrackBranchesInTree())
- ValidateTracksWithTrigger();
-
- // Add tracks to MUON data container
- for(Int_t i=0; i<GetNRecTracks(); i++) {
- AliMUONTrack * track = (AliMUONTrack*) GetRecTracksPtr()->At(i);
- fMUONData->AddRecTrack(*track);
- }
-
- return;
-}
-
-//__________________________________________________________________________
-void AliMUONTrackReconstructor::EventReconstructTrigger(void)
-{
- // To reconstruct one event
- AliDebug(1,"Enter EventReconstructTrigger");
- MakeTriggerTracks();
- return;
-}
-
- //__________________________________________________________________________
-void AliMUONTrackReconstructor::ResetHitsForRec(void)
-{
- // To reset the array and the number of HitsForRec,
- // and also the number of HitsForRec
- // and the index of the first HitForRec per chamber
- if (fHitsForRecPtr) fHitsForRecPtr->Delete();
- fNHitsForRec = 0;
- for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++)
- fNHitsForRecPerChamber[ch] = fIndexOfFirstHitForRecPerChamber[ch] = 0;
- return;
-}
-
- //__________________________________________________________________________
-void AliMUONTrackReconstructor::ResetSegments(void)
-{
- // To reset the TClonesArray of segments and the number of Segments
- // for all stations
- for (Int_t st = 0; st < AliMUONConstants::NTrackingCh()/2; st++) {
- if (fSegmentsPtr[st]) fSegmentsPtr[st]->Clear();
- fNSegments[st] = 0;
- }
- return;
-}
-
- //__________________________________________________________________________
-void AliMUONTrackReconstructor::ResetTracks(void)
-{
- // To reset the TClonesArray of reconstructed tracks
- if (fRecTracksPtr) fRecTracksPtr->Delete();
- // Delete in order that the Track destructors are called,
- // hence the space for the TClonesArray of pointers to TrackHit's is freed
- fNRecTracks = 0;
- return;
-}
-
-
- //__________________________________________________________________________
-void AliMUONTrackReconstructor::ResetTrackHits(void)
-{
- // To reset the TClonesArray of hits on reconstructed tracks
- if (fRecTrackHitsPtr) fRecTrackHitsPtr->Clear();
- fNRecTrackHits = 0;
- return;
-}
-
- //__________________________________________________________________________
-void AliMUONTrackReconstructor::MakeEventToBeReconstructed(void)
-{
- // To make the list of hits to be reconstructed,
- // either from the track ref. hits or from the raw clusters
- // according to the parameter set for the reconstructor
-
- AliDebug(1,"Enter MakeEventToBeReconstructed");
- //AZ ResetHitsForRec();
-
- // Reconstruction from raw clusters
- // AliMUON *MUON = (AliMUON*) gAlice->GetModule("MUON"); // necessary ????
- // Security on MUON ????
- // TreeR assumed to be be "prepared" in calling function
- // by "MUON->GetTreeR(nev)" ????
- TTree *treeR = fLoader->TreeR();
-
- //AZ? fMUONData->SetTreeAddress("RC");
- AddHitsForRecFromRawClusters(treeR);
- // No sorting: it is done automatically in the previous function
-
-
- AliDebug(1,"End of MakeEventToBeReconstructed");
- if (AliLog::GetGlobalDebugLevel() > 0) {
- AliDebug(1, Form("NHitsForRec: %d",fNHitsForRec));
- for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
- AliDebug(1, Form("Chamber(0...): %d",ch));
- AliDebug(1, Form("NHitsForRec: %d", fNHitsForRecPerChamber[ch]));
- AliDebug(1, Form("Index(first HitForRec): %d", fIndexOfFirstHitForRecPerChamber[ch]));
- for (Int_t hit = fIndexOfFirstHitForRecPerChamber[ch];
- hit < fIndexOfFirstHitForRecPerChamber[ch] + fNHitsForRecPerChamber[ch];
- hit++) {
- AliDebug(1, Form("HitForRec index(0...): %d",hit));
- ((*fHitsForRecPtr)[hit])->Dump();
- }
- }
- }
- return;
-}
-
- //__________________________________________________________________________
-void AliMUONTrackReconstructor::SortHitsForRecWithIncreasingChamber()
-{
- // Sort HitsForRec's in increasing order with respect to chamber number.
- // Uses the function "Compare".
- // Update the information for HitsForRec per chamber too.
- Int_t ch, nhits, prevch;
- fHitsForRecPtr->Sort();
- for (ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
- fNHitsForRecPerChamber[ch] = 0;
- fIndexOfFirstHitForRecPerChamber[ch] = 0;
- }
- prevch = 0; // previous chamber
- nhits = 0; // number of hits in current chamber
- // Loop over HitsForRec
- for (Int_t hit = 0; hit < fNHitsForRec; hit++) {
- // chamber number (0...)
- ch = ((AliMUONHitForRec*) ((*fHitsForRecPtr)[hit]))->GetChamberNumber();
- // increment number of hits in current chamber
- (fNHitsForRecPerChamber[ch])++;
- // update index of first HitForRec in current chamber
- // if chamber number different from previous one
- if (ch != prevch) {
- fIndexOfFirstHitForRecPerChamber[ch] = hit;
- prevch = ch;
- }
- }
- return;
+ /// Destructor for class AliMUONTrackReconstructor
+ delete fRecTracksPtr;
}
//__________________________________________________________________________
-void AliMUONTrackReconstructor::AddHitsForRecFromRawClusters(TTree* TR)
+void AliMUONTrackReconstructor::AddHitsForRecFromRawClusters()
{
- // To add to the list of hits for reconstruction all the raw clusters
- // No condition added, like in Fortran TRACKF_STAT,
- // on the radius between RMin and RMax.
+ /// To add to the list of hits for reconstruction all the raw clusters
+ TTree *treeR;
AliMUONHitForRec *hitForRec;
AliMUONRawCluster *clus;
- Int_t iclus, nclus, nTRentries;
+ Int_t iclus, nclus;
TClonesArray *rawclusters;
AliDebug(1,"Enter AddHitsForRecFromRawClusters");
-
- if (fTrackMethod != 3) { //AZ
- fMUONData->SetTreeAddress("RC"); //AZ
- nTRentries = Int_t(TR->GetEntries());
- if (nTRentries != 1) {
- AliError(Form("nTRentries = %d not equal to 1 ",nTRentries));
- exit(0);
- }
- fLoader->TreeR()->GetEvent(0); // only one entry
+
+ treeR = fMUONData->TreeR();
+ if (!treeR) {
+ AliError("TreeR must be loaded");
+ exit(0);
}
-
+
+ fMUONData->SetTreeAddress("RC");
+ fMUONData->GetRawClusters(); // only one entry
+
// Loop over tracking chambers
for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
- // number of HitsForRec to 0 for the chamber
- fNHitsForRecPerChamber[ch] = 0;
- // index of first HitForRec for the chamber
- if (ch == 0) fIndexOfFirstHitForRecPerChamber[ch] = 0;
- else fIndexOfFirstHitForRecPerChamber[ch] = fNHitsForRec;
rawclusters =fMUONData->RawClusters(ch);
nclus = (Int_t) (rawclusters->GetEntries());
// Loop over (cathode correlated) raw clusters
// and increment number of AliMUONHitForRec's (total and in chamber)
hitForRec = new ((*fHitsForRecPtr)[fNHitsForRec]) AliMUONHitForRec(clus);
fNHitsForRec++;
- (fNHitsForRecPerChamber[ch])++;
// more information into HitForRec
- // resolution: info should be already in raw cluster and taken from it ????
- //hitForRec->SetBendingReso2(fBendingResolution * fBendingResolution);
- //hitForRec->SetNonBendingReso2(fNonBendingResolution * fNonBendingResolution);
hitForRec->SetBendingReso2(clus->GetErrY() * clus->GetErrY());
hitForRec->SetNonBendingReso2(clus->GetErrX() * clus->GetErrX());
// original raw cluster
hitForRec->SetHitNumber(iclus);
// Z coordinate of the raw cluster (cm)
hitForRec->SetZ(clus->GetZ(0));
- if (AliLog::GetGlobalDebugLevel() > 1) {
- cout << "chamber (0...): " << ch <<
- " raw cluster (0...): " << iclus << endl;
- clus->Dump();
- cout << "AliMUONHitForRec number (1...): " << fNHitsForRec << endl;
- hitForRec->Dump();}
+ StdoutToAliDebug(3,
+ cout << "Chamber " << ch <<
+ " raw cluster " << iclus << " : " << endl;
+ clus->Print("full");
+ cout << "AliMUONHitForRec number (1...): " << fNHitsForRec << endl;
+ hitForRec->Print("full");
+ );
} // end of cluster loop
} // end of chamber loop
SortHitsForRecWithIncreasingChamber();
+
+ AliDebug(1,"End of AddHitsForRecFromRawClusters");
+ if (AliLog::GetGlobalDebugLevel() > 0) {
+ AliDebug(1, Form("NHitsForRec: %d",fNHitsForRec));
+ for (Int_t ch = 0; ch < AliMUONConstants::NTrackingCh(); ch++) {
+ AliDebug(1, Form("Chamber(0...): %d",ch));
+ AliDebug(1, Form("NHitsForRec: %d", fNHitsForRecPerChamber[ch]));
+ AliDebug(1, Form("Index(first HitForRec): %d", fIndexOfFirstHitForRecPerChamber[ch]));
+ for (Int_t hit = fIndexOfFirstHitForRecPerChamber[ch];
+ hit < fIndexOfFirstHitForRecPerChamber[ch] + fNHitsForRecPerChamber[ch];
+ hit++) {
+ AliDebug(1, Form("HitForRec index(0...): %d",hit));
+ ((*fHitsForRecPtr)[hit])->Dump();
+ }
+ }
+ }
+
return;
}
//__________________________________________________________________________
-void AliMUONTrackReconstructor::MakeSegments(void)
+void AliMUONTrackReconstructor::MakeTracks(void)
{
- // To make the list of segments in all stations,
- // from the list of hits to be reconstructed
- AliDebug(1,"Enter MakeSegments");
- //AZ ResetSegments();
- // Loop over stations
- Int_t nb = (fTrackMethod != 1) ? 3 : 0; //AZ
- for (Int_t st = nb; st < AliMUONConstants::NTrackingCh()/2; st++)
- MakeSegmentsPerStation(st);
- if (AliLog::GetGlobalDebugLevel() > 1) {
- cout << "end of MakeSegments" << endl;
- for (Int_t st = 0; st < AliMUONConstants::NTrackingCh()/2; st++) {
- cout << "station(0...): " << st
- << " Segments: " << fNSegments[st]
- << endl;
- for (Int_t seg = 0;
- seg < fNSegments[st];
- seg++) {
- cout << "Segment index(0...): " << seg << endl;
- ((*fSegmentsPtr[st])[seg])->Dump();
+ /// To make the tracks from the list of segments and points in all stations
+ AliDebug(1,"Enter MakeTracks");
+ // Look for candidates from at least 3 aligned points in stations(1..) 4 and 5
+ MakeTrackCandidates();
+ // Follow tracks in stations(1..) 3, 2 and 1
+ FollowTracks();
+ // Remove double tracks
+ RemoveDoubleTracks();
+ // Propagate tracks to the vertex through absorber
+ ExtrapTracksToVertex();
+ // Fill out the AliMUONTrack's
+ FillMUONTrack();
+}
+
+ //__________________________________________________________________________
+void AliMUONTrackReconstructor::MakeTrackCandidates(void)
+{
+ /// To make track candidates:
+ /// Start with segments station(1..) 4 or 5 then follow track in station 5 or 4.
+ /// Good candidates are made of at least three hitForRec's.
+ /// Keep only best candidates or all of them according to the flag fgkTrackAllTracks.
+ TClonesArray *segments;
+ AliMUONObjectPair *segment;
+ AliMUONHitForRec *hitForRec1, *hitForRec2;
+ AliMUONTrack *track;
+ AliMUONTrackParam *trackParamAtFirstHit;
+ Int_t iCandidate = 0;
+
+ AliDebug(1,"Enter MakeTrackCandidates");
+
+ // Loop over stations(1..) 5 and 4 and make track candidates
+ for (Int_t istat=4; istat>=3; istat--) {
+ // Make segments in the station
+ segments = MakeSegmentsInStation(istat);
+ // Loop over segments
+ for (Int_t iseg=0; iseg<segments->GetEntriesFast(); iseg++) {
+ AliDebug(1,Form("Making primary candidate(1..) %d",++iCandidate));
+ // Transform segments to tracks and put them at the end of fRecTracksPtr
+ segment = (AliMUONObjectPair*) ((*segments)[iseg]);
+ hitForRec1 = (AliMUONHitForRec*) segment->First();
+ hitForRec2 = (AliMUONHitForRec*) segment->Second();
+ track = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(hitForRec1, hitForRec2);
+ fNRecTracks++;
+ // Add MCS effects in parameter covariances
+ trackParamAtFirstHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
+ AliMUONTrackExtrap::AddMCSEffectInTrackParamCov(trackParamAtFirstHit,AliMUONConstants::ChamberThicknessInX0(),1.);
+ // Printout for debuging
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
+ cout<<endl<<"Track parameter covariances at first hit with multiple Coulomb scattering effects:"<<endl;
+ trackParamAtFirstHit->GetCovariances()->Print();
}
+ // Look for compatible hitForRec(s) in the other station
+ FollowTrackInStation(track,7-istat);
}
+ // delete the array of segments
+ delete segments;
}
- return;
+ fRecTracksPtr->Compress(); // this is essential before checking tracks
+
+ // Keep all different tracks or only the best ones as required
+ if (fgkTrackAllTracks) RemoveIdenticalTracks();
+ else RemoveDoubleTracks();
+
+ AliDebug(1,Form("Number of good candidates = %d",fNRecTracks));
+
}
//__________________________________________________________________________
-void AliMUONTrackReconstructor::MakeSegmentsPerStation(Int_t Station)
+void AliMUONTrackReconstructor::RemoveIdenticalTracks(void)
{
- // To make the list of segments in station number "Station" (0...)
- // from the list of hits to be reconstructed.
- // Updates "fNSegments"[Station].
- // Segments in stations 4 and 5 are sorted
- // according to increasing absolute value of "impact parameter"
- AliMUONHitForRec *hit1Ptr, *hit2Ptr;
- AliMUONSegment *segment;
- Bool_t last2st;
- Double_t bendingSlope, distBend, distNonBend, extBendCoor, extNonBendCoor,
- impactParam = 0., maxImpactParam = 0., minImpactParam = 0.; // =0 to avoid compilation warnings.
- AliDebug(1,Form("Enter MakeSegmentsPerStation (0...) %d",Station));
- // first and second chambers (0...) in the station
- Int_t ch1 = 2 * Station;
- Int_t ch2 = ch1 + 1;
- // variable true for stations downstream of the dipole:
- // Station(0..4) equal to 3 or 4
- if ((Station == 3) || (Station == 4)) {
- last2st = kTRUE;
- // maximum impact parameter (cm) according to fMinBendingMomentum...
- maxImpactParam =
- TMath::Abs(GetImpactParamFromBendingMomentum(fMinBendingMomentum));
- // minimum impact parameter (cm) according to fMaxBendingMomentum...
- minImpactParam =
- TMath::Abs(GetImpactParamFromBendingMomentum(fMaxBendingMomentum));
- }
- else last2st = kFALSE;
- // extrapolation factor from Z of first chamber to Z of second chamber
- // dZ to be changed to take into account fine structure of chambers ????
- Double_t extrapFact;
- // index for current segment
- Int_t segmentIndex = 0;
- // Loop over HitsForRec in the first chamber of the station
- for (Int_t hit1 = fIndexOfFirstHitForRecPerChamber[ch1];
- hit1 < fIndexOfFirstHitForRecPerChamber[ch1] + fNHitsForRecPerChamber[ch1];
- hit1++) {
- // pointer to the HitForRec
- hit1Ptr = (AliMUONHitForRec*) ((*fHitsForRecPtr)[hit1]);
- // extrapolation,
- // on the straight line joining the HitForRec to the vertex (0,0,0),
- // to the Z of the second chamber of the station
- // Loop over HitsForRec in the second chamber of the station
- for (Int_t hit2 = fIndexOfFirstHitForRecPerChamber[ch2];
- hit2 < fIndexOfFirstHitForRecPerChamber[ch2] + fNHitsForRecPerChamber[ch2];
- hit2++) {
- // pointer to the HitForRec
- hit2Ptr = (AliMUONHitForRec*) ((*fHitsForRecPtr)[hit2]);
- // absolute values of distances, in bending and non bending planes,
- // between the HitForRec in the second chamber
- // and the previous extrapolation
- extrapFact = hit2Ptr->GetZ()/ hit1Ptr->GetZ();
- extBendCoor = extrapFact * hit1Ptr->GetBendingCoor();
- extNonBendCoor = extrapFact * hit1Ptr->GetNonBendingCoor();
- distBend = TMath::Abs(hit2Ptr->GetBendingCoor() - extBendCoor);
- distNonBend = TMath::Abs(hit2Ptr->GetNonBendingCoor() - extNonBendCoor);
- if (last2st) {
- // bending slope
- if ( hit1Ptr->GetZ() - hit2Ptr->GetZ() != 0.0 ) {
- bendingSlope = (hit1Ptr->GetBendingCoor() - hit2Ptr->GetBendingCoor()) /
- (hit1Ptr->GetZ() - hit2Ptr->GetZ());
- // absolute value of impact parameter
- impactParam =
- TMath::Abs(hit1Ptr->GetBendingCoor() - hit1Ptr->GetZ() * bendingSlope);
- }
- else {
- AliWarning("hit1Ptr->GetZ() = hit2Ptr->GetZ(): impactParam set to maxImpactParam");
- impactParam = maxImpactParam;
- }
- }
- // check for distances not too large,
- // and impact parameter not too big if stations downstream of the dipole.
- // Conditions "distBend" and "impactParam" correlated for these stations ????
- if ((distBend < fSegmentMaxDistBending[Station]) &&
- (distNonBend < fSegmentMaxDistNonBending[Station]) &&
- (!last2st || (impactParam < maxImpactParam)) &&
- (!last2st || (impactParam > minImpactParam))) {
- // make new segment
- segment = new ((*fSegmentsPtr[Station])[segmentIndex])
- AliMUONSegment(hit1Ptr, hit2Ptr);
- // update "link" to this segment from the hit in the first chamber
- if (hit1Ptr->GetNSegments() == 0)
- hit1Ptr->SetIndexOfFirstSegment(segmentIndex);
- hit1Ptr->SetNSegments(hit1Ptr->GetNSegments() + 1);
- if (AliLog::GetGlobalDebugLevel() > 1) {
- cout << "segmentIndex(0...): " << segmentIndex
- << " distBend: " << distBend
- << " distNonBend: " << distNonBend
- << endl;
- segment->Dump();
- cout << "HitForRec in first chamber" << endl;
- hit1Ptr->Dump();
- cout << "HitForRec in second chamber" << endl;
- hit2Ptr->Dump();
- };
- // increment index for current segment
- segmentIndex++;
- }
- } //for (Int_t hit2
- } // for (Int_t hit1...
- fNSegments[Station] = segmentIndex;
- // Sorting according to "impact parameter" if station(1..5) 4 or 5,
- // i.e. Station(0..4) 3 or 4, using the function "Compare".
- // After this sorting, it is impossible to use
- // the "fNSegments" and "fIndexOfFirstSegment"
- // of the HitForRec in the first chamber to explore all segments formed with it.
- // Is this sorting really needed ????
- if ((Station == 3) || (Station == 4)) (fSegmentsPtr[Station])->Sort();
- AliDebug(1,Form("Station: %d NSegments: %d ", Station, fNSegments[Station]));
+ /// To remove identical tracks:
+ /// Tracks are considered identical if they have all their hits in common.
+ /// One keeps the track with the larger number of hits if need be
+ AliMUONTrack *track1, *track2, *trackToRemove;
+ Int_t hitsInCommon, nHits1, nHits2;
+ Bool_t removedTrack1;
+ // Loop over first track of the pair
+ track1 = (AliMUONTrack*) fRecTracksPtr->First();
+ while (track1) {
+ removedTrack1 = kFALSE;
+ nHits1 = track1->GetNTrackHits();
+ // Loop over second track of the pair
+ track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+ while (track2) {
+ nHits2 = track2->GetNTrackHits();
+ // number of hits in common between two tracks
+ hitsInCommon = track1->HitsInCommon(track2);
+ // check for identical tracks
+ if ((hitsInCommon == nHits1) || (hitsInCommon == nHits2)) {
+ // decide which track to remove
+ if (nHits2 > nHits1) {
+ // remove track1 and continue the first loop with the track next to track1
+ trackToRemove = track1;
+ track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+ fRecTracksPtr->Remove(trackToRemove);
+ fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
+ fNRecTracks--;
+ removedTrack1 = kTRUE;
+ break;
+ } else {
+ // remove track2 and continue the second loop with the track next to track2
+ trackToRemove = track2;
+ track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
+ fRecTracksPtr->Remove(trackToRemove);
+ fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
+ fNRecTracks--;
+ }
+ } else track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
+ } // track2
+ if (removedTrack1) continue;
+ track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+ } // track1
return;
}
//__________________________________________________________________________
-void AliMUONTrackReconstructor::MakeTracks(void)
+void AliMUONTrackReconstructor::RemoveDoubleTracks(void)
{
- // To make the tracks,
- // from the list of segments and points in all stations
- AliDebug(1,"Enter MakeTracks");
- // The order may be important for the following Reset's
- //AZ ResetTracks();
- //AZ ResetTrackHits();
- if (fTrackMethod != 1) { //AZ - Kalman filter
- MakeTrackCandidatesK();
- if (fRecTracksPtr->GetEntriesFast() == 0) return;
- // Follow tracks in stations(1..) 3, 2 and 1
- FollowTracksK();
- // Remove double tracks
- RemoveDoubleTracksK();
- // Propagate tracks to the vertex thru absorber
- GoToVertex();
- // Fill AliMUONTrack data members
- FillMUONTrack();
- } else {
- // Look for candidates from at least 3 aligned points in stations(1..) 4 and 5
- MakeTrackCandidates();
- // Follow tracks in stations(1..) 3, 2 and 1
- FollowTracks();
- // Remove double tracks
- RemoveDoubleTracks();
- UpdateTrackParamAtHit();
- UpdateHitForRecAtHit();
- }
+ /// To remove double tracks:
+ /// Tracks are considered identical if more than half of the hits of the track
+ /// which has the smaller number of hits are in common with the other track.
+ /// Among two identical tracks, one keeps the track with the larger number of hits
+ /// or, if these numbers are equal, the track with the minimum chi2.
+ AliMUONTrack *track1, *track2, *trackToRemove;
+ Int_t hitsInCommon, nHits1, nHits2;
+ Bool_t removedTrack1;
+ // Loop over first track of the pair
+ track1 = (AliMUONTrack*) fRecTracksPtr->First();
+ while (track1) {
+ removedTrack1 = kFALSE;
+ nHits1 = track1->GetNTrackHits();
+ // Loop over second track of the pair
+ track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+ while (track2) {
+ nHits2 = track2->GetNTrackHits();
+ // number of hits in common between two tracks
+ hitsInCommon = track1->HitsInCommon(track2);
+ // check for identical tracks
+ if (((nHits1 < nHits2) && (2 * hitsInCommon > nHits1)) || (2 * hitsInCommon > nHits2)) {
+ // decide which track to remove
+ if ((nHits1 > nHits2) || ((nHits1 == nHits2) && (track1->GetFitFMin() <= track2->GetFitFMin()))) {
+ // remove track2 and continue the second loop with the track next to track2
+ trackToRemove = track2;
+ track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
+ fRecTracksPtr->Remove(trackToRemove);
+ fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
+ fNRecTracks--;
+ } else {
+ // else remove track1 and continue the first loop with the track next to track1
+ trackToRemove = track1;
+ track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+ fRecTracksPtr->Remove(trackToRemove);
+ fRecTracksPtr->Compress(); // this is essential to retrieve the TClonesArray afterwards
+ fNRecTracks--;
+ removedTrack1 = kTRUE;
+ break;
+ }
+ } else track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
+ } // track2
+ if (removedTrack1) continue;
+ track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
+ } // track1
return;
}
//__________________________________________________________________________
-void AliMUONTrackReconstructor::ValidateTracksWithTrigger(void)
+void AliMUONTrackReconstructor::FollowTracks(void)
{
- // Try to match track from tracking system with trigger track
- AliMUONTrack *track;
- TClonesArray *recTriggerTracks;
+ /// Follow tracks in stations(1..) 3, 2 and 1
+ AliDebug(1,"Enter FollowTracks");
- fMUONData->SetTreeAddress("RL");
- fMUONData->GetRecTriggerTracks();
- recTriggerTracks = fMUONData->RecTriggerTracks();
-
+ AliMUONTrack *track, *nextTrack;
+ AliMUONTrackParam *trackParamAtFirstHit;
+ Double_t numberOfDegFree, chi2Norm;
+ Int_t CurrentNRecTracks;
+
+ for (Int_t station = 2; station >= 0; station--) {
+ // Save the actual number of reconstructed track in case of
+ // tracks are added or suppressed during the tracking procedure
+ // !! Do not compress fRecTracksPtr until the end of the loop over tracks !!
+ CurrentNRecTracks = fNRecTracks;
+ for (Int_t iRecTrack = 0; iRecTrack <CurrentNRecTracks; iRecTrack++) {
+ AliDebug(1,Form("FollowTracks: track candidate(1..) %d", iRecTrack+1));
+ track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
+ // Fit the track:
+ // Do not take into account the multiple scattering to speed up the fit
+ // Calculate the track parameter covariance matrix
+ // If "station" is station(1..) 3 then use the vertex to better constrain the fit
+ if (station==2) {
+ SetVertexForFit(track);
+ track->SetFitWithVertex(kTRUE);
+ } else track->SetFitWithVertex(kFALSE);
+ Fit(track,kFALSE, kTRUE);
+ // Remove the track if the normalized chi2 is too high
+ numberOfDegFree = (2. * track->GetNTrackHits() - 5.);
+ if (numberOfDegFree > 0) chi2Norm = track->GetFitFMin() / numberOfDegFree;
+ else chi2Norm = 1.e10;
+ if (chi2Norm > fgkMaxNormChi2) {
+ fRecTracksPtr->Remove(track);
+ fNRecTracks--;
+ continue;
+ }
+ // Add MCS effects in parameter covariances
+ trackParamAtFirstHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
+ AliMUONTrackExtrap::AddMCSEffectInTrackParamCov(trackParamAtFirstHit,AliMUONConstants::ChamberThicknessInX0(),1.);
+ // Printout for debuging
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
+ cout<<endl<<"Track parameter covariances at first hit with multiple Coulomb scattering effects:"<<endl;
+ trackParamAtFirstHit->GetCovariances()->Print();
+ }
+ // Look for compatible hitForRec in station(0..) "station"
+ FollowTrackInStation(track,station);
+ }
+ // Compress fRecTracksPtr for the next step
+ fRecTracksPtr->Compress();
+ // Keep only the best tracks if required
+ if (!fgkTrackAllTracks) RemoveDoubleTracks();
+ }
+
+ // Last fit of track candidates with all station
+ // Take into account the multiple scattering and remove bad tracks
+ Int_t trackIndex = -1;
track = (AliMUONTrack*) fRecTracksPtr->First();
while (track) {
- track->MatchTriggerTrack(recTriggerTracks);
- track = (AliMUONTrack*) fRecTracksPtr->After(track);
+ trackIndex++;
+ nextTrack = (AliMUONTrack*) fRecTracksPtr->After(track); // prepare next track
+ track->SetFitWithVertex(kFALSE); // just to be sure
+ Fit(track,kTRUE, kFALSE);
+ // Printout for debuging
+ if (AliLog::GetGlobalDebugLevel() >= 3) {
+ cout << "FollowTracks: track candidate(0..) " << trackIndex << " after final fit" << endl;
+ track->RecursiveDump();
+ }
+ // Remove the track if the normalized chi2 is too high
+ numberOfDegFree = (2.0 * track->GetNTrackHits() - 5);
+ if (numberOfDegFree > 0) chi2Norm = track->GetFitFMin() / numberOfDegFree;
+ else chi2Norm = 1.e10;
+ if (chi2Norm > fgkMaxNormChi2) {
+ fRecTracksPtr->Remove(track);
+ fNRecTracks--;
+ }
+ track = nextTrack;
}
-
+ fRecTracksPtr->Compress();
+
}
//__________________________________________________________________________
-Bool_t AliMUONTrackReconstructor::MakeTriggerTracks(void)
+void AliMUONTrackReconstructor::FollowTrackInStation(AliMUONTrack* trackCandidate, Int_t nextStation)
{
- // To make the trigger tracks from Local Trigger
- AliDebug(1, "Enter MakeTriggerTracks");
-
- Int_t nTRentries;
- Long_t gloTrigPat;
- TClonesArray *localTrigger;
- TClonesArray *globalTrigger;
- AliMUONLocalTrigger *locTrg;
- AliMUONGlobalTrigger *gloTrg;
-
- TTree* treeR = fLoader->TreeR();
-
- nTRentries = Int_t(treeR->GetEntries());
-
- treeR->GetEvent(0); // only one entry
-
- if (!(fMUONData->IsTriggerBranchesInTree())) {
- AliWarning(Form("Trigger information is not avalaible, nTRentries = %d not equal to 1",nTRentries));
- return kFALSE;
+ /// Follow trackCandidate in station(0..) nextStation and search for compatible HitForRec(s)
+ /// Keep all possibilities or only the best one(s) according to the flag fgkTrackAllTracks:
+ /// kTRUE: duplicate "trackCandidate" if there are several possibilities and add the new tracks at the end of
+ /// fRecTracksPtr to avoid conficts with other track candidates at this current stage of the tracking procedure.
+ /// Remove the obsolete "trackCandidate" at the end.
+ /// kFALSE: add only the best hit(s) to the "trackCandidate". Try to add a couple of hits in priority.
+ AliDebug(1,Form("Enter FollowTrackInStation(1..) %d", nextStation+1));
+
+ Int_t ch1 = 2*nextStation;
+ Int_t ch2 = 2*nextStation+1;
+ Double_t zCh2 = AliMUONConstants::DefaultChamberZ(ch2);
+ Double_t chi2WithOneHitForRec = 1.e10;
+ Double_t chi2WithTwoHitForRec = 1.e10;
+ Double_t maxChi2WithOneHitForRec = 2.*fgkMaxNormChi2; // 2 because 2 quantities in chi2
+ Double_t maxChi2WithTwoHitForRec = 4.*fgkMaxNormChi2; // 4 because 4 quantities in chi2
+ Double_t bestChi2WithOneHitForRec = maxChi2WithOneHitForRec;
+ Double_t bestChi2WithTwoHitForRec = maxChi2WithTwoHitForRec;
+ AliMUONTrack *newTrack = 0x0;
+ AliMUONHitForRec *hitForRecCh1, *hitForRecCh2;
+ AliMUONHitForRec *bestHitForRec1 = 0x0, *bestHitForRec2 = 0x0;
+ Bool_t *hitForRecCh1Used = new Bool_t[fNHitsForRecPerChamber[ch1]];
+ for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) hitForRecCh1Used[hit1] = kFALSE;
+ //
+ //Extrapolate trackCandidate to chamber "ch2" to save computing time in the next steps
+ AliMUONTrackParam *extrapTrackParamPtr = trackCandidate->GetExtrapTrackParam();
+ *extrapTrackParamPtr = *((AliMUONTrackParam*)(trackCandidate->GetTrackParamAtHit()->First()));
+ AliMUONTrackExtrap::ExtrapToZCov(extrapTrackParamPtr, zCh2);
+ AliMUONTrackParam extrapTrackParamSave(*extrapTrackParamPtr);
+ //
+ // Printout for debuging
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
+ TMatrixD* paramCovForDebug = extrapTrackParamPtr->GetCovariances();
+ cout<<endl<<"Track parameter covariances at first hit extrapolated to z = "<<zCh2<<":"<<endl;
+ paramCovForDebug->Print();
+ }
+ //
+ // look for candidates in chamber 2
+ // Printout for debuging
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+ cout << "FollowTrackInStation: look for hits in chamber(1..): " << ch2+1 << endl;
+ }
+ for (Int_t hit2 = 0; hit2 < fNHitsForRecPerChamber[ch2]; hit2++) {
+ hitForRecCh2 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch2]+hit2);
+ // extrapolate track parameters and covariances only once for this hit
+ AliMUONTrackExtrap::ExtrapToZCov(extrapTrackParamPtr, hitForRecCh2->GetZ());
+ chi2WithOneHitForRec = trackCandidate->TryOneHitForRec(hitForRecCh2);
+ // if good chi2 then try to attach a hitForRec in the other chamber too
+ if (chi2WithOneHitForRec < maxChi2WithOneHitForRec) {
+ // Printout for debuging
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+ cout << "FollowTrackInStation: look for second hits in chamber(1..): " << ch1+1 << endl;
+ }
+ Bool_t foundSecondHit = kFALSE;
+ for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) {
+ hitForRecCh1 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch1]+hit1);
+ chi2WithTwoHitForRec = trackCandidate->TryTwoHitForRec(hitForRecCh2, hitForRecCh1); // order hits like that to save computing time
+ // if good chi2 then create a new track by adding the 2 hitForRec to the "trackCandidate"
+ if (chi2WithTwoHitForRec < maxChi2WithTwoHitForRec) {
+ foundSecondHit = kTRUE;
+ if (fgkTrackAllTracks) {
+ // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
+ newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(*trackCandidate);
+ fNRecTracks++;
+ AliMUONTrackParam TrackParam1(extrapTrackParamSave);
+ AliMUONTrackExtrap::ExtrapToZ(&TrackParam1, hitForRecCh1->GetZ());
+ newTrack->AddTrackParamAtHit(&TrackParam1,hitForRecCh1);
+ AliMUONTrackParam TrackParam2(extrapTrackParamSave);
+ AliMUONTrackExtrap::ExtrapToZ(&TrackParam2, hitForRecCh2->GetZ());
+ newTrack->AddTrackParamAtHit(&TrackParam2,hitForRecCh2);
+ // Sort TrackParamAtHit according to increasing Z
+ newTrack->GetTrackParamAtHit()->Sort();
+ // Update the chi2 of the new track
+ if (newTrack->GetFitFMin()<0) newTrack->SetFitFMin(chi2WithTwoHitForRec);
+ else newTrack->SetFitFMin(newTrack->GetFitFMin() + chi2WithTwoHitForRec);
+ // Tag hitForRecCh1 as used
+ hitForRecCh1Used[hit1] = kTRUE;
+ // Printout for debuging
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+ cout << "FollowTrackInStation: added two hits in station(1..): " << nextStation+1
+ << " (Chi2 = " << chi2WithTwoHitForRec << ")" << endl;
+ if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
+ }
+ } else if (chi2WithTwoHitForRec < bestChi2WithTwoHitForRec) {
+ // keep track of the best couple of hits
+ bestChi2WithTwoHitForRec = chi2WithTwoHitForRec;
+ bestHitForRec1 = hitForRecCh1;
+ bestHitForRec2 = hitForRecCh2;
+ }
+ }
+ }
+ // if no hitForRecCh1 found then consider to add hitForRecCh2 only
+ if (!foundSecondHit) {
+ if (fgkTrackAllTracks) {
+ // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
+ newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(*trackCandidate);
+ fNRecTracks++;
+ AliMUONTrackParam TrackParam1(extrapTrackParamSave);
+ AliMUONTrackExtrap::ExtrapToZ(&TrackParam1, hitForRecCh2->GetZ());
+ newTrack->AddTrackParamAtHit(&TrackParam1,hitForRecCh2);
+ // Sort TrackParamAtHit according to increasing Z
+ newTrack->GetTrackParamAtHit()->Sort();
+ // Update the chi2 of the new track
+ if (newTrack->GetFitFMin()<0) newTrack->SetFitFMin(chi2WithOneHitForRec);
+ else newTrack->SetFitFMin(newTrack->GetFitFMin() + chi2WithOneHitForRec);
+ // Printout for debuging
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+ cout << "FollowTrackInStation: added one hit in chamber(1..): " << ch2+1
+ << " (Chi2 = " << chi2WithOneHitForRec << ")" << endl;
+ if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
+ }
+ } if (!bestHitForRec2 && chi2WithOneHitForRec < bestChi2WithOneHitForRec) {
+ // keep track of the best single hitForRec except if a couple
+ // of hits has already been found (i.e. bestHitForRec2!=0x0)
+ bestChi2WithOneHitForRec = chi2WithOneHitForRec;
+ bestHitForRec1 = hitForRecCh2;
+ }
+ }
}
-
- fMUONData->SetTreeAddress("TC");
- fMUONData->GetTrigger();
-
- // global trigger for trigger pattern
- gloTrigPat = 0;
- globalTrigger = fMUONData->GlobalTrigger();
- gloTrg = (AliMUONGlobalTrigger*)globalTrigger->UncheckedAt(0);
-
- if (gloTrg)
- gloTrigPat = gloTrg->GetGlobalPattern();
+ // reset the extrapolated track parameter for next step
+ trackCandidate->SetExtrapTrackParam(&extrapTrackParamSave);
+ }
+ //
+ // look for candidates in chamber 1 not already attached to a track
+ // if we want to keep all possible tracks or if no good couple of hitForRec has been found
+ if (fgkTrackAllTracks || !bestHitForRec2) {
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+ cout << "FollowTrackInStation: look for single hits in chamber(1..): " << ch1+1 << endl;
+ }
+ for (Int_t hit1 = 0; hit1 < fNHitsForRecPerChamber[ch1]; hit1++) {
+ hitForRecCh1 = (AliMUONHitForRec*) fHitsForRecPtr->UncheckedAt(fIndexOfFirstHitForRecPerChamber[ch1]+hit1);
+ if (hitForRecCh1Used[hit1]) continue; // Skip hitForRec already used
+ chi2WithOneHitForRec = trackCandidate->TryOneHitForRec(hitForRecCh1);
+ // if good chi2 then create a new track by adding the good hitForRec in "ch1" to the "trackCandidate"
+ // We do not try to attach a hitForRec in the other chamber too since it has already been done above
+ if (chi2WithOneHitForRec < maxChi2WithOneHitForRec) {
+ if (fgkTrackAllTracks) {
+ // copy trackCandidate into a new track put at the end of fRecTracksPtr and add the new hitForRec's
+ newTrack = new ((*fRecTracksPtr)[fRecTracksPtr->GetLast()+1]) AliMUONTrack(*trackCandidate);
+ fNRecTracks++;
+ AliMUONTrackParam TrackParam1(extrapTrackParamSave);
+ AliMUONTrackExtrap::ExtrapToZ(&TrackParam1, hitForRecCh1->GetZ());
+ newTrack->AddTrackParamAtHit(&TrackParam1,hitForRecCh1);
+ // Sort TrackParamAtHit according to increasing Z
+ newTrack->GetTrackParamAtHit()->Sort();
+ // Update the chi2 of the new track
+ if (newTrack->GetFitFMin()<0) newTrack->SetFitFMin(chi2WithOneHitForRec);
+ else newTrack->SetFitFMin(newTrack->GetFitFMin() + chi2WithOneHitForRec);
+ // Printout for debuging
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+ cout << "FollowTrackInStation: added one hit in chamber(1..): " << ch1+1
+ << " (Chi2 = " << chi2WithOneHitForRec << ")" << endl;
+ if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
+ }
+ } if (!bestHitForRec2 && chi2WithOneHitForRec < bestChi2WithOneHitForRec) {
+ // keep track of the best single hitForRec except if a couple
+ // of hits has already been found (i.e. bestHitForRec1!=0x0)
+ bestChi2WithOneHitForRec = chi2WithOneHitForRec;
+ bestHitForRec1 = hitForRecCh1;
+ }
+ }
+ }
+ }
+ //
+ // fill out the best track if required else clean up the fRecTracksPtr array
+ if (!fgkTrackAllTracks && bestHitForRec1) {
+ AliMUONTrackParam TrackParam1(extrapTrackParamSave);
+ AliMUONTrackExtrap::ExtrapToZ(&TrackParam1, bestHitForRec1->GetZ());
+ trackCandidate->AddTrackParamAtHit(&TrackParam1,bestHitForRec1);
+ if (bestHitForRec2) {
+ AliMUONTrackParam TrackParam2(extrapTrackParamSave);
+ AliMUONTrackExtrap::ExtrapToZ(&TrackParam2, bestHitForRec2->GetZ());
+ trackCandidate->AddTrackParamAtHit(&TrackParam2,bestHitForRec2);
+ // Sort TrackParamAtHit according to increasing Z
+ trackCandidate->GetTrackParamAtHit()->Sort();
+ // Update the chi2 of the new track
+ if (trackCandidate->GetFitFMin()<0) trackCandidate->SetFitFMin(bestChi2WithTwoHitForRec);
+ else trackCandidate->SetFitFMin(trackCandidate->GetFitFMin() + bestChi2WithTwoHitForRec);
+ // Printout for debuging
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+ cout << "FollowTrackInStation: added the two best hits in station(1..): " << nextStation+1
+ << " (Chi2 = " << bestChi2WithTwoHitForRec << ")" << endl;
+ if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
+ }
+ } else {
+ // Sort TrackParamAtHit according to increasing Z
+ trackCandidate->GetTrackParamAtHit()->Sort();
+ // Update the chi2 of the new track
+ if (trackCandidate->GetFitFMin()<0) trackCandidate->SetFitFMin(bestChi2WithOneHitForRec);
+ else trackCandidate->SetFitFMin(trackCandidate->GetFitFMin() + bestChi2WithOneHitForRec);
+ // Printout for debuging
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 1) || (AliLog::GetGlobalDebugLevel() >= 1)) {
+ cout << "FollowTrackInStation: added the best hit in station(1..): " << nextStation+1
+ << " (Chi2 = " << bestChi2WithOneHitForRec << ")" << endl;
+ if (AliLog::GetGlobalDebugLevel() >= 3) newTrack->RecursiveDump();
+ }
+ }
+ } else {
+ fRecTracksPtr->Remove(trackCandidate); // obsolete track
+ fNRecTracks--;
+ }
-
- // local trigger for tracking
- localTrigger = fMUONData->LocalTrigger();
- Int_t nlocals = (Int_t) (localTrigger->GetEntries());
-
- Float_t z11 = AliMUONConstants::DefaultChamberZ(10);
- Float_t z21 = AliMUONConstants::DefaultChamberZ(12);
-
- Float_t y11 = 0.;
- Int_t stripX21 = 0;
- Float_t y21 = 0.;
- Float_t x11 = 0.;
-
- for (Int_t i=0; i<nlocals; i++) { // loop on Local Trigger
- locTrg = (AliMUONLocalTrigger*)localTrigger->UncheckedAt(i);
-
- AliDebug(1, "AliMUONTrackReconstructor::MakeTriggerTrack using NEW trigger \n");
- AliMUONTriggerCircuitNew* circuit =
- (AliMUONTriggerCircuitNew*)fTriggerCircuit->At(locTrg->LoCircuit()-1); // -1 !!!
-
- y11 = circuit->GetY11Pos(locTrg->LoStripX());
- stripX21 = locTrg->LoStripX()+locTrg->LoDev()+1;
- y21 = circuit->GetY21Pos(stripX21);
- x11 = circuit->GetX11Pos(locTrg->LoStripY());
-
- AliDebug(1, Form(" MakeTriggerTrack %d %d %d %d %d %f %f %f \n",i,locTrg->LoCircuit(),
- locTrg->LoStripX(),locTrg->LoStripX()+locTrg->LoDev()+1,locTrg->LoStripY(),y11, y21, x11));
-
- Float_t thetax = TMath::ATan2( x11 , z11 );
- Float_t thetay = TMath::ATan2( (y21-y11) , (z21-z11) );
-
- fTriggerTrack->SetX11(x11);
- fTriggerTrack->SetY11(y11);
- fTriggerTrack->SetThetax(thetax);
- fTriggerTrack->SetThetay(thetay);
- fTriggerTrack->SetGTPattern(gloTrigPat);
-
- fMUONData->AddRecTriggerTrack(*fTriggerTrack);
- } // end of loop on Local Trigger
- return kTRUE;
}
//__________________________________________________________________________
-Int_t AliMUONTrackReconstructor::MakeTrackCandidatesWithTwoSegments(AliMUONSegment *BegSegment)
+void AliMUONTrackReconstructor::SetVertexForFit(AliMUONTrack* trackCandidate)
{
- // To make track candidates with two segments in stations(1..) 4 and 5,
- // the first segment being pointed to by "BegSegment".
- // Returns the number of such track candidates.
- Int_t endStation, iEndSegment, nbCan2Seg;
- AliMUONSegment *endSegment;
- AliMUONSegment *extrapSegment = NULL;
- AliMUONTrack *recTrack;
- Double_t mcsFactor;
- AliDebug(1,"Enter MakeTrackCandidatesWithTwoSegments");
- // Station for the end segment
- endStation = 7 - (BegSegment->GetHitForRec1())->GetChamberNumber() / 2;
- // multiple scattering factor corresponding to one chamber
- mcsFactor = 0.0136 /
- GetBendingMomentumFromImpactParam(BegSegment->GetBendingImpact());
- mcsFactor = fChamberThicknessInX0 * mcsFactor * mcsFactor;
- // linear extrapolation to end station
- // number of candidates with 2 segments to 0
- nbCan2Seg = 0;
- // Loop over segments in the end station
- for (iEndSegment = 0; iEndSegment < fNSegments[endStation]; iEndSegment++) {
- // pointer to segment
- endSegment = (AliMUONSegment*) ((*fSegmentsPtr[endStation])[iEndSegment]);
- // test compatibility between current segment and "extrapSegment"
- // 4 because 4 quantities in chi2
- extrapSegment =
- BegSegment->CreateSegmentFromLinearExtrapToStation(endSegment->GetZ(), mcsFactor);
- if ((endSegment->
- NormalizedChi2WithSegment(extrapSegment,
- fMaxSigma2Distance)) <= 4.0) {
- // both segments compatible:
- // make track candidate from "begSegment" and "endSegment"
- AliDebug(2,Form("TrackCandidate with Segment %d in Station(0..) %d", iEndSegment, endStation));
- // flag for both segments in one track:
- // to be done in track constructor ????
- BegSegment->SetInTrack(kTRUE);
- endSegment->SetInTrack(kTRUE);
- recTrack = new ((*fRecTracksPtr)[fNRecTracks])
- AliMUONTrack(BegSegment, endSegment, this);
- fNRecTracks++;
- if (AliLog::GetGlobalDebugLevel() > 1) recTrack->RecursiveDump();
- // increment number of track candidates with 2 segments
- nbCan2Seg++;
- }
- delete extrapSegment; // should not delete HitForRec's it points to !!!!
- } // for (iEndSegment = 0;...
- return nbCan2Seg;
+ /// Add the vertex as a measured hit to constrain the fit of the "trackCandidate"
+ /// Compute the vertex resolution from natural vertex dispersion and
+ /// multiple scattering effets according to trackCandidate path in absorber
+ /// It is necessary to account for multiple scattering effects here instead of during the fit of
+ /// the "trackCandidate" to do not influence the result by changing track resolution at vertex
+ AliDebug(1,"Enter SetVertexForFit");
+
+ Double_t nonBendingReso2 = fNonBendingVertexDispersion * fNonBendingVertexDispersion;
+ Double_t bendingReso2 = fBendingVertexDispersion * fBendingVertexDispersion;
+ // add multiple scattering effets
+ AliMUONTrackParam paramAtVertex(*((AliMUONTrackParam*)(trackCandidate->GetTrackParamAtHit()->First())));
+ paramAtVertex.DeleteCovariances(); // to be sure to account only for multiple scattering
+ AliMUONTrackExtrap::ExtrapToVertexUncorrected(¶mAtVertex,0.);
+ TMatrixD* paramCov = paramAtVertex.GetCovariances();
+ nonBendingReso2 += (*paramCov)(0,0);
+ bendingReso2 += (*paramCov)(2,2);
+ // Set the vertex
+ AliMUONHitForRec vertex; // Coordinates set to (0.,0.,0.) by default
+ vertex.SetNonBendingReso2(nonBendingReso2);
+ vertex.SetBendingReso2(bendingReso2);
+ trackCandidate->SetVertex(&vertex);
}
//__________________________________________________________________________
-Int_t AliMUONTrackReconstructor::MakeTrackCandidatesWithOneSegmentAndOnePoint(AliMUONSegment *BegSegment)
+void AliMUONTrackReconstructor::Fit(AliMUONTrack *track, Bool_t includeMCS, Bool_t calcCov)
{
- // To make track candidates with one segment and one point
- // in stations(1..) 4 and 5,
- // the segment being pointed to by "BegSegment".
- Int_t ch, ch1, ch2, endStation, iHit, iHitMax, iHitMin, nbCan1Seg1Hit;
- AliMUONHitForRec *extrapHitForRec= NULL;
- AliMUONHitForRec *hit;
- AliMUONTrack *recTrack;
- Double_t mcsFactor;
- AliDebug(1,"Enter MakeTrackCandidatesWithOneSegmentAndOnePoint");
- // station for the end point
- endStation = 7 - (BegSegment->GetHitForRec1())->GetChamberNumber() / 2;
- // multiple scattering factor corresponding to one chamber
- mcsFactor = 0.0136 /
- GetBendingMomentumFromImpactParam(BegSegment->GetBendingImpact());
- mcsFactor = fChamberThicknessInX0 * mcsFactor * mcsFactor;
- // first and second chambers(0..) in the end station
- ch1 = 2 * endStation;
- ch2 = ch1 + 1;
- // number of candidates to 0
- nbCan1Seg1Hit = 0;
- // Loop over chambers of the end station
- for (ch = ch2; ch >= ch1; ch--) {
- // limits for the hit index in the loop
- iHitMin = fIndexOfFirstHitForRecPerChamber[ch];
- iHitMax = iHitMin + fNHitsForRecPerChamber[ch];
- // Loop over HitForRec's in the chamber
- for (iHit = iHitMin; iHit < iHitMax; iHit++) {
- // pointer to HitForRec
- hit = (AliMUONHitForRec*) ((*fHitsForRecPtr)[iHit]);
- // test compatibility between current HitForRec and "extrapHitForRec"
- // 2 because 2 quantities in chi2
- // linear extrapolation to chamber
- extrapHitForRec =
- BegSegment->CreateHitForRecFromLinearExtrapToChamber( hit->GetZ(), mcsFactor);
- if ((hit->
- NormalizedChi2WithHitForRec(extrapHitForRec,
- fMaxSigma2Distance)) <= 2.0) {
- // both HitForRec's compatible:
- // make track candidate from begSegment and current HitForRec
- AliDebug(2, Form("TrackCandidate with HitForRec %d in Chamber(0..) %d", iHit, ch));
- // flag for beginning segments in one track:
- // to be done in track constructor ????
- BegSegment->SetInTrack(kTRUE);
- recTrack = new ((*fRecTracksPtr)[fNRecTracks])
- AliMUONTrack(BegSegment, hit, this);
- // the right place to eliminate "double counting" ???? how ????
- fNRecTracks++;
- if (AliLog::GetGlobalDebugLevel() > 1) recTrack->RecursiveDump();
- // increment number of track candidates
- nbCan1Seg1Hit++;
- }
- delete extrapHitForRec;
- } // for (iHit = iHitMin;...
- } // for (ch = ch2;...
- return nbCan1Seg1Hit;
+ /// Fit the track "track" with or without multiple Coulomb scattering according to "includeMCS".
+
+ Double_t benC, errorParam, invBenP, nonBenC, x, y;
+ AliMUONTrackParam *trackParam;
+ Double_t arg[1], fedm, errdef, fitFMin;
+ Int_t npari, nparx;
+ Int_t status, covStatus;
+
+ // Clear MINUIT parameters
+ gMinuit->mncler();
+ // Give the fitted track to MINUIT
+ gMinuit->SetObjectFit(track);
+ if ((AliLog::GetDebugLevel("MUON","AliMUONTrackReconstructor") >= 2) || (AliLog::GetGlobalDebugLevel() >= 2)) {
+ // Define print level
+ arg[0] = 1;
+ gMinuit->mnexcm("SET PRI", arg, 1, status);
+ // Print covariance matrix
+ gMinuit->mnexcm("SHO COV", arg, 0, status);
+ } else {
+ arg[0] = -1;
+ gMinuit->mnexcm("SET PRI", arg, 1, status);
+ }
+ // No warnings
+ gMinuit->mnexcm("SET NOW", arg, 0, status);
+ // Define strategy
+ //arg[0] = 2;
+ //gMinuit->mnexcm("SET STR", arg, 1, status);
+
+ // Switch between available FCN according to "includeMCS"
+ if (includeMCS) gMinuit->SetFCN(TrackChi2MCS);
+ else gMinuit->SetFCN(TrackChi2);
+
+ // Set fitted parameters (!! The order is very important for the covariance matrix !!)
+ trackParam = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
+ // could be tried with no limits for the search (min=max=0) ????
+ // mandatory limits in non Bending to avoid NaN values of parameters
+ gMinuit->mnparm(0, "X", trackParam->GetNonBendingCoor(), 0.03, -500.0, 500.0, status);
+ gMinuit->mnparm(1, "NonBenS", trackParam->GetNonBendingSlope(), 0.001, -0.5, 0.5, status);
+ // mandatory limits in Bending to avoid NaN values of parameters
+ gMinuit->mnparm(2, "Y", trackParam->GetBendingCoor(), 0.10, -500.0, 500.0, status);
+ gMinuit->mnparm(3, "BenS", trackParam->GetBendingSlope(), 0.001, -0.5, 0.5, status);
+ gMinuit->mnparm(4, "InvBenP", trackParam->GetInverseBendingMomentum(), 0.003, -0.4, 0.4, status);
+
+ // minimization
+ gMinuit->mnexcm("MIGRAD", arg, 0, status);
+
+ // Calculate the covariance matrix more accurately if required
+ if (calcCov) gMinuit->mnexcm("HESSE", arg, 0, status);
+
+ // get results into "invBenP", "benC", "nonBenC" ("x", "y")
+ gMinuit->GetParameter(0, x, errorParam);
+ trackParam->SetNonBendingCoor(x);
+ gMinuit->GetParameter(1, nonBenC, errorParam);
+ trackParam->SetNonBendingSlope(nonBenC);
+ gMinuit->GetParameter(2, y, errorParam);
+ trackParam->SetBendingCoor(y);
+ gMinuit->GetParameter(3, benC, errorParam);
+ trackParam->SetBendingSlope(benC);
+ gMinuit->GetParameter(4, invBenP, errorParam);
+ trackParam->SetInverseBendingMomentum(invBenP);
+
+ // global result of the fit
+ gMinuit->mnstat(fitFMin, fedm, errdef, npari, nparx, covStatus);
+ track->SetFitFMin(fitFMin);
+
+ // Get the covariance matrix if required
+ if (calcCov) {
+ // Covariance matrix according to HESSE status
+ // If problem then keep only the diagonal terms (variances)
+ Double_t matrix[5][5];
+ gMinuit->mnemat(&matrix[0][0],5);
+ if (covStatus == 3) trackParam->SetCovariances(matrix);
+ else trackParam->SetVariances(matrix);
+ } else *(trackParam->GetCovariances()) = 0;
+
}
//__________________________________________________________________________
-void AliMUONTrackReconstructor::MakeTrackCandidates(void)
+void TrackChi2(Int_t & /*NParam*/, Double_t * /*Gradient*/, Double_t &Chi2, Double_t *Param, Int_t /*Flag*/)
{
- // To make track candidates
- // with at least 3 aligned points in stations(1..) 4 and 5
- // (two Segment's or one Segment and one HitForRec)
- Int_t begStation, iBegSegment, nbCan1Seg1Hit, nbCan2Seg;
- AliMUONSegment *begSegment;
- AliDebug(1,"Enter MakeTrackCandidates");
- // Loop over stations(1..) 5 and 4 for the beginning segment
- for (begStation = 4; begStation > 2; begStation--) {
- // Loop over segments in the beginning station
- for (iBegSegment = 0; iBegSegment < fNSegments[begStation]; iBegSegment++) {
- // pointer to segment
- begSegment = (AliMUONSegment*) ((*fSegmentsPtr[begStation])[iBegSegment]);
- AliDebug(2,Form("Look for TrackCandidate's with Segment %d in Station(0..) %d", iBegSegment, begStation));
- // Look for track candidates with two segments,
- // "begSegment" and all compatible segments in other station.
- // Only for beginning station(1..) 5
- // because candidates with 2 segments have to looked for only once.
- if (begStation == 4)
- nbCan2Seg = MakeTrackCandidatesWithTwoSegments(begSegment);
- // Look for track candidates with one segment and one point,
- // "begSegment" and all compatible HitForRec's in other station.
- // Only if "begSegment" does not belong already to a track candidate.
- // Is that a too strong condition ????
- if (!(begSegment->GetInTrack()))
- nbCan1Seg1Hit = MakeTrackCandidatesWithOneSegmentAndOnePoint(begSegment);
- } // for (iBegSegment = 0;...
- } // for (begStation = 4;...
- return;
+ /// Return the "Chi2" to be minimized with Minuit for track fitting,
+ /// with "NParam" parameters
+ /// and their current values in array pointed to by "Param".
+ /// Assumes that the track hits are sorted according to increasing Z.
+ /// Track parameters at each TrackHit are updated accordingly.
+ /// Multiple Coulomb scattering is not taken into account
+
+ AliMUONTrack *trackBeingFitted = (AliMUONTrack*) gMinuit->GetObjectFit();
+// AliMUONTrack *trackBeingFitted = (AliMUONTrack*) AliMUONTrackReconstructor::Fitter()->GetObjectFit();
+ AliMUONTrackParam param1;
+ AliMUONTrackParam* trackParamAtHit;
+ AliMUONHitForRec* hitForRec;
+ Chi2 = 0.0; // initialize Chi2
+ Double_t dX, dY;
+
+ // copy of track parameters to be fitted
+ param1 = *((AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->First()));
+ param1.SetNonBendingCoor(Param[0]);
+ param1.SetNonBendingSlope(Param[1]);
+ param1.SetBendingCoor(Param[2]);
+ param1.SetBendingSlope(Param[3]);
+ param1.SetInverseBendingMomentum(Param[4]);
+
+ // Take the vertex into account in the fit if required
+ if (trackBeingFitted->GetFitWithVertex()) {
+ AliMUONTrackParam paramAtVertex(param1);
+ AliMUONTrackExtrap::ExtrapToZ(¶mAtVertex, 0.);
+ AliMUONHitForRec *vertex = trackBeingFitted->GetVertex();
+ if (!vertex) {
+ cout<<"Error in TrackChi2: Want to use the vertex in tracking but it has not been created!!"<<endl;
+ exit(-1);
+ }
+ dX = vertex->GetNonBendingCoor() - paramAtVertex.GetNonBendingCoor();
+ dY = vertex->GetBendingCoor() - paramAtVertex.GetBendingCoor();
+ Chi2 += dX * dX / vertex->GetNonBendingReso2() + dY * dY / vertex->GetBendingReso2();
+ }
+
+ // Follow track through all planes of track hits
+ trackParamAtHit = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->First());
+ while (trackParamAtHit) {
+ hitForRec = trackParamAtHit->GetHitForRecPtr();
+ // extrapolation to the plane of the hitForRec attached to the current trackParamAtHit
+ AliMUONTrackExtrap::ExtrapToZ(¶m1, hitForRec->GetZ());
+ // update track parameters of the current hit
+ trackParamAtHit->SetTrackParam(param1);
+ // Increment Chi2
+ // done hit per hit, with hit resolution,
+ // and not with point and angle like in "reco_muon.F" !!!!
+ dX = hitForRec->GetNonBendingCoor() - param1.GetNonBendingCoor();
+ dY = hitForRec->GetBendingCoor() - param1.GetBendingCoor();
+ Chi2 = Chi2 + dX * dX / hitForRec->GetNonBendingReso2() + dY * dY / hitForRec->GetBendingReso2();
+ trackParamAtHit = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->After(trackParamAtHit));
+ }
}
//__________________________________________________________________________
-void AliMUONTrackReconstructor::FollowTracks(void)
+void TrackChi2MCS(Int_t & /*NParam*/, Double_t * /*Gradient*/, Double_t &Chi2, Double_t *Param, Int_t /*Flag*/)
{
- // Follow tracks in stations(1..) 3, 2 and 1
- // too long: should be made more modular !!!!
- AliMUONHitForRec *bestHit, *extrapHit, *hit;
- AliMUONSegment *bestSegment, *extrapSegment, *segment;
- AliMUONTrack *track, *nextTrack;
- AliMUONTrackParam *trackParam1, trackParam[2], trackParamVertex;
- // -1 to avoid compilation warnings
- Int_t ch = -1, chInStation, chBestHit = -1, iHit, iSegment, station, trackIndex;
- Double_t bestChi2, chi2, dZ1, dZ2, dZ3, maxSigma2Distance, mcsFactor;
- Double_t bendingMomentum, chi2Norm = 0.;
-
-
- // local maxSigma2Distance, for easy increase in testing
- maxSigma2Distance = fMaxSigma2Distance;
- AliDebug(2,"Enter FollowTracks");
- // Loop over track candidates
- track = (AliMUONTrack*) fRecTracksPtr->First();
- trackIndex = -1;
- while (track) {
- // Follow function for each track candidate ????
- trackIndex++;
- nextTrack = (AliMUONTrack*) fRecTracksPtr->After(track); // prepare next track
- AliDebug(2,Form("FollowTracks: track candidate(0..): %d", trackIndex));
- // Fit track candidate
- track->SetFitMCS(0); // without multiple Coulomb scattering
- track->SetFitNParam(3); // with 3 parameters (X = Y = 0)
- track->SetFitStart(0); // from parameters at vertex
- track->Fit();
- if (AliLog::GetGlobalDebugLevel()> 2) {
- cout << "FollowTracks: track candidate(0..): " << trackIndex
- << " after fit in stations(0..) 3 and 4" << endl;
- track->RecursiveDump();
+ /// Return the "Chi2" to be minimized with Minuit for track fitting,
+ /// with "NParam" parameters
+ /// and their current values in array pointed to by "Param".
+ /// Assumes that the track hits are sorted according to increasing Z.
+ /// Track parameters at each TrackHit are updated accordingly.
+ /// Multiple Coulomb scattering is taken into account with covariance matrix.
+
+ AliMUONTrack *trackBeingFitted = (AliMUONTrack*) gMinuit->GetObjectFit();
+// AliMUONTrack *trackBeingFitted = (AliMUONTrack*) AliMUONTrackReconstructor::Fitter()->GetObjectFit();
+ AliMUONTrackParam param1;
+ AliMUONTrackParam* trackParamAtHit;
+ AliMUONHitForRec* hitForRec;
+ Chi2 = 0.0; // initialize Chi2
+ Int_t chCurrent, chPrev = 0, hitNumber, hitNumber1, hitNumber2, hitNumber3;
+ Double_t z1, z2, z3;
+ AliMUONTrackParam *trackParamAtHit1, *trackParamAtHit2, *trackParamAtHit3;
+ AliMUONHitForRec *hitForRec1, *hitForRec2;
+ Double_t hbc1, hbc2, pbc1, pbc2;
+ Double_t hnbc1, hnbc2, pnbc1, pnbc2;
+ Int_t numberOfHit = trackBeingFitted->GetNTrackHits();
+ TMatrixD *covBending = new TMatrixD(numberOfHit, numberOfHit);
+ TMatrixD *covNonBending = new TMatrixD(numberOfHit, numberOfHit);
+ Double_t *msa2 = new Double_t[numberOfHit];
+
+ // copy of track parameters to be fitted
+ param1 = *((AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->First()));
+ param1.SetNonBendingCoor(Param[0]);
+ param1.SetNonBendingSlope(Param[1]);
+ param1.SetBendingCoor(Param[2]);
+ param1.SetBendingSlope(Param[3]);
+ param1.SetInverseBendingMomentum(Param[4]);
+
+ // Take the vertex into account in the fit if required
+ if (trackBeingFitted->GetFitWithVertex()) {
+ AliMUONTrackParam paramAtVertex(param1);
+ AliMUONTrackExtrap::ExtrapToZ(¶mAtVertex, 0.);
+ AliMUONHitForRec *vertex = trackBeingFitted->GetVertex();
+ if (!vertex) {
+ cout<<"Error in TrackChi2MCS: Want to use the vertex in tracking but it has not been created!!"<<endl;
+ exit(-1);
}
- // Loop over stations(1..) 3, 2 and 1
- // something SPECIAL for stations 2 and 1 for majority 3 coincidence ????
- // otherwise: majority coincidence 2 !!!!
- for (station = 2; station >= 0; station--) {
- // Track parameters at first track hit (smallest Z)
- trackParam1 = ((AliMUONTrackHit*)
- (track->GetTrackHitsPtr()->First()))->GetTrackParam();
- // extrapolation to station
- trackParam1->ExtrapToStation(station, trackParam);
- extrapSegment = new AliMUONSegment(); // empty segment
- // multiple scattering factor corresponding to one chamber
- // and momentum in bending plane (not total)
- mcsFactor = 0.0136 * trackParam1->GetInverseBendingMomentum();
- mcsFactor = fChamberThicknessInX0 * mcsFactor * mcsFactor;
- // Z difference from previous station
- dZ1 = AliMUONConstants::DefaultChamberZ(2 * station) -
- AliMUONConstants::DefaultChamberZ(2 * station + 2);
- // Z difference between the two previous stations
- dZ2 = AliMUONConstants::DefaultChamberZ(2 * station + 2) -
- AliMUONConstants::DefaultChamberZ(2 * station + 4);
- // Z difference between the two chambers in the previous station
- dZ3 = AliMUONConstants::DefaultChamberZ(2 * station) -
- AliMUONConstants::DefaultChamberZ(2 * station + 1);
- extrapSegment->SetBendingCoorReso2(fBendingResolution * fBendingResolution);
- extrapSegment->
- SetNonBendingCoorReso2(fNonBendingResolution * fNonBendingResolution);
- extrapSegment->UpdateFromStationTrackParam
- (trackParam, mcsFactor, dZ1, dZ2, dZ3, station,
- trackParam1->GetInverseBendingMomentum());
- bestChi2 = 5.0;
- bestSegment = NULL;
- if (AliLog::GetGlobalDebugLevel() > 2) {
- cout << "FollowTracks: track candidate(0..): " << trackIndex
- << " Look for segment in station(0..): " << station << endl;
- }
+ Double_t dX = vertex->GetNonBendingCoor() - paramAtVertex.GetNonBendingCoor();
+ Double_t dY = vertex->GetBendingCoor() - paramAtVertex.GetBendingCoor();
+ Chi2 += dX * dX / vertex->GetNonBendingReso2() + dY * dY / vertex->GetBendingReso2();
+ }
+
+ // Predicted coordinates and multiple scattering angles are first calculated
+ for (hitNumber = 0; hitNumber < numberOfHit; hitNumber++) {
+ trackParamAtHit = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber));
+ hitForRec = trackParamAtHit->GetHitForRecPtr();
+ // extrapolation to the plane of the hitForRec attached to the current trackParamAtHit
+ AliMUONTrackExtrap::ExtrapToZ(¶m1, hitForRec->GetZ());
+ // update track parameters of the current hit
+ trackParamAtHit->SetTrackParam(param1);
+ // square of multiple scattering angle at current hit, with one chamber
+ msa2[hitNumber] = MultipleScatteringAngle2(¶m1);
+ // correction for eventual missing hits or multiple hits in a chamber,
+ // according to the number of chambers
+ // between the current hit and the previous one
+ chCurrent = hitForRec->GetChamberNumber();
+ if (hitNumber > 0) msa2[hitNumber] = msa2[hitNumber] * (chCurrent - chPrev);
+ chPrev = chCurrent;
+ }
- // Loop over segments in station
- for (iSegment = 0; iSegment < fNSegments[station]; iSegment++) {
- // Look for best compatible Segment in station
- // should consider all possibilities ????
- // multiple scattering ????
- // separation in 2 functions: Segment and HitForRec ????
- segment = (AliMUONSegment*) ((*fSegmentsPtr[station])[iSegment]);
- // correction of corrected segment (fBendingCoor and fNonBendingCoor)
- // according to real Z value of "segment" and slopes of "extrapSegment"
- (&(trackParam[0]))->ExtrapToZ(segment->GetZ());
- (&(trackParam[1]))->ExtrapToZ(segment->GetZ());
- extrapSegment->SetBendingCoor((&(trackParam[0]))->GetBendingCoor());
- extrapSegment->SetNonBendingCoor((&(trackParam[0]))->GetNonBendingCoor());
- extrapSegment->SetBendingSlope((&(trackParam[0]))->GetBendingSlope());
- extrapSegment->SetNonBendingSlope((&(trackParam[0]))->GetNonBendingSlope());
- chi2 = segment->
- NormalizedChi2WithSegment(extrapSegment, maxSigma2Distance);
- if (chi2 < bestChi2) {
- // update best Chi2 and Segment if better found
- bestSegment = segment;
- bestChi2 = chi2;
- }
+ // Calculates the covariance matrix
+ for (hitNumber1 = 0; hitNumber1 < numberOfHit; hitNumber1++) {
+ trackParamAtHit1 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber1));
+ hitForRec1 = trackParamAtHit1->GetHitForRecPtr();
+ z1 = hitForRec1->GetZ();
+ for (hitNumber2 = hitNumber1; hitNumber2 < numberOfHit; hitNumber2++) {
+ trackParamAtHit2 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber2));
+ z2 = trackParamAtHit2->GetHitForRecPtr()->GetZ();
+ // initialization to 0 (diagonal plus upper triangular part)
+ (*covBending)(hitNumber2, hitNumber1) = 0.0;
+ // contribution from multiple scattering in bending plane:
+ // loop over upstream hits
+ for (hitNumber3 = 0; hitNumber3 < hitNumber1; hitNumber3++) {
+ trackParamAtHit3 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber3));
+ z3 = trackParamAtHit3->GetHitForRecPtr()->GetZ();
+ (*covBending)(hitNumber2, hitNumber1) = (*covBending)(hitNumber2, hitNumber1) + ((z1 - z3) * (z2 - z3) * msa2[hitNumber3]);
}
- if (bestSegment) {
- // best segment found: add it to track candidate
- (&(trackParam[0]))->ExtrapToZ(bestSegment->GetZ());
- (&(trackParam[1]))->ExtrapToZ(bestSegment->GetZ());
- track->AddSegment(bestSegment);
- // set track parameters at these two TrakHit's
- track->SetTrackParamAtHit(track->GetNTrackHits() - 2, &(trackParam[0]));
- track->SetTrackParamAtHit(track->GetNTrackHits() - 1, &(trackParam[1]));
- AliDebug(3, Form("FollowTracks: track candidate(0..): %d Added segment in station(0..): %d", trackIndex, station));
- if (AliLog::GetGlobalDebugLevel()>2) track->RecursiveDump();
- }
- else {
- // No best segment found:
- // Look for best compatible HitForRec in station:
- // should consider all possibilities ????
- // multiple scattering ???? do about like for extrapSegment !!!!
- extrapHit = new AliMUONHitForRec(); // empty hit
- bestChi2 = 3.0;
- bestHit = NULL;
- AliDebug(3, Form("FollowTracks: track candidate(0..): %d Segment not found, look for hit in station(0..): %d ",
- trackIndex, station));
-
- // Loop over chambers of the station
- for (chInStation = 0; chInStation < 2; chInStation++) {
- ch = 2 * station + chInStation;
- for (iHit = fIndexOfFirstHitForRecPerChamber[ch];
- iHit < fIndexOfFirstHitForRecPerChamber[ch] +
- fNHitsForRecPerChamber[ch];
- iHit++) {
- hit = (AliMUONHitForRec*) ((*fHitsForRecPtr)[iHit]);
- // coordinates of extrapolated hit
- (&(trackParam[chInStation]))->ExtrapToZ(hit->GetZ());
- extrapHit->
- SetBendingCoor((&(trackParam[chInStation]))->GetBendingCoor());
- extrapHit->
- SetNonBendingCoor((&(trackParam[chInStation]))->GetNonBendingCoor());
- // resolutions from "extrapSegment"
- extrapHit->SetBendingReso2(extrapSegment->GetBendingCoorReso2());
- extrapHit->SetNonBendingReso2(extrapSegment->GetNonBendingCoorReso2());
- // Loop over hits in the chamber
- // condition for hit not already in segment ????
- chi2 = hit->NormalizedChi2WithHitForRec(extrapHit, maxSigma2Distance);
- if (chi2 < bestChi2) {
- // update best Chi2 and HitForRec if better found
- bestHit = hit;
- bestChi2 = chi2;
- chBestHit = chInStation;
- }
- }
- }
- if (bestHit) {
- // best hit found: add it to track candidate
- (&(trackParam[chBestHit]))->ExtrapToZ(bestHit->GetZ());
- track->AddHitForRec(bestHit);
- // set track parameters at this TrackHit
- track->SetTrackParamAtHit(track->GetNTrackHits() - 1,
- &(trackParam[chBestHit]));
- if (AliLog::GetGlobalDebugLevel() > 2) {
- cout << "FollowTracks: track candidate(0..): " << trackIndex
- << " Added hit in station(0..): " << station << endl;
- track->RecursiveDump();
- }
- }
- else {
- // Remove current track candidate
- // and corresponding TrackHit's, ...
- track->Remove();
- delete extrapSegment;
- delete extrapHit;
- break; // stop the search for this candidate:
- // exit from the loop over station
- }
- delete extrapHit;
- }
- delete extrapSegment;
- // Sort track hits according to increasing Z
- track->GetTrackHitsPtr()->Sort();
- // Update track parameters at first track hit (smallest Z)
- trackParam1 = ((AliMUONTrackHit*)
- (track->GetTrackHitsPtr()->First()))->GetTrackParam();
- bendingMomentum = 0.;
- if (TMath::Abs(trackParam1->GetInverseBendingMomentum()) > 0.)
- bendingMomentum = TMath::Abs(1/(trackParam1->GetInverseBendingMomentum()));
- // Track removed if bendingMomentum not in window [min, max]
- if ((bendingMomentum < fMinBendingMomentum) || (bendingMomentum > fMaxBendingMomentum)) {
- track->Remove();
- break; // stop the search for this candidate:
- // exit from the loop over station
- }
- // Track fit
- // with multiple Coulomb scattering if all stations
- if (station == 0) track->SetFitMCS(1);
- // without multiple Coulomb scattering if not all stations
- else track->SetFitMCS(0);
- track->SetFitNParam(5); // with 5 parameters (momentum and position)
- track->SetFitStart(1); // from parameters at first hit
- track->Fit();
- Double_t numberOfDegFree = (2.0 * track->GetNTrackHits() - 5);
- if (numberOfDegFree > 0) {
- chi2Norm = track->GetFitFMin() / numberOfDegFree;
+ // equal contribution from multiple scattering in non bending plane
+ (*covNonBending)(hitNumber2, hitNumber1) = (*covBending)(hitNumber2, hitNumber1);
+ if (hitNumber1 == hitNumber2) {
+ // Diagonal elements: add contribution from position measurements
+ // in bending plane
+ (*covBending)(hitNumber2, hitNumber1) = (*covBending)(hitNumber2, hitNumber1) + hitForRec1->GetBendingReso2();
+ // and in non bending plane
+ (*covNonBending)(hitNumber2, hitNumber1) = (*covNonBending)(hitNumber2, hitNumber1) + hitForRec1->GetNonBendingReso2();
} else {
- chi2Norm = 1.e10;
+ // Non diagonal elements: symmetrization
+ // for bending plane
+ (*covBending)(hitNumber1, hitNumber2) = (*covBending)(hitNumber2, hitNumber1);
+ // and non bending plane
+ (*covNonBending)(hitNumber1, hitNumber2) = (*covNonBending)(hitNumber2, hitNumber1);
}
- // Track removed if normalized chi2 too high
- if (chi2Norm > fMaxChi2) {
- track->Remove();
- break; // stop the search for this candidate:
- // exit from the loop over station
- }
- if (AliLog::GetGlobalDebugLevel() > 2) {
- cout << "FollowTracks: track candidate(0..): " << trackIndex
- << " after fit from station(0..): " << station << " to 4" << endl;
- track->RecursiveDump();
- }
- // Track extrapolation to the vertex through the absorber (Branson)
- // after going through the first station
- if (station == 0) {
- trackParamVertex = *trackParam1;
- (&trackParamVertex)->ExtrapToVertex(0.,0.,0.);
- track->SetTrackParamAtVertex(&trackParamVertex);
- if (AliLog::GetGlobalDebugLevel() > 0) {
- cout << "FollowTracks: track candidate(0..): " << trackIndex
- << " after extrapolation to vertex" << endl;
- track->RecursiveDump();
- }
+ } // for (hitNumber2 = hitNumber1;...
+ } // for (hitNumber1 = 0;...
+
+ // Inversion of covariance matrices
+ Int_t ifailBending;
+ gMinuit->mnvert(&((*covBending)(0,0)), numberOfHit, numberOfHit, numberOfHit, ifailBending);
+ Int_t ifailNonBending;
+ gMinuit->mnvert(&((*covNonBending)(0,0)), numberOfHit, numberOfHit, numberOfHit, ifailNonBending);
+
+ // It would be worth trying to calculate the inverse of the covariance matrix
+ // only once per fit, since it cannot change much in principle,
+ // and it would save a lot of computing time !!!!
+
+ // Calculates Chi2
+ if ((ifailBending == 0) && (ifailNonBending == 0)) {
+ // with Multiple Scattering if inversion correct
+ for (hitNumber1 = 0; hitNumber1 < numberOfHit ; hitNumber1++) {
+ trackParamAtHit1 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber1));
+ hitForRec1 = trackParamAtHit1->GetHitForRecPtr();
+ hbc1 = hitForRec1->GetBendingCoor();
+ pbc1 = trackParamAtHit1->GetBendingCoor();
+ hnbc1 = hitForRec1->GetNonBendingCoor();
+ pnbc1 = trackParamAtHit1->GetNonBendingCoor();
+ for (hitNumber2 = 0; hitNumber2 < numberOfHit; hitNumber2++) {
+ trackParamAtHit2 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber2));
+ hitForRec2 = trackParamAtHit2->GetHitForRecPtr();
+ hbc2 = hitForRec2->GetBendingCoor();
+ pbc2 = trackParamAtHit2->GetBendingCoor();
+ hnbc2 = hitForRec2->GetNonBendingCoor();
+ pnbc2 = trackParamAtHit2->GetNonBendingCoor();
+ Chi2 += ((*covBending)(hitNumber2, hitNumber1) * (hbc1 - pbc1) * (hbc2 - pbc2)) +
+ ((*covNonBending)(hitNumber2, hitNumber1) * (hnbc1 - pnbc1) * (hnbc2 - pnbc2));
}
- } // for (station = 2;...
- // go really to next track
- track = nextTrack;
- } // while (track)
- // Compression of track array (necessary after Remove ????)
- fRecTracksPtr->Compress();
- return;
+ }
+ } else {
+ // without Multiple Scattering if inversion impossible
+ for (hitNumber1 = 0; hitNumber1 < numberOfHit ; hitNumber1++) {
+ trackParamAtHit1 = (AliMUONTrackParam*) (trackBeingFitted->GetTrackParamAtHit()->UncheckedAt(hitNumber1));
+ hitForRec1 = trackParamAtHit1->GetHitForRecPtr();
+ hbc1 = hitForRec1->GetBendingCoor();
+ pbc1 = trackParamAtHit1->GetBendingCoor();
+ hnbc1 = hitForRec1->GetNonBendingCoor();
+ pnbc1 = trackParamAtHit1->GetNonBendingCoor();
+ Chi2 += ((hbc1 - pbc1) * (hbc1 - pbc1) / hitForRec1->GetBendingReso2()) +
+ ((hnbc1 - pnbc1) * (hnbc1 - pnbc1) / hitForRec1->GetNonBendingReso2());
+ }
+ }
+
+ delete covBending;
+ delete covNonBending;
+ delete [] msa2;
}
//__________________________________________________________________________
-void AliMUONTrackReconstructor::RemoveDoubleTracks(void)
+Double_t MultipleScatteringAngle2(AliMUONTrackParam *param)
{
- // To remove double tracks.
- // Tracks are considered identical
- // if they have at least half of their hits in common.
- // Among two identical tracks, one keeps the track with the larger number of hits
- // or, if these numbers are equal, the track with the minimum Chi2.
- AliMUONTrack *track1, *track2, *trackToRemove;
- Bool_t identicalTracks;
- Int_t hitsInCommon, nHits1, nHits2;
- identicalTracks = kTRUE;
- while (identicalTracks) {
- identicalTracks = kFALSE;
- // Loop over first track of the pair
- track1 = (AliMUONTrack*) fRecTracksPtr->First();
- while (track1 && (!identicalTracks)) {
- nHits1 = track1->GetNTrackHits();
- // Loop over second track of the pair
- track2 = (AliMUONTrack*) fRecTracksPtr->After(track1);
- while (track2 && (!identicalTracks)) {
- nHits2 = track2->GetNTrackHits();
- // number of hits in common between two tracks
- hitsInCommon = track1->HitsInCommon(track2);
- // check for identical tracks
- if ((4 * hitsInCommon) >= (nHits1 + nHits2)) {
- identicalTracks = kTRUE;
- // decide which track to remove
- if (nHits1 > nHits2) trackToRemove = track2;
- else if (nHits1 < nHits2) trackToRemove = track1;
- else if ((track1->GetFitFMin()) < (track2->GetFitFMin()))
- trackToRemove = track2;
- else trackToRemove = track1;
- // remove it
- trackToRemove->Remove();
- }
- track2 = (AliMUONTrack*) fRecTracksPtr->After(track2);
- } // track2
- track1 = (AliMUONTrack*) fRecTracksPtr->After(track1);
- } // track1
- }
- return;
+ /// Returns square of multiple Coulomb scattering angle
+ /// from TrackParamAtHit pointed to by "param"
+ Double_t slopeBending, slopeNonBending, radiationLength, inverseBendingMomentum2, inverseTotalMomentum2;
+ Double_t varMultipleScatteringAngle;
+ slopeBending = param->GetBendingSlope();
+ slopeNonBending = param->GetNonBendingSlope();
+ // thickness in radiation length for the current track,
+ // taking local angle into account
+ radiationLength = AliMUONConstants::ChamberThicknessInX0() *
+ TMath::Sqrt(1.0 + slopeBending*slopeBending + slopeNonBending*slopeNonBending);
+ inverseBendingMomentum2 = param->GetInverseBendingMomentum() * param->GetInverseBendingMomentum();
+ inverseTotalMomentum2 = inverseBendingMomentum2 * (1.0 + slopeBending * slopeBending) /
+ (1.0 + slopeBending *slopeBending + slopeNonBending * slopeNonBending);
+ varMultipleScatteringAngle = 0.0136 * (1.0 + 0.038 * TMath::Log(radiationLength));
+ // The velocity is assumed to be 1 !!!!
+ varMultipleScatteringAngle = inverseTotalMomentum2 * radiationLength * varMultipleScatteringAngle * varMultipleScatteringAngle;
+ return varMultipleScatteringAngle;
}
//__________________________________________________________________________
-void AliMUONTrackReconstructor::UpdateTrackParamAtHit()
+void AliMUONTrackReconstructor::ExtrapTracksToVertex()
{
- // Set track parameters after track fitting. Fill fTrackParamAtHit of AliMUONTrack's
+ /// propagate tracks to the vertex through the absorber (Branson)
AliMUONTrack *track;
- AliMUONTrackHit *trackHit;
- AliMUONTrackParam *trackParam;
- track = (AliMUONTrack*) fRecTracksPtr->First();
- while (track) {
- trackHit = (AliMUONTrackHit*) (track->GetTrackHitsPtr())->First();
- while (trackHit) {
- trackParam = trackHit->GetTrackParam();
- track->AddTrackParamAtHit(trackParam);
- trackHit = (AliMUONTrackHit*) (track->GetTrackHitsPtr())->After(trackHit);
- } // trackHit
- track = (AliMUONTrack*) fRecTracksPtr->After(track);
- } // track
- return;
+ AliMUONTrackParam trackParamVertex;
+ AliMUONHitForRec *vertex;
+ Double_t vX, vY, vZ;
+
+ for (Int_t iRecTrack = 0; iRecTrack <fNRecTracks; iRecTrack++) {
+ track = (AliMUONTrack*) fRecTracksPtr->UncheckedAt(iRecTrack);
+ trackParamVertex = *((AliMUONTrackParam*)(track->GetTrackParamAtHit()->First()));
+ vertex = track->GetVertex();
+ if (vertex) { // if track as a vertex defined, use it
+ vX = vertex->GetNonBendingCoor();
+ vY = vertex->GetBendingCoor();
+ vZ = vertex->GetZ();
+ } else { // else vertex = (0.,0.,0.)
+ vX = 0.;
+ vY = 0.;
+ vZ = 0.;
+ }
+ AliMUONTrackExtrap::ExtrapToVertex(&trackParamVertex, vX, vY, vZ);
+ track->SetTrackParamAtVertex(&trackParamVertex);
+
+ if (AliLog::GetGlobalDebugLevel() > 0) {
+ cout << "FollowTracks: track candidate(0..): " << iRecTrack
+ << " after extrapolation to vertex" << endl;
+ track->RecursiveDump();
+ }
+ }
+
}
//__________________________________________________________________________
-void AliMUONTrackReconstructor::UpdateHitForRecAtHit()
+void AliMUONTrackReconstructor::FillMUONTrack()
{
- // Set cluster parameterss after track fitting. Fill fHitForRecAtHit of AliMUONTrack's
+ /// Fill fHitForRecAtHit of AliMUONTrack's
AliMUONTrack *track;
- AliMUONTrackHit *trackHit;
- AliMUONHitForRec *hitForRec;
+ AliMUONTrackParam *trackParamAtHit;
track = (AliMUONTrack*) fRecTracksPtr->First();
while (track) {
- trackHit = (AliMUONTrackHit*) (track->GetTrackHitsPtr())->First();
- while (trackHit) {
- hitForRec = trackHit->GetHitForRecPtr();
- track->AddHitForRecAtHit(hitForRec);
- trackHit = (AliMUONTrackHit*) (track->GetTrackHitsPtr())->After(trackHit);
- } // trackHit
+ trackParamAtHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->First());
+ while (trackParamAtHit) {
+ track->AddHitForRecAtHit(trackParamAtHit->GetHitForRecPtr());
+ trackParamAtHit = (AliMUONTrackParam*) (track->GetTrackParamAtHit()->After(trackParamAtHit));
+ }
track = (AliMUONTrack*) fRecTracksPtr->After(track);
- } // track
- return;
-}
-
- //__________________________________________________________________________
-void AliMUONTrackReconstructor::FillMUONTrack()
-{
- // Set track parameters at hits for Kalman track. Fill fTrackParamAtHit of AliMUONTrack's
- AliMUONTrackK *track;
- track = (AliMUONTrackK*) fRecTracksPtr->First();
- while (track) {
- track->FillMUONTrack();
- track = (AliMUONTrackK*) fRecTracksPtr->After(track);
- }
+ }
return;
}
//__________________________________________________________________________
void AliMUONTrackReconstructor::EventDump(void)
{
- // Dump reconstructed event (track parameters at vertex and at first hit),
- // and the particle parameters
-
+ /// Dump reconstructed event (track parameters at vertex and at first hit),
+ /// and the particle parameters
AliMUONTrack *track;
AliMUONTrackParam *trackParam, *trackParam1;
Double_t bendingSlope, nonBendingSlope, pYZ;
fRecTracksPtr->Compress(); // for simple loop without "Next" since no hole
// Loop over reconstructed tracks
for (trackIndex = 0; trackIndex < fNRecTracks; trackIndex++) {
- if (fTrackMethod != 1) continue; //AZ - skip the rest for now
AliDebug(1, Form("track number: %d", trackIndex));
// function for each track for modularity ????
track = (AliMUONTrack*) ((*fRecTracksPtr)[trackIndex]);
z, x, y, pX, pY, pZ, c));
// track parameters at first hit
- trackParam1 = ((AliMUONTrackHit*)
- (track->GetTrackHitsPtr()->First()))->GetTrackParam();
+ trackParam1 = (AliMUONTrackParam*) track->GetTrackParamAtHit()->First();
x = trackParam1->GetNonBendingCoor();
y = trackParam1->GetBendingCoor();
z = trackParam1->GetZ();
}
-//__________________________________________________________________________
-void AliMUONTrackReconstructor::EventDumpTrigger(void)
-{
- // Dump reconstructed trigger event
- // and the particle parameters
-
- AliMUONTriggerTrack *triggertrack ;
- Int_t nTriggerTracks = fMUONData->RecTriggerTracks()->GetEntriesFast();
-
- AliDebug(1, "****** enter EventDumpTrigger ******");
- AliDebug(1, Form("Number of Reconstructed tracks : %d ", nTriggerTracks));
-
- // Loop over reconstructed tracks
- for (Int_t trackIndex = 0; trackIndex < nTriggerTracks; trackIndex++) {
- triggertrack = (AliMUONTriggerTrack*)fMUONData->RecTriggerTracks()->At(trackIndex);
- printf(" trigger track number %i x11=%f y11=%f thetax=%f thetay=%f \n",
- trackIndex,
- triggertrack->GetX11(),triggertrack->GetY11(),
- triggertrack->GetThetax(),triggertrack->GetThetay());
- }
-}
-
-//__________________________________________________________________________
-void AliMUONTrackReconstructor::MakeTrackCandidatesK(void)
-{
- // To make initial tracks for Kalman filter from the list of segments
- Int_t istat, iseg;
- AliMUONSegment *segment;
- AliMUONTrackK *trackK;
-
- AliDebug(1,"Enter MakeTrackCandidatesK");
-
- AliMUONTrackK a(this, fHitsForRecPtr);
- // Loop over stations(1...) 5 and 4
- for (istat=4; istat>=3; istat--) {
- // Loop over segments in the station
- for (iseg=0; iseg<fNSegments[istat]; iseg++) {
- // Transform segments to tracks and evaluate covariance matrix
- segment = (AliMUONSegment*) ((*fSegmentsPtr[istat])[iseg]);
- trackK = new ((*fRecTracksPtr)[fNRecTracks++]) AliMUONTrackK(segment);
- } // for (iseg=0;...)
- } // for (istat=4;...)
- return;
-}
-
-//__________________________________________________________________________
-void AliMUONTrackReconstructor::FollowTracksK(void)
-{
- // Follow tracks using Kalman filter
- Bool_t ok;
- Int_t icand, ichamBeg = 0, ichamEnd, chamBits;
- Double_t zDipole1, zDipole2;
- AliMUONTrackK *trackK;
- AliMUONHitForRec *hit;
- AliMUONRawCluster *clus;
- TClonesArray *rawclusters;
- clus = 0; rawclusters = 0;
-
- zDipole1 = GetSimpleBPosition() + GetSimpleBLength()/2;
- zDipole2 = zDipole1 - GetSimpleBLength();
-
- // Print hits
- trackK = (AliMUONTrackK*) ((*fRecTracksPtr)[0]);
-
- if (trackK->DebugLevel() > 0) {
- for (Int_t i1=0; i1<fNHitsForRec; i1++) {
- hit = (AliMUONHitForRec*) ((*fHitsForRecPtr)[i1]);
- printf(" Hit # %d %10.4f %10.4f %10.4f",
- hit->GetChamberNumber(), hit->GetBendingCoor(),
- hit->GetNonBendingCoor(), hit->GetZ());
-
- // from raw clusters
- rawclusters = fMUONData->RawClusters(hit->GetChamberNumber());
- clus = (AliMUONRawCluster*) rawclusters->UncheckedAt(hit->
- GetHitNumber());
- printf(" %d", clus->GetTrack(1));
- if (clus->GetTrack(2) != -1) printf(" %d \n", clus->GetTrack(2));
- else printf("\n");
-
- }
- } // if (trackK->DebugLevel() > 0)
-
- icand = -1;
- Int_t nSeeds;
- nSeeds = fNRecTracks; // starting number of seeds
- // Loop over track candidates
- while (icand < fNRecTracks-1) {
- icand ++;
- if (trackK->DebugLevel()>0) cout << " *** Kalman track candidate No. " << icand << endl;
- trackK = (AliMUONTrackK*) ((*fRecTracksPtr)[icand]);
- if (trackK->GetRecover() < 0) continue; // failed track
-
- // Discard candidate which will produce the double track
- /*
- if (icand > 0) {
- ok = CheckCandidateK(icand,nSeeds);
- if (!ok) {
- trackK->SetRecover(-1); // mark candidate to be removed
- continue;
- }
- }
- */
-
- ok = kTRUE;
- if (trackK->GetRecover() == 0)
- hit = (AliMUONHitForRec*) trackK->GetTrackHits()->Last(); // last hit
- else
- hit = trackK->GetHitLastOk(); // hit where track stopped
-
- if (hit) ichamBeg = hit->GetChamberNumber();
- ichamEnd = 0;
- // Check propagation direction
- if (!hit) { ichamBeg = ichamEnd; AliFatal(" ??? "); }
- else if (trackK->GetTrackDir() < 0) {
- ichamEnd = 9; // forward propagation
- ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kFALSE,zDipole1,zDipole2);
- if (ok) {
- ichamBeg = ichamEnd;
- ichamEnd = 6; // backward propagation
- // Change weight matrix and zero fChi2 for backpropagation
- trackK->StartBack();
- trackK->SetTrackDir(1);
- ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kTRUE,zDipole1,zDipole2);
- ichamBeg = ichamEnd;
- ichamEnd = 0;
- }
- } else {
- if (trackK->GetBPFlag()) {
- // backpropagation
- ichamEnd = 6; // backward propagation
- // Change weight matrix and zero fChi2 for backpropagation
- trackK->StartBack();
- ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kTRUE,zDipole1,zDipole2);
- ichamBeg = ichamEnd;
- ichamEnd = 0;
- }
- }
-
- if (ok) {
- trackK->SetTrackDir(1);
- trackK->SetBPFlag(kFALSE);
- ok = trackK->KalmanFilter(ichamBeg,ichamEnd,kFALSE,zDipole1,zDipole2);
- }
- if (!ok) { trackK->SetRecover(-1); continue; } // mark candidate to be removed
-
- // Apply smoother
- if (trackK->GetRecover() >= 0) {
- ok = trackK->Smooth();
- if (!ok) trackK->SetRecover(-1); // mark candidate to be removed
- }
-
- // Majority 3 of 4 in first 2 stations
- if (!ok) continue;
- chamBits = 0;
- Double_t chi2max = 0;
- for (Int_t i=0; i<trackK->GetNTrackHits(); i++) {
- hit = (AliMUONHitForRec*) (*trackK->GetTrackHits())[i];
- chamBits |= BIT(hit->GetChamberNumber());
- if (trackK->GetChi2PerPoint(i) > chi2max) chi2max = trackK->GetChi2PerPoint(i);
- }
- if (!((chamBits&3)==3 || (chamBits>>2&3)==3) && chi2max > 25) {
- //trackK->Recover();
- trackK->SetRecover(-1); //mark candidate to be removed
- continue;
- }
- if (ok) trackK->SetTrackQuality(0); // compute "track quality"
- } // while
-
- for (Int_t i=0; i<fNRecTracks; i++) {
- trackK = (AliMUONTrackK*) ((*fRecTracksPtr)[i]);
- if (trackK->GetRecover() < 0) fRecTracksPtr->RemoveAt(i);
- }
-
- // Compress TClonesArray
- fRecTracksPtr->Compress();
- fNRecTracks = fRecTracksPtr->GetEntriesFast();
- return;
-}
-
-//__________________________________________________________________________
-Bool_t AliMUONTrackReconstructor::CheckCandidateK(Int_t icand, Int_t nSeeds) const
-{
- // Discards track candidate if it will produce the double track (having
- // the same seed segment hits as hits of a good track found before)
- AliMUONTrackK *track1, *track2;
- AliMUONHitForRec *hit1, *hit2, *hit;
-
- track1 = (AliMUONTrackK*) ((*fRecTracksPtr)[icand]);
- hit1 = (AliMUONHitForRec*) (*track1->GetTrackHits())[0]; // 1'st hit
- hit2 = (AliMUONHitForRec*) (*track1->GetTrackHits())[1]; // 2'nd hit
-
- for (Int_t i=0; i<icand; i++) {
- track2 = (AliMUONTrackK*) ((*fRecTracksPtr)[i]);
- //if (track2->GetRecover() < 0) continue;
- if (track2->GetRecover() < 0 && icand >= nSeeds) continue;
-
- if (track1->GetStartSegment() == track2->GetStartSegment()) {
- return kFALSE;
- } else {
- Int_t nSame = 0;
- for (Int_t j=0; j<track2->GetNTrackHits(); j++) {
- hit = (AliMUONHitForRec*) (*track2->GetTrackHits())[j];
- if (hit == hit1 || hit == hit2) {
- nSame++;
- if (nSame == 2) return kFALSE;
- }
- } // for (Int_t j=0;
- }
- } // for (Int_t i=0;
- return kTRUE;
-}
-
-//__________________________________________________________________________
-void AliMUONTrackReconstructor::RemoveDoubleTracksK(void)
-{
- // Removes double tracks (sharing more than half of their hits). Keeps
- // the track with higher quality
- AliMUONTrackK *track1, *track2, *trackToKill;
-
- // Sort tracks according to their quality
- fRecTracksPtr->Sort();
-
- // Loop over first track of the pair
- track1 = (AliMUONTrackK*) fRecTracksPtr->First();
- Int_t debug = track1->DebugLevel();
- while (track1) {
- // Loop over second track of the pair
- track2 = (AliMUONTrackK*) fRecTracksPtr->After(track1);
- while (track2) {
- // Check whether or not to keep track2
- if (!track2->KeepTrack(track1)) {
- if (debug >= 0) cout << " Killed track: " << 1/(*track2->GetTrackParameters())(4,0) <<
- " " << track2->GetTrackQuality() << endl;
- trackToKill = track2;
- track2 = (AliMUONTrackK*) fRecTracksPtr->After(track2);
- trackToKill->Kill();
- fRecTracksPtr->Compress();
- } else track2 = (AliMUONTrackK*) fRecTracksPtr->After(track2);
- } // track2
- track1 = (AliMUONTrackK*) fRecTracksPtr->After(track1);
- } // track1
-
- fNRecTracks = fRecTracksPtr->GetEntriesFast();
- if (debug >= 0) cout << " Number of Kalman tracks: " << fNRecTracks << endl;
-}
-
-//__________________________________________________________________________
-void AliMUONTrackReconstructor::GoToVertex(void)
-{
- // Propagates track to the vertex thru absorber
- // (using Branson correction for now)
-
- Double_t zVertex;
- zVertex = 0;
- for (Int_t i=0; i<fNRecTracks; i++) {
- //((AliMUONTrackK*)(*fRecTracksPtr)[i])->Branson();
- ((AliMUONTrackK*)(*fRecTracksPtr)[i])->SetTrackQuality(1); // compute Chi2
- //((AliMUONTrackK*)(*fRecTracksPtr)[i])->GoToZ(zVertex); // w/out absorber
- ((AliMUONTrackK*)(*fRecTracksPtr)[i])->GoToVertex(1); // with absorber
- }
-}
-
-//__________________________________________________________________________
-void AliMUONTrackReconstructor::SetTrackMethod(Int_t iTrackMethod)
-{
- // Set track method and recreate track container if necessary
-
- fTrackMethod = TMath::Min (iTrackMethod, 3);
- fTrackMethod = TMath::Max (fTrackMethod, 1);
- if (fTrackMethod != 1) {
- if (fRecTracksPtr) delete fRecTracksPtr;
- fRecTracksPtr = new TClonesArray("AliMUONTrackK", 10);
- if (fTrackMethod == 2) cout << " *** Tracking with the Kalman filter *** " << endl;
- else cout << " *** Combined cluster / track finder ***" << endl;
- } else cout << " *** Original tracking *** " << endl;
-
-}